The great whitespace cleanup

This commit is contained in:
Andrew Rabert 2018-03-24 15:25:12 -04:00
parent 75ad0a0239
commit a72f978001
256 changed files with 20257 additions and 20257 deletions

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson Copyright 2014 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.activity; package net.nullsum.audinaut.activity;
@ -46,200 +46,200 @@ import net.nullsum.audinaut.util.LoadingTask;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
public class EditPlayActionActivity extends SubsonicActivity { public class EditPlayActionActivity extends SubsonicActivity {
private CheckBox shuffleCheckbox; private CheckBox shuffleCheckbox;
private CheckBox startYearCheckbox; private CheckBox startYearCheckbox;
private EditText startYearBox; private EditText startYearBox;
private CheckBox endYearCheckbox; private CheckBox endYearCheckbox;
private EditText endYearBox; private EditText endYearBox;
private Button genreButton; private Button genreButton;
private Spinner offlineSpinner; private Spinner offlineSpinner;
private String doNothing; private String doNothing;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setTitle(R.string.tasker_start_playing_title); setTitle(R.string.tasker_start_playing_title);
setContentView(R.layout.edit_play_action); setContentView(R.layout.edit_play_action);
final Activity context = this; final Activity context = this;
doNothing = context.getResources().getString(R.string.tasker_edit_do_nothing); doNothing = context.getResources().getString(R.string.tasker_edit_do_nothing);
shuffleCheckbox = (CheckBox) findViewById(R.id.edit_shuffle_checkbox); shuffleCheckbox = (CheckBox) findViewById(R.id.edit_shuffle_checkbox);
shuffleCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { shuffleCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton view, boolean isChecked) { public void onCheckedChanged(CompoundButton view, boolean isChecked) {
startYearCheckbox.setEnabled(isChecked); startYearCheckbox.setEnabled(isChecked);
endYearCheckbox.setEnabled(isChecked); endYearCheckbox.setEnabled(isChecked);
genreButton.setEnabled(isChecked); genreButton.setEnabled(isChecked);
} }
}); });
startYearCheckbox = (CheckBox) findViewById(R.id.edit_start_year_checkbox); startYearCheckbox = (CheckBox) findViewById(R.id.edit_start_year_checkbox);
startYearBox = (EditText) findViewById(R.id.edit_start_year); startYearBox = (EditText) findViewById(R.id.edit_start_year);
// Disable/enable number box if checked // Disable/enable number box if checked
startYearCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { startYearCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton view, boolean isChecked) { public void onCheckedChanged(CompoundButton view, boolean isChecked) {
startYearBox.setEnabled(isChecked); startYearBox.setEnabled(isChecked);
} }
}); });
endYearCheckbox = (CheckBox) findViewById(R.id.edit_end_year_checkbox); endYearCheckbox = (CheckBox) findViewById(R.id.edit_end_year_checkbox);
endYearBox = (EditText) findViewById(R.id.edit_end_year); endYearBox = (EditText) findViewById(R.id.edit_end_year);
endYearCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { endYearCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton view, boolean isChecked) { public void onCheckedChanged(CompoundButton view, boolean isChecked) {
endYearBox.setEnabled(isChecked); endYearBox.setEnabled(isChecked);
} }
}); });
genreButton = (Button) findViewById(R.id.edit_genre_spinner); genreButton = (Button) findViewById(R.id.edit_genre_spinner);
genreButton.setOnClickListener(new View.OnClickListener() { genreButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) { public void onClick(View v) {
new LoadingTask<List<Genre>>(context, true) { new LoadingTask<List<Genre>>(context, true) {
@Override @Override
protected List<Genre> doInBackground() throws Throwable { protected List<Genre> doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(context); MusicService musicService = MusicServiceFactory.getMusicService(context);
return musicService.getGenres(false, context, this); return musicService.getGenres(false, context, this);
} }
@Override @Override
protected void done(final List<Genre> genres) { protected void done(final List<Genre> genres) {
List<String> names = new ArrayList<String>(); List<String> names = new ArrayList<String>();
String blank = context.getResources().getString(R.string.select_genre_blank); String blank = context.getResources().getString(R.string.select_genre_blank);
names.add(doNothing); names.add(doNothing);
names.add(blank); names.add(blank);
for(Genre genre: genres) { for(Genre genre: genres) {
names.add(genre.getName()); names.add(genre.getName());
} }
final List<String> finalNames = names; final List<String> finalNames = names;
AlertDialog.Builder builder = new AlertDialog.Builder(context); AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.shuffle_pick_genre) builder.setTitle(R.string.shuffle_pick_genre)
.setItems(names.toArray(new CharSequence[names.size()]), new DialogInterface.OnClickListener() { .setItems(names.toArray(new CharSequence[names.size()]), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
if(which == 1) { if(which == 1) {
genreButton.setText(""); genreButton.setText("");
} else { } else {
genreButton.setText(finalNames.get(which)); genreButton.setText(finalNames.get(which));
} }
} }
}); });
AlertDialog dialog = builder.create(); AlertDialog dialog = builder.create();
dialog.show(); dialog.show();
} }
@Override @Override
protected void error(Throwable error) { protected void error(Throwable error) {
String msg; String msg;
if (error instanceof OfflineException) { if (error instanceof OfflineException) {
msg = getErrorMessage(error); msg = getErrorMessage(error);
} else { } else {
msg = context.getResources().getString(R.string.playlist_error) + " " + getErrorMessage(error); msg = context.getResources().getString(R.string.playlist_error) + " " + getErrorMessage(error);
} }
Util.toast(context, msg, false); Util.toast(context, msg, false);
} }
}.execute(); }.execute();
} }
}); });
genreButton.setText(doNothing); genreButton.setText(doNothing);
offlineSpinner = (Spinner) findViewById(R.id.edit_offline_spinner); offlineSpinner = (Spinner) findViewById(R.id.edit_offline_spinner);
ArrayAdapter<CharSequence> offlineAdapter = ArrayAdapter.createFromResource(this, R.array.editServerOptions, android.R.layout.simple_spinner_item); ArrayAdapter<CharSequence> offlineAdapter = ArrayAdapter.createFromResource(this, R.array.editServerOptions, android.R.layout.simple_spinner_item);
offlineAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); offlineAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
offlineSpinner.setAdapter(offlineAdapter); offlineSpinner.setAdapter(offlineAdapter);
// Setup default for everything // Setup default for everything
Bundle extras = getIntent().getBundleExtra(Constants.TASKER_EXTRA_BUNDLE); Bundle extras = getIntent().getBundleExtra(Constants.TASKER_EXTRA_BUNDLE);
if(extras != null) { if(extras != null) {
if(extras.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE)) { if(extras.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE)) {
shuffleCheckbox.setChecked(true); shuffleCheckbox.setChecked(true);
} }
String startYear = extras.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, null); String startYear = extras.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, null);
if(startYear != null) { if(startYear != null) {
startYearCheckbox.setEnabled(true); startYearCheckbox.setEnabled(true);
startYearBox.setText(startYear); startYearBox.setText(startYear);
} }
String endYear = extras.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, null); String endYear = extras.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, null);
if(endYear != null) { if(endYear != null) {
endYearCheckbox.setEnabled(true); endYearCheckbox.setEnabled(true);
endYearBox.setText(endYear); endYearBox.setText(endYear);
} }
String genre = extras.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, doNothing); String genre = extras.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, doNothing);
if(genre != null) { if(genre != null) {
genreButton.setText(genre); genreButton.setText(genre);
} }
int offline = extras.getInt(Constants.PREFERENCES_KEY_OFFLINE, 0); int offline = extras.getInt(Constants.PREFERENCES_KEY_OFFLINE, 0);
if(offline != 0) { if(offline != 0) {
offlineSpinner.setSelection(offline); offlineSpinner.setSelection(offline);
} }
} }
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
} }
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater(); MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.tasker_configuration, menu); menuInflater.inflate(R.menu.tasker_configuration, menu);
return true; return true;
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId() == android.R.id.home) { if(item.getItemId() == android.R.id.home) {
cancel(); cancel();
return true; return true;
} else if(item.getItemId() == R.id.menu_accept) { } else if(item.getItemId() == R.id.menu_accept) {
accept(); accept();
return true; return true;
} else if(item.getItemId() == R.id.menu_cancel) { } else if(item.getItemId() == R.id.menu_cancel) {
cancel(); cancel();
return true; return true;
} }
return false; return false;
} }
private void accept() { private void accept() {
Intent intent = new Intent(); Intent intent = new Intent();
String blurb = getResources().getString(shuffleCheckbox.isChecked() ? R.string.tasker_start_playing_shuffled : R.string.tasker_start_playing); String blurb = getResources().getString(shuffleCheckbox.isChecked() ? R.string.tasker_start_playing_shuffled : R.string.tasker_start_playing);
intent.putExtra("com.twofortyfouram.locale.intent.extra.BLURB", blurb); intent.putExtra("com.twofortyfouram.locale.intent.extra.BLURB", blurb);
// Get settings user specified // Get settings user specified
Bundle data = new Bundle(); Bundle data = new Bundle();
boolean shuffle = shuffleCheckbox.isChecked(); boolean shuffle = shuffleCheckbox.isChecked();
data.putBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, shuffle); data.putBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, shuffle);
if(shuffle) { if(shuffle) {
if(startYearCheckbox.isChecked()) { if(startYearCheckbox.isChecked()) {
data.putString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, startYearBox.getText().toString()); data.putString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, startYearBox.getText().toString());
} }
if(endYearCheckbox.isChecked()) { if(endYearCheckbox.isChecked()) {
data.putString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, endYearBox.getText().toString()); data.putString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, endYearBox.getText().toString());
} }
String genre = genreButton.getText().toString(); String genre = genreButton.getText().toString();
if(!genre.equals(doNothing)) { if(!genre.equals(doNothing)) {
data.putString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, genre); data.putString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, genre);
} }
} }
int offline = offlineSpinner.getSelectedItemPosition(); int offline = offlineSpinner.getSelectedItemPosition();
if(offline != 0) { if(offline != 0) {
data.putInt(Constants.PREFERENCES_KEY_OFFLINE, offline); data.putInt(Constants.PREFERENCES_KEY_OFFLINE, offline);
} }
intent.putExtra(Constants.TASKER_EXTRA_BUNDLE, data); intent.putExtra(Constants.TASKER_EXTRA_BUNDLE, data);
setResult(Activity.RESULT_OK, intent); setResult(Activity.RESULT_OK, intent);
finish(); finish();
} }
private void cancel() { private void cancel() {
setResult(Activity.RESULT_CANCELED); setResult(Activity.RESULT_CANCELED);
finish(); finish();
} }
} }

View File

@ -38,48 +38,48 @@ import net.nullsum.audinaut.provider.AudinautSearchProvider;
*/ */
public class QueryReceiverActivity extends Activity { public class QueryReceiverActivity extends Activity {
private static final String TAG = QueryReceiverActivity.class.getSimpleName(); private static final String TAG = QueryReceiverActivity.class.getSimpleName();
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
Intent intent = getIntent(); Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) { if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
doSearch(); doSearch();
} else if(Intent.ACTION_VIEW.equals(intent.getAction())) { } else if(Intent.ACTION_VIEW.equals(intent.getAction())) {
showResult(intent.getDataString(), intent.getStringExtra(SearchManager.EXTRA_DATA_KEY)); showResult(intent.getDataString(), intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
} }
finish(); finish();
Util.disablePendingTransition(this); Util.disablePendingTransition(this);
} }
private void doSearch() { private void doSearch() {
String query = getIntent().getStringExtra(SearchManager.QUERY); String query = getIntent().getStringExtra(SearchManager.QUERY);
if (query != null) { if (query != null) {
Intent intent = new Intent(QueryReceiverActivity.this, SubsonicFragmentActivity.class); Intent intent = new Intent(QueryReceiverActivity.this, SubsonicFragmentActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_QUERY, query); intent.putExtra(Constants.INTENT_EXTRA_NAME_QUERY, query);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(QueryReceiverActivity.this, intent); Util.startActivityWithoutTransition(QueryReceiverActivity.this, intent);
} }
} }
private void showResult(String albumId, String name) { private void showResult(String albumId, String name) {
if (albumId != null) { if (albumId != null) {
Intent intent = new Intent(this, SubsonicFragmentActivity.class); Intent intent = new Intent(this, SubsonicFragmentActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(Constants.INTENT_EXTRA_VIEW_ALBUM, true); intent.putExtra(Constants.INTENT_EXTRA_VIEW_ALBUM, true);
if(albumId.indexOf("ar-") == 0) { if(albumId.indexOf("ar-") == 0) {
intent.putExtra(Constants.INTENT_EXTRA_NAME_ARTIST, true); intent.putExtra(Constants.INTENT_EXTRA_NAME_ARTIST, true);
albumId = albumId.replace("ar-", ""); albumId = albumId.replace("ar-", "");
} else if(albumId.indexOf("so-") == 0) { } else if(albumId.indexOf("so-") == 0) {
intent.putExtra(Constants.INTENT_EXTRA_SEARCH_SONG, name); intent.putExtra(Constants.INTENT_EXTRA_SEARCH_SONG, name);
albumId = albumId.replace("so-", ""); albumId = albumId.replace("so-", "");
} }
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, albumId); intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, albumId);
if (name != null) { if (name != null) {
intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, name); intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, name);
} }
Util.startActivityWithoutTransition(this, intent); Util.startActivityWithoutTransition(this, intent);
} }
} }
} }

View File

@ -28,29 +28,29 @@ import net.nullsum.audinaut.fragments.SettingsFragment;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
public class SettingsActivity extends SubsonicActivity { public class SettingsActivity extends SubsonicActivity {
private static final String TAG = SettingsActivity.class.getSimpleName(); private static final String TAG = SettingsActivity.class.getSimpleName();
private PreferenceCompatFragment fragment; private PreferenceCompatFragment fragment;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
lastSelectedPosition = R.id.drawer_settings; lastSelectedPosition = R.id.drawer_settings;
setContentView(R.layout.settings_activity); setContentView(R.layout.settings_activity);
if (savedInstanceState == null) { if (savedInstanceState == null) {
fragment = new SettingsFragment(); fragment = new SettingsFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putInt(Constants.INTENT_EXTRA_FRAGMENT_TYPE, R.xml.settings); args.putInt(Constants.INTENT_EXTRA_FRAGMENT_TYPE, R.xml.settings);
fragment.setArguments(args); fragment.setArguments(args);
fragment.setRetainInstance(true); fragment.setRetainInstance(true);
currentFragment = fragment; currentFragment = fragment;
currentFragment.setPrimaryFragment(true); currentFragment.setPrimaryFragment(true);
getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, currentFragment, currentFragment.getSupportTag() + "").commit(); getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, currentFragment, currentFragment.getSupportTag() + "").commit();
} }
Toolbar mainToolbar = (Toolbar) findViewById(R.id.main_toolbar); Toolbar mainToolbar = (Toolbar) findViewById(R.id.main_toolbar);
setSupportActionBar(mainToolbar); setSupportActionBar(mainToolbar);
} }
} }

View File

@ -40,7 +40,7 @@ import net.nullsum.audinaut.provider.AudinautSearchProvider;
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class VoiceQueryReceiverActivity extends Activity { public class VoiceQueryReceiverActivity extends Activity {
private static final String TAG = VoiceQueryReceiverActivity.class.getSimpleName(); private static final String TAG = VoiceQueryReceiverActivity.class.getSimpleName();
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -53,7 +53,7 @@ public class VoiceQueryReceiverActivity extends Activity {
intent.putExtra(Constants.INTENT_EXTRA_NAME_QUERY, query); intent.putExtra(Constants.INTENT_EXTRA_NAME_QUERY, query);
intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
intent.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, getIntent().getStringExtra(MediaStore.EXTRA_MEDIA_FOCUS)); intent.putExtra(MediaStore.EXTRA_MEDIA_FOCUS, getIntent().getStringExtra(MediaStore.EXTRA_MEDIA_FOCUS));
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(VoiceQueryReceiverActivity.this, intent); Util.startActivityWithoutTransition(VoiceQueryReceiverActivity.this, intent);
} }
finish(); finish();

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
@ -24,21 +24,21 @@ import net.nullsum.audinaut.util.ImageLoader;
import net.nullsum.audinaut.view.FastScroller; import net.nullsum.audinaut.view.FastScroller;
public class AlphabeticalAlbumAdapter extends EntryInfiniteGridAdapter implements FastScroller.BubbleTextGetter { public class AlphabeticalAlbumAdapter extends EntryInfiniteGridAdapter implements FastScroller.BubbleTextGetter {
public AlphabeticalAlbumAdapter(Context context, List<MusicDirectory.Entry> entries, ImageLoader imageLoader, boolean largeCell) { public AlphabeticalAlbumAdapter(Context context, List<MusicDirectory.Entry> entries, ImageLoader imageLoader, boolean largeCell) {
super(context, entries, imageLoader, largeCell); super(context, entries, imageLoader, largeCell);
} }
@Override @Override
public String getTextToShowInBubble(int position) { public String getTextToShowInBubble(int position) {
// Make sure that we are not trying to get an item for the loading placeholder // Make sure that we are not trying to get an item for the loading placeholder
if(position >= sections.get(0).size()) { if(position >= sections.get(0).size()) {
if(sections.get(0).size() > 0) { if(sections.get(0).size() > 0) {
return getTextToShowInBubble(position - 1); return getTextToShowInBubble(position - 1);
} else { } else {
return "*"; return "*";
} }
} else { } else {
return getNameIndex(getItemForPosition(position).getAlbum()); return getNameIndex(getItemForPosition(position).getAlbum());
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
@ -38,125 +38,125 @@ import net.nullsum.audinaut.view.SongView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
public class ArtistAdapter extends SectionAdapter<Serializable> implements FastScroller.BubbleTextGetter { public class ArtistAdapter extends SectionAdapter<Serializable> implements FastScroller.BubbleTextGetter {
public static int VIEW_TYPE_SONG = 3; public static int VIEW_TYPE_SONG = 3;
public static int VIEW_TYPE_ARTIST = 4; public static int VIEW_TYPE_ARTIST = 4;
private List<MusicFolder> musicFolders; private List<MusicFolder> musicFolders;
private OnMusicFolderChanged onMusicFolderChanged; private OnMusicFolderChanged onMusicFolderChanged;
public ArtistAdapter(Context context, List<Serializable> artists, OnItemClickedListener listener) { public ArtistAdapter(Context context, List<Serializable> artists, OnItemClickedListener listener) {
this(context, artists, null, listener, null); this(context, artists, null, listener, null);
} }
public ArtistAdapter(Context context, List<Serializable> artists, List<MusicFolder> musicFolders, OnItemClickedListener onItemClickedListener, OnMusicFolderChanged onMusicFolderChanged) { public ArtistAdapter(Context context, List<Serializable> artists, List<MusicFolder> musicFolders, OnItemClickedListener onItemClickedListener, OnMusicFolderChanged onMusicFolderChanged) {
super(context, artists); super(context, artists);
this.musicFolders = musicFolders; this.musicFolders = musicFolders;
this.onItemClickedListener = onItemClickedListener; this.onItemClickedListener = onItemClickedListener;
this.onMusicFolderChanged = onMusicFolderChanged; this.onMusicFolderChanged = onMusicFolderChanged;
if(musicFolders != null) { if(musicFolders != null) {
this.singleSectionHeader = true; this.singleSectionHeader = true;
} }
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) { public UpdateView.UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) {
final View header = LayoutInflater.from(context).inflate(R.layout.select_artist_header, parent, false); final View header = LayoutInflater.from(context).inflate(R.layout.select_artist_header, parent, false);
header.setOnClickListener(new View.OnClickListener() { header.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
PopupMenu popup = new PopupMenu(context, header.findViewById(R.id.select_artist_folder_2)); PopupMenu popup = new PopupMenu(context, header.findViewById(R.id.select_artist_folder_2));
popup.getMenu().add(R.string.select_artist_all_folders); popup.getMenu().add(R.string.select_artist_all_folders);
for (MusicFolder musicFolder : musicFolders) { for (MusicFolder musicFolder : musicFolders) {
popup.getMenu().add(musicFolder.getName()); popup.getMenu().add(musicFolder.getName());
} }
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override @Override
public boolean onMenuItemClick(MenuItem item) { public boolean onMenuItemClick(MenuItem item) {
for (MusicFolder musicFolder : musicFolders) { for (MusicFolder musicFolder : musicFolders) {
if(item.getTitle().equals(musicFolder.getName())) { if(item.getTitle().equals(musicFolder.getName())) {
if(onMusicFolderChanged != null) { if(onMusicFolderChanged != null) {
onMusicFolderChanged.onMusicFolderChanged(musicFolder); onMusicFolderChanged.onMusicFolderChanged(musicFolder);
} }
return true; return true;
} }
} }
if(onMusicFolderChanged != null) { if(onMusicFolderChanged != null) {
onMusicFolderChanged.onMusicFolderChanged(null); onMusicFolderChanged.onMusicFolderChanged(null);
} }
return true; return true;
} }
}); });
popup.show(); popup.show();
} }
}); });
return new UpdateView.UpdateViewHolder(header, false); return new UpdateView.UpdateViewHolder(header, false);
} }
@Override @Override
public void onBindHeaderHolder(UpdateView.UpdateViewHolder holder, String header, int sectionIndex) { public void onBindHeaderHolder(UpdateView.UpdateViewHolder holder, String header, int sectionIndex) {
TextView folderName = (TextView) holder.getView().findViewById(R.id.select_artist_folder_2); TextView folderName = (TextView) holder.getView().findViewById(R.id.select_artist_folder_2);
String musicFolderId = Util.getSelectedMusicFolderId(context); String musicFolderId = Util.getSelectedMusicFolderId(context);
if(musicFolderId != null) { if(musicFolderId != null) {
for (MusicFolder musicFolder : musicFolders) { for (MusicFolder musicFolder : musicFolders) {
if (musicFolder.getId().equals(musicFolderId)) { if (musicFolder.getId().equals(musicFolderId)) {
folderName.setText(musicFolder.getName()); folderName.setText(musicFolder.getName());
break; break;
} }
} }
} else { } else {
folderName.setText(R.string.select_artist_all_folders); folderName.setText(R.string.select_artist_all_folders);
} }
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) {
UpdateView updateView = null; UpdateView updateView = null;
if(viewType == VIEW_TYPE_ARTIST) { if(viewType == VIEW_TYPE_ARTIST) {
updateView = new ArtistView(context); updateView = new ArtistView(context);
} else if(viewType == VIEW_TYPE_SONG) { } else if(viewType == VIEW_TYPE_SONG) {
updateView = new SongView(context); updateView = new SongView(context);
} }
return new UpdateView.UpdateViewHolder(updateView); return new UpdateView.UpdateViewHolder(updateView);
} }
@Override @Override
public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Serializable item, int viewType) { public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Serializable item, int viewType) {
UpdateView view = holder.getUpdateView(); UpdateView view = holder.getUpdateView();
if(viewType == VIEW_TYPE_ARTIST) { if(viewType == VIEW_TYPE_ARTIST) {
view.setObject(item); view.setObject(item);
} else if(viewType == VIEW_TYPE_SONG) { } else if(viewType == VIEW_TYPE_SONG) {
SongView songView = (SongView) view; SongView songView = (SongView) view;
Entry entry = (Entry) item; Entry entry = (Entry) item;
songView.setObject(entry, checkable); songView.setObject(entry, checkable);
} }
} }
@Override @Override
public int getItemViewType(Serializable item) { public int getItemViewType(Serializable item) {
if(item instanceof Artist) { if(item instanceof Artist) {
return VIEW_TYPE_ARTIST; return VIEW_TYPE_ARTIST;
} else { } else {
return VIEW_TYPE_SONG; return VIEW_TYPE_SONG;
} }
} }
@Override @Override
public String getTextToShowInBubble(int position) { public String getTextToShowInBubble(int position) {
Object item = getItemForPosition(position); Object item = getItemForPosition(position);
if(item instanceof Artist) { if(item instanceof Artist) {
return getNameIndex(((Artist) item).getName(), true); return getNameIndex(((Artist) item).getName(), true);
} else { } else {
return null; return null;
} }
} }
public interface OnMusicFolderChanged { public interface OnMusicFolderChanged {
void onMusicFolderChanged(MusicFolder musicFolder); void onMusicFolderChanged(MusicFolder musicFolder);
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
@ -24,25 +24,25 @@ import net.nullsum.audinaut.view.BasicListView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
public class BasicListAdapter extends SectionAdapter<String> { public class BasicListAdapter extends SectionAdapter<String> {
public static int VIEW_TYPE_LINE = 1; public static int VIEW_TYPE_LINE = 1;
public BasicListAdapter(Context context, List<String> strings, OnItemClickedListener listener) { public BasicListAdapter(Context context, List<String> strings, OnItemClickedListener listener) {
super(context, strings); super(context, strings);
this.onItemClickedListener = listener; this.onItemClickedListener = listener;
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) {
return new UpdateView.UpdateViewHolder(new BasicListView(context)); return new UpdateView.UpdateViewHolder(new BasicListView(context));
} }
@Override @Override
public void onBindViewHolder(UpdateView.UpdateViewHolder holder, String item, int viewType) { public void onBindViewHolder(UpdateView.UpdateViewHolder holder, String item, int viewType) {
holder.getUpdateView().setObject(item); holder.getUpdateView().setObject(item);
} }
@Override @Override
public int getItemViewType(String item) { public int getItemViewType(String item) {
return VIEW_TYPE_LINE; return VIEW_TYPE_LINE;
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
@ -30,33 +30,33 @@ import java.util.List;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
public class DetailsAdapter extends ArrayAdapter<String> { public class DetailsAdapter extends ArrayAdapter<String> {
private List<String> headers; private List<String> headers;
private List<String> details; private List<String> details;
public DetailsAdapter(Context context, int layout, List<String> headers, List<String> details) { public DetailsAdapter(Context context, int layout, List<String> headers, List<String> details) {
super(context, layout, headers); super(context, layout, headers);
this.headers = headers; this.headers = headers;
this.details = details; this.details = details;
} }
@Override @Override
public View getView(int position, View convertView, ViewGroup parent){ public View getView(int position, View convertView, ViewGroup parent){
View view; View view;
if(convertView == null) { if(convertView == null) {
view = LayoutInflater.from(getContext()).inflate(R.layout.details_item, null); view = LayoutInflater.from(getContext()).inflate(R.layout.details_item, null);
} else { } else {
view = convertView; view = convertView;
} }
TextView nameView = (TextView) view.findViewById(R.id.detail_name); TextView nameView = (TextView) view.findViewById(R.id.detail_name);
TextView detailsView = (TextView) view.findViewById(R.id.detail_value); TextView detailsView = (TextView) view.findViewById(R.id.detail_value);
nameView.setText(headers.get(position)); nameView.setText(headers.get(position));
detailsView.setText(details.get(position)); detailsView.setText(details.get(position));
Linkify.addLinks(detailsView, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES); Linkify.addLinks(detailsView, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES);
return view; return view;
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson Copyright 2014 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
@ -33,42 +33,42 @@ import net.nullsum.audinaut.view.SongView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
public class DownloadFileAdapter extends SectionAdapter<DownloadFile> implements FastScroller.BubbleTextGetter { public class DownloadFileAdapter extends SectionAdapter<DownloadFile> implements FastScroller.BubbleTextGetter {
public static int VIEW_TYPE_DOWNLOAD_FILE = 1; public static int VIEW_TYPE_DOWNLOAD_FILE = 1;
public DownloadFileAdapter(Context context, List<DownloadFile> entries, OnItemClickedListener onItemClickedListener) { public DownloadFileAdapter(Context context, List<DownloadFile> entries, OnItemClickedListener onItemClickedListener) {
super(context, entries); super(context, entries);
this.onItemClickedListener = onItemClickedListener; this.onItemClickedListener = onItemClickedListener;
this.checkable = true; this.checkable = true;
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) {
return new UpdateView.UpdateViewHolder(new SongView(context)); return new UpdateView.UpdateViewHolder(new SongView(context));
} }
@Override @Override
public void onBindViewHolder(UpdateView.UpdateViewHolder holder, DownloadFile item, int viewType) { public void onBindViewHolder(UpdateView.UpdateViewHolder holder, DownloadFile item, int viewType) {
SongView songView = (SongView) holder.getUpdateView(); SongView songView = (SongView) holder.getUpdateView();
songView.setObject(item.getSong(), Util.isBatchMode(context)); songView.setObject(item.getSong(), Util.isBatchMode(context));
songView.setDownloadFile(item); songView.setDownloadFile(item);
} }
@Override @Override
public int getItemViewType(DownloadFile item) { public int getItemViewType(DownloadFile item) {
return VIEW_TYPE_DOWNLOAD_FILE; return VIEW_TYPE_DOWNLOAD_FILE;
} }
@Override @Override
public String getTextToShowInBubble(int position) { public String getTextToShowInBubble(int position) {
return null; return null;
} }
@Override @Override
public void onCreateActionModeMenu(Menu menu, MenuInflater menuInflater) { public void onCreateActionModeMenu(Menu menu, MenuInflater menuInflater) {
if(Util.isOffline(context)) { if(Util.isOffline(context)) {
menuInflater.inflate(R.menu.multiselect_nowplaying_offline, menu); menuInflater.inflate(R.menu.multiselect_nowplaying_offline, menu);
} else { } else {
menuInflater.inflate(R.menu.multiselect_nowplaying, menu); menuInflater.inflate(R.menu.multiselect_nowplaying, menu);
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
@ -35,122 +35,122 @@ import net.nullsum.audinaut.view.UpdateView;
import net.nullsum.audinaut.view.UpdateView.UpdateViewHolder; import net.nullsum.audinaut.view.UpdateView.UpdateViewHolder;
public class EntryGridAdapter extends SectionAdapter<Entry> { public class EntryGridAdapter extends SectionAdapter<Entry> {
private static String TAG = EntryGridAdapter.class.getSimpleName(); private static String TAG = EntryGridAdapter.class.getSimpleName();
public static int VIEW_TYPE_ALBUM_CELL = 1; public static int VIEW_TYPE_ALBUM_CELL = 1;
public static int VIEW_TYPE_ALBUM_LINE = 2; public static int VIEW_TYPE_ALBUM_LINE = 2;
public static int VIEW_TYPE_SONG = 3; public static int VIEW_TYPE_SONG = 3;
private ImageLoader imageLoader; private ImageLoader imageLoader;
private boolean largeAlbums; private boolean largeAlbums;
private boolean showArtist = false; private boolean showArtist = false;
private boolean showAlbum = false; private boolean showAlbum = false;
private boolean removeFromPlaylist = false; private boolean removeFromPlaylist = false;
private View header; private View header;
public EntryGridAdapter(Context context, List<Entry> entries, ImageLoader imageLoader, boolean largeCell) { public EntryGridAdapter(Context context, List<Entry> entries, ImageLoader imageLoader, boolean largeCell) {
super(context, entries); super(context, entries);
this.imageLoader = imageLoader; this.imageLoader = imageLoader;
this.largeAlbums = largeCell; this.largeAlbums = largeCell;
// Always show artist if they aren't all the same // Always show artist if they aren't all the same
String artist = null; String artist = null;
for(MusicDirectory.Entry entry: entries) { for(MusicDirectory.Entry entry: entries) {
if(artist == null) { if(artist == null) {
artist = entry.getArtist(); artist = entry.getArtist();
} }
if(artist != null && !artist.equals(entry.getArtist())) { if(artist != null && !artist.equals(entry.getArtist())) {
showArtist = true; showArtist = true;
} }
} }
checkable = true; checkable = true;
} }
@Override @Override
public UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) {
UpdateView updateView = null; UpdateView updateView = null;
if(viewType == VIEW_TYPE_ALBUM_LINE || viewType == VIEW_TYPE_ALBUM_CELL) { if(viewType == VIEW_TYPE_ALBUM_LINE || viewType == VIEW_TYPE_ALBUM_CELL) {
updateView = new AlbumView(context, viewType == VIEW_TYPE_ALBUM_CELL); updateView = new AlbumView(context, viewType == VIEW_TYPE_ALBUM_CELL);
} else if(viewType == VIEW_TYPE_SONG) { } else if(viewType == VIEW_TYPE_SONG) {
updateView = new SongView(context); updateView = new SongView(context);
} }
return new UpdateViewHolder(updateView); return new UpdateViewHolder(updateView);
} }
@Override @Override
public void onBindViewHolder(UpdateViewHolder holder, Entry entry, int viewType) { public void onBindViewHolder(UpdateViewHolder holder, Entry entry, int viewType) {
UpdateView view = holder.getUpdateView(); UpdateView view = holder.getUpdateView();
if(viewType == VIEW_TYPE_ALBUM_CELL || viewType == VIEW_TYPE_ALBUM_LINE) { if(viewType == VIEW_TYPE_ALBUM_CELL || viewType == VIEW_TYPE_ALBUM_LINE) {
AlbumView albumView = (AlbumView) view; AlbumView albumView = (AlbumView) view;
albumView.setShowArtist(showArtist); albumView.setShowArtist(showArtist);
albumView.setObject(entry, imageLoader); albumView.setObject(entry, imageLoader);
} else if(viewType == VIEW_TYPE_SONG) { } else if(viewType == VIEW_TYPE_SONG) {
SongView songView = (SongView) view; SongView songView = (SongView) view;
songView.setShowAlbum(showAlbum); songView.setShowAlbum(showAlbum);
songView.setObject(entry, checkable); songView.setObject(entry, checkable);
} }
} }
public UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) { public UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) {
return new UpdateViewHolder(header, false); return new UpdateViewHolder(header, false);
} }
public void onBindHeaderHolder(UpdateViewHolder holder, String header, int sectionIndex) { public void onBindHeaderHolder(UpdateViewHolder holder, String header, int sectionIndex) {
} }
@Override @Override
public int getItemViewType(Entry entry) { public int getItemViewType(Entry entry) {
if(entry.isDirectory()) { if(entry.isDirectory()) {
if (largeAlbums) { if (largeAlbums) {
return VIEW_TYPE_ALBUM_CELL; return VIEW_TYPE_ALBUM_CELL;
} else { } else {
return VIEW_TYPE_ALBUM_LINE; return VIEW_TYPE_ALBUM_LINE;
} }
} else { } else {
return VIEW_TYPE_SONG; return VIEW_TYPE_SONG;
} }
} }
public void setHeader(View header) { public void setHeader(View header) {
this.header = header; this.header = header;
this.singleSectionHeader = true; this.singleSectionHeader = true;
} }
public View getHeader() { public View getHeader() {
return header; return header;
} }
public void setShowArtist(boolean showArtist) { public void setShowArtist(boolean showArtist) {
this.showArtist = showArtist; this.showArtist = showArtist;
} }
public void setShowAlbum(boolean showAlbum) { public void setShowAlbum(boolean showAlbum) {
this.showAlbum = showAlbum; this.showAlbum = showAlbum;
} }
public void removeAt(int index) { public void removeAt(int index) {
sections.get(0).remove(index); sections.get(0).remove(index);
if(header != null) { if(header != null) {
index++; index++;
} }
notifyItemRemoved(index); notifyItemRemoved(index);
} }
public void setRemoveFromPlaylist(boolean removeFromPlaylist) { public void setRemoveFromPlaylist(boolean removeFromPlaylist) {
this.removeFromPlaylist = removeFromPlaylist; this.removeFromPlaylist = removeFromPlaylist;
} }
@Override @Override
public void onCreateActionModeMenu(Menu menu, MenuInflater menuInflater) { public void onCreateActionModeMenu(Menu menu, MenuInflater menuInflater) {
if(Util.isOffline(context)) { if(Util.isOffline(context)) {
menuInflater.inflate(R.menu.multiselect_media_offline, menu); menuInflater.inflate(R.menu.multiselect_media_offline, menu);
} else { } else {
menuInflater.inflate(R.menu.multiselect_media, menu); menuInflater.inflate(R.menu.multiselect_media, menu);
} }
if(!removeFromPlaylist) { if(!removeFromPlaylist) {
menu.removeItem(R.id.menu_remove_playlist); menu.removeItem(R.id.menu_remove_playlist);
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
@ -33,120 +33,120 @@ import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
public class EntryInfiniteGridAdapter extends EntryGridAdapter { public class EntryInfiniteGridAdapter extends EntryGridAdapter {
public static int VIEW_TYPE_LOADING = 4; public static int VIEW_TYPE_LOADING = 4;
private String type; private String type;
private String extra; private String extra;
private int size; private int size;
private boolean loading = false; private boolean loading = false;
private boolean allLoaded = false; private boolean allLoaded = false;
public EntryInfiniteGridAdapter(Context context, List<Entry> entries, ImageLoader imageLoader, boolean largeCell) { public EntryInfiniteGridAdapter(Context context, List<Entry> entries, ImageLoader imageLoader, boolean largeCell) {
super(context, entries, imageLoader, largeCell); super(context, entries, imageLoader, largeCell);
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType == VIEW_TYPE_LOADING) { if(viewType == VIEW_TYPE_LOADING) {
View progress = LayoutInflater.from(context).inflate(R.layout.tab_progress, null); View progress = LayoutInflater.from(context).inflate(R.layout.tab_progress, null);
progress.setVisibility(View.VISIBLE); progress.setVisibility(View.VISIBLE);
return new UpdateView.UpdateViewHolder(progress, false); return new UpdateView.UpdateViewHolder(progress, false);
} }
return super.onCreateViewHolder(parent, viewType); return super.onCreateViewHolder(parent, viewType);
} }
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
if(isLoadingView(position)) { if(isLoadingView(position)) {
return VIEW_TYPE_LOADING; return VIEW_TYPE_LOADING;
} }
return super.getItemViewType(position); return super.getItemViewType(position);
} }
@Override @Override
public void onBindViewHolder(UpdateView.UpdateViewHolder holder, int position) { public void onBindViewHolder(UpdateView.UpdateViewHolder holder, int position) {
if(!isLoadingView(position)) { if(!isLoadingView(position)) {
super.onBindViewHolder(holder, position); super.onBindViewHolder(holder, position);
} }
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
int size = super.getItemCount(); int size = super.getItemCount();
if(!allLoaded) { if(!allLoaded) {
size++; size++;
} }
return size; return size;
} }
public void setData(String type, String extra, int size) { public void setData(String type, String extra, int size) {
this.type = type; this.type = type;
this.extra = extra; this.extra = extra;
this.size = size; this.size = size;
if(super.getItemCount() < size) { if(super.getItemCount() < size) {
allLoaded = true; allLoaded = true;
} }
} }
public void loadMore() { public void loadMore() {
if(loading || allLoaded) { if(loading || allLoaded) {
return; return;
} }
loading = true; loading = true;
new SilentBackgroundTask<Void>(context) { new SilentBackgroundTask<Void>(context) {
private List<Entry> newData; private List<Entry> newData;
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
newData = cacheInBackground(); newData = cacheInBackground();
return null; return null;
} }
@Override @Override
protected void done(Void result) { protected void done(Void result) {
appendCachedData(newData); appendCachedData(newData);
loading = false; loading = false;
if(newData.size() < size) { if(newData.size() < size) {
allLoaded = true; allLoaded = true;
notifyDataSetChanged(); notifyDataSetChanged();
} }
} }
}.execute(); }.execute();
} }
protected List<Entry> cacheInBackground() throws Exception { protected List<Entry> cacheInBackground() throws Exception {
MusicService service = MusicServiceFactory.getMusicService(context); MusicService service = MusicServiceFactory.getMusicService(context);
MusicDirectory result; MusicDirectory result;
int offset = sections.get(0).size(); int offset = sections.get(0).size();
if("genres".equals(type) || "years".equals(type)) { if("genres".equals(type) || "years".equals(type)) {
result = service.getAlbumList(type, extra, size, offset, false, context, null); result = service.getAlbumList(type, extra, size, offset, false, context, null);
} else if("genres".equals(type) || "genres-songs".equals(type)) { } else if("genres".equals(type) || "genres-songs".equals(type)) {
result = service.getSongsByGenre(extra, size, offset, context, null); result = service.getSongsByGenre(extra, size, offset, context, null);
}else if(type.indexOf(MainFragment.SONGS_LIST_PREFIX) != -1) { }else if(type.indexOf(MainFragment.SONGS_LIST_PREFIX) != -1) {
result = service.getSongList(type, size, offset, context, null); result = service.getSongList(type, size, offset, context, null);
} else { } else {
result = service.getAlbumList(type, size, offset, false, context, null); result = service.getAlbumList(type, size, offset, false, context, null);
} }
return result.getChildren(); return result.getChildren();
} }
protected void appendCachedData(List<Entry> newData) { protected void appendCachedData(List<Entry> newData) {
if(newData.size() > 0) { if(newData.size() > 0) {
int start = sections.get(0).size(); int start = sections.get(0).size();
sections.get(0).addAll(newData); sections.get(0).addAll(newData);
this.notifyItemRangeInserted(start, newData.size()); this.notifyItemRangeInserted(start, newData.size());
} }
} }
protected boolean isLoadingView(int position) { protected boolean isLoadingView(int position) {
return !allLoaded && position >= sections.get(0).size(); return !allLoaded && position >= sections.get(0).size();
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
@ -31,120 +31,120 @@ import net.nullsum.audinaut.view.BasicHeaderView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
public abstract class ExpandableSectionAdapter<T> extends SectionAdapter<T> { public abstract class ExpandableSectionAdapter<T> extends SectionAdapter<T> {
private static final String TAG = ExpandableSectionAdapter.class.getSimpleName(); private static final String TAG = ExpandableSectionAdapter.class.getSimpleName();
private static final int DEFAULT_VISIBLE = 4; private static final int DEFAULT_VISIBLE = 4;
private static final int EXPAND_TOGGLE = R.attr.select_server; private static final int EXPAND_TOGGLE = R.attr.select_server;
private static final int COLLAPSE_TOGGLE = R.attr.select_tabs; private static final int COLLAPSE_TOGGLE = R.attr.select_tabs;
protected List<Integer> sectionsDefaultVisible; protected List<Integer> sectionsDefaultVisible;
protected List<List<T>> sectionsExtras; protected List<List<T>> sectionsExtras;
protected int expandToggleRes; protected int expandToggleRes;
protected int collapseToggleRes; protected int collapseToggleRes;
protected ExpandableSectionAdapter() {} protected ExpandableSectionAdapter() {}
public ExpandableSectionAdapter(Context context, List<T> section) { public ExpandableSectionAdapter(Context context, List<T> section) {
List<List<T>> sections = new ArrayList<>(); List<List<T>> sections = new ArrayList<>();
sections.add(section); sections.add(section);
init(context, Arrays.asList("Section"), sections, Arrays.asList((Integer) null)); init(context, Arrays.asList("Section"), sections, Arrays.asList((Integer) null));
} }
public ExpandableSectionAdapter(Context context, List<String> headers, List<List<T>> sections) { public ExpandableSectionAdapter(Context context, List<String> headers, List<List<T>> sections) {
init(context, headers, sections, null); init(context, headers, sections, null);
} }
public ExpandableSectionAdapter(Context context, List<String> headers, List<List<T>> sections, List<Integer> sectionsDefaultVisible) { public ExpandableSectionAdapter(Context context, List<String> headers, List<List<T>> sections, List<Integer> sectionsDefaultVisible) {
init(context, headers, sections, sectionsDefaultVisible); init(context, headers, sections, sectionsDefaultVisible);
} }
protected void init(Context context, List<String> headers, List<List<T>> fullSections, List<Integer> sectionsDefaultVisible) { protected void init(Context context, List<String> headers, List<List<T>> fullSections, List<Integer> sectionsDefaultVisible) {
this.context = context; this.context = context;
this.headers = headers; this.headers = headers;
this.sectionsDefaultVisible = sectionsDefaultVisible; this.sectionsDefaultVisible = sectionsDefaultVisible;
if(sectionsDefaultVisible == null) { if(sectionsDefaultVisible == null) {
sectionsDefaultVisible = new ArrayList<>(fullSections.size()); sectionsDefaultVisible = new ArrayList<>(fullSections.size());
for(int i = 0; i < fullSections.size(); i++) { for(int i = 0; i < fullSections.size(); i++) {
sectionsDefaultVisible.add(DEFAULT_VISIBLE); sectionsDefaultVisible.add(DEFAULT_VISIBLE);
} }
} }
this.sections = new ArrayList<>(); this.sections = new ArrayList<>();
this.sectionsExtras = new ArrayList<>(); this.sectionsExtras = new ArrayList<>();
int i = 0; int i = 0;
for(List<T> fullSection: fullSections) { for(List<T> fullSection: fullSections) {
List<T> visibleSection = new ArrayList<>(); List<T> visibleSection = new ArrayList<>();
Integer defaultVisible = sectionsDefaultVisible.get(i); Integer defaultVisible = sectionsDefaultVisible.get(i);
if(defaultVisible == null || defaultVisible >= fullSection.size()) { if(defaultVisible == null || defaultVisible >= fullSection.size()) {
visibleSection.addAll(fullSection); visibleSection.addAll(fullSection);
this.sectionsExtras.add(null); this.sectionsExtras.add(null);
} else { } else {
visibleSection.addAll(fullSection.subList(0, defaultVisible)); visibleSection.addAll(fullSection.subList(0, defaultVisible));
this.sectionsExtras.add(fullSection.subList(defaultVisible, fullSection.size())); this.sectionsExtras.add(fullSection.subList(defaultVisible, fullSection.size()));
} }
this.sections.add(visibleSection); this.sections.add(visibleSection);
i++; i++;
} }
expandToggleRes = DrawableTint.getDrawableRes(context, EXPAND_TOGGLE); expandToggleRes = DrawableTint.getDrawableRes(context, EXPAND_TOGGLE);
collapseToggleRes = DrawableTint.getDrawableRes(context, COLLAPSE_TOGGLE); collapseToggleRes = DrawableTint.getDrawableRes(context, COLLAPSE_TOGGLE);
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) { public UpdateView.UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) {
return new UpdateView.UpdateViewHolder(new BasicHeaderView(context, R.layout.expandable_header)); return new UpdateView.UpdateViewHolder(new BasicHeaderView(context, R.layout.expandable_header));
} }
@Override @Override
public void onBindHeaderHolder(UpdateView.UpdateViewHolder holder, String header, final int sectionIndex) { public void onBindHeaderHolder(UpdateView.UpdateViewHolder holder, String header, final int sectionIndex) {
UpdateView view = holder.getUpdateView(); UpdateView view = holder.getUpdateView();
ImageView toggleSelectionView = (ImageView) view.findViewById(R.id.item_select); ImageView toggleSelectionView = (ImageView) view.findViewById(R.id.item_select);
List<T> visibleSelection = sections.get(sectionIndex); List<T> visibleSelection = sections.get(sectionIndex);
List<T> sectionExtras = sectionsExtras.get(sectionIndex); List<T> sectionExtras = sectionsExtras.get(sectionIndex);
if(sectionExtras != null && !sectionExtras.isEmpty()) { if(sectionExtras != null && !sectionExtras.isEmpty()) {
toggleSelectionView.setVisibility(View.VISIBLE); toggleSelectionView.setVisibility(View.VISIBLE);
toggleSelectionView.setOnClickListener(new View.OnClickListener() { toggleSelectionView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
List<T> visibleSelection = sections.get(sectionIndex); List<T> visibleSelection = sections.get(sectionIndex);
List<T> sectionExtras = sectionsExtras.get(sectionIndex); List<T> sectionExtras = sectionsExtras.get(sectionIndex);
// Update icon // Update icon
int selectToggleAttr; int selectToggleAttr;
if (!visibleSelection.contains(sectionExtras.get(0))) { if (!visibleSelection.contains(sectionExtras.get(0))) {
selectToggleAttr = COLLAPSE_TOGGLE; selectToggleAttr = COLLAPSE_TOGGLE;
// Update how many are displayed // Update how many are displayed
int lastIndex = getItemPosition(visibleSelection.get(visibleSelection.size() - 1)); int lastIndex = getItemPosition(visibleSelection.get(visibleSelection.size() - 1));
visibleSelection.addAll(sectionExtras); visibleSelection.addAll(sectionExtras);
notifyItemRangeInserted(lastIndex, sectionExtras.size()); notifyItemRangeInserted(lastIndex, sectionExtras.size());
} else { } else {
selectToggleAttr = EXPAND_TOGGLE; selectToggleAttr = EXPAND_TOGGLE;
// Update how many are displayed // Update how many are displayed
visibleSelection.removeAll(sectionExtras); visibleSelection.removeAll(sectionExtras);
int lastIndex = getItemPosition(visibleSelection.get(visibleSelection.size() - 1)); int lastIndex = getItemPosition(visibleSelection.get(visibleSelection.size() - 1));
notifyItemRangeRemoved(lastIndex, sectionExtras.size()); notifyItemRangeRemoved(lastIndex, sectionExtras.size());
} }
((ImageView) v).setImageResource(DrawableTint.getDrawableRes(context, selectToggleAttr)); ((ImageView) v).setImageResource(DrawableTint.getDrawableRes(context, selectToggleAttr));
} }
}); });
int selectToggleAttr; int selectToggleAttr;
if (!visibleSelection.contains(sectionExtras.get(0))) { if (!visibleSelection.contains(sectionExtras.get(0))) {
selectToggleAttr = EXPAND_TOGGLE; selectToggleAttr = EXPAND_TOGGLE;
} else { } else {
selectToggleAttr = COLLAPSE_TOGGLE; selectToggleAttr = COLLAPSE_TOGGLE;
} }
toggleSelectionView.setImageResource(DrawableTint.getDrawableRes(context, selectToggleAttr)); toggleSelectionView.setImageResource(DrawableTint.getDrawableRes(context, selectToggleAttr));
} else { } else {
toggleSelectionView.setVisibility(View.GONE); toggleSelectionView.setVisibility(View.GONE);
} }
if(view != null) { if(view != null) {
view.setObject(header); view.setObject(header);
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
@ -25,30 +25,30 @@ import net.nullsum.audinaut.view.UpdateView;
import java.util.List; import java.util.List;
public class GenreAdapter extends SectionAdapter<Genre> implements FastScroller.BubbleTextGetter{ public class GenreAdapter extends SectionAdapter<Genre> implements FastScroller.BubbleTextGetter{
public static int VIEW_TYPE_GENRE = 1; public static int VIEW_TYPE_GENRE = 1;
public GenreAdapter(Context context, List<Genre> genres, OnItemClickedListener listener) { public GenreAdapter(Context context, List<Genre> genres, OnItemClickedListener listener) {
super(context, genres); super(context, genres);
this.onItemClickedListener = listener; this.onItemClickedListener = listener;
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) {
return new UpdateView.UpdateViewHolder(new GenreView(context)); return new UpdateView.UpdateViewHolder(new GenreView(context));
} }
@Override @Override
public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Genre item, int viewType) { public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Genre item, int viewType) {
holder.getUpdateView().setObject(item); holder.getUpdateView().setObject(item);
} }
@Override @Override
public int getItemViewType(Genre item) { public int getItemViewType(Genre item) {
return VIEW_TYPE_GENRE; return VIEW_TYPE_GENRE;
} }
@Override @Override
public String getTextToShowInBubble(int position) { public String getTextToShowInBubble(int position) {
return getNameIndex(getItemForPosition(position).getName()); return getNameIndex(getItemForPosition(position).getName());
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
@ -30,55 +30,55 @@ import net.nullsum.audinaut.view.BasicListView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
public class MainAdapter extends SectionAdapter<Integer> { public class MainAdapter extends SectionAdapter<Integer> {
public static final int VIEW_TYPE_ALBUM_LIST = 1; public static final int VIEW_TYPE_ALBUM_LIST = 1;
public MainAdapter(Context context, List<String> headers, List<List<Integer>> sections, OnItemClickedListener onItemClickedListener) { public MainAdapter(Context context, List<String> headers, List<List<Integer>> sections, OnItemClickedListener onItemClickedListener) {
super(context, headers, sections); super(context, headers, sections);
this.onItemClickedListener = onItemClickedListener; this.onItemClickedListener = onItemClickedListener;
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) {
UpdateView updateView = new BasicListView(context); UpdateView updateView = new BasicListView(context);
return new UpdateView.UpdateViewHolder(updateView); return new UpdateView.UpdateViewHolder(updateView);
} }
@Override @Override
public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Integer item, int viewType) { public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Integer item, int viewType) {
UpdateView updateView = holder.getUpdateView(); UpdateView updateView = holder.getUpdateView();
if(viewType == VIEW_TYPE_ALBUM_LIST) { if(viewType == VIEW_TYPE_ALBUM_LIST) {
updateView.setObject(context.getResources().getString(item)); updateView.setObject(context.getResources().getString(item));
} else { } else {
updateView.setObject(item); updateView.setObject(item);
} }
} }
@Override @Override
public int getItemViewType(Integer item) { public int getItemViewType(Integer item) {
return VIEW_TYPE_ALBUM_LIST; return VIEW_TYPE_ALBUM_LIST;
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) { public UpdateView.UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) {
return new UpdateView.UpdateViewHolder(new BasicHeaderView(context, R.layout.album_list_header)); return new UpdateView.UpdateViewHolder(new BasicHeaderView(context, R.layout.album_list_header));
} }
@Override @Override
public void onBindHeaderHolder(UpdateView.UpdateViewHolder holder, String header, int sectionIndex) { public void onBindHeaderHolder(UpdateView.UpdateViewHolder holder, String header, int sectionIndex) {
UpdateView view = holder.getUpdateView(); UpdateView view = holder.getUpdateView();
CheckBox checkBox = (CheckBox) view.findViewById(R.id.item_checkbox); CheckBox checkBox = (CheckBox) view.findViewById(R.id.item_checkbox);
String display; String display;
if("songs".equals(header)) { if("songs".equals(header)) {
display = context.getResources().getString(R.string.search_songs); display = context.getResources().getString(R.string.search_songs);
checkBox.setVisibility(View.GONE); checkBox.setVisibility(View.GONE);
} else { } else {
display = header; display = header;
checkBox.setVisibility(View.GONE); checkBox.setVisibility(View.GONE);
} }
if(view != null) { if(view != null) {
view.setObject(display); view.setObject(display);
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
@ -26,47 +26,47 @@ import net.nullsum.audinaut.view.PlaylistView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
public class PlaylistAdapter extends SectionAdapter<Playlist> implements FastScroller.BubbleTextGetter { public class PlaylistAdapter extends SectionAdapter<Playlist> implements FastScroller.BubbleTextGetter {
public static int VIEW_TYPE_PLAYLIST = 1; public static int VIEW_TYPE_PLAYLIST = 1;
private ImageLoader imageLoader; private ImageLoader imageLoader;
private boolean largeCell; private boolean largeCell;
public PlaylistAdapter(Context context, List<Playlist> playlists, ImageLoader imageLoader, boolean largeCell, OnItemClickedListener listener) { public PlaylistAdapter(Context context, List<Playlist> playlists, ImageLoader imageLoader, boolean largeCell, OnItemClickedListener listener) {
super(context, playlists); super(context, playlists);
this.imageLoader = imageLoader; this.imageLoader = imageLoader;
this.largeCell = largeCell; this.largeCell = largeCell;
this.onItemClickedListener = listener; this.onItemClickedListener = listener;
} }
public PlaylistAdapter(Context context, List<String> headers, List<List<Playlist>> sections, ImageLoader imageLoader, boolean largeCell, OnItemClickedListener listener) { public PlaylistAdapter(Context context, List<String> headers, List<List<Playlist>> sections, ImageLoader imageLoader, boolean largeCell, OnItemClickedListener listener) {
super(context, headers, sections); super(context, headers, sections);
this.imageLoader = imageLoader; this.imageLoader = imageLoader;
this.largeCell = largeCell; this.largeCell = largeCell;
this.onItemClickedListener = listener; this.onItemClickedListener = listener;
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) {
return new UpdateView.UpdateViewHolder(new PlaylistView(context, imageLoader, largeCell)); return new UpdateView.UpdateViewHolder(new PlaylistView(context, imageLoader, largeCell));
} }
@Override @Override
public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Playlist playlist, int viewType) { public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Playlist playlist, int viewType) {
holder.getUpdateView().setObject(playlist); holder.getUpdateView().setObject(playlist);
holder.setItem(playlist); holder.setItem(playlist);
} }
@Override @Override
public int getItemViewType(Playlist playlist) { public int getItemViewType(Playlist playlist) {
return VIEW_TYPE_PLAYLIST; return VIEW_TYPE_PLAYLIST;
} }
@Override @Override
public String getTextToShowInBubble(int position) { public String getTextToShowInBubble(int position) {
Object item = getItemForPosition(position); Object item = getItemForPosition(position);
if(item instanceof Playlist) { if(item instanceof Playlist) {
return getNameIndex(((Playlist) item).getName()); return getNameIndex(((Playlist) item).getName());
} else { } else {
return null; return null;
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
@ -45,96 +45,96 @@ import static net.nullsum.audinaut.adapter.EntryGridAdapter.VIEW_TYPE_ALBUM_LINE
import static net.nullsum.audinaut.adapter.EntryGridAdapter.VIEW_TYPE_SONG; import static net.nullsum.audinaut.adapter.EntryGridAdapter.VIEW_TYPE_SONG;
public class SearchAdapter extends ExpandableSectionAdapter<Serializable> { public class SearchAdapter extends ExpandableSectionAdapter<Serializable> {
private ImageLoader imageLoader; private ImageLoader imageLoader;
private boolean largeAlbums; private boolean largeAlbums;
private static final int MAX_ARTISTS = 10; private static final int MAX_ARTISTS = 10;
private static final int MAX_ALBUMS = 4; private static final int MAX_ALBUMS = 4;
private static final int MAX_SONGS = 10; private static final int MAX_SONGS = 10;
public SearchAdapter(Context context, SearchResult searchResult, ImageLoader imageLoader, boolean largeAlbums, OnItemClickedListener listener) { public SearchAdapter(Context context, SearchResult searchResult, ImageLoader imageLoader, boolean largeAlbums, OnItemClickedListener listener) {
this.imageLoader = imageLoader; this.imageLoader = imageLoader;
this.largeAlbums = largeAlbums; this.largeAlbums = largeAlbums;
List<List<Serializable>> sections = new ArrayList<>(); List<List<Serializable>> sections = new ArrayList<>();
List<String> headers = new ArrayList<>(); List<String> headers = new ArrayList<>();
List<Integer> defaultVisible = new ArrayList<>(); List<Integer> defaultVisible = new ArrayList<>();
Resources res = context.getResources(); Resources res = context.getResources();
if(!searchResult.getArtists().isEmpty()) { if(!searchResult.getArtists().isEmpty()) {
sections.add((List<Serializable>) (List<?>) searchResult.getArtists()); sections.add((List<Serializable>) (List<?>) searchResult.getArtists());
headers.add(res.getString(R.string.search_artists)); headers.add(res.getString(R.string.search_artists));
defaultVisible.add(MAX_ARTISTS); defaultVisible.add(MAX_ARTISTS);
} }
if(!searchResult.getAlbums().isEmpty()) { if(!searchResult.getAlbums().isEmpty()) {
sections.add((List<Serializable>) (List<?>) searchResult.getAlbums()); sections.add((List<Serializable>) (List<?>) searchResult.getAlbums());
headers.add(res.getString(R.string.search_albums)); headers.add(res.getString(R.string.search_albums));
defaultVisible.add(MAX_ALBUMS); defaultVisible.add(MAX_ALBUMS);
} }
if(!searchResult.getSongs().isEmpty()) { if(!searchResult.getSongs().isEmpty()) {
sections.add((List<Serializable>) (List<?>) searchResult.getSongs()); sections.add((List<Serializable>) (List<?>) searchResult.getSongs());
headers.add(res.getString(R.string.search_songs)); headers.add(res.getString(R.string.search_songs));
defaultVisible.add(MAX_SONGS); defaultVisible.add(MAX_SONGS);
} }
init(context, headers, sections, defaultVisible); init(context, headers, sections, defaultVisible);
this.onItemClickedListener = listener; this.onItemClickedListener = listener;
checkable = true; checkable = true;
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) {
UpdateView updateView = null; UpdateView updateView = null;
if(viewType == VIEW_TYPE_ALBUM_CELL || viewType == VIEW_TYPE_ALBUM_LINE) { if(viewType == VIEW_TYPE_ALBUM_CELL || viewType == VIEW_TYPE_ALBUM_LINE) {
updateView = new AlbumView(context, viewType == VIEW_TYPE_ALBUM_CELL); updateView = new AlbumView(context, viewType == VIEW_TYPE_ALBUM_CELL);
} else if(viewType == VIEW_TYPE_SONG) { } else if(viewType == VIEW_TYPE_SONG) {
updateView = new SongView(context); updateView = new SongView(context);
} else if(viewType == VIEW_TYPE_ARTIST) { } else if(viewType == VIEW_TYPE_ARTIST) {
updateView = new ArtistView(context); updateView = new ArtistView(context);
} }
return new UpdateView.UpdateViewHolder(updateView); return new UpdateView.UpdateViewHolder(updateView);
} }
@Override @Override
public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Serializable item, int viewType) { public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Serializable item, int viewType) {
UpdateView view = holder.getUpdateView(); UpdateView view = holder.getUpdateView();
if(viewType == VIEW_TYPE_ALBUM_CELL || viewType == VIEW_TYPE_ALBUM_LINE) { if(viewType == VIEW_TYPE_ALBUM_CELL || viewType == VIEW_TYPE_ALBUM_LINE) {
AlbumView albumView = (AlbumView) view; AlbumView albumView = (AlbumView) view;
albumView.setObject((Entry) item, imageLoader); albumView.setObject((Entry) item, imageLoader);
} else if(viewType == VIEW_TYPE_SONG) { } else if(viewType == VIEW_TYPE_SONG) {
SongView songView = (SongView) view; SongView songView = (SongView) view;
songView.setObject((Entry) item, true); songView.setObject((Entry) item, true);
} else if(viewType == VIEW_TYPE_ARTIST) { } else if(viewType == VIEW_TYPE_ARTIST) {
view.setObject(item); view.setObject(item);
} }
} }
@Override @Override
public int getItemViewType(Serializable item) { public int getItemViewType(Serializable item) {
if(item instanceof Entry) { if(item instanceof Entry) {
Entry entry = (Entry) item; Entry entry = (Entry) item;
if (entry.isDirectory()) { if (entry.isDirectory()) {
if (largeAlbums) { if (largeAlbums) {
return VIEW_TYPE_ALBUM_CELL; return VIEW_TYPE_ALBUM_CELL;
} else { } else {
return VIEW_TYPE_ALBUM_LINE; return VIEW_TYPE_ALBUM_LINE;
} }
} else { } else {
return VIEW_TYPE_SONG; return VIEW_TYPE_SONG;
} }
} else { } else {
return VIEW_TYPE_ARTIST; return VIEW_TYPE_ARTIST;
} }
} }
@Override @Override
public void onCreateActionModeMenu(Menu menu, MenuInflater menuInflater) { public void onCreateActionModeMenu(Menu menu, MenuInflater menuInflater) {
if(Util.isOffline(context)) { if(Util.isOffline(context)) {
menuInflater.inflate(R.menu.multiselect_media_offline, menu); menuInflater.inflate(R.menu.multiselect_media_offline, menu);
} else { } else {
menuInflater.inflate(R.menu.multiselect_media, menu); menuInflater.inflate(R.menu.multiselect_media, menu);
} }
menu.removeItem(R.id.menu_remove_playlist); menu.removeItem(R.id.menu_remove_playlist);
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
@ -46,471 +46,471 @@ import net.nullsum.audinaut.view.UpdateView;
import net.nullsum.audinaut.view.UpdateView.UpdateViewHolder; import net.nullsum.audinaut.view.UpdateView.UpdateViewHolder;
public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewHolder<T>> { public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewHolder<T>> {
private static String TAG = SectionAdapter.class.getSimpleName(); private static String TAG = SectionAdapter.class.getSimpleName();
public static int VIEW_TYPE_HEADER = 0; public static int VIEW_TYPE_HEADER = 0;
public static String[] ignoredArticles; public static String[] ignoredArticles;
protected Context context; protected Context context;
protected List<String> headers; protected List<String> headers;
protected List<List<T>> sections; protected List<List<T>> sections;
protected boolean singleSectionHeader; protected boolean singleSectionHeader;
protected OnItemClickedListener<T> onItemClickedListener; protected OnItemClickedListener<T> onItemClickedListener;
protected List<T> selected = new ArrayList<>(); protected List<T> selected = new ArrayList<>();
protected List<UpdateView> selectedViews = new ArrayList<>(); protected List<UpdateView> selectedViews = new ArrayList<>();
protected ActionMode currentActionMode; protected ActionMode currentActionMode;
protected boolean checkable = false; protected boolean checkable = false;
protected SectionAdapter() {} protected SectionAdapter() {}
public SectionAdapter(Context context, List<T> section) { public SectionAdapter(Context context, List<T> section) {
this(context, section, false); this(context, section, false);
} }
public SectionAdapter(Context context, List<T> section, boolean singleSectionHeader) { public SectionAdapter(Context context, List<T> section, boolean singleSectionHeader) {
this.context = context; this.context = context;
this.headers = Arrays.asList("Section"); this.headers = Arrays.asList("Section");
this.sections = new ArrayList<>(); this.sections = new ArrayList<>();
this.sections.add(section); this.sections.add(section);
this.singleSectionHeader = singleSectionHeader; this.singleSectionHeader = singleSectionHeader;
} }
public SectionAdapter(Context context, List<String> headers, List<List<T>> sections) { public SectionAdapter(Context context, List<String> headers, List<List<T>> sections) {
this(context, headers, sections, true); this(context, headers, sections, true);
} }
public SectionAdapter(Context context, List<String> headers, List<List<T>> sections, boolean singleSectionHeader){ public SectionAdapter(Context context, List<String> headers, List<List<T>> sections, boolean singleSectionHeader){
this.context = context; this.context = context;
this.headers = headers; this.headers = headers;
this.sections = sections; this.sections = sections;
this.singleSectionHeader = singleSectionHeader; this.singleSectionHeader = singleSectionHeader;
} }
public void replaceExistingData(List<T> section) { public void replaceExistingData(List<T> section) {
this.sections = new ArrayList<>(); this.sections = new ArrayList<>();
this.sections.add(section); this.sections.add(section);
notifyDataSetChanged(); notifyDataSetChanged();
} }
public void replaceExistingData(List<String> headers, List<List<T>> sections) { public void replaceExistingData(List<String> headers, List<List<T>> sections) {
this.headers = headers; this.headers = headers;
this.sections = sections; this.sections = sections;
notifyDataSetChanged(); notifyDataSetChanged();
} }
@Override @Override
public UpdateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { public UpdateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if(viewType == VIEW_TYPE_HEADER) { if(viewType == VIEW_TYPE_HEADER) {
return onCreateHeaderHolder(parent); return onCreateHeaderHolder(parent);
} else { } else {
final UpdateViewHolder<T> holder = onCreateSectionViewHolder(parent, viewType); final UpdateViewHolder<T> holder = onCreateSectionViewHolder(parent, viewType);
final UpdateView updateView = holder.getUpdateView(); final UpdateView updateView = holder.getUpdateView();
if(updateView != null) { if(updateView != null) {
updateView.getChildAt(0).setOnClickListener(new View.OnClickListener() { updateView.getChildAt(0).setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
T item = holder.getItem(); T item = holder.getItem();
updateView.onClick(); updateView.onClick();
if (currentActionMode != null) { if (currentActionMode != null) {
if(updateView.isCheckable()) { if(updateView.isCheckable()) {
if (selected.contains(item)) { if (selected.contains(item)) {
selected.remove(item); selected.remove(item);
selectedViews.remove(updateView); selectedViews.remove(updateView);
setChecked(updateView, false); setChecked(updateView, false);
} else { } else {
selected.add(item); selected.add(item);
selectedViews.add(updateView); selectedViews.add(updateView);
setChecked(updateView, true); setChecked(updateView, true);
} }
if (selected.isEmpty()) { if (selected.isEmpty()) {
currentActionMode.finish(); currentActionMode.finish();
} else { } else {
currentActionMode.setTitle(context.getResources().getString(R.string.select_album_n_selected, selected.size())); currentActionMode.setTitle(context.getResources().getString(R.string.select_album_n_selected, selected.size()));
} }
} }
} else if (onItemClickedListener != null) { } else if (onItemClickedListener != null) {
onItemClickedListener.onItemClicked(updateView, item); onItemClickedListener.onItemClicked(updateView, item);
} }
} }
}); });
View moreButton = updateView.findViewById(R.id.item_more); View moreButton = updateView.findViewById(R.id.item_more);
if (moreButton != null) { if (moreButton != null) {
moreButton.setOnClickListener(new View.OnClickListener() { moreButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
try { try {
final T item = holder.getItem(); final T item = holder.getItem();
if (onItemClickedListener != null) { if (onItemClickedListener != null) {
PopupMenu popup = new PopupMenu(context, v); PopupMenu popup = new PopupMenu(context, v);
onItemClickedListener.onCreateContextMenu(popup.getMenu(), popup.getMenuInflater(), updateView, item); onItemClickedListener.onCreateContextMenu(popup.getMenu(), popup.getMenuInflater(), updateView, item);
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override @Override
public boolean onMenuItemClick(MenuItem menuItem) { public boolean onMenuItemClick(MenuItem menuItem) {
return onItemClickedListener.onContextItemSelected(menuItem, updateView, item); return onItemClickedListener.onContextItemSelected(menuItem, updateView, item);
} }
}); });
popup.show(); popup.show();
} }
} catch(Exception e) { } catch(Exception e) {
Log.w(TAG, "Failed to show popup", e); Log.w(TAG, "Failed to show popup", e);
} }
} }
}); });
if(checkable) { if(checkable) {
updateView.getChildAt(0).setOnLongClickListener(new View.OnLongClickListener() { updateView.getChildAt(0).setOnLongClickListener(new View.OnLongClickListener() {
@Override @Override
public boolean onLongClick(View v) { public boolean onLongClick(View v) {
if(updateView.isCheckable()) { if(updateView.isCheckable()) {
if (currentActionMode == null) { if (currentActionMode == null) {
startActionMode(holder); startActionMode(holder);
} else { } else {
updateView.getChildAt(0).performClick(); updateView.getChildAt(0).performClick();
} }
} }
return true; return true;
} }
}); });
} }
} }
} }
return holder; return holder;
} }
} }
@Override @Override
public void onBindViewHolder(UpdateViewHolder holder, int position) { public void onBindViewHolder(UpdateViewHolder holder, int position) {
UpdateView updateView = holder.getUpdateView(); UpdateView updateView = holder.getUpdateView();
if(sections.size() == 1 && !singleSectionHeader) { if(sections.size() == 1 && !singleSectionHeader) {
T item = sections.get(0).get(position); T item = sections.get(0).get(position);
onBindViewHolder(holder, item, getItemViewType(position)); onBindViewHolder(holder, item, getItemViewType(position));
postBindView(updateView, item); postBindView(updateView, item);
holder.setItem(item); holder.setItem(item);
return; return;
} }
int subPosition = 0; int subPosition = 0;
int subHeader = 0; int subHeader = 0;
for(List<T> section: sections) { for(List<T> section: sections) {
boolean validHeader = headers.get(subHeader) != null; boolean validHeader = headers.get(subHeader) != null;
if(position == subPosition && validHeader) { if(position == subPosition && validHeader) {
onBindHeaderHolder(holder, headers.get(subHeader), subHeader); onBindHeaderHolder(holder, headers.get(subHeader), subHeader);
return; return;
} }
int headerOffset = validHeader ? 1 : 0; int headerOffset = validHeader ? 1 : 0;
if(position < (subPosition + section.size() + headerOffset)) { if(position < (subPosition + section.size() + headerOffset)) {
T item = section.get(position - subPosition - headerOffset); T item = section.get(position - subPosition - headerOffset);
onBindViewHolder(holder, item, getItemViewType(item)); onBindViewHolder(holder, item, getItemViewType(item));
postBindView(updateView, item); postBindView(updateView, item);
holder.setItem(item); holder.setItem(item);
return; return;
} }
subPosition += section.size(); subPosition += section.size();
if(validHeader) { if(validHeader) {
subPosition += 1; subPosition += 1;
} }
subHeader++; subHeader++;
} }
} }
private void postBindView(UpdateView updateView, T item) { private void postBindView(UpdateView updateView, T item) {
if(updateView.isCheckable()) { if(updateView.isCheckable()) {
setChecked(updateView, selected.contains(item)); setChecked(updateView, selected.contains(item));
} }
View moreButton = updateView.findViewById(R.id.item_more); View moreButton = updateView.findViewById(R.id.item_more);
if(moreButton != null) { if(moreButton != null) {
if(onItemClickedListener != null) { if(onItemClickedListener != null) {
PopupMenu popup = new PopupMenu(context, moreButton); PopupMenu popup = new PopupMenu(context, moreButton);
Menu menu = popup.getMenu(); Menu menu = popup.getMenu();
onItemClickedListener.onCreateContextMenu(popup.getMenu(), popup.getMenuInflater(), updateView, item); onItemClickedListener.onCreateContextMenu(popup.getMenu(), popup.getMenuInflater(), updateView, item);
if (menu.size() == 0) { if (menu.size() == 0) {
moreButton.setVisibility(View.GONE); moreButton.setVisibility(View.GONE);
} else { } else {
moreButton.setVisibility(View.VISIBLE); moreButton.setVisibility(View.VISIBLE);
} }
} else { } else {
moreButton.setVisibility(View.VISIBLE); moreButton.setVisibility(View.VISIBLE);
} }
} }
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
if(sections.size() == 1 && !singleSectionHeader) { if(sections.size() == 1 && !singleSectionHeader) {
return sections.get(0).size(); return sections.get(0).size();
} }
int count = 0; int count = 0;
for(String header: headers) { for(String header: headers) {
if(header != null) { if(header != null) {
count++; count++;
} }
} }
for(List<T> section: sections) { for(List<T> section: sections) {
count += section.size(); count += section.size();
} }
return count; return count;
} }
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
if(sections.size() == 1 && !singleSectionHeader) { if(sections.size() == 1 && !singleSectionHeader) {
return getItemViewType(sections.get(0).get(position)); return getItemViewType(sections.get(0).get(position));
} }
int subPosition = 0; int subPosition = 0;
int subHeader = 0; int subHeader = 0;
for(List<T> section: sections) { for(List<T> section: sections) {
boolean validHeader = headers.get(subHeader) != null; boolean validHeader = headers.get(subHeader) != null;
if(position == subPosition && validHeader) { if(position == subPosition && validHeader) {
return VIEW_TYPE_HEADER; return VIEW_TYPE_HEADER;
} }
int headerOffset = validHeader ? 1 : 0; int headerOffset = validHeader ? 1 : 0;
if(position < (subPosition + section.size() + headerOffset)) { if(position < (subPosition + section.size() + headerOffset)) {
return getItemViewType(section.get(position - subPosition - headerOffset)); return getItemViewType(section.get(position - subPosition - headerOffset));
} }
subPosition += section.size(); subPosition += section.size();
if(validHeader) { if(validHeader) {
subPosition += 1; subPosition += 1;
} }
subHeader++; subHeader++;
} }
return -1; return -1;
} }
public UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) { public UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) {
return new UpdateViewHolder(new BasicHeaderView(context)); return new UpdateViewHolder(new BasicHeaderView(context));
} }
public void onBindHeaderHolder(UpdateViewHolder holder, String header, int sectionIndex) { public void onBindHeaderHolder(UpdateViewHolder holder, String header, int sectionIndex) {
UpdateView view = holder.getUpdateView(); UpdateView view = holder.getUpdateView();
if(view != null) { if(view != null) {
view.setObject(header); view.setObject(header);
} }
} }
public T getItemForPosition(int position) { public T getItemForPosition(int position) {
if(sections.size() == 1 && !singleSectionHeader) { if(sections.size() == 1 && !singleSectionHeader) {
return sections.get(0).get(position); return sections.get(0).get(position);
} }
int subPosition = 0; int subPosition = 0;
for(List<T> section: sections) { for(List<T> section: sections) {
if(position == subPosition) { if(position == subPosition) {
return null; return null;
} }
if(position <= (subPosition + section.size())) { if(position <= (subPosition + section.size())) {
return section.get(position - subPosition - 1); return section.get(position - subPosition - 1);
} }
subPosition += section.size() + 1; subPosition += section.size() + 1;
} }
return null; return null;
} }
public int getItemPosition(T item) { public int getItemPosition(T item) {
if(sections.size() == 1 && !singleSectionHeader) { if(sections.size() == 1 && !singleSectionHeader) {
return sections.get(0).indexOf(item); return sections.get(0).indexOf(item);
} }
int subPosition = 0; int subPosition = 0;
for(List<T> section: sections) { for(List<T> section: sections) {
subPosition += section.size() + 1; subPosition += section.size() + 1;
int position = section.indexOf(item); int position = section.indexOf(item);
if(position != -1) { if(position != -1) {
return position + subPosition; return position + subPosition;
} }
} }
return -1; return -1;
} }
public void setOnItemClickedListener(OnItemClickedListener<T> onItemClickedListener) { public void setOnItemClickedListener(OnItemClickedListener<T> onItemClickedListener) {
this.onItemClickedListener = onItemClickedListener; this.onItemClickedListener = onItemClickedListener;
} }
public void addSelected(T item) { public void addSelected(T item) {
selected.add(item); selected.add(item);
} }
public List<T> getSelected() { public List<T> getSelected() {
List<T> selected = new ArrayList<>(); List<T> selected = new ArrayList<>();
selected.addAll(this.selected); selected.addAll(this.selected);
return selected; return selected;
} }
public void clearSelected() { public void clearSelected() {
// TODO: This needs to work with multiple sections // TODO: This needs to work with multiple sections
for(T item: selected) { for(T item: selected) {
int index = sections.get(0).indexOf(item); int index = sections.get(0).indexOf(item);
if(singleSectionHeader) { if(singleSectionHeader) {
index++; index++;
} }
} }
selected.clear(); selected.clear();
for(UpdateView updateView: selectedViews) { for(UpdateView updateView: selectedViews) {
updateView.setChecked(false); updateView.setChecked(false);
} }
} }
public void moveItem(int from, int to) { public void moveItem(int from, int to) {
List<T> section = sections.get(0); List<T> section = sections.get(0);
int max = section.size(); int max = section.size();
if(to >= max) { if(to >= max) {
to = max - 1; to = max - 1;
} else if(to < 0) { } else if(to < 0) {
to = 0; to = 0;
} }
T moved = section.remove(from); T moved = section.remove(from);
section.add(to, moved); section.add(to, moved);
notifyItemMoved(from, to); notifyItemMoved(from, to);
} }
public void removeItem(T item) { public void removeItem(T item) {
int subPosition = 0; int subPosition = 0;
for(List<T> section: sections) { for(List<T> section: sections) {
if(sections.size() > 1 || singleSectionHeader) { if(sections.size() > 1 || singleSectionHeader) {
subPosition++; subPosition++;
} }
int index = section.indexOf(item); int index = section.indexOf(item);
if (index != -1) { if (index != -1) {
section.remove(item); section.remove(item);
notifyItemRemoved(subPosition + index); notifyItemRemoved(subPosition + index);
break; break;
} }
subPosition += section.size(); subPosition += section.size();
} }
} }
public abstract UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType); public abstract UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType);
public abstract void onBindViewHolder(UpdateViewHolder holder, T item, int viewType); public abstract void onBindViewHolder(UpdateViewHolder holder, T item, int viewType);
public abstract int getItemViewType(T item); public abstract int getItemViewType(T item);
public void setCheckable(boolean checkable) { public void setCheckable(boolean checkable) {
this.checkable = checkable; this.checkable = checkable;
} }
public void setChecked(UpdateView updateView, boolean checked) { public void setChecked(UpdateView updateView, boolean checked) {
updateView.setChecked(checked); updateView.setChecked(checked);
} }
public void onCreateActionModeMenu(Menu menu, MenuInflater menuInflater) {} public void onCreateActionModeMenu(Menu menu, MenuInflater menuInflater) {}
private void startActionMode(final UpdateView.UpdateViewHolder<T> holder) { private void startActionMode(final UpdateView.UpdateViewHolder<T> holder) {
final UpdateView<T> updateView = holder.getUpdateView(); final UpdateView<T> updateView = holder.getUpdateView();
if (context instanceof SubsonicFragmentActivity && currentActionMode == null) { if (context instanceof SubsonicFragmentActivity && currentActionMode == null) {
final SubsonicFragmentActivity fragmentActivity = (SubsonicFragmentActivity) context; final SubsonicFragmentActivity fragmentActivity = (SubsonicFragmentActivity) context;
fragmentActivity.startSupportActionMode(new ActionMode.Callback() { fragmentActivity.startSupportActionMode(new ActionMode.Callback() {
@Override @Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) { public boolean onCreateActionMode(ActionMode mode, Menu menu) {
currentActionMode = mode; currentActionMode = mode;
T item = holder.getItem(); T item = holder.getItem();
selected.add(item); selected.add(item);
selectedViews.add(updateView); selectedViews.add(updateView);
setChecked(updateView, true); setChecked(updateView, true);
onCreateActionModeMenu(menu, mode.getMenuInflater()); onCreateActionModeMenu(menu, mode.getMenuInflater());
MenuUtil.hideMenuItems(context, menu, updateView); MenuUtil.hideMenuItems(context, menu, updateView);
mode.setTitle(context.getResources().getString(R.string.select_album_n_selected, selected.size())); mode.setTitle(context.getResources().getString(R.string.select_album_n_selected, selected.size()));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true)) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true)) {
TypedValue typedValue = new TypedValue(); TypedValue typedValue = new TypedValue();
Resources.Theme theme = context.getTheme(); Resources.Theme theme = context.getTheme();
theme.resolveAttribute(R.attr.colorPrimaryDark, typedValue, true); theme.resolveAttribute(R.attr.colorPrimaryDark, typedValue, true);
int colorPrimaryDark = typedValue.data; int colorPrimaryDark = typedValue.data;
Window window = ((SubsonicFragmentActivity) context).getWindow(); Window window = ((SubsonicFragmentActivity) context).getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.setStatusBarColor(colorPrimaryDark); window.setStatusBarColor(colorPrimaryDark);
} }
return true; return true;
} }
@Override @Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) { public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false; return false;
} }
@Override @Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) { public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (fragmentActivity.onOptionsItemSelected(item)) { if (fragmentActivity.onOptionsItemSelected(item)) {
currentActionMode.finish(); currentActionMode.finish();
return true; return true;
} else { } else {
return false; return false;
} }
} }
@Override @Override
public void onDestroyActionMode(ActionMode mode) { public void onDestroyActionMode(ActionMode mode) {
currentActionMode = null; currentActionMode = null;
selected.clear(); selected.clear();
for (UpdateView<T> updateView : selectedViews) { for (UpdateView<T> updateView : selectedViews) {
updateView.setChecked(false); updateView.setChecked(false);
} }
selectedViews.clear(); selectedViews.clear();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true)) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true)) {
Window window = ((SubsonicFragmentActivity) context).getWindow(); Window window = ((SubsonicFragmentActivity) context).getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
} }
} }
}); });
} }
} }
public void stopActionMode() { public void stopActionMode() {
if(currentActionMode != null) { if(currentActionMode != null) {
currentActionMode.finish(); currentActionMode.finish();
} }
} }
public String getNameIndex(String name) { public String getNameIndex(String name) {
return getNameIndex(name, false); return getNameIndex(name, false);
} }
public String getNameIndex(String name, boolean removeIgnoredArticles) { public String getNameIndex(String name, boolean removeIgnoredArticles) {
if(name == null) { if(name == null) {
return "*"; return "*";
} }
if(removeIgnoredArticles) { if(removeIgnoredArticles) {
if (ignoredArticles == null) { if (ignoredArticles == null) {
SharedPreferences prefs = Util.getPreferences(context); SharedPreferences prefs = Util.getPreferences(context);
String ignoredArticlesString = prefs.getString(Constants.CACHE_KEY_IGNORE, "The El La Los Las Le Les"); String ignoredArticlesString = prefs.getString(Constants.CACHE_KEY_IGNORE, "The El La Los Las Le Les");
ignoredArticles = ignoredArticlesString.split(" "); ignoredArticles = ignoredArticlesString.split(" ");
} }
name = name.toLowerCase(); name = name.toLowerCase();
for (String article : ignoredArticles) { for (String article : ignoredArticles) {
int index = name.indexOf(article.toLowerCase() + " "); int index = name.indexOf(article.toLowerCase() + " ");
if (index == 0) { if (index == 0) {
name = name.substring(article.length() + 1); name = name.substring(article.length() + 1);
} }
} }
} }
String index = name.substring(0, 1).toUpperCase(); String index = name.substring(0, 1).toUpperCase();
if (!Character.isLetter(index.charAt(0))) { if (!Character.isLetter(index.charAt(0))) {
index = "#"; index = "#";
} }
return index; return index;
} }
public interface OnItemClickedListener<T> { public interface OnItemClickedListener<T> {
void onItemClicked(UpdateView<T> updateView, T item); void onItemClicked(UpdateView<T> updateView, T item);
void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<T> updateView, T item); void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<T> updateView, T item);
boolean onContextItemSelected(MenuItem menuItem, UpdateView<T> updateView, T item); boolean onContextItemSelected(MenuItem menuItem, UpdateView<T> updateView, T item);
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson Copyright 2014 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
@ -36,86 +36,86 @@ import net.nullsum.audinaut.view.UpdateView;
import static net.nullsum.audinaut.domain.User.Setting; import static net.nullsum.audinaut.domain.User.Setting;
public class SettingsAdapter extends SectionAdapter<Setting> { public class SettingsAdapter extends SectionAdapter<Setting> {
private static final String TAG = SettingsAdapter.class.getSimpleName(); private static final String TAG = SettingsAdapter.class.getSimpleName();
public final int VIEW_TYPE_SETTING = 1; public final int VIEW_TYPE_SETTING = 1;
public final int VIEW_TYPE_SETTING_HEADER = 2; public final int VIEW_TYPE_SETTING_HEADER = 2;
private final User user; private final User user;
private final boolean editable; private final boolean editable;
private final ImageLoader imageLoader; private final ImageLoader imageLoader;
public SettingsAdapter(Context context, User user, List<String> headers, List<List<User.Setting>> settingSections, ImageLoader imageLoader, boolean editable, OnItemClickedListener<Setting> onItemClickedListener) { public SettingsAdapter(Context context, User user, List<String> headers, List<List<User.Setting>> settingSections, ImageLoader imageLoader, boolean editable, OnItemClickedListener<Setting> onItemClickedListener) {
super(context, headers, settingSections, imageLoader != null); super(context, headers, settingSections, imageLoader != null);
this.user = user; this.user = user;
this.imageLoader = imageLoader; this.imageLoader = imageLoader;
this.editable = editable; this.editable = editable;
this.onItemClickedListener = onItemClickedListener; this.onItemClickedListener = onItemClickedListener;
for(List<Setting> settings: sections) { for(List<Setting> settings: sections) {
for (Setting setting : settings) { for (Setting setting : settings) {
if (setting.getValue()) { if (setting.getValue()) {
addSelected(setting); addSelected(setting);
} }
} }
} }
} }
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
int viewType = super.getItemViewType(position); int viewType = super.getItemViewType(position);
if(viewType == SectionAdapter.VIEW_TYPE_HEADER) { if(viewType == SectionAdapter.VIEW_TYPE_HEADER) {
if(position == 0 && imageLoader != null) { if(position == 0 && imageLoader != null) {
return VIEW_TYPE_HEADER; return VIEW_TYPE_HEADER;
} else { } else {
return VIEW_TYPE_SETTING_HEADER; return VIEW_TYPE_SETTING_HEADER;
} }
} else { } else {
return viewType; return viewType;
} }
} }
public void onBindHeaderHolder(UpdateView.UpdateViewHolder holder, String description, int sectionIndex) { public void onBindHeaderHolder(UpdateView.UpdateViewHolder holder, String description, int sectionIndex) {
View header = holder.getView(); View header = holder.getView();
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) {
if(viewType == VIEW_TYPE_SETTING_HEADER) { if(viewType == VIEW_TYPE_SETTING_HEADER) {
return new UpdateView.UpdateViewHolder(new BasicHeaderView(context)); return new UpdateView.UpdateViewHolder(new BasicHeaderView(context));
} else { } else {
return new UpdateView.UpdateViewHolder(new SettingView(context)); return new UpdateView.UpdateViewHolder(new SettingView(context));
} }
} }
@Override @Override
public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Setting item, int viewType) { public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Setting item, int viewType) {
holder.getUpdateView().setObject(item, editable); holder.getUpdateView().setObject(item, editable);
} }
@Override @Override
public int getItemViewType(Setting item) { public int getItemViewType(Setting item) {
return VIEW_TYPE_SETTING; return VIEW_TYPE_SETTING;
} }
@Override @Override
public void setChecked(UpdateView updateView, boolean checked) { public void setChecked(UpdateView updateView, boolean checked) {
if(updateView instanceof SettingView) { if(updateView instanceof SettingView) {
updateView.setChecked(checked); updateView.setChecked(checked);
} }
} }
public static SettingsAdapter getSettingsAdapter(Context context, User user, ImageLoader imageLoader, OnItemClickedListener<Setting> onItemClickedListener) { public static SettingsAdapter getSettingsAdapter(Context context, User user, ImageLoader imageLoader, OnItemClickedListener<Setting> onItemClickedListener) {
return getSettingsAdapter(context, user, imageLoader, true, onItemClickedListener); return getSettingsAdapter(context, user, imageLoader, true, onItemClickedListener);
} }
public static SettingsAdapter getSettingsAdapter(Context context, User user, ImageLoader imageLoader, boolean isEditable, OnItemClickedListener<Setting> onItemClickedListener) { public static SettingsAdapter getSettingsAdapter(Context context, User user, ImageLoader imageLoader, boolean isEditable, OnItemClickedListener<Setting> onItemClickedListener) {
List<String> headers = new ArrayList<>(); List<String> headers = new ArrayList<>();
List<List<User.Setting>> settingsSections = new ArrayList<>(); List<List<User.Setting>> settingsSections = new ArrayList<>();
settingsSections.add(user.getSettings()); settingsSections.add(user.getSettings());
if(user.getMusicFolderSettings() != null) { if(user.getMusicFolderSettings() != null) {
settingsSections.add(user.getMusicFolderSettings()); settingsSections.add(user.getMusicFolderSettings());
} }
return new SettingsAdapter(context, user, headers, settingsSections, imageLoader, isEditable, onItemClickedListener); return new SettingsAdapter(context, user, headers, settingsSections, imageLoader, isEditable, onItemClickedListener);
} }
} }

View File

@ -29,27 +29,27 @@ public class AudioEffectsController {
private static final String TAG = AudioEffectsController.class.getSimpleName(); private static final String TAG = AudioEffectsController.class.getSimpleName();
private final Context context; private final Context context;
private int audioSessionId = 0; private int audioSessionId = 0;
private EqualizerController equalizerController; private EqualizerController equalizerController;
public AudioEffectsController(Context context, int audioSessionId) { public AudioEffectsController(Context context, int audioSessionId) {
this.context = context; this.context = context;
this.audioSessionId = audioSessionId; this.audioSessionId = audioSessionId;
} }
public void release() { public void release() {
if(equalizerController != null) { if(equalizerController != null) {
equalizerController.release(); equalizerController.release();
} }
} }
public EqualizerController getEqualizerController() { public EqualizerController getEqualizerController() {
if (equalizerController == null) { if (equalizerController == null) {
equalizerController = new EqualizerController(context, audioSessionId); equalizerController = new EqualizerController(context, audioSessionId);
equalizerController.loadSettings(); equalizerController.loadSettings();
} }
return equalizerController; return equalizerController;
} }
} }

View File

@ -1,20 +1,20 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson Copyright 2014 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.audiofx; package net.nullsum.audinaut.audiofx;
@ -23,55 +23,55 @@ import android.media.audiofx.LoudnessEnhancer;
import android.util.Log; import android.util.Log;
public class LoudnessEnhancerController { public class LoudnessEnhancerController {
private static final String TAG = LoudnessEnhancerController.class.getSimpleName(); private static final String TAG = LoudnessEnhancerController.class.getSimpleName();
private final Context context; private final Context context;
private LoudnessEnhancer enhancer; private LoudnessEnhancer enhancer;
private boolean released = false; private boolean released = false;
private int audioSessionId = 0; private int audioSessionId = 0;
public LoudnessEnhancerController(Context context, int audioSessionId) { public LoudnessEnhancerController(Context context, int audioSessionId) {
this.context = context; this.context = context;
try { try {
this.audioSessionId = audioSessionId; this.audioSessionId = audioSessionId;
enhancer = new LoudnessEnhancer(audioSessionId); enhancer = new LoudnessEnhancer(audioSessionId);
} catch (Throwable x) { } catch (Throwable x) {
Log.w(TAG, "Failed to create enhancer", x); Log.w(TAG, "Failed to create enhancer", x);
} }
} }
public boolean isAvailable() { public boolean isAvailable() {
return enhancer != null; return enhancer != null;
} }
public boolean isEnabled() { public boolean isEnabled() {
try { try {
return isAvailable() && enhancer.getEnabled(); return isAvailable() && enhancer.getEnabled();
} catch(Exception e) { } catch(Exception e) {
return false; return false;
} }
} }
public void enable() { public void enable() {
enhancer.setEnabled(true); enhancer.setEnabled(true);
} }
public void disable() { public void disable() {
enhancer.setEnabled(false); enhancer.setEnabled(false);
} }
public float getGain() { public float getGain() {
return enhancer.getTargetGain(); return enhancer.getTargetGain();
} }
public void setGain(int gain) { public void setGain(int gain) {
enhancer.setTargetGain(gain); enhancer.setTargetGain(gain);
} }
public void release() { public void release() {
if (isAvailable()) { if (isAvailable()) {
enhancer.release(); enhancer.release();
released = true; released = true;
} }
} }
} }

View File

@ -43,19 +43,19 @@ import net.nullsum.audinaut.util.Util;
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class MusicDirectory implements Serializable { public class MusicDirectory implements Serializable {
private static final String TAG = MusicDirectory.class.getSimpleName(); private static final String TAG = MusicDirectory.class.getSimpleName();
private String name; private String name;
private String id; private String id;
private String parent; private String parent;
private List<Entry> children; private List<Entry> children;
public MusicDirectory() { public MusicDirectory() {
children = new ArrayList<Entry>(); children = new ArrayList<Entry>();
} }
public MusicDirectory(List<Entry> children) { public MusicDirectory(List<Entry> children) {
this.children = children; this.children = children;
} }
public String getName() { public String getName() {
return name; return name;
@ -65,34 +65,34 @@ public class MusicDirectory implements Serializable {
this.name = name; this.name = name;
} }
public String getId() { public String getId() {
return id; return id;
} }
public void setId(String id) { public void setId(String id) {
this.id = id; this.id = id;
} }
public String getParent() { public String getParent() {
return parent; return parent;
} }
public void setParent(String parent) { public void setParent(String parent) {
this.parent = parent; this.parent = parent;
} }
public void addChild(Entry child) { public void addChild(Entry child) {
if(child != null) { if(child != null) {
children.add(child); children.add(child);
} }
} }
public void addChildren(List<Entry> children) { public void addChildren(List<Entry> children) {
this.children.addAll(children); this.children.addAll(children);
} }
public void replaceChildren(List<Entry> children) { public void replaceChildren(List<Entry> children) {
this.children = children; this.children = children;
} }
public synchronized List<Entry> getChildren() { public synchronized List<Entry> getChildren() {
return getChildren(true, true); return getChildren(true, true);
@ -111,209 +111,209 @@ public class MusicDirectory implements Serializable {
} }
return result; return result;
} }
public synchronized List<Entry> getSongs() { public synchronized List<Entry> getSongs() {
List<Entry> result = new ArrayList<Entry>(); List<Entry> result = new ArrayList<Entry>();
for (Entry child : children) { for (Entry child : children) {
if (child != null && !child.isDirectory()) { if (child != null && !child.isDirectory()) {
result.add(child); result.add(child);
} }
} }
return result; return result;
} }
public synchronized int getChildrenSize() { public synchronized int getChildrenSize() {
return children.size(); return children.size();
} }
public void shuffleChildren() { public void shuffleChildren() {
Collections.shuffle(this.children); Collections.shuffle(this.children);
} }
public void sortChildren(Context context, int instance) { public void sortChildren(Context context, int instance) {
sortChildren(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_CUSTOM_SORT_ENABLED, true)); sortChildren(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_CUSTOM_SORT_ENABLED, true));
} }
public void sortChildren(boolean byYear) { public void sortChildren(boolean byYear) {
EntryComparator.sort(children, byYear); EntryComparator.sort(children, byYear);
} }
public synchronized boolean updateMetadata(MusicDirectory refreshedDirectory) { public synchronized boolean updateMetadata(MusicDirectory refreshedDirectory) {
boolean metadataUpdated = false; boolean metadataUpdated = false;
Iterator<Entry> it = children.iterator(); Iterator<Entry> it = children.iterator();
while(it.hasNext()) { while(it.hasNext()) {
Entry entry = it.next(); Entry entry = it.next();
int index = refreshedDirectory.children.indexOf(entry); int index = refreshedDirectory.children.indexOf(entry);
if(index != -1) { if(index != -1) {
final Entry refreshed = refreshedDirectory.children.get(index); final Entry refreshed = refreshedDirectory.children.get(index);
entry.setTitle(refreshed.getTitle()); entry.setTitle(refreshed.getTitle());
entry.setAlbum(refreshed.getAlbum()); entry.setAlbum(refreshed.getAlbum());
entry.setArtist(refreshed.getArtist()); entry.setArtist(refreshed.getArtist());
entry.setTrack(refreshed.getTrack()); entry.setTrack(refreshed.getTrack());
entry.setYear(refreshed.getYear()); entry.setYear(refreshed.getYear());
entry.setGenre(refreshed.getGenre()); entry.setGenre(refreshed.getGenre());
entry.setTranscodedContentType(refreshed.getTranscodedContentType()); entry.setTranscodedContentType(refreshed.getTranscodedContentType());
entry.setTranscodedSuffix(refreshed.getTranscodedSuffix()); entry.setTranscodedSuffix(refreshed.getTranscodedSuffix());
entry.setDiscNumber(refreshed.getDiscNumber()); entry.setDiscNumber(refreshed.getDiscNumber());
entry.setType(refreshed.getType()); entry.setType(refreshed.getType());
if(!Util.equals(entry.getCoverArt(), refreshed.getCoverArt())) { if(!Util.equals(entry.getCoverArt(), refreshed.getCoverArt())) {
metadataUpdated = true; metadataUpdated = true;
entry.setCoverArt(refreshed.getCoverArt()); entry.setCoverArt(refreshed.getCoverArt());
} }
new UpdateHelper.EntryInstanceUpdater(entry) { new UpdateHelper.EntryInstanceUpdater(entry) {
@Override @Override
public void update(Entry found) { public void update(Entry found) {
found.setTitle(refreshed.getTitle()); found.setTitle(refreshed.getTitle());
found.setAlbum(refreshed.getAlbum()); found.setAlbum(refreshed.getAlbum());
found.setArtist(refreshed.getArtist()); found.setArtist(refreshed.getArtist());
found.setTrack(refreshed.getTrack()); found.setTrack(refreshed.getTrack());
found.setYear(refreshed.getYear()); found.setYear(refreshed.getYear());
found.setGenre(refreshed.getGenre()); found.setGenre(refreshed.getGenre());
found.setTranscodedContentType(refreshed.getTranscodedContentType()); found.setTranscodedContentType(refreshed.getTranscodedContentType());
found.setTranscodedSuffix(refreshed.getTranscodedSuffix()); found.setTranscodedSuffix(refreshed.getTranscodedSuffix());
found.setDiscNumber(refreshed.getDiscNumber()); found.setDiscNumber(refreshed.getDiscNumber());
found.setType(refreshed.getType()); found.setType(refreshed.getType());
if(!Util.equals(found.getCoverArt(), refreshed.getCoverArt())) { if(!Util.equals(found.getCoverArt(), refreshed.getCoverArt())) {
found.setCoverArt(refreshed.getCoverArt()); found.setCoverArt(refreshed.getCoverArt());
metadataUpdate = DownloadService.METADATA_UPDATED_COVER_ART; metadataUpdate = DownloadService.METADATA_UPDATED_COVER_ART;
} }
} }
}.execute(); }.execute();
} }
} }
return metadataUpdated; return metadataUpdated;
} }
public synchronized boolean updateEntriesList(Context context, int instance, MusicDirectory refreshedDirectory) { public synchronized boolean updateEntriesList(Context context, int instance, MusicDirectory refreshedDirectory) {
boolean changed = false; boolean changed = false;
Iterator<Entry> it = children.iterator(); Iterator<Entry> it = children.iterator();
while(it.hasNext()) { while(it.hasNext()) {
Entry entry = it.next(); Entry entry = it.next();
// No longer exists in here // No longer exists in here
if(refreshedDirectory.children.indexOf(entry) == -1) { if(refreshedDirectory.children.indexOf(entry) == -1) {
it.remove(); it.remove();
changed = true; changed = true;
} }
} }
// Make sure we contain all children from refreshed set // Make sure we contain all children from refreshed set
boolean resort = false; boolean resort = false;
for(Entry refreshed: refreshedDirectory.children) { for(Entry refreshed: refreshedDirectory.children) {
if(!this.children.contains(refreshed)) { if(!this.children.contains(refreshed)) {
this.children.add(refreshed); this.children.add(refreshed);
resort = true; resort = true;
changed = true; changed = true;
} }
} }
if(resort) { if(resort) {
this.sortChildren(context, instance); this.sortChildren(context, instance);
} }
return changed; return changed;
} }
public static class Entry implements Serializable { public static class Entry implements Serializable {
public static final int TYPE_SONG = 0; public static final int TYPE_SONG = 0;
private String id; private String id;
private String parent; private String parent;
private String grandParent; private String grandParent;
private String albumId; private String albumId;
private String artistId; private String artistId;
private boolean directory; private boolean directory;
private String title; private String title;
private String album; private String album;
private String artist; private String artist;
private Integer track; private Integer track;
private Integer year; private Integer year;
private String genre; private String genre;
private String contentType; private String contentType;
private String suffix; private String suffix;
private String transcodedContentType; private String transcodedContentType;
private String transcodedSuffix; private String transcodedSuffix;
private String coverArt; private String coverArt;
private Long size; private Long size;
private Integer duration; private Integer duration;
private Integer bitRate; private Integer bitRate;
private String path; private String path;
private Integer discNumber; private Integer discNumber;
private int type = 0; private int type = 0;
private int closeness; private int closeness;
private transient Artist linkedArtist; private transient Artist linkedArtist;
public Entry() { public Entry() {
} }
public Entry(String id) { public Entry(String id) {
this.id = id; this.id = id;
} }
public Entry(Artist artist) { public Entry(Artist artist) {
this.id = artist.getId(); this.id = artist.getId();
this.title = artist.getName(); this.title = artist.getName();
this.directory = true; this.directory = true;
this.linkedArtist = artist; this.linkedArtist = artist;
} }
public void loadMetadata(File file) { public void loadMetadata(File file) {
try { try {
MediaMetadataRetriever metadata = new MediaMetadataRetriever(); MediaMetadataRetriever metadata = new MediaMetadataRetriever();
metadata.setDataSource(file.getAbsolutePath()); metadata.setDataSource(file.getAbsolutePath());
String discNumber = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER); String discNumber = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER);
if(discNumber == null) { if(discNumber == null) {
discNumber = "1/1"; discNumber = "1/1";
} }
int slashIndex = discNumber.indexOf("/"); int slashIndex = discNumber.indexOf("/");
if(slashIndex > 0) { if(slashIndex > 0) {
discNumber = discNumber.substring(0, slashIndex); discNumber = discNumber.substring(0, slashIndex);
} }
try { try {
setDiscNumber(Integer.parseInt(discNumber)); setDiscNumber(Integer.parseInt(discNumber));
} catch(Exception e) { } catch(Exception e) {
Log.w(TAG, "Non numbers in disc field!"); Log.w(TAG, "Non numbers in disc field!");
} }
String bitrate = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE); String bitrate = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE);
setBitRate(Integer.parseInt((bitrate != null) ? bitrate : "0") / 1000); setBitRate(Integer.parseInt((bitrate != null) ? bitrate : "0") / 1000);
String length = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); String length = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
setDuration(Integer.parseInt(length) / 1000); setDuration(Integer.parseInt(length) / 1000);
String artist = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST); String artist = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
if(artist != null) { if(artist != null) {
setArtist(artist); setArtist(artist);
} }
String album = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM); String album = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
if(album != null) { if(album != null) {
setAlbum(album); setAlbum(album);
} }
metadata.release(); metadata.release();
} catch(Exception e) { } catch(Exception e) {
Log.i(TAG, "Device doesn't properly support MediaMetadataRetreiver", e); Log.i(TAG, "Device doesn't properly support MediaMetadataRetreiver", e);
} }
} }
public void rebaseTitleOffPath() { public void rebaseTitleOffPath() {
try { try {
String filename = getPath(); String filename = getPath();
if(filename == null) { if(filename == null) {
return; return;
} }
int index = filename.lastIndexOf('/'); int index = filename.lastIndexOf('/');
if (index != -1) { if (index != -1) {
filename = filename.substring(index + 1); filename = filename.substring(index + 1);
if (getTrack() != null) { if (getTrack() != null) {
filename = filename.replace(String.format("%02d ", getTrack()), ""); filename = filename.replace(String.format("%02d ", getTrack()), "");
} }
index = filename.lastIndexOf('.'); index = filename.lastIndexOf('.');
if(index != -1) { if(index != -1) {
filename = filename.substring(0, index); filename = filename.substring(0, index);
} }
setTitle(filename); setTitle(filename);
} }
} catch(Exception e) { } catch(Exception e) {
Log.w(TAG, "Failed to update title based off of path", e); Log.w(TAG, "Failed to update title based off of path", e);
} }
} }
public String getId() { public String getId() {
return id; return id;
@ -331,7 +331,7 @@ public class MusicDirectory implements Serializable {
this.parent = parent; this.parent = parent;
} }
public String getGrandParent() { public String getGrandParent() {
return grandParent; return grandParent;
} }
@ -339,21 +339,21 @@ public class MusicDirectory implements Serializable {
this.grandParent = grandParent; this.grandParent = grandParent;
} }
public String getAlbumId() { public String getAlbumId() {
return albumId; return albumId;
} }
public void setAlbumId(String albumId) { public void setAlbumId(String albumId) {
this.albumId = albumId; this.albumId = albumId;
} }
public String getArtistId() { public String getArtistId() {
return artistId; return artistId;
} }
public void setArtistId(String artistId) { public void setArtistId(String artistId) {
this.artistId = artistId; this.artistId = artistId;
} }
public boolean isDirectory() { public boolean isDirectory() {
return directory; return directory;
@ -375,17 +375,17 @@ public class MusicDirectory implements Serializable {
return album; return album;
} }
public boolean isAlbum() { public boolean isAlbum() {
return getParent() != null || getArtist() != null; return getParent() != null || getArtist() != null;
} }
public String getAlbumDisplay() { public String getAlbumDisplay() {
if(album != null && title.startsWith("Disc ")) { if(album != null && title.startsWith("Disc ")) {
return album; return album;
} else { } else {
return title; return title;
} }
} }
public void setAlbum(String album) { public void setAlbum(String album) {
this.album = album; this.album = album;
@ -495,43 +495,43 @@ public class MusicDirectory implements Serializable {
this.path = path; this.path = path;
} }
public Integer getDiscNumber() { public Integer getDiscNumber() {
return discNumber; return discNumber;
} }
public void setDiscNumber(Integer discNumber) { public void setDiscNumber(Integer discNumber) {
this.discNumber = discNumber; this.discNumber = discNumber;
} }
public int getType() { public int getType() {
return type; return type;
} }
public void setType(int type) { public void setType(int type) {
this.type = type; this.type = type;
} }
public boolean isSong() { public boolean isSong() {
return type == TYPE_SONG; return type == TYPE_SONG;
} }
public int getCloseness() { public int getCloseness() {
return closeness; return closeness;
} }
public void setCloseness(int closeness) { public void setCloseness(int closeness) {
this.closeness = closeness; this.closeness = closeness;
} }
public boolean isOnlineId(Context context) { public boolean isOnlineId(Context context) {
try { try {
String cacheLocation = Util.getPreferences(context).getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); String cacheLocation = Util.getPreferences(context).getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
return cacheLocation == null || id == null || id.indexOf(cacheLocation) == -1; return cacheLocation == null || id == null || id.indexOf(cacheLocation) == -1;
} catch(Exception e) { } catch(Exception e) {
Log.w(TAG, "Failed to check online id validity"); Log.w(TAG, "Failed to check online id validity");
// Err on the side of default functionality // Err on the side of default functionality
return true; return true;
} }
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
@ -555,72 +555,72 @@ public class MusicDirectory implements Serializable {
public String toString() { public String toString() {
return title; return title;
} }
} }
public static class EntryComparator implements Comparator<Entry> { public static class EntryComparator implements Comparator<Entry> {
private boolean byYear; private boolean byYear;
private Collator collator; private Collator collator;
public EntryComparator(boolean byYear) { public EntryComparator(boolean byYear) {
this.byYear = byYear; this.byYear = byYear;
this.collator = Collator.getInstance(Locale.US); this.collator = Collator.getInstance(Locale.US);
this.collator.setStrength(Collator.PRIMARY); this.collator.setStrength(Collator.PRIMARY);
} }
public int compare(Entry lhs, Entry rhs) { public int compare(Entry lhs, Entry rhs) {
if(lhs.isDirectory() && !rhs.isDirectory()) { if(lhs.isDirectory() && !rhs.isDirectory()) {
return -1; return -1;
} else if(!lhs.isDirectory() && rhs.isDirectory()) { } else if(!lhs.isDirectory() && rhs.isDirectory()) {
return 1; return 1;
} else if(lhs.isDirectory() && rhs.isDirectory()) { } else if(lhs.isDirectory() && rhs.isDirectory()) {
if(byYear) { if(byYear) {
Integer lhsYear = lhs.getYear(); Integer lhsYear = lhs.getYear();
Integer rhsYear = rhs.getYear(); Integer rhsYear = rhs.getYear();
if(lhsYear != null && rhsYear != null) { if(lhsYear != null && rhsYear != null) {
return lhsYear.compareTo(rhsYear); return lhsYear.compareTo(rhsYear);
} else if(lhsYear != null) { } else if(lhsYear != null) {
return -1; return -1;
} else if(rhsYear != null) { } else if(rhsYear != null) {
return 1; return 1;
} }
} }
return collator.compare(lhs.getAlbumDisplay(), rhs.getAlbumDisplay()); return collator.compare(lhs.getAlbumDisplay(), rhs.getAlbumDisplay());
} }
Integer lhsDisc = lhs.getDiscNumber(); Integer lhsDisc = lhs.getDiscNumber();
Integer rhsDisc = rhs.getDiscNumber(); Integer rhsDisc = rhs.getDiscNumber();
if(lhsDisc != null && rhsDisc != null) { if(lhsDisc != null && rhsDisc != null) {
if(lhsDisc < rhsDisc) { if(lhsDisc < rhsDisc) {
return -1; return -1;
} else if(lhsDisc > rhsDisc) { } else if(lhsDisc > rhsDisc) {
return 1; return 1;
} }
} }
Integer lhsTrack = lhs.getTrack(); Integer lhsTrack = lhs.getTrack();
Integer rhsTrack = rhs.getTrack(); Integer rhsTrack = rhs.getTrack();
if(lhsTrack != null && rhsTrack != null && lhsTrack != rhsTrack) { if(lhsTrack != null && rhsTrack != null && lhsTrack != rhsTrack) {
return lhsTrack.compareTo(rhsTrack); return lhsTrack.compareTo(rhsTrack);
} else if(lhsTrack != null) { } else if(lhsTrack != null) {
return -1; return -1;
} else if(rhsTrack != null) { } else if(rhsTrack != null) {
return 1; return 1;
} }
return collator.compare(lhs.getTitle(), rhs.getTitle()); return collator.compare(lhs.getTitle(), rhs.getTitle());
} }
public static void sort(List<Entry> entries) { public static void sort(List<Entry> entries) {
sort(entries, true); sort(entries, true);
} }
public static void sort(List<Entry> entries, boolean byYear) { public static void sort(List<Entry> entries, boolean byYear) {
try { try {
Collections.sort(entries, new EntryComparator(byYear)); Collections.sort(entries, new EntryComparator(byYear));
} catch (Exception e) { } catch (Exception e) {
Log.w(TAG, "Failed to sort MusicDirectory"); Log.w(TAG, "Failed to sort MusicDirectory");
} }
} }
} }
} }

View File

@ -32,49 +32,49 @@ import java.util.List;
* @version $Id$ * @version $Id$
*/ */
public class MusicFolder implements Serializable { public class MusicFolder implements Serializable {
private static final String TAG = MusicFolder.class.getSimpleName(); private static final String TAG = MusicFolder.class.getSimpleName();
private String id; private String id;
private String name; private String name;
private boolean enabled; private boolean enabled;
public MusicFolder() { public MusicFolder() {
} }
public MusicFolder(String id, String name) { public MusicFolder(String id, String name) {
this.id = id; this.id = id;
this.name = name; this.name = name;
} }
public String getId() { public String getId() {
return id; return id;
} }
public String getName() { public String getName() {
return name; return name;
} }
public void setEnabled(boolean enabled) { public void setEnabled(boolean enabled) {
this.enabled = enabled; this.enabled = enabled;
} }
public boolean getEnabled() { public boolean getEnabled() {
return enabled; return enabled;
} }
public static class MusicFolderComparator implements Comparator<MusicFolder> { public static class MusicFolderComparator implements Comparator<MusicFolder> {
public int compare(MusicFolder lhsMusicFolder, MusicFolder rhsMusicFolder) { public int compare(MusicFolder lhsMusicFolder, MusicFolder rhsMusicFolder) {
if(lhsMusicFolder == rhsMusicFolder || lhsMusicFolder.getName().equals(rhsMusicFolder.getName())) { if(lhsMusicFolder == rhsMusicFolder || lhsMusicFolder.getName().equals(rhsMusicFolder.getName())) {
return 0; return 0;
} else { } else {
return lhsMusicFolder.getName().compareToIgnoreCase(rhsMusicFolder.getName()); return lhsMusicFolder.getName().compareToIgnoreCase(rhsMusicFolder.getName());
} }
} }
} }
public static void sort(List<MusicFolder> musicFolders) { public static void sort(List<MusicFolder> musicFolders) {
try { try {
Collections.sort(musicFolders, new MusicFolderComparator()); Collections.sort(musicFolders, new MusicFolderComparator());
} catch (Exception e) { } catch (Exception e) {
Log.w(TAG, "Failed to sort music folders", e); Log.w(TAG, "Failed to sort music folders", e);
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.domain; package net.nullsum.audinaut.domain;
@ -21,10 +21,10 @@ import java.util.Date;
import java.util.List; import java.util.List;
public class PlayerQueue implements Serializable { public class PlayerQueue implements Serializable {
public List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(); public List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>();
public List<MusicDirectory.Entry> toDelete = new ArrayList<MusicDirectory.Entry>(); public List<MusicDirectory.Entry> toDelete = new ArrayList<MusicDirectory.Entry>();
public int currentPlayingIndex; public int currentPlayingIndex;
public int currentPlayingPosition; public int currentPlayingPosition;
public boolean renameCurrent = false; public boolean renameCurrent = false;
public Date changed = null; public Date changed = null;
} }

View File

@ -34,31 +34,31 @@ public class Playlist implements Serializable {
private String id; private String id;
private String name; private String name;
private String owner; private String owner;
private String comment; private String comment;
private String songCount; private String songCount;
private Boolean pub; private Boolean pub;
private Date created; private Date created;
private Date changed; private Date changed;
private Integer duration; private Integer duration;
public Playlist() { public Playlist() {
} }
public Playlist(String id, String name) { public Playlist(String id, String name) {
this.id = id; this.id = id;
this.name = name; this.name = name;
} }
public Playlist(String id, String name, String owner, String comment, String songCount, String pub, String created, String changed, Integer duration) { public Playlist(String id, String name, String owner, String comment, String songCount, String pub, String created, String changed, Integer duration) {
this.id = id; this.id = id;
this.name = name; this.name = name;
this.owner = (owner == null) ? "" : owner; this.owner = (owner == null) ? "" : owner;
this.comment = (comment == null) ? "" : comment; this.comment = (comment == null) ? "" : comment;
this.songCount = (songCount == null) ? "" : songCount; this.songCount = (songCount == null) ? "" : songCount;
this.pub = (pub == null) ? null : (pub.equals("true")); this.pub = (pub == null) ? null : (pub.equals("true"));
setCreated(created); setCreated(created);
setChanged(changed); setChanged(changed);
this.duration = duration; this.duration = duration;
} }
public String getId() { public String getId() {
@ -77,111 +77,111 @@ public class Playlist implements Serializable {
this.name = name; this.name = name;
} }
public String getOwner() { public String getOwner() {
return this.owner; return this.owner;
} }
public void setOwner(String owner) { public void setOwner(String owner) {
this.owner = owner; this.owner = owner;
} }
public String getComment() { public String getComment() {
return this.comment; return this.comment;
} }
public void setComment(String comment) { public void setComment(String comment) {
this.comment = comment; this.comment = comment;
} }
public String getSongCount() { public String getSongCount() {
return this.songCount; return this.songCount;
} }
public void setSongCount(String songCount) { public void setSongCount(String songCount) {
this.songCount = songCount; this.songCount = songCount;
} }
public Boolean getPublic() { public Boolean getPublic() {
return this.pub; return this.pub;
} }
public void setPublic(Boolean pub) { public void setPublic(Boolean pub) {
this.pub = pub; this.pub = pub;
} }
public Date getCreated() { public Date getCreated() {
return created; return created;
} }
public void setCreated(String created) { public void setCreated(String created) {
if (created != null) { if (created != null) {
try { try {
this.created = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(created); this.created = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(created);
} catch (ParseException e) { } catch (ParseException e) {
this.created = null; this.created = null;
} }
} else { } else {
this.created = null; this.created = null;
} }
} }
public void setCreated(Date created) { public void setCreated(Date created) {
this.created = created; this.created = created;
} }
public Date getChanged() { public Date getChanged() {
return changed; return changed;
} }
public void setChanged(String changed) { public void setChanged(String changed) {
if (changed != null) { if (changed != null) {
try { try {
this.changed = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(changed); this.changed = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(changed);
} catch (ParseException e) { } catch (ParseException e) {
this.changed = null; this.changed = null;
} }
} else { } else {
this.changed = null; this.changed = null;
} }
} }
public void setChanged(Date changed) { public void setChanged(Date changed) {
this.changed = changed; this.changed = changed;
} }
public Integer getDuration() { public Integer getDuration() {
return duration; return duration;
} }
public void setDuration(Integer duration) { public void setDuration(Integer duration) {
this.duration = duration; this.duration = duration;
} }
@Override @Override
public String toString() { public String toString() {
return name; return name;
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if(o == this) { if(o == this) {
return true; return true;
} else if(o == null) { } else if(o == null) {
return false; return false;
} else if(o instanceof String) { } else if(o instanceof String) {
return o.equals(this.id); return o.equals(this.id);
} else if(o.getClass() != getClass()) { } else if(o.getClass() != getClass()) {
return false; return false;
} }
Playlist playlist = (Playlist) o; Playlist playlist = (Playlist) o;
return playlist.id.equals(this.id); return playlist.id.equals(this.id);
} }
public static class PlaylistComparator implements Comparator<Playlist> { public static class PlaylistComparator implements Comparator<Playlist> {
@Override @Override
public int compare(Playlist playlist1, Playlist playlist2) { public int compare(Playlist playlist1, Playlist playlist2) {
return playlist1.getName().compareToIgnoreCase(playlist2.getName()); return playlist1.getName().compareToIgnoreCase(playlist2.getName());
} }
public static List<Playlist> sort(List<Playlist> playlists) { public static List<Playlist> sort(List<Playlist> playlists) {
Collections.sort(playlists, new PlaylistComparator()); Collections.sort(playlists, new PlaylistComparator());
return playlists; return playlists;
} }
} }
} }

View File

@ -27,67 +27,67 @@ import java.util.regex.Pattern;
*/ */
public class SearchCritera { public class SearchCritera {
private final String query; private final String query;
private final int artistCount; private final int artistCount;
private final int albumCount; private final int albumCount;
private final int songCount; private final int songCount;
private Pattern pattern; private Pattern pattern;
public SearchCritera(String query, int artistCount, int albumCount, int songCount) { public SearchCritera(String query, int artistCount, int albumCount, int songCount) {
this.query = query; this.query = query;
this.artistCount = artistCount; this.artistCount = artistCount;
this.albumCount = albumCount; this.albumCount = albumCount;
this.songCount = songCount; this.songCount = songCount;
} }
public String getQuery() { public String getQuery() {
return query; return query;
} }
public int getArtistCount() { public int getArtistCount() {
return artistCount; return artistCount;
} }
public int getAlbumCount() { public int getAlbumCount() {
return albumCount; return albumCount;
} }
public int getSongCount() { public int getSongCount() {
return songCount; return songCount;
} }
/** /**
* Returns and caches a pattern instance that can be used to check if a * Returns and caches a pattern instance that can be used to check if a
* string matches the query. * string matches the query.
*/ */
public Pattern getPattern() { public Pattern getPattern() {
// If the pattern wasn't already cached, create a new regular expression // If the pattern wasn't already cached, create a new regular expression
// from the search string : // from the search string :
// * Surround the search string with ".*" (match anything) // * Surround the search string with ".*" (match anything)
// * Replace spaces and wildcard '*' characters with ".*" // * Replace spaces and wildcard '*' characters with ".*"
// * All other characters are properly quoted // * All other characters are properly quoted
if (this.pattern == null) { if (this.pattern == null) {
String regex = ".*"; String regex = ".*";
String currentPart = ""; String currentPart = "";
for (int i = 0; i < query.length(); i++) { for (int i = 0; i < query.length(); i++) {
char c = query.charAt(i); char c = query.charAt(i);
if (c == '*' || c == ' ') { if (c == '*' || c == ' ') {
regex += Pattern.quote(currentPart); regex += Pattern.quote(currentPart);
regex += ".*"; regex += ".*";
currentPart = ""; currentPart = "";
} else { } else {
currentPart += c; currentPart += c;
} }
} }
if (currentPart.length() > 0) { if (currentPart.length() > 0) {
regex += Pattern.quote(currentPart); regex += Pattern.quote(currentPart);
} }
regex += ".*"; regex += ".*";
this.pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); this.pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
} }
return this.pattern; return this.pattern;
} }
} }

View File

@ -50,13 +50,13 @@ public class SearchResult implements Serializable {
return songs; return songs;
} }
public boolean hasArtists() { public boolean hasArtists() {
return !artists.isEmpty(); return !artists.isEmpty();
} }
public boolean hasAlbums() { public boolean hasAlbums() {
return !albums.isEmpty(); return !albums.isEmpty();
} }
public boolean hasSongs() { public boolean hasSongs() {
return !songs.isEmpty(); return !songs.isEmpty();
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson Copyright 2014 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.domain; package net.nullsum.audinaut.domain;
@ -22,125 +22,125 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class User implements Serializable { public class User implements Serializable {
public static final String ADMIN = "adminRole"; public static final String ADMIN = "adminRole";
public static final String SETTINGS = "settingsRole"; public static final String SETTINGS = "settingsRole";
public static final String DOWNLOAD = "downloadRole"; public static final String DOWNLOAD = "downloadRole";
public static final String UPLOAD = "uploadRole"; public static final String UPLOAD = "uploadRole";
public static final String COVERART = "coverArtRole"; public static final String COVERART = "coverArtRole";
public static final String COMMENT = "commentRole"; public static final String COMMENT = "commentRole";
public static final String STREAM = "streamRole"; public static final String STREAM = "streamRole";
public static final List<String> ROLES = new ArrayList<>(); public static final List<String> ROLES = new ArrayList<>();
static { static {
ROLES.add(ADMIN); ROLES.add(ADMIN);
ROLES.add(SETTINGS); ROLES.add(SETTINGS);
ROLES.add(STREAM); ROLES.add(STREAM);
ROLES.add(DOWNLOAD); ROLES.add(DOWNLOAD);
ROLES.add(UPLOAD); ROLES.add(UPLOAD);
ROLES.add(COVERART); ROLES.add(COVERART);
ROLES.add(COMMENT); ROLES.add(COMMENT);
} }
private String username; private String username;
private String password; private String password;
private String email; private String email;
private List<Setting> settings = new ArrayList<Setting>(); private List<Setting> settings = new ArrayList<Setting>();
private List<Setting> musicFolders; private List<Setting> musicFolders;
public User() { public User() {
} }
public String getUsername() { public String getUsername() {
return username; return username;
} }
public void setUsername(String username) { public void setUsername(String username) {
this.username = username; this.username = username;
} }
public String getPassword() { public String getPassword() {
return password; return password;
} }
public void setPassword(String password) { public void setPassword(String password) {
this.password = password; this.password = password;
} }
public String getEmail() { public String getEmail() {
return email; return email;
} }
public void setEmail(String email) { public void setEmail(String email) {
this.email = email; this.email = email;
} }
public List<Setting> getSettings() { public List<Setting> getSettings() {
return settings; return settings;
} }
public void setSettings(List<Setting> settings) { public void setSettings(List<Setting> settings) {
this.settings.clear(); this.settings.clear();
this.settings.addAll(settings); this.settings.addAll(settings);
} }
public void addSetting(String name, Boolean value) { public void addSetting(String name, Boolean value) {
settings.add(new Setting(name, value)); settings.add(new Setting(name, value));
} }
public void addMusicFolder(MusicFolder musicFolder) { public void addMusicFolder(MusicFolder musicFolder) {
if(musicFolders == null) { if(musicFolders == null) {
musicFolders = new ArrayList<>(); musicFolders = new ArrayList<>();
} }
musicFolders.add(new MusicFolderSetting(musicFolder.getId(), musicFolder.getName(), false)); musicFolders.add(new MusicFolderSetting(musicFolder.getId(), musicFolder.getName(), false));
} }
public void addMusicFolder(MusicFolderSetting musicFolderSetting, boolean defaultValue) { public void addMusicFolder(MusicFolderSetting musicFolderSetting, boolean defaultValue) {
if(musicFolders == null) { if(musicFolders == null) {
musicFolders = new ArrayList<>(); musicFolders = new ArrayList<>();
} }
musicFolders.add(new MusicFolderSetting(musicFolderSetting.getName(), musicFolderSetting.getLabel(), defaultValue)); musicFolders.add(new MusicFolderSetting(musicFolderSetting.getName(), musicFolderSetting.getLabel(), defaultValue));
} }
public List<Setting> getMusicFolderSettings() { public List<Setting> getMusicFolderSettings() {
return musicFolders; return musicFolders;
} }
public static class Setting implements Serializable { public static class Setting implements Serializable {
private String name; private String name;
private Boolean value; private Boolean value;
public Setting() { public Setting() {
} }
public Setting(String name, Boolean value) { public Setting(String name, Boolean value) {
this.name = name; this.name = name;
this.value = value; this.value = value;
} }
public String getName() { public String getName() {
return name; return name;
} }
public Boolean getValue() { public Boolean getValue() {
return value; return value;
} }
public void setValue(Boolean value) { public void setValue(Boolean value) {
this.value = value; this.value = value;
} }
} }
public static class MusicFolderSetting extends Setting { public static class MusicFolderSetting extends Setting {
private String label; private String label;
public MusicFolderSetting() { public MusicFolderSetting() {
} }
public MusicFolderSetting(String name, String label, Boolean value) { public MusicFolderSetting(String name, String label, Boolean value) {
super(name, value); super(name, value);
this.label = label; this.label = label;
} }
public String getLabel() { public String getLabel() {
return label; return label;
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson Copyright 2014 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.fragments; package net.nullsum.audinaut.fragments;
@ -46,145 +46,145 @@ import net.nullsum.audinaut.adapter.DownloadFileAdapter;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
public class DownloadFragment extends SelectRecyclerFragment<DownloadFile> implements SectionAdapter.OnItemClickedListener<DownloadFile> { public class DownloadFragment extends SelectRecyclerFragment<DownloadFile> implements SectionAdapter.OnItemClickedListener<DownloadFile> {
private long currentRevision; private long currentRevision;
private ScheduledExecutorService executorService; private ScheduledExecutorService executorService;
public DownloadFragment() { public DownloadFragment() {
serialize = false; serialize = false;
pullToRefresh = false; pullToRefresh = false;
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
super.onCreateView(inflater, container, bundle); super.onCreateView(inflater, container, bundle);
ItemTouchHelper touchHelper = new ItemTouchHelper(new DownloadFileItemHelperCallback(this, false)); ItemTouchHelper touchHelper = new ItemTouchHelper(new DownloadFileItemHelperCallback(this, false));
touchHelper.attachToRecyclerView(recyclerView); touchHelper.attachToRecyclerView(recyclerView);
return rootView; return rootView;
} }
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
final Handler handler = new Handler(); final Handler handler = new Handler();
Runnable runnable = new Runnable() { Runnable runnable = new Runnable() {
@Override @Override
public void run() { public void run() {
handler.post(new Runnable() { handler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
update(); update();
} }
}); });
} }
}; };
executorService = Executors.newSingleThreadScheduledExecutor(); executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS); executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS);
} }
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
executorService.shutdown(); executorService.shutdown();
} }
@Override @Override
public int getOptionsMenu() { public int getOptionsMenu() {
return R.menu.downloading; return R.menu.downloading;
} }
@Override @Override
public SectionAdapter getAdapter(List<DownloadFile> objs) { public SectionAdapter getAdapter(List<DownloadFile> objs) {
return new DownloadFileAdapter(context, objs, this); return new DownloadFileAdapter(context, objs, this);
} }
@Override @Override
public List<DownloadFile> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { public List<DownloadFile> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception {
DownloadService downloadService = getDownloadService(); DownloadService downloadService = getDownloadService();
if(downloadService == null) { if(downloadService == null) {
return new ArrayList<DownloadFile>(); return new ArrayList<DownloadFile>();
} }
List<DownloadFile> songList = new ArrayList<DownloadFile>(); List<DownloadFile> songList = new ArrayList<DownloadFile>();
songList.addAll(downloadService.getBackgroundDownloads()); songList.addAll(downloadService.getBackgroundDownloads());
currentRevision = downloadService.getDownloadListUpdateRevision(); currentRevision = downloadService.getDownloadListUpdateRevision();
return songList; return songList;
} }
@Override @Override
public int getTitleResource() { public int getTitleResource() {
return R.string.button_bar_downloading; return R.string.button_bar_downloading;
} }
@Override @Override
public void onItemClicked(UpdateView<DownloadFile> updateView, DownloadFile item) { public void onItemClicked(UpdateView<DownloadFile> updateView, DownloadFile item) {
} }
@Override @Override
public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<DownloadFile> updateView, DownloadFile downloadFile) { public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<DownloadFile> updateView, DownloadFile downloadFile) {
MusicDirectory.Entry selectedItem = downloadFile.getSong(); MusicDirectory.Entry selectedItem = downloadFile.getSong();
onCreateContextMenuSupport(menu, menuInflater, updateView, selectedItem); onCreateContextMenuSupport(menu, menuInflater, updateView, selectedItem);
if(!Util.isOffline(context)) { if(!Util.isOffline(context)) {
menu.removeItem(R.id.song_menu_remove_playlist); menu.removeItem(R.id.song_menu_remove_playlist);
} }
recreateContextMenu(menu); recreateContextMenu(menu);
} }
@Override @Override
public boolean onContextItemSelected(MenuItem menuItem, UpdateView<DownloadFile> updateView, DownloadFile downloadFile) { public boolean onContextItemSelected(MenuItem menuItem, UpdateView<DownloadFile> updateView, DownloadFile downloadFile) {
MusicDirectory.Entry selectedItem = downloadFile.getSong(); MusicDirectory.Entry selectedItem = downloadFile.getSong();
return onContextItemSelected(menuItem, selectedItem); return onContextItemSelected(menuItem, selectedItem);
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem menuItem) { public boolean onOptionsItemSelected(MenuItem menuItem) {
if(super.onOptionsItemSelected(menuItem)) { if(super.onOptionsItemSelected(menuItem)) {
return true; return true;
} }
switch (menuItem.getItemId()) { switch (menuItem.getItemId()) {
case R.id.menu_remove_all: case R.id.menu_remove_all:
Util.confirmDialog(context, R.string.download_menu_remove_all, "", new DialogInterface.OnClickListener() { Util.confirmDialog(context, R.string.download_menu_remove_all, "", new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
new SilentBackgroundTask<Void>(context) { new SilentBackgroundTask<Void>(context) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
getDownloadService().clearBackground(); getDownloadService().clearBackground();
return null; return null;
} }
@Override @Override
protected void done(Void result) { protected void done(Void result) {
update(); update();
} }
}.execute(); }.execute();
} }
}); });
return true; return true;
} }
return false; return false;
} }
private void update() { private void update() {
DownloadService downloadService = getDownloadService(); DownloadService downloadService = getDownloadService();
if (downloadService == null || objects == null || adapter == null) { if (downloadService == null || objects == null || adapter == null) {
return; return;
} }
if (currentRevision != downloadService.getDownloadListUpdateRevision()) { if (currentRevision != downloadService.getDownloadListUpdateRevision()) {
List<DownloadFile> downloadFileList = downloadService.getBackgroundDownloads(); List<DownloadFile> downloadFileList = downloadService.getBackgroundDownloads();
objects.clear(); objects.clear();
objects.addAll(downloadFileList); objects.addAll(downloadFileList);
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
currentRevision = downloadService.getDownloadListUpdateRevision(); currentRevision = downloadService.getDownloadListUpdateRevision();
} }
} }
} }

View File

@ -48,412 +48,412 @@ import net.nullsum.audinaut.util.Util;
* Created by Scott on 10/27/13. * Created by Scott on 10/27/13.
*/ */
public class EqualizerFragment extends SubsonicFragment { public class EqualizerFragment extends SubsonicFragment {
private static final String TAG = EqualizerFragment.class.getSimpleName(); private static final String TAG = EqualizerFragment.class.getSimpleName();
private static final int MENU_GROUP_PRESET = 100; private static final int MENU_GROUP_PRESET = 100;
private final Map<Short, SeekBar> bars = new HashMap<Short, SeekBar>(); private final Map<Short, SeekBar> bars = new HashMap<Short, SeekBar>();
private SeekBar bassBar; private SeekBar bassBar;
private SeekBar loudnessBar; private SeekBar loudnessBar;
private EqualizerController equalizerController; private EqualizerController equalizerController;
private Equalizer equalizer; private Equalizer equalizer;
private BassBoost bass; private BassBoost bass;
private LoudnessEnhancerController loudnessEnhancer; private LoudnessEnhancerController loudnessEnhancer;
private short masterLevel = 0; private short masterLevel = 0;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
rootView = inflater.inflate(R.layout.equalizer, container, false); rootView = inflater.inflate(R.layout.equalizer, container, false);
try { try {
DownloadService service = DownloadService.getInstance(); DownloadService service = DownloadService.getInstance();
equalizerController = service.getEqualizerController(); equalizerController = service.getEqualizerController();
equalizer = equalizerController.getEqualizer(); equalizer = equalizerController.getEqualizer();
bass = equalizerController.getBassBoost(); bass = equalizerController.getBassBoost();
loudnessEnhancer = equalizerController.getLoudnessEnhancerController(); loudnessEnhancer = equalizerController.getLoudnessEnhancerController();
initEqualizer(); initEqualizer();
} catch(Exception e) { } catch(Exception e) {
Log.e(TAG, "Failed to initialize EQ", e); Log.e(TAG, "Failed to initialize EQ", e);
Util.toast(context, "Failed to initialize EQ"); Util.toast(context, "Failed to initialize EQ");
context.onBackPressed(); context.onBackPressed();
} }
final View presetButton = rootView.findViewById(R.id.equalizer_preset); final View presetButton = rootView.findViewById(R.id.equalizer_preset);
registerForContextMenu(presetButton); registerForContextMenu(presetButton);
presetButton.setOnClickListener(new View.OnClickListener() { presetButton.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
presetButton.showContextMenu(); presetButton.showContextMenu();
} }
}); });
CheckBox enabledCheckBox = (CheckBox) rootView.findViewById(R.id.equalizer_enabled); CheckBox enabledCheckBox = (CheckBox) rootView.findViewById(R.id.equalizer_enabled);
enabledCheckBox.setChecked(equalizer.getEnabled()); enabledCheckBox.setChecked(equalizer.getEnabled());
enabledCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { enabledCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) { public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
try { try {
setEqualizerEnabled(b); setEqualizerEnabled(b);
} catch(Exception e) { } catch(Exception e) {
Log.e(TAG, "Failed to set EQ enabled", e); Log.e(TAG, "Failed to set EQ enabled", e);
Util.toast(context, "Failed to set EQ enabled"); Util.toast(context, "Failed to set EQ enabled");
context.onBackPressed(); context.onBackPressed();
} }
} }
}); });
setTitle(R.string.equalizer_label); setTitle(R.string.equalizer_label);
setSubtitle(null); setSubtitle(null);
return rootView; return rootView;
} }
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
try { try {
equalizerController.saveSettings(); equalizerController.saveSettings();
if (!equalizer.getEnabled()) { if (!equalizer.getEnabled()) {
equalizerController.release(); equalizerController.release();
} }
} catch(Exception e) { } catch(Exception e) {
Log.w(TAG, "Failed to release controller", e); Log.w(TAG, "Failed to release controller", e);
} }
} }
@Override @Override
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
equalizerController = DownloadService.getInstance().getEqualizerController(); equalizerController = DownloadService.getInstance().getEqualizerController();
equalizer = equalizerController.getEqualizer(); equalizer = equalizerController.getEqualizer();
bass = equalizerController.getBassBoost(); bass = equalizerController.getBassBoost();
} }
@Override @Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo); super.onCreateContextMenu(menu, view, menuInfo);
if(!primaryFragment) { if(!primaryFragment) {
return; return;
} }
short currentPreset; short currentPreset;
try { try {
currentPreset = equalizer.getCurrentPreset(); currentPreset = equalizer.getCurrentPreset();
} catch (Exception x) { } catch (Exception x) {
currentPreset = -1; currentPreset = -1;
} }
for (short preset = 0; preset < equalizer.getNumberOfPresets(); preset++) { for (short preset = 0; preset < equalizer.getNumberOfPresets(); preset++) {
MenuItem menuItem = menu.add(MENU_GROUP_PRESET, preset, preset, equalizer.getPresetName(preset)); MenuItem menuItem = menu.add(MENU_GROUP_PRESET, preset, preset, equalizer.getPresetName(preset));
if (preset == currentPreset) { if (preset == currentPreset) {
menuItem.setChecked(true); menuItem.setChecked(true);
} }
} }
menu.setGroupCheckable(MENU_GROUP_PRESET, true, true); menu.setGroupCheckable(MENU_GROUP_PRESET, true, true);
} }
@Override @Override
public boolean onContextItemSelected(MenuItem menuItem) { public boolean onContextItemSelected(MenuItem menuItem) {
short preset = (short) menuItem.getItemId(); short preset = (short) menuItem.getItemId();
for(int i = 0; i < 10; i++) { for(int i = 0; i < 10; i++) {
try { try {
equalizer.usePreset(preset); equalizer.usePreset(preset);
i = 10; i = 10;
} catch (UnsupportedOperationException e) { } catch (UnsupportedOperationException e) {
equalizerController.release(); equalizerController.release();
equalizer = equalizerController.getEqualizer(); equalizer = equalizerController.getEqualizer();
bass = equalizerController.getBassBoost(); bass = equalizerController.getBassBoost();
loudnessEnhancer = equalizerController.getLoudnessEnhancerController(); loudnessEnhancer = equalizerController.getLoudnessEnhancerController();
} }
} }
updateBars(false); updateBars(false);
return true; return true;
} }
private void setEqualizerEnabled(boolean enabled) { private void setEqualizerEnabled(boolean enabled) {
SharedPreferences prefs = Util.getPreferences(context); SharedPreferences prefs = Util.getPreferences(context);
SharedPreferences.Editor editor = prefs.edit(); SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean(Constants.PREFERENCES_EQUALIZER_ON, enabled); editor.putBoolean(Constants.PREFERENCES_EQUALIZER_ON, enabled);
editor.apply(); editor.apply();
for(int i = 0; i < 10; i++) { for(int i = 0; i < 10; i++) {
try { try {
equalizer.setEnabled(enabled); equalizer.setEnabled(enabled);
updateBars(true); updateBars(true);
i = 10; i = 10;
} catch (UnsupportedOperationException e) { } catch (UnsupportedOperationException e) {
equalizerController.release(); equalizerController.release();
equalizer = equalizerController.getEqualizer(); equalizer = equalizerController.getEqualizer();
bass = equalizerController.getBassBoost(); bass = equalizerController.getBassBoost();
loudnessEnhancer = equalizerController.getLoudnessEnhancerController(); loudnessEnhancer = equalizerController.getLoudnessEnhancerController();
} }
} }
} }
private void updateBars(boolean changedEnabled) { private void updateBars(boolean changedEnabled) {
try { try {
boolean isEnabled = equalizer.getEnabled(); boolean isEnabled = equalizer.getEnabled();
short minEQLevel = equalizer.getBandLevelRange()[0]; short minEQLevel = equalizer.getBandLevelRange()[0];
short maxEQLevel = equalizer.getBandLevelRange()[1]; short maxEQLevel = equalizer.getBandLevelRange()[1];
for (Map.Entry<Short, SeekBar> entry : bars.entrySet()) { for (Map.Entry<Short, SeekBar> entry : bars.entrySet()) {
short band = entry.getKey(); short band = entry.getKey();
SeekBar bar = entry.getValue(); SeekBar bar = entry.getValue();
bar.setEnabled(isEnabled); bar.setEnabled(isEnabled);
if (band >= (short) 0) { if (band >= (short) 0) {
short setLevel; short setLevel;
if (changedEnabled) { if (changedEnabled) {
setLevel = (short) (equalizer.getBandLevel(band) - masterLevel); setLevel = (short) (equalizer.getBandLevel(band) - masterLevel);
if (isEnabled) { if (isEnabled) {
bar.setProgress(equalizer.getBandLevel(band) - minEQLevel); bar.setProgress(equalizer.getBandLevel(band) - minEQLevel);
} else { } else {
bar.setProgress(-minEQLevel); bar.setProgress(-minEQLevel);
} }
} else { } else {
bar.setProgress(equalizer.getBandLevel(band) - minEQLevel); bar.setProgress(equalizer.getBandLevel(band) - minEQLevel);
setLevel = (short) (equalizer.getBandLevel(band) + masterLevel); setLevel = (short) (equalizer.getBandLevel(band) + masterLevel);
} }
if (setLevel < minEQLevel) { if (setLevel < minEQLevel) {
setLevel = minEQLevel; setLevel = minEQLevel;
} else if (setLevel > maxEQLevel) { } else if (setLevel > maxEQLevel) {
setLevel = maxEQLevel; setLevel = maxEQLevel;
} }
equalizer.setBandLevel(band, setLevel); equalizer.setBandLevel(band, setLevel);
} else if (!isEnabled) { } else if (!isEnabled) {
bar.setProgress(-minEQLevel); bar.setProgress(-minEQLevel);
} }
} }
bassBar.setEnabled(isEnabled); bassBar.setEnabled(isEnabled);
if (loudnessBar != null) { if (loudnessBar != null) {
loudnessBar.setEnabled(isEnabled); loudnessBar.setEnabled(isEnabled);
} }
if (changedEnabled && !isEnabled) { if (changedEnabled && !isEnabled) {
bass.setStrength((short) 0); bass.setStrength((short) 0);
bassBar.setProgress(0); bassBar.setProgress(0);
if (loudnessBar != null) { if (loudnessBar != null) {
loudnessEnhancer.setGain(0); loudnessEnhancer.setGain(0);
loudnessBar.setProgress(0); loudnessBar.setProgress(0);
} }
} }
if (!isEnabled) { if (!isEnabled) {
masterLevel = 0; masterLevel = 0;
SharedPreferences prefs = Util.getPreferences(context); SharedPreferences prefs = Util.getPreferences(context);
SharedPreferences.Editor editor = prefs.edit(); SharedPreferences.Editor editor = prefs.edit();
editor.putInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, masterLevel); editor.putInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, masterLevel);
editor.apply(); editor.apply();
} }
} catch(Exception e) { } catch(Exception e) {
Log.e(TAG, "Failed to update bars"); Log.e(TAG, "Failed to update bars");
} }
} }
private void initEqualizer() { private void initEqualizer() {
LinearLayout layout = (LinearLayout) rootView.findViewById(R.id.equalizer_layout); LinearLayout layout = (LinearLayout) rootView.findViewById(R.id.equalizer_layout);
final short minEQLevel = equalizer.getBandLevelRange()[0]; final short minEQLevel = equalizer.getBandLevelRange()[0];
final short maxEQLevel = equalizer.getBandLevelRange()[1]; final short maxEQLevel = equalizer.getBandLevelRange()[1];
// Setup Pregain // Setup Pregain
SharedPreferences prefs = Util.getPreferences(context); SharedPreferences prefs = Util.getPreferences(context);
masterLevel = (short)prefs.getInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, 0); masterLevel = (short)prefs.getInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, 0);
initPregain(layout, minEQLevel, maxEQLevel); initPregain(layout, minEQLevel, maxEQLevel);
for (short i = 0; i < equalizer.getNumberOfBands(); i++) { for (short i = 0; i < equalizer.getNumberOfBands(); i++) {
final short band = i; final short band = i;
View bandBar = LayoutInflater.from(context).inflate(R.layout.equalizer_bar, null); View bandBar = LayoutInflater.from(context).inflate(R.layout.equalizer_bar, null);
TextView freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency); TextView freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency);
final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level); final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level);
SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar); SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar);
freqTextView.setText((equalizer.getCenterFreq(band) / 1000) + " Hz"); freqTextView.setText((equalizer.getCenterFreq(band) / 1000) + " Hz");
bars.put(band, bar); bars.put(band, bar);
bar.setMax(maxEQLevel - minEQLevel); bar.setMax(maxEQLevel - minEQLevel);
short level = equalizer.getBandLevel(band); short level = equalizer.getBandLevel(band);
if(equalizer.getEnabled()) { if(equalizer.getEnabled()) {
level = (short) (level - masterLevel); level = (short) (level - masterLevel);
} }
bar.setProgress(level - minEQLevel); bar.setProgress(level - minEQLevel);
bar.setEnabled(equalizer.getEnabled()); bar.setEnabled(equalizer.getEnabled());
updateLevelText(levelTextView, level); updateLevelText(levelTextView, level);
bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override @Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
try { try {
short level = (short) (progress + minEQLevel); short level = (short) (progress + minEQLevel);
if (fromUser) { if (fromUser) {
equalizer.setBandLevel(band, (short) (level + masterLevel)); equalizer.setBandLevel(band, (short) (level + masterLevel));
} }
updateLevelText(levelTextView, level); updateLevelText(levelTextView, level);
} catch(Exception e) { } catch(Exception e) {
Log.e(TAG, "Failed to change equalizer", e); Log.e(TAG, "Failed to change equalizer", e);
} }
} }
@Override @Override
public void onStartTrackingTouch(SeekBar seekBar) { public void onStartTrackingTouch(SeekBar seekBar) {
} }
@Override @Override
public void onStopTrackingTouch(SeekBar seekBar) { public void onStopTrackingTouch(SeekBar seekBar) {
} }
}); });
layout.addView(bandBar); layout.addView(bandBar);
} }
LinearLayout specialLayout = (LinearLayout) rootView.findViewById(R.id.special_effects_layout); LinearLayout specialLayout = (LinearLayout) rootView.findViewById(R.id.special_effects_layout);
// Setup bass booster // Setup bass booster
View bandBar = LayoutInflater.from(context).inflate(R.layout.equalizer_bar, null); View bandBar = LayoutInflater.from(context).inflate(R.layout.equalizer_bar, null);
TextView freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency); TextView freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency);
final TextView bassTextView = (TextView) bandBar.findViewById(R.id.equalizer_level); final TextView bassTextView = (TextView) bandBar.findViewById(R.id.equalizer_level);
bassBar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar); bassBar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar);
freqTextView.setText(R.string.equalizer_bass_booster); freqTextView.setText(R.string.equalizer_bass_booster);
bassBar.setEnabled(equalizer.getEnabled()); bassBar.setEnabled(equalizer.getEnabled());
short bassLevel = 0; short bassLevel = 0;
if(bass.getEnabled()) { if(bass.getEnabled()) {
bassLevel = bass.getRoundedStrength(); bassLevel = bass.getRoundedStrength();
} }
bassTextView.setText(context.getResources().getString(R.string.equalizer_bass_size, bassLevel)); bassTextView.setText(context.getResources().getString(R.string.equalizer_bass_size, bassLevel));
bassBar.setMax(1000); bassBar.setMax(1000);
bassBar.setProgress(bassLevel); bassBar.setProgress(bassLevel);
bassBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { bassBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override @Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
try { try {
bassTextView.setText(context.getResources().getString(R.string.equalizer_bass_size, progress)); bassTextView.setText(context.getResources().getString(R.string.equalizer_bass_size, progress));
if (fromUser) { if (fromUser) {
if (progress > 0) { if (progress > 0) {
if (!bass.getEnabled()) { if (!bass.getEnabled()) {
bass.setEnabled(true); bass.setEnabled(true);
} }
bass.setStrength((short) progress); bass.setStrength((short) progress);
} else if (progress == 0 && bass.getEnabled()) { } else if (progress == 0 && bass.getEnabled()) {
bass.setStrength((short) progress); bass.setStrength((short) progress);
bass.setEnabled(false); bass.setEnabled(false);
} }
} }
} catch(Exception e) { } catch(Exception e) {
Log.w(TAG, "Error on changing bass: ", e); Log.w(TAG, "Error on changing bass: ", e);
} }
} }
@Override @Override
public void onStartTrackingTouch(SeekBar seekBar) { public void onStartTrackingTouch(SeekBar seekBar) {
} }
@Override @Override
public void onStopTrackingTouch(SeekBar seekBar) { public void onStopTrackingTouch(SeekBar seekBar) {
} }
}); });
specialLayout.addView(bandBar); specialLayout.addView(bandBar);
if(loudnessEnhancer != null && loudnessEnhancer.isAvailable()) { if(loudnessEnhancer != null && loudnessEnhancer.isAvailable()) {
// Setup loudness enhancer // Setup loudness enhancer
bandBar = LayoutInflater.from(context).inflate(R.layout.equalizer_bar, null); bandBar = LayoutInflater.from(context).inflate(R.layout.equalizer_bar, null);
freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency); freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency);
final TextView loudnessTextView = (TextView) bandBar.findViewById(R.id.equalizer_level); final TextView loudnessTextView = (TextView) bandBar.findViewById(R.id.equalizer_level);
loudnessBar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar); loudnessBar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar);
freqTextView.setText(R.string.equalizer_voice_booster); freqTextView.setText(R.string.equalizer_voice_booster);
loudnessBar.setEnabled(equalizer.getEnabled()); loudnessBar.setEnabled(equalizer.getEnabled());
int loudnessLevel = 0; int loudnessLevel = 0;
if(loudnessEnhancer.isEnabled()) { if(loudnessEnhancer.isEnabled()) {
loudnessLevel = (int) loudnessEnhancer.getGain(); loudnessLevel = (int) loudnessEnhancer.getGain();
} }
loudnessBar.setProgress(loudnessLevel / 100); loudnessBar.setProgress(loudnessLevel / 100);
loudnessTextView.setText(context.getResources().getString(R.string.equalizer_db_size, loudnessLevel / 100)); loudnessTextView.setText(context.getResources().getString(R.string.equalizer_db_size, loudnessLevel / 100));
loudnessBar.setMax(15); loudnessBar.setMax(15);
loudnessBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { loudnessBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override @Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
try { try {
loudnessTextView.setText(context.getResources().getString(R.string.equalizer_db_size, progress)); loudnessTextView.setText(context.getResources().getString(R.string.equalizer_db_size, progress));
if(fromUser) { if(fromUser) {
if(progress > 0) { if(progress > 0) {
if(!loudnessEnhancer.isEnabled()) { if(!loudnessEnhancer.isEnabled()) {
loudnessEnhancer.enable(); loudnessEnhancer.enable();
} }
loudnessEnhancer.setGain(progress * 100); loudnessEnhancer.setGain(progress * 100);
} else if(progress == 0 && loudnessEnhancer.isEnabled()) { } else if(progress == 0 && loudnessEnhancer.isEnabled()) {
loudnessEnhancer.setGain(progress * 100); loudnessEnhancer.setGain(progress * 100);
loudnessEnhancer.disable(); loudnessEnhancer.disable();
} }
} }
} catch(Exception e) { } catch(Exception e) {
Log.w(TAG, "Error on changing loudness: ", e); Log.w(TAG, "Error on changing loudness: ", e);
} }
} }
@Override @Override
public void onStartTrackingTouch(SeekBar seekBar) { public void onStartTrackingTouch(SeekBar seekBar) {
} }
@Override @Override
public void onStopTrackingTouch(SeekBar seekBar) { public void onStopTrackingTouch(SeekBar seekBar) {
} }
}); });
specialLayout.addView(bandBar); specialLayout.addView(bandBar);
} }
} }
private void initPregain(LinearLayout layout, final short minEQLevel, final short maxEQLevel) { private void initPregain(LinearLayout layout, final short minEQLevel, final short maxEQLevel) {
View bandBar = LayoutInflater.from(context).inflate(R.layout.equalizer_bar, null); View bandBar = LayoutInflater.from(context).inflate(R.layout.equalizer_bar, null);
TextView freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency); TextView freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency);
final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level); final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level);
SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar); SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar);
freqTextView.setText("Master"); freqTextView.setText("Master");
bars.put((short)-1, bar); bars.put((short)-1, bar);
bar.setMax(maxEQLevel - minEQLevel); bar.setMax(maxEQLevel - minEQLevel);
bar.setProgress(masterLevel - minEQLevel); bar.setProgress(masterLevel - minEQLevel);
bar.setEnabled(equalizer.getEnabled()); bar.setEnabled(equalizer.getEnabled());
updateLevelText(levelTextView, masterLevel); updateLevelText(levelTextView, masterLevel);
bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override @Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
try { try {
masterLevel = (short) (progress + minEQLevel); masterLevel = (short) (progress + minEQLevel);
if (fromUser) { if (fromUser) {
SharedPreferences prefs = Util.getPreferences(context); SharedPreferences prefs = Util.getPreferences(context);
SharedPreferences.Editor editor = prefs.edit(); SharedPreferences.Editor editor = prefs.edit();
editor.putInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, masterLevel); editor.putInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, masterLevel);
editor.apply(); editor.apply();
for (short i = 0; i < equalizer.getNumberOfBands(); i++) { for (short i = 0; i < equalizer.getNumberOfBands(); i++) {
short level = (short) ((bars.get(i).getProgress() + minEQLevel) + masterLevel); short level = (short) ((bars.get(i).getProgress() + minEQLevel) + masterLevel);
equalizer.setBandLevel(i, level); equalizer.setBandLevel(i, level);
} }
} }
updateLevelText(levelTextView, masterLevel); updateLevelText(levelTextView, masterLevel);
} catch(Exception e) { } catch(Exception e) {
Log.e(TAG, "Failed to change equalizer", e); Log.e(TAG, "Failed to change equalizer", e);
} }
} }
@Override @Override
public void onStartTrackingTouch(SeekBar seekBar) { public void onStartTrackingTouch(SeekBar seekBar) {
} }
@Override @Override
public void onStopTrackingTouch(SeekBar seekBar) { public void onStopTrackingTouch(SeekBar seekBar) {
} }
}); });
layout.addView(bandBar); layout.addView(bandBar);
} }
private void updateLevelText(TextView levelTextView, short level) { private void updateLevelText(TextView levelTextView, short level) {
levelTextView.setText((level > 0 ? "+" : "") + context.getResources().getString(R.string.equalizer_db_size, level / 100)); levelTextView.setText((level > 0 ? "+" : "") + context.getResources().getString(R.string.equalizer_db_size, level / 100));
} }
} }

View File

@ -42,179 +42,179 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
public class MainFragment extends SelectRecyclerFragment<Integer> { public class MainFragment extends SelectRecyclerFragment<Integer> {
private static final String TAG = MainFragment.class.getSimpleName(); private static final String TAG = MainFragment.class.getSimpleName();
public static final String SONGS_LIST_PREFIX = "songs-"; public static final String SONGS_LIST_PREFIX = "songs-";
public static final String SONGS_NEWEST = SONGS_LIST_PREFIX + "newest"; public static final String SONGS_NEWEST = SONGS_LIST_PREFIX + "newest";
public static final String SONGS_TOP_PLAYED = SONGS_LIST_PREFIX + "topPlayed"; public static final String SONGS_TOP_PLAYED = SONGS_LIST_PREFIX + "topPlayed";
public static final String SONGS_RECENT = SONGS_LIST_PREFIX + "recent"; public static final String SONGS_RECENT = SONGS_LIST_PREFIX + "recent";
public static final String SONGS_FREQUENT = SONGS_LIST_PREFIX + "frequent"; public static final String SONGS_FREQUENT = SONGS_LIST_PREFIX + "frequent";
public MainFragment() { public MainFragment() {
super(); super();
pullToRefresh = false; pullToRefresh = false;
serialize = false; serialize = false;
backgroundUpdate = false; backgroundUpdate = false;
alwaysFullscreen = true; alwaysFullscreen = true;
} }
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
menuInflater.inflate(R.menu.main, menu); menuInflater.inflate(R.menu.main, menu);
onFinishSetupOptionsMenu(menu); onFinishSetupOptionsMenu(menu);
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
if(super.onOptionsItemSelected(item)) { if(super.onOptionsItemSelected(item)) {
return true; return true;
} }
return false; return false;
} }
@Override @Override
public int getOptionsMenu() { public int getOptionsMenu() {
return 0; return 0;
} }
@Override @Override
public SectionAdapter getAdapter(List objs) { public SectionAdapter getAdapter(List objs) {
List<List<Integer>> sections = new ArrayList<>(); List<List<Integer>> sections = new ArrayList<>();
List<String> headers = new ArrayList<>(); List<String> headers = new ArrayList<>();
List<Integer> albums = new ArrayList<>(); List<Integer> albums = new ArrayList<>();
albums.add(R.string.main_albums_random); albums.add(R.string.main_albums_random);
albums.add(R.string.main_albums_alphabetical); albums.add(R.string.main_albums_alphabetical);
albums.add(R.string.main_albums_genres); albums.add(R.string.main_albums_genres);
albums.add(R.string.main_albums_year); albums.add(R.string.main_albums_year);
albums.add(R.string.main_albums_recent); albums.add(R.string.main_albums_recent);
albums.add(R.string.main_albums_frequent); albums.add(R.string.main_albums_frequent);
sections.add(albums); sections.add(albums);
headers.add("albums"); headers.add("albums");
return new MainAdapter(context, headers, sections, this); return new MainAdapter(context, headers, sections, this);
} }
@Override @Override
public List<Integer> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { public List<Integer> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception {
return Arrays.asList(0); return Arrays.asList(0);
} }
@Override @Override
public int getTitleResource() { public int getTitleResource() {
return R.string.common_appname; return R.string.common_appname;
} }
private void showAlbumList(String type) { private void showAlbumList(String type) {
if("genres".equals(type)) { if("genres".equals(type)) {
SubsonicFragment fragment = new SelectGenreFragment(); SubsonicFragment fragment = new SelectGenreFragment();
replaceFragment(fragment); replaceFragment(fragment);
} else if("years".equals(type)) { } else if("years".equals(type)) {
SubsonicFragment fragment = new SelectYearFragment(); SubsonicFragment fragment = new SelectYearFragment();
replaceFragment(fragment); replaceFragment(fragment);
} else { } else {
// Clear out recently added count when viewing // Clear out recently added count when viewing
if("newest".equals(type)) { if("newest".equals(type)) {
SharedPreferences.Editor editor = Util.getPreferences(context).edit(); SharedPreferences.Editor editor = Util.getPreferences(context).edit();
editor.putInt(Constants.PREFERENCES_KEY_RECENT_COUNT + Util.getActiveServer(context), 0); editor.putInt(Constants.PREFERENCES_KEY_RECENT_COUNT + Util.getActiveServer(context), 0);
editor.apply(); editor.apply();
} }
SubsonicFragment fragment = new SelectDirectoryFragment(); SubsonicFragment fragment = new SelectDirectoryFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type); args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type);
args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20); args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20);
args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0); args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
fragment.setArguments(args); fragment.setArguments(args);
replaceFragment(fragment); replaceFragment(fragment);
} }
} }
private void showAboutDialog() { private void showAboutDialog() {
new LoadingTask<Void>(context) { new LoadingTask<Void>(context) {
Long[] used; Long[] used;
long bytesTotalFs; long bytesTotalFs;
long bytesAvailableFs; long bytesAvailableFs;
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
File rootFolder = FileUtil.getMusicDirectory(context); File rootFolder = FileUtil.getMusicDirectory(context);
StatFs stat = new StatFs(rootFolder.getPath()); StatFs stat = new StatFs(rootFolder.getPath());
bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize(); bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize();
bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize(); bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
used = FileUtil.getUsedSize(context, rootFolder); used = FileUtil.getUsedSize(context, rootFolder);
return null; return null;
} }
@Override @Override
protected void done(Void result) { protected void done(Void result) {
List<Integer> headers = new ArrayList<>(); List<Integer> headers = new ArrayList<>();
List<String> details = new ArrayList<>(); List<String> details = new ArrayList<>();
headers.add(R.string.details_author); headers.add(R.string.details_author);
details.add("Andrew Rabert"); details.add("Andrew Rabert");
headers.add(R.string.details_email); headers.add(R.string.details_email);
details.add("ar@nullsum.net"); details.add("ar@nullsum.net");
try { try {
headers.add(R.string.details_version); headers.add(R.string.details_version);
details.add(context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName); details.add(context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName);
} catch(Exception e) { } catch(Exception e) {
details.add(""); details.add("");
} }
Resources res = context.getResources(); Resources res = context.getResources();
headers.add(R.string.details_files_cached); headers.add(R.string.details_files_cached);
details.add(Long.toString(used[0])); details.add(Long.toString(used[0]));
headers.add(R.string.details_files_permanent); headers.add(R.string.details_files_permanent);
details.add(Long.toString(used[1])); details.add(Long.toString(used[1]));
headers.add(R.string.details_used_space); headers.add(R.string.details_used_space);
details.add(res.getString(R.string.details_of, Util.formatLocalizedBytes(used[2], context), Util.formatLocalizedBytes(Util.getCacheSizeMB(context) * 1024L * 1024L, context))); details.add(res.getString(R.string.details_of, Util.formatLocalizedBytes(used[2], context), Util.formatLocalizedBytes(Util.getCacheSizeMB(context) * 1024L * 1024L, context)));
headers.add(R.string.details_available_space); headers.add(R.string.details_available_space);
details.add(res.getString(R.string.details_of, Util.formatLocalizedBytes(bytesAvailableFs, context), Util.formatLocalizedBytes(bytesTotalFs, context))); details.add(res.getString(R.string.details_of, Util.formatLocalizedBytes(bytesAvailableFs, context), Util.formatLocalizedBytes(bytesTotalFs, context)));
Util.showDetailsDialog(context, R.string.main_about_title, headers, details); Util.showDetailsDialog(context, R.string.main_about_title, headers, details);
} }
}.execute(); }.execute();
} }
@Override @Override
public void onItemClicked(UpdateView<Integer> updateView, Integer item) { public void onItemClicked(UpdateView<Integer> updateView, Integer item) {
if (item == R.string.main_albums_random) { if (item == R.string.main_albums_random) {
showAlbumList("random"); showAlbumList("random");
} else if (item == R.string.main_albums_recent) { } else if (item == R.string.main_albums_recent) {
showAlbumList("recent"); showAlbumList("recent");
} else if (item == R.string.main_albums_frequent) { } else if (item == R.string.main_albums_frequent) {
showAlbumList("frequent"); showAlbumList("frequent");
} else if(item == R.string.main_albums_genres) { } else if(item == R.string.main_albums_genres) {
showAlbumList("genres"); showAlbumList("genres");
} else if(item == R.string.main_albums_year) { } else if(item == R.string.main_albums_year) {
showAlbumList("years"); showAlbumList("years");
} else if(item == R.string.main_albums_alphabetical) { } else if(item == R.string.main_albums_alphabetical) {
showAlbumList("alphabeticalByName"); showAlbumList("alphabeticalByName");
} else if (item == R.string.main_songs_newest) { } else if (item == R.string.main_songs_newest) {
showAlbumList(SONGS_NEWEST); showAlbumList(SONGS_NEWEST);
} else if (item == R.string.main_songs_top_played) { } else if (item == R.string.main_songs_top_played) {
showAlbumList(SONGS_TOP_PLAYED); showAlbumList(SONGS_TOP_PLAYED);
} else if (item == R.string.main_songs_recent) { } else if (item == R.string.main_songs_recent) {
showAlbumList(SONGS_RECENT); showAlbumList(SONGS_RECENT);
} else if (item == R.string.main_songs_frequent) { } else if (item == R.string.main_songs_frequent) {
showAlbumList(SONGS_FREQUENT); showAlbumList(SONGS_FREQUENT);
} }
} }
@Override @Override
public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Integer> updateView, Integer item) {} public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Integer> updateView, Integer item) {}
@Override @Override
public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Integer> updateView, Integer item) { public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Integer> updateView, Integer item) {
return false; return false;
} }
} }

View File

@ -1,20 +1,20 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson Copyright 2014 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.fragments; package net.nullsum.audinaut.fragments;
@ -42,293 +42,293 @@ import net.nullsum.audinaut.R;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
public abstract class PreferenceCompatFragment extends SubsonicFragment { public abstract class PreferenceCompatFragment extends SubsonicFragment {
private static final String TAG = PreferenceCompatFragment.class.getSimpleName(); private static final String TAG = PreferenceCompatFragment.class.getSimpleName();
private static final int FIRST_REQUEST_CODE = 100; private static final int FIRST_REQUEST_CODE = 100;
private static final int MSG_BIND_PREFERENCES = 1; private static final int MSG_BIND_PREFERENCES = 1;
private static final String PREFERENCES_TAG = "android:preferences"; private static final String PREFERENCES_TAG = "android:preferences";
private boolean mHavePrefs; private boolean mHavePrefs;
private boolean mInitDone; private boolean mInitDone;
private ListView mList; private ListView mList;
private PreferenceManager mPreferenceManager; private PreferenceManager mPreferenceManager;
private Handler mHandler = new Handler() { private Handler mHandler = new Handler() {
@Override @Override
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
switch (msg.what) { switch (msg.what) {
case MSG_BIND_PREFERENCES: case MSG_BIND_PREFERENCES:
bindPreferences(); bindPreferences();
break; break;
} }
} }
}; };
final private Runnable mRequestFocus = new Runnable() { final private Runnable mRequestFocus = new Runnable() {
public void run() { public void run() {
mList.focusableViewAvailable(mList); mList.focusableViewAvailable(mList);
} }
}; };
private void bindPreferences() { private void bindPreferences() {
PreferenceScreen localPreferenceScreen = getPreferenceScreen(); PreferenceScreen localPreferenceScreen = getPreferenceScreen();
if (localPreferenceScreen != null) { if (localPreferenceScreen != null) {
ListView localListView = getListView(); ListView localListView = getListView();
localPreferenceScreen.bind(localListView); localPreferenceScreen.bind(localListView);
} }
} }
private void ensureList() { private void ensureList() {
if (mList == null) { if (mList == null) {
View view = getView(); View view = getView();
if (view == null) { if (view == null) {
throw new IllegalStateException("Content view not yet created"); throw new IllegalStateException("Content view not yet created");
} }
View listView = view.findViewById(android.R.id.list); View listView = view.findViewById(android.R.id.list);
if (!(listView instanceof ListView)) { if (!(listView instanceof ListView)) {
throw new RuntimeException("Content has view with id attribute 'android.R.id.list' that is not a ListView class"); throw new RuntimeException("Content has view with id attribute 'android.R.id.list' that is not a ListView class");
} }
mList = (ListView)listView; mList = (ListView)listView;
if (mList == null) { if (mList == null) {
throw new RuntimeException("Your content must have a ListView whose id attribute is 'android.R.id.list'"); throw new RuntimeException("Your content must have a ListView whose id attribute is 'android.R.id.list'");
} }
mHandler.post(mRequestFocus); mHandler.post(mRequestFocus);
} }
} }
private void postBindPreferences() { private void postBindPreferences() {
if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) { if (mHandler.hasMessages(MSG_BIND_PREFERENCES)) {
mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget(); mHandler.obtainMessage(MSG_BIND_PREFERENCES).sendToTarget();
} }
} }
private void requirePreferenceManager() { private void requirePreferenceManager() {
if (this.mPreferenceManager == null) { if (this.mPreferenceManager == null) {
throw new RuntimeException("This should be called after super.onCreate."); throw new RuntimeException("This should be called after super.onCreate.");
} }
} }
public void addPreferencesFromIntent(Intent intent) { public void addPreferencesFromIntent(Intent intent) {
requirePreferenceManager(); requirePreferenceManager();
PreferenceScreen screen = inflateFromIntent(intent, getPreferenceScreen()); PreferenceScreen screen = inflateFromIntent(intent, getPreferenceScreen());
setPreferenceScreen(screen); setPreferenceScreen(screen);
} }
public PreferenceScreen addPreferencesFromResource(int resId) { public PreferenceScreen addPreferencesFromResource(int resId) {
requirePreferenceManager(); requirePreferenceManager();
PreferenceScreen screen = inflateFromResource(getActivity(), resId, getPreferenceScreen()); PreferenceScreen screen = inflateFromResource(getActivity(), resId, getPreferenceScreen());
setPreferenceScreen(screen); setPreferenceScreen(screen);
for(int i = 0; i < screen.getPreferenceCount(); i++) { for(int i = 0; i < screen.getPreferenceCount(); i++) {
Preference preference = screen.getPreference(i); Preference preference = screen.getPreference(i);
if(preference instanceof PreferenceScreen && preference.getKey() != null) { if(preference instanceof PreferenceScreen && preference.getKey() != null) {
preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { preference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override @Override
public boolean onPreferenceClick(Preference preference) { public boolean onPreferenceClick(Preference preference) {
onStartNewFragment(preference.getKey()); onStartNewFragment(preference.getKey());
return false; return false;
} }
}); });
} }
} }
return screen; return screen;
} }
public Preference findPreference(CharSequence key) { public Preference findPreference(CharSequence key) {
if (mPreferenceManager == null) { if (mPreferenceManager == null) {
return null; return null;
} }
return mPreferenceManager.findPreference(key); return mPreferenceManager.findPreference(key);
} }
public ListView getListView() { public ListView getListView() {
ensureList(); ensureList();
return mList; return mList;
} }
public PreferenceManager getPreferenceManager() { public PreferenceManager getPreferenceManager() {
return mPreferenceManager; return mPreferenceManager;
} }
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY); getListView().setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
if (mHavePrefs) { if (mHavePrefs) {
bindPreferences(); bindPreferences();
} }
mInitDone = true; mInitDone = true;
if (savedInstanceState != null) { if (savedInstanceState != null) {
Bundle localBundle = savedInstanceState.getBundle(PREFERENCES_TAG); Bundle localBundle = savedInstanceState.getBundle(PREFERENCES_TAG);
if (localBundle != null) { if (localBundle != null) {
PreferenceScreen screen = getPreferenceScreen(); PreferenceScreen screen = getPreferenceScreen();
if (screen != null) { if (screen != null) {
screen.restoreHierarchyState(localBundle); screen.restoreHierarchyState(localBundle);
} }
} }
} }
} }
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
dispatchActivityResult(requestCode, resultCode, data); dispatchActivityResult(requestCode, resultCode, data);
} }
@Override @Override
public void onCreate(Bundle paramBundle) { public void onCreate(Bundle paramBundle) {
super.onCreate(paramBundle); super.onCreate(paramBundle);
mPreferenceManager = createPreferenceManager(); mPreferenceManager = createPreferenceManager();
int res = this.getArguments().getInt(Constants.INTENT_EXTRA_FRAGMENT_TYPE, 0); int res = this.getArguments().getInt(Constants.INTENT_EXTRA_FRAGMENT_TYPE, 0);
if(res != 0) { if(res != 0) {
PreferenceScreen preferenceScreen = addPreferencesFromResource(res); PreferenceScreen preferenceScreen = addPreferencesFromResource(res);
onInitPreferences(preferenceScreen); onInitPreferences(preferenceScreen);
} }
} }
@Override @Override
public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle) { public View onCreateView(LayoutInflater paramLayoutInflater, ViewGroup paramViewGroup, Bundle paramBundle) {
return paramLayoutInflater.inflate(R.layout.preferences, paramViewGroup, false); return paramLayoutInflater.inflate(R.layout.preferences, paramViewGroup, false);
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
dispatchActivityDestroy(); dispatchActivityDestroy();
} }
@Override @Override
public void onDestroyView() { public void onDestroyView() {
mList = null; mList = null;
mHandler.removeCallbacks(mRequestFocus); mHandler.removeCallbacks(mRequestFocus);
mHandler.removeMessages(MSG_BIND_PREFERENCES); mHandler.removeMessages(MSG_BIND_PREFERENCES);
super.onDestroyView(); super.onDestroyView();
} }
@Override @Override
public void onSaveInstanceState(Bundle bundle) { public void onSaveInstanceState(Bundle bundle) {
super.onSaveInstanceState(bundle); super.onSaveInstanceState(bundle);
PreferenceScreen screen = getPreferenceScreen(); PreferenceScreen screen = getPreferenceScreen();
if (screen != null) { if (screen != null) {
Bundle localBundle = new Bundle(); Bundle localBundle = new Bundle();
screen.saveHierarchyState(localBundle); screen.saveHierarchyState(localBundle);
bundle.putBundle(PREFERENCES_TAG, localBundle); bundle.putBundle(PREFERENCES_TAG, localBundle);
} }
} }
@Override @Override
public void onStop() { public void onStop() {
super.onStop(); super.onStop();
dispatchActivityStop(); dispatchActivityStop();
} }
/** Access methods with visibility private **/ /** Access methods with visibility private **/
private PreferenceManager createPreferenceManager() { private PreferenceManager createPreferenceManager() {
try { try {
Constructor<PreferenceManager> c = PreferenceManager.class.getDeclaredConstructor(Activity.class, int.class); Constructor<PreferenceManager> c = PreferenceManager.class.getDeclaredConstructor(Activity.class, int.class);
c.setAccessible(true); c.setAccessible(true);
return c.newInstance(this.getActivity(), FIRST_REQUEST_CODE); return c.newInstance(this.getActivity(), FIRST_REQUEST_CODE);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
private PreferenceScreen getPreferenceScreen() { private PreferenceScreen getPreferenceScreen() {
try { try {
Method m = PreferenceManager.class.getDeclaredMethod("getPreferenceScreen"); Method m = PreferenceManager.class.getDeclaredMethod("getPreferenceScreen");
m.setAccessible(true); m.setAccessible(true);
return (PreferenceScreen) m.invoke(mPreferenceManager); return (PreferenceScreen) m.invoke(mPreferenceManager);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
protected void setPreferenceScreen(PreferenceScreen preferenceScreen) { protected void setPreferenceScreen(PreferenceScreen preferenceScreen) {
try { try {
Method m = PreferenceManager.class.getDeclaredMethod("setPreferences", PreferenceScreen.class); Method m = PreferenceManager.class.getDeclaredMethod("setPreferences", PreferenceScreen.class);
m.setAccessible(true); m.setAccessible(true);
boolean result = (Boolean) m.invoke(mPreferenceManager, preferenceScreen); boolean result = (Boolean) m.invoke(mPreferenceManager, preferenceScreen);
if (result && preferenceScreen != null) { if (result && preferenceScreen != null) {
mHavePrefs = true; mHavePrefs = true;
if (mInitDone) { if (mInitDone) {
postBindPreferences(); postBindPreferences();
} }
} }
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
private void dispatchActivityResult(int requestCode, int resultCode, Intent data) { private void dispatchActivityResult(int requestCode, int resultCode, Intent data) {
try { try {
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityResult", int.class, int.class, Intent.class); Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityResult", int.class, int.class, Intent.class);
m.setAccessible(true); m.setAccessible(true);
m.invoke(mPreferenceManager, requestCode, resultCode, data); m.invoke(mPreferenceManager, requestCode, resultCode, data);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
private void dispatchActivityDestroy() { private void dispatchActivityDestroy() {
try { try {
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityDestroy"); Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityDestroy");
m.setAccessible(true); m.setAccessible(true);
m.invoke(mPreferenceManager); m.invoke(mPreferenceManager);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
private void dispatchActivityStop() { private void dispatchActivityStop() {
try { try {
Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityStop"); Method m = PreferenceManager.class.getDeclaredMethod("dispatchActivityStop");
m.setAccessible(true); m.setAccessible(true);
m.invoke(mPreferenceManager); m.invoke(mPreferenceManager);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
private void setFragment(PreferenceFragment preferenceFragment) { private void setFragment(PreferenceFragment preferenceFragment) {
try { try {
Method m = PreferenceManager.class.getDeclaredMethod("setFragment", PreferenceFragment.class); Method m = PreferenceManager.class.getDeclaredMethod("setFragment", PreferenceFragment.class);
m.setAccessible(true); m.setAccessible(true);
m.invoke(mPreferenceManager, preferenceFragment); m.invoke(mPreferenceManager, preferenceFragment);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
} }
public PreferenceScreen inflateFromResource(Context context, int resId, PreferenceScreen rootPreferences) { public PreferenceScreen inflateFromResource(Context context, int resId, PreferenceScreen rootPreferences) {
PreferenceScreen preferenceScreen ; PreferenceScreen preferenceScreen ;
try { try {
Method m = PreferenceManager.class.getDeclaredMethod("inflateFromResource", Context.class, int.class, PreferenceScreen.class); Method m = PreferenceManager.class.getDeclaredMethod("inflateFromResource", Context.class, int.class, PreferenceScreen.class);
m.setAccessible(true); m.setAccessible(true);
preferenceScreen = (PreferenceScreen) m.invoke(mPreferenceManager, context, resId, rootPreferences); preferenceScreen = (PreferenceScreen) m.invoke(mPreferenceManager, context, resId, rootPreferences);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return preferenceScreen; return preferenceScreen;
} }
public PreferenceScreen inflateFromIntent(Intent queryIntent, PreferenceScreen rootPreferences) { public PreferenceScreen inflateFromIntent(Intent queryIntent, PreferenceScreen rootPreferences) {
PreferenceScreen preferenceScreen ; PreferenceScreen preferenceScreen ;
try { try {
Method m = PreferenceManager.class.getDeclaredMethod("inflateFromIntent", Intent.class, PreferenceScreen.class); Method m = PreferenceManager.class.getDeclaredMethod("inflateFromIntent", Intent.class, PreferenceScreen.class);
m.setAccessible(true); m.setAccessible(true);
preferenceScreen = (PreferenceScreen) m.invoke(mPreferenceManager, queryIntent, rootPreferences); preferenceScreen = (PreferenceScreen) m.invoke(mPreferenceManager, queryIntent, rootPreferences);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
return preferenceScreen; return preferenceScreen;
} }
protected abstract void onInitPreferences(PreferenceScreen preferenceScreen); protected abstract void onInitPreferences(PreferenceScreen preferenceScreen);
protected abstract void onStartNewFragment(String name); protected abstract void onStartNewFragment(String name);
} }

View File

@ -38,254 +38,254 @@ import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
public class SearchFragment extends SubsonicFragment implements SectionAdapter.OnItemClickedListener<Serializable> { public class SearchFragment extends SubsonicFragment implements SectionAdapter.OnItemClickedListener<Serializable> {
private static final String TAG = SearchFragment.class.getSimpleName(); private static final String TAG = SearchFragment.class.getSimpleName();
private static final int MAX_ARTISTS = 20; private static final int MAX_ARTISTS = 20;
private static final int MAX_ALBUMS = 20; private static final int MAX_ALBUMS = 20;
private static final int MAX_SONGS = 50; private static final int MAX_SONGS = 50;
private static final int MIN_CLOSENESS = 1; private static final int MIN_CLOSENESS = 1;
protected RecyclerView recyclerView; protected RecyclerView recyclerView;
protected SearchAdapter adapter; protected SearchAdapter adapter;
protected boolean largeAlbums = false; protected boolean largeAlbums = false;
private SearchResult searchResult; private SearchResult searchResult;
private boolean skipSearch = false; private boolean skipSearch = false;
private String currentQuery; private String currentQuery;
public SearchFragment() { public SearchFragment() {
super(); super();
alwaysStartFullscreen = true; alwaysStartFullscreen = true;
} }
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if(savedInstanceState != null) { if(savedInstanceState != null) {
searchResult = (SearchResult) savedInstanceState.getSerializable(Constants.FRAGMENT_LIST); searchResult = (SearchResult) savedInstanceState.getSerializable(Constants.FRAGMENT_LIST);
} }
largeAlbums = Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_LARGE_ALBUM_ART, true); largeAlbums = Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_LARGE_ALBUM_ART, true);
} }
@Override @Override
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
outState.putSerializable(Constants.FRAGMENT_LIST, searchResult); outState.putSerializable(Constants.FRAGMENT_LIST, searchResult);
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
rootView = inflater.inflate(R.layout.abstract_recycler_fragment, container, false); rootView = inflater.inflate(R.layout.abstract_recycler_fragment, container, false);
setTitle(R.string.search_title); setTitle(R.string.search_title);
refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout);
refreshLayout.setEnabled(false); refreshLayout.setEnabled(false);
recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_recycler); recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_recycler);
setupLayoutManager(recyclerView, largeAlbums); setupLayoutManager(recyclerView, largeAlbums);
registerForContextMenu(recyclerView); registerForContextMenu(recyclerView);
context.onNewIntent(context.getIntent()); context.onNewIntent(context.getIntent());
if(searchResult != null) { if(searchResult != null) {
skipSearch = true; skipSearch = true;
recyclerView.setAdapter(adapter = new SearchAdapter(context, searchResult, getImageLoader(), largeAlbums, this)); recyclerView.setAdapter(adapter = new SearchAdapter(context, searchResult, getImageLoader(), largeAlbums, this));
} }
return rootView; return rootView;
} }
@Override @Override
public void setIsOnlyVisible(boolean isOnlyVisible) { public void setIsOnlyVisible(boolean isOnlyVisible) {
boolean update = this.isOnlyVisible != isOnlyVisible; boolean update = this.isOnlyVisible != isOnlyVisible;
super.setIsOnlyVisible(isOnlyVisible); super.setIsOnlyVisible(isOnlyVisible);
if(update && adapter != null) { if(update && adapter != null) {
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if(layoutManager instanceof GridLayoutManager) { if(layoutManager instanceof GridLayoutManager) {
((GridLayoutManager) layoutManager).setSpanCount(getRecyclerColumnCount()); ((GridLayoutManager) layoutManager).setSpanCount(getRecyclerColumnCount());
} }
} }
} }
@Override @Override
public GridLayoutManager.SpanSizeLookup getSpanSizeLookup(final GridLayoutManager gridLayoutManager) { public GridLayoutManager.SpanSizeLookup getSpanSizeLookup(final GridLayoutManager gridLayoutManager) {
return new GridLayoutManager.SpanSizeLookup() { return new GridLayoutManager.SpanSizeLookup() {
@Override @Override
public int getSpanSize(int position) { public int getSpanSize(int position) {
int viewType = adapter.getItemViewType(position); int viewType = adapter.getItemViewType(position);
if(viewType == EntryGridAdapter.VIEW_TYPE_SONG || viewType == EntryGridAdapter.VIEW_TYPE_HEADER || viewType == ArtistAdapter.VIEW_TYPE_ARTIST) { if(viewType == EntryGridAdapter.VIEW_TYPE_SONG || viewType == EntryGridAdapter.VIEW_TYPE_HEADER || viewType == ArtistAdapter.VIEW_TYPE_ARTIST) {
return gridLayoutManager.getSpanCount(); return gridLayoutManager.getSpanCount();
} else { } else {
return 1; return 1;
} }
} }
}; };
} }
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
menuInflater.inflate(R.menu.search, menu); menuInflater.inflate(R.menu.search, menu);
onFinishSetupOptionsMenu(menu); onFinishSetupOptionsMenu(menu);
} }
@Override @Override
public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Serializable> updateView, Serializable item) { public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Serializable> updateView, Serializable item) {
onCreateContextMenuSupport(menu, menuInflater, updateView, item); onCreateContextMenuSupport(menu, menuInflater, updateView, item);
if(item instanceof MusicDirectory.Entry && !Util.isOffline(context)) { if(item instanceof MusicDirectory.Entry && !Util.isOffline(context)) {
menu.removeItem(R.id.song_menu_remove_playlist); menu.removeItem(R.id.song_menu_remove_playlist);
} }
recreateContextMenu(menu); recreateContextMenu(menu);
} }
@Override @Override
public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Serializable> updateView, Serializable item) { public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Serializable> updateView, Serializable item) {
return onContextItemSelected(menuItem, item); return onContextItemSelected(menuItem, item);
} }
@Override @Override
public void refresh(boolean refresh) { public void refresh(boolean refresh) {
context.onNewIntent(context.getIntent()); context.onNewIntent(context.getIntent());
} }
@Override @Override
public void onItemClicked(UpdateView<Serializable> updateView, Serializable item) { public void onItemClicked(UpdateView<Serializable> updateView, Serializable item) {
if (item instanceof Artist) { if (item instanceof Artist) {
onArtistSelected((Artist) item, false); onArtistSelected((Artist) item, false);
} else if (item instanceof MusicDirectory.Entry) { } else if (item instanceof MusicDirectory.Entry) {
MusicDirectory.Entry entry = (MusicDirectory.Entry) item; MusicDirectory.Entry entry = (MusicDirectory.Entry) item;
if (entry.isDirectory()) { if (entry.isDirectory()) {
onAlbumSelected(entry, false); onAlbumSelected(entry, false);
} else { } else {
onSongSelected(entry, false, true, true, false); onSongSelected(entry, false, true, true, false);
} }
} }
} }
@Override @Override
protected List<MusicDirectory.Entry> getSelectedEntries() { protected List<MusicDirectory.Entry> getSelectedEntries() {
List<Serializable> selected = adapter.getSelected(); List<Serializable> selected = adapter.getSelected();
List<MusicDirectory.Entry> selectedMedia = new ArrayList<>(); List<MusicDirectory.Entry> selectedMedia = new ArrayList<>();
for(Serializable ser: selected) { for(Serializable ser: selected) {
if(ser instanceof MusicDirectory.Entry) { if(ser instanceof MusicDirectory.Entry) {
selectedMedia.add((MusicDirectory.Entry) ser); selectedMedia.add((MusicDirectory.Entry) ser);
} }
} }
return selectedMedia; return selectedMedia;
} }
@Override @Override
protected boolean isShowArtistEnabled() { protected boolean isShowArtistEnabled() {
return true; return true;
} }
public void search(final String query, final boolean autoplay) { public void search(final String query, final boolean autoplay) {
if(skipSearch) { if(skipSearch) {
skipSearch = false; skipSearch = false;
return; return;
} }
currentQuery = query; currentQuery = query;
BackgroundTask<SearchResult> task = new TabBackgroundTask<SearchResult>(this) { BackgroundTask<SearchResult> task = new TabBackgroundTask<SearchResult>(this) {
@Override @Override
protected SearchResult doInBackground() throws Throwable { protected SearchResult doInBackground() throws Throwable {
SearchCritera criteria = new SearchCritera(query, MAX_ARTISTS, MAX_ALBUMS, MAX_SONGS); SearchCritera criteria = new SearchCritera(query, MAX_ARTISTS, MAX_ALBUMS, MAX_SONGS);
MusicService service = MusicServiceFactory.getMusicService(context); MusicService service = MusicServiceFactory.getMusicService(context);
return service.search(criteria, context, this); return service.search(criteria, context, this);
} }
@Override @Override
protected void done(SearchResult result) { protected void done(SearchResult result) {
searchResult = result; searchResult = result;
recyclerView.setAdapter(adapter = new SearchAdapter(context, searchResult, getImageLoader(), largeAlbums, SearchFragment.this)); recyclerView.setAdapter(adapter = new SearchAdapter(context, searchResult, getImageLoader(), largeAlbums, SearchFragment.this));
if (autoplay) { if (autoplay) {
autoplay(query); autoplay(query);
} }
} }
}; };
task.execute(); task.execute();
if(searchItem != null) { if(searchItem != null) {
MenuItemCompat.collapseActionView(searchItem); MenuItemCompat.collapseActionView(searchItem);
} }
} }
protected String getCurrentQuery() { protected String getCurrentQuery() {
return currentQuery; return currentQuery;
} }
private void onArtistSelected(Artist artist, boolean autoplay) { private void onArtistSelected(Artist artist, boolean autoplay) {
SubsonicFragment fragment = new SelectDirectoryFragment(); SubsonicFragment fragment = new SelectDirectoryFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
if(autoplay) { if(autoplay) {
args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
} }
args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true);
fragment.setArguments(args); fragment.setArguments(args);
replaceFragment(fragment); replaceFragment(fragment);
} }
private void onAlbumSelected(MusicDirectory.Entry album, boolean autoplay) { private void onAlbumSelected(MusicDirectory.Entry album, boolean autoplay) {
SubsonicFragment fragment = new SelectDirectoryFragment(); SubsonicFragment fragment = new SelectDirectoryFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_ID, album.getId()); args.putString(Constants.INTENT_EXTRA_NAME_ID, album.getId());
args.putString(Constants.INTENT_EXTRA_NAME_NAME, album.getTitle()); args.putString(Constants.INTENT_EXTRA_NAME_NAME, album.getTitle());
if(autoplay) { if(autoplay) {
args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
} }
fragment.setArguments(args); fragment.setArguments(args);
replaceFragment(fragment); replaceFragment(fragment);
} }
private void onSongSelected(MusicDirectory.Entry song, boolean save, boolean append, boolean autoplay, boolean playNext) { private void onSongSelected(MusicDirectory.Entry song, boolean save, boolean append, boolean autoplay, boolean playNext) {
DownloadService downloadService = getDownloadService(); DownloadService downloadService = getDownloadService();
if (downloadService != null) { if (downloadService != null) {
if (!append) { if (!append) {
downloadService.clear(); downloadService.clear();
} }
downloadService.download(Arrays.asList(song), save, false, playNext, false); downloadService.download(Arrays.asList(song), save, false, playNext, false);
if (autoplay) { if (autoplay) {
downloadService.play(downloadService.size() - 1); downloadService.play(downloadService.size() - 1);
} }
Util.toast(context, getResources().getQuantityString(R.plurals.select_album_n_songs_added, 1, 1)); Util.toast(context, getResources().getQuantityString(R.plurals.select_album_n_songs_added, 1, 1));
} }
} }
private void autoplay(String query) { private void autoplay(String query) {
query = query.toLowerCase(); query = query.toLowerCase();
Artist artist = null; Artist artist = null;
if(!searchResult.getArtists().isEmpty()) { if(!searchResult.getArtists().isEmpty()) {
artist = searchResult.getArtists().get(0); artist = searchResult.getArtists().get(0);
artist.setCloseness(Util.getStringDistance(artist.getName().toLowerCase(), query)); artist.setCloseness(Util.getStringDistance(artist.getName().toLowerCase(), query));
} }
MusicDirectory.Entry album = null; MusicDirectory.Entry album = null;
if(!searchResult.getAlbums().isEmpty()) { if(!searchResult.getAlbums().isEmpty()) {
album = searchResult.getAlbums().get(0); album = searchResult.getAlbums().get(0);
album.setCloseness(Util.getStringDistance(album.getTitle().toLowerCase(), query)); album.setCloseness(Util.getStringDistance(album.getTitle().toLowerCase(), query));
} }
MusicDirectory.Entry song = null; MusicDirectory.Entry song = null;
if(!searchResult.getSongs().isEmpty()) { if(!searchResult.getSongs().isEmpty()) {
song = searchResult.getSongs().get(0); song = searchResult.getSongs().get(0);
song.setCloseness(Util.getStringDistance(song.getTitle().toLowerCase(), query)); song.setCloseness(Util.getStringDistance(song.getTitle().toLowerCase(), query));
} }
if(artist != null && (artist.getCloseness() <= MIN_CLOSENESS || if(artist != null && (artist.getCloseness() <= MIN_CLOSENESS ||
(album == null || artist.getCloseness() <= album.getCloseness()) && (album == null || artist.getCloseness() <= album.getCloseness()) &&
(song == null || artist.getCloseness() <= song.getCloseness()))) { (song == null || artist.getCloseness() <= song.getCloseness()))) {
onArtistSelected(artist, true); onArtistSelected(artist, true);
} else if(album != null && (album.getCloseness() <= MIN_CLOSENESS || } else if(album != null && (album.getCloseness() <= MIN_CLOSENESS ||
song == null || album.getCloseness() <= song.getCloseness())) { song == null || album.getCloseness() <= song.getCloseness())) {
onAlbumSelected(album, true); onAlbumSelected(album, true);
} else if(song != null) { } else if(song != null) {
onSongSelected(song, false, false, true, false); onSongSelected(song, false, false, true, false);
} }
} }
} }

View File

@ -29,224 +29,224 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
public class SelectArtistFragment extends SelectRecyclerFragment<Serializable> implements ArtistAdapter.OnMusicFolderChanged { public class SelectArtistFragment extends SelectRecyclerFragment<Serializable> implements ArtistAdapter.OnMusicFolderChanged {
private static final String TAG = SelectArtistFragment.class.getSimpleName(); private static final String TAG = SelectArtistFragment.class.getSimpleName();
private List<MusicFolder> musicFolders = null; private List<MusicFolder> musicFolders = null;
private List<Entry> entries; private List<Entry> entries;
private String groupId; private String groupId;
private String groupName; private String groupName;
public SelectArtistFragment() { public SelectArtistFragment() {
super(); super();
} }
@Override @Override
public void onCreate(Bundle bundle) { public void onCreate(Bundle bundle) {
super.onCreate(bundle); super.onCreate(bundle);
if(bundle != null) { if(bundle != null) {
musicFolders = (List<MusicFolder>) bundle.getSerializable(Constants.FRAGMENT_LIST2); musicFolders = (List<MusicFolder>) bundle.getSerializable(Constants.FRAGMENT_LIST2);
} }
artist = true; artist = true;
} }
@Override @Override
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
outState.putSerializable(Constants.FRAGMENT_LIST2, (Serializable) musicFolders); outState.putSerializable(Constants.FRAGMENT_LIST2, (Serializable) musicFolders);
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
Bundle args = getArguments(); Bundle args = getArguments();
if(args != null) { if(args != null) {
if(args.getBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, false)) { if(args.getBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, false)) {
groupId = args.getString(Constants.INTENT_EXTRA_NAME_ID); groupId = args.getString(Constants.INTENT_EXTRA_NAME_ID);
groupName = args.getString(Constants.INTENT_EXTRA_NAME_NAME); groupName = args.getString(Constants.INTENT_EXTRA_NAME_NAME);
if (groupName != null) { if (groupName != null) {
setTitle(groupName); setTitle(groupName);
context.invalidateOptionsMenu(); context.invalidateOptionsMenu();
} }
} }
} }
super.onCreateView(inflater, container, bundle); super.onCreateView(inflater, container, bundle);
return rootView; return rootView;
} }
@Override @Override
public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Serializable> updateView, Serializable item) { public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Serializable> updateView, Serializable item) {
onCreateContextMenuSupport(menu, menuInflater, updateView, item); onCreateContextMenuSupport(menu, menuInflater, updateView, item);
recreateContextMenu(menu); recreateContextMenu(menu);
} }
@Override @Override
public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Serializable> updateView, Serializable item) { public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Serializable> updateView, Serializable item) {
return onContextItemSelected(menuItem, item); return onContextItemSelected(menuItem, item);
} }
@Override @Override
public void onItemClicked(UpdateView<Serializable> updateView, Serializable item) { public void onItemClicked(UpdateView<Serializable> updateView, Serializable item) {
SubsonicFragment fragment; SubsonicFragment fragment;
if(item instanceof Artist) { if(item instanceof Artist) {
Artist artist = (Artist) item; Artist artist = (Artist) item;
if ((Util.isFirstLevelArtist(context) || Util.isOffline(context) || Util.isTagBrowsing(context)) || groupId != null) { if ((Util.isFirstLevelArtist(context) || Util.isOffline(context) || Util.isTagBrowsing(context)) || groupId != null) {
fragment = new SelectDirectoryFragment(); fragment = new SelectDirectoryFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
if (!Util.isOffline(context)) { if (!Util.isOffline(context)) {
args.putSerializable(Constants.INTENT_EXTRA_NAME_DIRECTORY, new Entry(artist)); args.putSerializable(Constants.INTENT_EXTRA_NAME_DIRECTORY, new Entry(artist));
} }
args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true);
fragment.setArguments(args); fragment.setArguments(args);
} else { } else {
fragment = new SelectArtistFragment(); fragment = new SelectArtistFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true);
if (!Util.isOffline(context)) { if (!Util.isOffline(context)) {
args.putSerializable(Constants.INTENT_EXTRA_NAME_DIRECTORY, new Entry(artist)); args.putSerializable(Constants.INTENT_EXTRA_NAME_DIRECTORY, new Entry(artist));
} }
fragment.setArguments(args); fragment.setArguments(args);
} }
replaceFragment(fragment); replaceFragment(fragment);
} else { } else {
Entry entry = (Entry) item; Entry entry = (Entry) item;
onSongPress(entries, entry); onSongPress(entries, entry);
} }
} }
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
super.onCreateOptionsMenu(menu, menuInflater); super.onCreateOptionsMenu(menu, menuInflater);
if(Util.isOffline(context) || Util.isTagBrowsing(context) || groupId != null) { if(Util.isOffline(context) || Util.isTagBrowsing(context) || groupId != null) {
menu.removeItem(R.id.menu_first_level_artist); menu.removeItem(R.id.menu_first_level_artist);
} else { } else {
if (Util.isFirstLevelArtist(context)) { if (Util.isFirstLevelArtist(context)) {
menu.findItem(R.id.menu_first_level_artist).setChecked(true); menu.findItem(R.id.menu_first_level_artist).setChecked(true);
} }
} }
} }
@Override @Override
public int getOptionsMenu() { public int getOptionsMenu() {
return R.menu.select_artist; return R.menu.select_artist;
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
if(super.onOptionsItemSelected(item)) { if(super.onOptionsItemSelected(item)) {
return true; return true;
} }
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.menu_first_level_artist: case R.id.menu_first_level_artist:
toggleFirstLevelArtist(); toggleFirstLevelArtist();
break; break;
} }
return false; return false;
} }
@Override @Override
public SectionAdapter getAdapter(List<Serializable> objects) { public SectionAdapter getAdapter(List<Serializable> objects) {
return new ArtistAdapter(context, objects, musicFolders, this, this); return new ArtistAdapter(context, objects, musicFolders, this, this);
} }
@Override @Override
public List<Serializable> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { public List<Serializable> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception {
List<Serializable> items; List<Serializable> items;
if(groupId == null) { if(groupId == null) {
if (!Util.isOffline(context) && !Util.isTagBrowsing(context)) { if (!Util.isOffline(context) && !Util.isTagBrowsing(context)) {
musicFolders = musicService.getMusicFolders(refresh, context, listener); musicFolders = musicService.getMusicFolders(refresh, context, listener);
// Hide folders option if there is only one // Hide folders option if there is only one
if (musicFolders.size() == 1) { if (musicFolders.size() == 1) {
musicFolders = null; musicFolders = null;
Util.setSelectedMusicFolderId(context, null); Util.setSelectedMusicFolderId(context, null);
} }
} else { } else {
musicFolders = null; musicFolders = null;
} }
String musicFolderId = Util.getSelectedMusicFolderId(context); String musicFolderId = Util.getSelectedMusicFolderId(context);
Indexes indexes = musicService.getIndexes(musicFolderId, refresh, context, listener); Indexes indexes = musicService.getIndexes(musicFolderId, refresh, context, listener);
indexes.sortChildren(context); indexes.sortChildren(context);
items = new ArrayList<>(indexes.getShortcuts().size() + indexes.getArtists().size()); items = new ArrayList<>(indexes.getShortcuts().size() + indexes.getArtists().size());
items.addAll(indexes.getShortcuts()); items.addAll(indexes.getShortcuts());
items.addAll(indexes.getArtists()); items.addAll(indexes.getArtists());
entries = indexes.getEntries(); entries = indexes.getEntries();
items.addAll(entries); items.addAll(entries);
} else { } else {
List<Artist> artists = new ArrayList<>(); List<Artist> artists = new ArrayList<>();
items = new ArrayList<>(); items = new ArrayList<>();
MusicDirectory dir = musicService.getMusicDirectory(groupId, groupName, refresh, context, listener); MusicDirectory dir = musicService.getMusicDirectory(groupId, groupName, refresh, context, listener);
for(Entry entry: dir.getChildren(true, false)) { for(Entry entry: dir.getChildren(true, false)) {
Artist artist = new Artist(); Artist artist = new Artist();
artist.setId(entry.getId()); artist.setId(entry.getId());
artist.setName(entry.getTitle()); artist.setName(entry.getTitle());
artists.add(artist); artists.add(artist);
} }
Indexes indexes = new Indexes(); Indexes indexes = new Indexes();
//indexes.setArtists = artists; //indexes.setArtists = artists;
indexes.sortChildren(context); indexes.sortChildren(context);
items.addAll(indexes.getArtists()); items.addAll(indexes.getArtists());
entries = dir.getChildren(false, true); entries = dir.getChildren(false, true);
for(Entry entry: entries) { for(Entry entry: entries) {
items.add(entry); items.add(entry);
} }
} }
return items; return items;
} }
@Override @Override
public int getTitleResource() { public int getTitleResource() {
return groupId == null ? R.string.button_bar_browse : 0; return groupId == null ? R.string.button_bar_browse : 0;
} }
@Override @Override
public void setEmpty(boolean empty) { public void setEmpty(boolean empty) {
super.setEmpty(empty); super.setEmpty(empty);
if(empty && !Util.isOffline(context)) { if(empty && !Util.isOffline(context)) {
objects.clear(); objects.clear();
recyclerView.setAdapter(new ArtistAdapter(context, objects, musicFolders, this, this)); recyclerView.setAdapter(new ArtistAdapter(context, objects, musicFolders, this, this));
recyclerView.setVisibility(View.VISIBLE); recyclerView.setVisibility(View.VISIBLE);
View view = rootView.findViewById(R.id.tab_progress); View view = rootView.findViewById(R.id.tab_progress);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams(); LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams();
params.height = 0; params.height = 0;
params.weight = 5; params.weight = 5;
view.setLayoutParams(params); view.setLayoutParams(params);
} }
} }
private void toggleFirstLevelArtist() { private void toggleFirstLevelArtist() {
Util.toggleFirstLevelArtist(context); Util.toggleFirstLevelArtist(context);
context.invalidateOptionsMenu(); context.invalidateOptionsMenu();
} }
@Override @Override
public void onMusicFolderChanged(MusicFolder selectedFolder) { public void onMusicFolderChanged(MusicFolder selectedFolder) {
String startMusicFolderId = Util.getSelectedMusicFolderId(context); String startMusicFolderId = Util.getSelectedMusicFolderId(context);
String musicFolderId = selectedFolder == null ? null : selectedFolder.getId(); String musicFolderId = selectedFolder == null ? null : selectedFolder.getId();
if(!Util.equals(startMusicFolderId, musicFolderId)) { if(!Util.equals(startMusicFolderId, musicFolderId)) {
Util.setSelectedMusicFolderId(context, musicFolderId); Util.setSelectedMusicFolderId(context, musicFolderId);
context.invalidate(); context.invalidate();
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.fragments; package net.nullsum.audinaut.fragments;
@ -32,46 +32,46 @@ import net.nullsum.audinaut.view.UpdateView;
import java.util.List; import java.util.List;
public class SelectGenreFragment extends SelectRecyclerFragment<Genre> { public class SelectGenreFragment extends SelectRecyclerFragment<Genre> {
private static final String TAG = SelectGenreFragment.class.getSimpleName(); private static final String TAG = SelectGenreFragment.class.getSimpleName();
@Override @Override
public int getOptionsMenu() { public int getOptionsMenu() {
return R.menu.empty; return R.menu.empty;
} }
@Override @Override
public SectionAdapter getAdapter(List<Genre> objs) { public SectionAdapter getAdapter(List<Genre> objs) {
return new GenreAdapter(context, objs, this); return new GenreAdapter(context, objs, this);
} }
@Override @Override
public List<Genre> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { public List<Genre> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception {
return musicService.getGenres(refresh, context, listener); return musicService.getGenres(refresh, context, listener);
} }
@Override @Override
public int getTitleResource() { public int getTitleResource() {
return R.string.main_albums_genres; return R.string.main_albums_genres;
} }
@Override @Override
public void onItemClicked(UpdateView<Genre> updateView, Genre genre) { public void onItemClicked(UpdateView<Genre> updateView, Genre genre) {
SubsonicFragment fragment = new SelectDirectoryFragment(); SubsonicFragment fragment = new SelectDirectoryFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, "genres"); args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, "genres");
args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20); args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20);
args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0); args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA, genre.getName()); args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA, genre.getName());
fragment.setArguments(args); fragment.setArguments(args);
replaceFragment(fragment); replaceFragment(fragment);
} }
@Override @Override
public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Genre> updateView, Genre item) {} public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Genre> updateView, Genre item) {}
@Override @Override
public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Genre> updateView, Genre item) { public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Genre> updateView, Genre item) {
return false; return false;
} }
} }

View File

@ -36,311 +36,311 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
public class SelectPlaylistFragment extends SelectRecyclerFragment<Playlist> { public class SelectPlaylistFragment extends SelectRecyclerFragment<Playlist> {
private static final String TAG = SelectPlaylistFragment.class.getSimpleName(); private static final String TAG = SelectPlaylistFragment.class.getSimpleName();
@Override @Override
public void onCreate(Bundle bundle) { public void onCreate(Bundle bundle) {
super.onCreate(bundle); super.onCreate(bundle);
if (Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_LARGE_ALBUM_ART, true)) { if (Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_LARGE_ALBUM_ART, true)) {
largeAlbums = true; largeAlbums = true;
} }
} }
@Override @Override
public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Playlist> updateView, Playlist playlist) { public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Playlist> updateView, Playlist playlist) {
if (Util.isOffline(context)) { if (Util.isOffline(context)) {
menuInflater.inflate(R.menu.select_playlist_context_offline, menu); menuInflater.inflate(R.menu.select_playlist_context_offline, menu);
} }
else { else {
menuInflater.inflate(R.menu.select_playlist_context, menu); menuInflater.inflate(R.menu.select_playlist_context, menu);
if(playlist.getPublic() != null && playlist.getPublic() == true && playlist.getId().indexOf(".m3u") == -1 && !UserUtil.getCurrentUsername(context).equals(playlist.getOwner())) { if(playlist.getPublic() != null && playlist.getPublic() == true && playlist.getId().indexOf(".m3u") == -1 && !UserUtil.getCurrentUsername(context).equals(playlist.getOwner())) {
menu.removeItem(R.id.playlist_update_info); menu.removeItem(R.id.playlist_update_info);
menu.removeItem(R.id.playlist_menu_delete); menu.removeItem(R.id.playlist_menu_delete);
} }
} }
recreateContextMenu(menu); recreateContextMenu(menu);
} }
@Override @Override
public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Playlist> updateView, Playlist playlist) { public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Playlist> updateView, Playlist playlist) {
SubsonicFragment fragment; SubsonicFragment fragment;
Bundle args; Bundle args;
FragmentTransaction trans; FragmentTransaction trans;
switch (menuItem.getItemId()) { switch (menuItem.getItemId()) {
case R.id.playlist_menu_download: case R.id.playlist_menu_download:
downloadPlaylist(playlist.getId(), playlist.getName(), false, true, false, false, true); downloadPlaylist(playlist.getId(), playlist.getName(), false, true, false, false, true);
break; break;
case R.id.playlist_menu_play_now: case R.id.playlist_menu_play_now:
fragment = new SelectDirectoryFragment(); fragment = new SelectDirectoryFragment();
args = new Bundle(); args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
fragment.setArguments(args); fragment.setArguments(args);
replaceFragment(fragment); replaceFragment(fragment);
break; break;
case R.id.playlist_menu_play_shuffled: case R.id.playlist_menu_play_shuffled:
fragment = new SelectDirectoryFragment(); fragment = new SelectDirectoryFragment();
args = new Bundle(); args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
args.putBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); args.putBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, true);
args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
fragment.setArguments(args); fragment.setArguments(args);
replaceFragment(fragment); replaceFragment(fragment);
break; break;
case R.id.playlist_menu_delete: case R.id.playlist_menu_delete:
deletePlaylist(playlist); deletePlaylist(playlist);
break; break;
case R.id.playlist_info: case R.id.playlist_info:
displayPlaylistInfo(playlist); displayPlaylistInfo(playlist);
break; break;
case R.id.playlist_update_info: case R.id.playlist_update_info:
updatePlaylistInfo(playlist); updatePlaylistInfo(playlist);
break; break;
} }
return false; return false;
} }
@Override @Override
public int getOptionsMenu() { public int getOptionsMenu() {
return R.menu.abstract_top_menu; return R.menu.abstract_top_menu;
} }
@Override @Override
public SectionAdapter<Playlist> getAdapter(List<Playlist> playlists) { public SectionAdapter<Playlist> getAdapter(List<Playlist> playlists) {
List<Playlist> mine = new ArrayList<>(); List<Playlist> mine = new ArrayList<>();
String currentUsername = UserUtil.getCurrentUsername(context); String currentUsername = UserUtil.getCurrentUsername(context);
for(Playlist playlist: playlists) { for(Playlist playlist: playlists) {
if(playlist.getOwner() == null || playlist.getOwner().equals(currentUsername)) { if(playlist.getOwner() == null || playlist.getOwner().equals(currentUsername)) {
mine.add(playlist); mine.add(playlist);
} }
} }
return new PlaylistAdapter(context, playlists, getImageLoader(), largeAlbums, this); return new PlaylistAdapter(context, playlists, getImageLoader(), largeAlbums, this);
} }
@Override @Override
public List<Playlist> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { public List<Playlist> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception {
List<Playlist> playlists = musicService.getPlaylists(refresh, context, listener); List<Playlist> playlists = musicService.getPlaylists(refresh, context, listener);
if(!Util.isOffline(context) && refresh) { if(!Util.isOffline(context) && refresh) {
new CacheCleaner(context, getDownloadService()).cleanPlaylists(playlists); new CacheCleaner(context, getDownloadService()).cleanPlaylists(playlists);
} }
return playlists; return playlists;
} }
@Override @Override
public int getTitleResource() { public int getTitleResource() {
return R.string.playlist_label; return R.string.playlist_label;
} }
@Override @Override
public void onItemClicked(UpdateView<Playlist> updateView, Playlist playlist) { public void onItemClicked(UpdateView<Playlist> updateView, Playlist playlist) {
SubsonicFragment fragment = new SelectDirectoryFragment(); SubsonicFragment fragment = new SelectDirectoryFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId());
args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
if((playlist.getOwner() != null && playlist.getOwner().equals(UserUtil.getCurrentUsername(context)) || playlist.getId().indexOf(".m3u") != -1)) { if((playlist.getOwner() != null && playlist.getOwner().equals(UserUtil.getCurrentUsername(context)) || playlist.getId().indexOf(".m3u") != -1)) {
args.putBoolean(Constants.INTENT_EXTRA_NAME_PLAYLIST_OWNER, true); args.putBoolean(Constants.INTENT_EXTRA_NAME_PLAYLIST_OWNER, true);
} }
fragment.setArguments(args); fragment.setArguments(args);
replaceFragment(fragment); replaceFragment(fragment);
} }
@Override @Override
public void onFinishRefresh() { public void onFinishRefresh() {
Bundle args = getArguments(); Bundle args = getArguments();
if(args != null) { if(args != null) {
String playlistId = args.getString(Constants.INTENT_EXTRA_NAME_ID, null); String playlistId = args.getString(Constants.INTENT_EXTRA_NAME_ID, null);
if (playlistId != null && objects != null) { if (playlistId != null && objects != null) {
for (Playlist playlist : objects) { for (Playlist playlist : objects) {
if (playlistId.equals(playlist.getId())) { if (playlistId.equals(playlist.getId())) {
onItemClicked(null, playlist); onItemClicked(null, playlist);
break; break;
} }
} }
} }
} }
} }
private void deletePlaylist(final Playlist playlist) { private void deletePlaylist(final Playlist playlist) {
Util.confirmDialog(context, R.string.common_delete, playlist.getName(), new DialogInterface.OnClickListener() { Util.confirmDialog(context, R.string.common_delete, playlist.getName(), new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
new LoadingTask<Void>(context, false) { new LoadingTask<Void>(context, false) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(context); MusicService musicService = MusicServiceFactory.getMusicService(context);
musicService.deletePlaylist(playlist.getId(), context, null); musicService.deletePlaylist(playlist.getId(), context, null);
SyncUtil.removeSyncedPlaylist(context, playlist.getId()); SyncUtil.removeSyncedPlaylist(context, playlist.getId());
return null; return null;
} }
@Override @Override
protected void done(Void result) { protected void done(Void result) {
adapter.removeItem(playlist); adapter.removeItem(playlist);
Util.toast(context, context.getResources().getString(R.string.menu_deleted_playlist, playlist.getName())); Util.toast(context, context.getResources().getString(R.string.menu_deleted_playlist, playlist.getName()));
} }
@Override @Override
protected void error(Throwable error) { protected void error(Throwable error) {
String msg; String msg;
if (error instanceof OfflineException) { if (error instanceof OfflineException) {
msg = getErrorMessage(error); msg = getErrorMessage(error);
} else { } else {
msg = context.getResources().getString(R.string.menu_deleted_playlist_error, playlist.getName()) + " " + getErrorMessage(error); msg = context.getResources().getString(R.string.menu_deleted_playlist_error, playlist.getName()) + " " + getErrorMessage(error);
} }
Util.toast(context, msg, false); Util.toast(context, msg, false);
} }
}.execute(); }.execute();
} }
}); });
} }
private void displayPlaylistInfo(final Playlist playlist) { private void displayPlaylistInfo(final Playlist playlist) {
List<Integer> headers = new ArrayList<>(); List<Integer> headers = new ArrayList<>();
List<String> details = new ArrayList<>(); List<String> details = new ArrayList<>();
headers.add(R.string.details_title); headers.add(R.string.details_title);
details.add(playlist.getName()); details.add(playlist.getName());
if(playlist.getOwner() != null) { if(playlist.getOwner() != null) {
headers.add(R.string.details_owner); headers.add(R.string.details_owner);
details.add(playlist.getOwner()); details.add(playlist.getOwner());
} }
if(playlist.getComment() != null) { if(playlist.getComment() != null) {
headers.add(R.string.details_comments); headers.add(R.string.details_comments);
details.add(playlist.getComment()); details.add(playlist.getComment());
} }
headers.add(R.string.details_song_count); headers.add(R.string.details_song_count);
details.add(playlist.getSongCount()); details.add(playlist.getSongCount());
if(playlist.getDuration() != null) { if(playlist.getDuration() != null) {
headers.add(R.string.details_length); headers.add(R.string.details_length);
details.add(Util.formatDuration(playlist.getDuration())); details.add(Util.formatDuration(playlist.getDuration()));
} }
if(playlist.getPublic() != null) { if(playlist.getPublic() != null) {
headers.add(R.string.details_public); headers.add(R.string.details_public);
details.add(Util.formatBoolean(context, playlist.getPublic())); details.add(Util.formatBoolean(context, playlist.getPublic()));
} }
if(playlist.getCreated() != null) { if(playlist.getCreated() != null) {
headers.add(R.string.details_created); headers.add(R.string.details_created);
DateFormat dateFormat = DateFormat.getDateInstance(); DateFormat dateFormat = DateFormat.getDateInstance();
details.add(dateFormat.format(playlist.getCreated())); details.add(dateFormat.format(playlist.getCreated()));
} }
if(playlist.getChanged() != null) { if(playlist.getChanged() != null) {
headers.add(R.string.details_updated); headers.add(R.string.details_updated);
DateFormat dateFormat = DateFormat.getDateInstance(); DateFormat dateFormat = DateFormat.getDateInstance();
details.add(dateFormat.format(playlist.getChanged())); details.add(dateFormat.format(playlist.getChanged()));
} }
Util.showDetailsDialog(context, R.string.details_title_playlist, headers, details); Util.showDetailsDialog(context, R.string.details_title_playlist, headers, details);
} }
private void updatePlaylistInfo(final Playlist playlist) { private void updatePlaylistInfo(final Playlist playlist) {
View dialogView = context.getLayoutInflater().inflate(R.layout.update_playlist, null); View dialogView = context.getLayoutInflater().inflate(R.layout.update_playlist, null);
final EditText nameBox = (EditText)dialogView.findViewById(R.id.get_playlist_name); final EditText nameBox = (EditText)dialogView.findViewById(R.id.get_playlist_name);
final EditText commentBox = (EditText)dialogView.findViewById(R.id.get_playlist_comment); final EditText commentBox = (EditText)dialogView.findViewById(R.id.get_playlist_comment);
final CheckBox publicBox = (CheckBox)dialogView.findViewById(R.id.get_playlist_public); final CheckBox publicBox = (CheckBox)dialogView.findViewById(R.id.get_playlist_public);
nameBox.setText(playlist.getName()); nameBox.setText(playlist.getName());
commentBox.setText(playlist.getComment()); commentBox.setText(playlist.getComment());
Boolean pub = playlist.getPublic(); Boolean pub = playlist.getPublic();
if(pub == null) { if(pub == null) {
publicBox.setEnabled(false); publicBox.setEnabled(false);
} else { } else {
publicBox.setChecked(pub); publicBox.setChecked(pub);
} }
new AlertDialog.Builder(context) new AlertDialog.Builder(context)
.setIcon(android.R.drawable.ic_dialog_alert) .setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.playlist_update_info) .setTitle(R.string.playlist_update_info)
.setView(dialogView) .setView(dialogView)
.setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
new LoadingTask<Void>(context, false) { new LoadingTask<Void>(context, false) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
String name = nameBox.getText().toString(); String name = nameBox.getText().toString();
String comment = commentBox.getText().toString(); String comment = commentBox.getText().toString();
boolean isPublic = publicBox.isChecked(); boolean isPublic = publicBox.isChecked();
MusicService musicService = MusicServiceFactory.getMusicService(context); MusicService musicService = MusicServiceFactory.getMusicService(context);
musicService.updatePlaylist(playlist.getId(), name, comment, isPublic, context, null); musicService.updatePlaylist(playlist.getId(), name, comment, isPublic, context, null);
playlist.setName(name); playlist.setName(name);
playlist.setComment(comment); playlist.setComment(comment);
playlist.setPublic(isPublic); playlist.setPublic(isPublic);
return null; return null;
} }
@Override @Override
protected void done(Void result) { protected void done(Void result) {
Util.toast(context, context.getResources().getString(R.string.playlist_updated_info, playlist.getName())); Util.toast(context, context.getResources().getString(R.string.playlist_updated_info, playlist.getName()));
} }
@Override @Override
protected void error(Throwable error) { protected void error(Throwable error) {
String msg; String msg;
if (error instanceof OfflineException) { if (error instanceof OfflineException) {
msg = getErrorMessage(error); msg = getErrorMessage(error);
} else { } else {
msg = context.getResources().getString(R.string.playlist_updated_info_error, playlist.getName()) + " " + getErrorMessage(error); msg = context.getResources().getString(R.string.playlist_updated_info_error, playlist.getName()) + " " + getErrorMessage(error);
} }
Util.toast(context, msg, false); Util.toast(context, msg, false);
} }
}.execute(); }.execute();
} }
}) })
.setNegativeButton(R.string.common_cancel, null) .setNegativeButton(R.string.common_cancel, null)
.show(); .show();
} }
private void syncPlaylist(Playlist playlist) { private void syncPlaylist(Playlist playlist) {
SyncUtil.addSyncedPlaylist(context, playlist.getId()); SyncUtil.addSyncedPlaylist(context, playlist.getId());
downloadPlaylist(playlist.getId(), playlist.getName(), true, true, false, false, true); downloadPlaylist(playlist.getId(), playlist.getName(), true, true, false, false, true);
} }
private void stopSyncPlaylist(final Playlist playlist) { private void stopSyncPlaylist(final Playlist playlist) {
SyncUtil.removeSyncedPlaylist(context, playlist.getId()); SyncUtil.removeSyncedPlaylist(context, playlist.getId());
new LoadingTask<Void>(context, false) { new LoadingTask<Void>(context, false) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
// Unpin all of the songs in playlist // Unpin all of the songs in playlist
MusicService musicService = MusicServiceFactory.getMusicService(context); MusicService musicService = MusicServiceFactory.getMusicService(context);
MusicDirectory root = musicService.getPlaylist(true, playlist.getId(), playlist.getName(), context, this); MusicDirectory root = musicService.getPlaylist(true, playlist.getId(), playlist.getName(), context, this);
for(MusicDirectory.Entry entry: root.getChildren()) { for(MusicDirectory.Entry entry: root.getChildren()) {
DownloadFile file = new DownloadFile(context, entry, false); DownloadFile file = new DownloadFile(context, entry, false);
file.unpin(); file.unpin();
} }
return null; return null;
} }
@Override @Override
protected void done(Void result) { protected void done(Void result) {
} }
}.execute(); }.execute();
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.fragments; package net.nullsum.audinaut.fragments;
@ -46,174 +46,174 @@ import net.nullsum.audinaut.util.TabBackgroundTask;
import net.nullsum.audinaut.view.FastScroller; import net.nullsum.audinaut.view.FastScroller;
public abstract class SelectRecyclerFragment<T> extends SubsonicFragment implements SectionAdapter.OnItemClickedListener<T> { public abstract class SelectRecyclerFragment<T> extends SubsonicFragment implements SectionAdapter.OnItemClickedListener<T> {
private static final String TAG = SelectRecyclerFragment.class.getSimpleName(); private static final String TAG = SelectRecyclerFragment.class.getSimpleName();
protected RecyclerView recyclerView; protected RecyclerView recyclerView;
protected FastScroller fastScroller; protected FastScroller fastScroller;
protected SectionAdapter<T> adapter; protected SectionAdapter<T> adapter;
protected UpdateTask currentTask; protected UpdateTask currentTask;
protected List<T> objects; protected List<T> objects;
protected boolean serialize = true; protected boolean serialize = true;
protected boolean largeAlbums = false; protected boolean largeAlbums = false;
protected boolean pullToRefresh = true; protected boolean pullToRefresh = true;
protected boolean backgroundUpdate = true; protected boolean backgroundUpdate = true;
@Override @Override
public void onCreate(Bundle bundle) { public void onCreate(Bundle bundle) {
super.onCreate(bundle); super.onCreate(bundle);
if(bundle != null && serialize) { if(bundle != null && serialize) {
objects = (List<T>) bundle.getSerializable(Constants.FRAGMENT_LIST); objects = (List<T>) bundle.getSerializable(Constants.FRAGMENT_LIST);
} }
} }
@Override @Override
public void onSaveInstanceState(Bundle outState) { public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
if(serialize) { if(serialize) {
outState.putSerializable(Constants.FRAGMENT_LIST, (Serializable) objects); outState.putSerializable(Constants.FRAGMENT_LIST, (Serializable) objects);
} }
} }
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
rootView = inflater.inflate(R.layout.abstract_recycler_fragment, container, false); rootView = inflater.inflate(R.layout.abstract_recycler_fragment, container, false);
refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout);
refreshLayout.setOnRefreshListener(this); refreshLayout.setOnRefreshListener(this);
recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_recycler); recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_recycler);
fastScroller = (FastScroller) rootView.findViewById(R.id.fragment_fast_scroller); fastScroller = (FastScroller) rootView.findViewById(R.id.fragment_fast_scroller);
setupLayoutManager(); setupLayoutManager();
if(pullToRefresh) { if(pullToRefresh) {
setupScrollList(recyclerView); setupScrollList(recyclerView);
} else { } else {
refreshLayout.setEnabled(false); refreshLayout.setEnabled(false);
} }
if(objects == null) { if(objects == null) {
refresh(false); refresh(false);
} else { } else {
recyclerView.setAdapter(adapter = getAdapter(objects)); recyclerView.setAdapter(adapter = getAdapter(objects));
} }
return rootView; return rootView;
} }
@Override @Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
if(!primaryFragment) { if(!primaryFragment) {
return; return;
} }
menuInflater.inflate(getOptionsMenu(), menu); menuInflater.inflate(getOptionsMenu(), menu);
onFinishSetupOptionsMenu(menu); onFinishSetupOptionsMenu(menu);
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@Override @Override
public void setIsOnlyVisible(boolean isOnlyVisible) { public void setIsOnlyVisible(boolean isOnlyVisible) {
boolean update = this.isOnlyVisible != isOnlyVisible; boolean update = this.isOnlyVisible != isOnlyVisible;
super.setIsOnlyVisible(isOnlyVisible); super.setIsOnlyVisible(isOnlyVisible);
if(update && adapter != null) { if(update && adapter != null) {
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if(layoutManager instanceof GridLayoutManager) { if(layoutManager instanceof GridLayoutManager) {
((GridLayoutManager) layoutManager).setSpanCount(getRecyclerColumnCount()); ((GridLayoutManager) layoutManager).setSpanCount(getRecyclerColumnCount());
} }
} }
} }
@Override @Override
protected void refresh(final boolean refresh) { protected void refresh(final boolean refresh) {
int titleRes = getTitleResource(); int titleRes = getTitleResource();
if(titleRes != 0) { if(titleRes != 0) {
setTitle(getTitleResource()); setTitle(getTitleResource());
} }
if(backgroundUpdate) { if(backgroundUpdate) {
recyclerView.setVisibility(View.GONE); recyclerView.setVisibility(View.GONE);
} }
// Cancel current running task before starting another one // Cancel current running task before starting another one
if(currentTask != null) { if(currentTask != null) {
currentTask.cancel(); currentTask.cancel();
} }
currentTask = new UpdateTask(this, refresh); currentTask = new UpdateTask(this, refresh);
if(backgroundUpdate) { if(backgroundUpdate) {
currentTask.execute(); currentTask.execute();
} else { } else {
objects = new ArrayList<T>(); objects = new ArrayList<T>();
try { try {
objects = getObjects(null, refresh, null); objects = getObjects(null, refresh, null);
} catch (Exception x) { } catch (Exception x) {
Log.e(TAG, "Failed to load", x); Log.e(TAG, "Failed to load", x);
} }
currentTask.done(objects); currentTask.done(objects);
} }
} }
public SectionAdapter getCurrentAdapter() { public SectionAdapter getCurrentAdapter() {
return adapter; return adapter;
} }
private void setupLayoutManager() { private void setupLayoutManager() {
setupLayoutManager(recyclerView, largeAlbums); setupLayoutManager(recyclerView, largeAlbums);
} }
public abstract int getOptionsMenu(); public abstract int getOptionsMenu();
public abstract SectionAdapter<T> getAdapter(List<T> objs); public abstract SectionAdapter<T> getAdapter(List<T> objs);
public abstract List<T> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception; public abstract List<T> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception;
public abstract int getTitleResource(); public abstract int getTitleResource();
public void onFinishRefresh() { public void onFinishRefresh() {
} }
private class UpdateTask extends TabBackgroundTask<List<T>> { private class UpdateTask extends TabBackgroundTask<List<T>> {
private boolean refresh; private boolean refresh;
public UpdateTask(SubsonicFragment fragment, boolean refresh) { public UpdateTask(SubsonicFragment fragment, boolean refresh) {
super(fragment); super(fragment);
this.refresh = refresh; this.refresh = refresh;
} }
@Override @Override
public List<T> doInBackground() throws Exception { public List<T> doInBackground() throws Exception {
MusicService musicService = MusicServiceFactory.getMusicService(context); MusicService musicService = MusicServiceFactory.getMusicService(context);
objects = new ArrayList<T>(); objects = new ArrayList<T>();
try { try {
objects = getObjects(musicService, refresh, this); objects = getObjects(musicService, refresh, this);
} catch (Exception x) { } catch (Exception x) {
Log.e(TAG, "Failed to load", x); Log.e(TAG, "Failed to load", x);
} }
return objects; return objects;
} }
@Override @Override
public void done(List<T> result) { public void done(List<T> result) {
if (result != null && !result.isEmpty()) { if (result != null && !result.isEmpty()) {
recyclerView.setAdapter(adapter = getAdapter(result)); recyclerView.setAdapter(adapter = getAdapter(result));
if(!fastScroller.isAttached()) { if(!fastScroller.isAttached()) {
fastScroller.attachRecyclerView(recyclerView); fastScroller.attachRecyclerView(recyclerView);
} }
onFinishRefresh(); onFinishRefresh();
recyclerView.setVisibility(View.VISIBLE); recyclerView.setVisibility(View.VISIBLE);
} else { } else {
setEmpty(true); setEmpty(true);
} }
currentTask = null; currentTask = null;
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.fragments; package net.nullsum.audinaut.fragments;
@ -33,56 +33,56 @@ import net.nullsum.audinaut.view.UpdateView;
public class SelectYearFragment extends SelectRecyclerFragment<String> { public class SelectYearFragment extends SelectRecyclerFragment<String> {
public SelectYearFragment() { public SelectYearFragment() {
super(); super();
pullToRefresh = false; pullToRefresh = false;
serialize = false; serialize = false;
backgroundUpdate = false; backgroundUpdate = false;
} }
@Override @Override
public int getOptionsMenu() { public int getOptionsMenu() {
return R.menu.empty; return R.menu.empty;
} }
@Override @Override
public SectionAdapter getAdapter(List<String> objs) { public SectionAdapter getAdapter(List<String> objs) {
return new BasicListAdapter(context, objs, this); return new BasicListAdapter(context, objs, this);
} }
@Override @Override
public List<String> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { public List<String> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception {
List<String> decades = new ArrayList<>(); List<String> decades = new ArrayList<>();
for(int i = 2010; i >= 1800; i -= 10) { for(int i = 2010; i >= 1800; i -= 10) {
decades.add(String.valueOf(i)); decades.add(String.valueOf(i));
} }
return decades; return decades;
} }
@Override @Override
public int getTitleResource() { public int getTitleResource() {
return R.string.main_albums_year; return R.string.main_albums_year;
} }
@Override @Override
public void onItemClicked(UpdateView<String> updateView, String decade) { public void onItemClicked(UpdateView<String> updateView, String decade) {
SubsonicFragment fragment = new SelectDirectoryFragment(); SubsonicFragment fragment = new SelectDirectoryFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, "years"); args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, "years");
args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20); args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20);
args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0); args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA, decade); args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA, decade);
fragment.setArguments(args); fragment.setArguments(args);
replaceFragment(fragment); replaceFragment(fragment);
} }
@Override @Override
public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<String> updateView, String item) {} public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<String> updateView, String item) {}
@Override @Override
public boolean onContextItemSelected(MenuItem menuItem, UpdateView<String> updateView, String item) { public boolean onContextItemSelected(MenuItem menuItem, UpdateView<String> updateView, String item) {
return false; return false;
} }
} }

View File

@ -46,164 +46,164 @@ import net.nullsum.audinaut.util.Util;
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class AudinautSearchProvider extends ContentProvider { public class AudinautSearchProvider extends ContentProvider {
private static final String TAG = AudinautSearchProvider.class.getSimpleName(); private static final String TAG = AudinautSearchProvider.class.getSimpleName();
private static final String RESOURCE_PREFIX = "android.resource://net.nullsum.audinaut/"; private static final String RESOURCE_PREFIX = "android.resource://net.nullsum.audinaut/";
private static final String[] COLUMNS = {"_id", private static final String[] COLUMNS = {"_id",
SearchManager.SUGGEST_COLUMN_TEXT_1, SearchManager.SUGGEST_COLUMN_TEXT_1,
SearchManager.SUGGEST_COLUMN_TEXT_2, SearchManager.SUGGEST_COLUMN_TEXT_2,
SearchManager.SUGGEST_COLUMN_INTENT_DATA, SearchManager.SUGGEST_COLUMN_INTENT_DATA,
SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA,
SearchManager.SUGGEST_COLUMN_ICON_1}; SearchManager.SUGGEST_COLUMN_ICON_1};
@Override @Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
if(selectionArgs[0].isEmpty()) { if(selectionArgs[0].isEmpty()) {
return null; return null;
} }
String query = selectionArgs[0] + "*"; String query = selectionArgs[0] + "*";
SearchResult searchResult = search(query); SearchResult searchResult = search(query);
return createCursor(selectionArgs[0], searchResult); return createCursor(selectionArgs[0], searchResult);
} }
private SearchResult search(String query) { private SearchResult search(String query) {
MusicService musicService = MusicServiceFactory.getMusicService(getContext()); MusicService musicService = MusicServiceFactory.getMusicService(getContext());
if (musicService == null) { if (musicService == null) {
return null; return null;
} }
try { try {
return musicService.search(new SearchCritera(query, 5, 10, 10), getContext(), null); return musicService.search(new SearchCritera(query, 5, 10, 10), getContext(), null);
} catch (Exception e) { } catch (Exception e) {
return null; return null;
} }
} }
private Cursor createCursor(String query, SearchResult searchResult) { private Cursor createCursor(String query, SearchResult searchResult) {
MatrixCursor cursor = new MatrixCursor(COLUMNS); MatrixCursor cursor = new MatrixCursor(COLUMNS);
if (searchResult == null) { if (searchResult == null) {
return cursor; return cursor;
} }
// Add all results into one pot // Add all results into one pot
List<Object> results = new ArrayList<Object>(); List<Object> results = new ArrayList<Object>();
results.addAll(searchResult.getArtists()); results.addAll(searchResult.getArtists());
results.addAll(searchResult.getAlbums()); results.addAll(searchResult.getAlbums());
results.addAll(searchResult.getSongs()); results.addAll(searchResult.getSongs());
// For each, calculate its string distance to the query // For each, calculate its string distance to the query
for(Object obj: results) { for(Object obj: results) {
if(obj instanceof Artist) { if(obj instanceof Artist) {
Artist artist = (Artist) obj; Artist artist = (Artist) obj;
artist.setCloseness(Util.getStringDistance(query, artist.getName())); artist.setCloseness(Util.getStringDistance(query, artist.getName()));
} else { } else {
MusicDirectory.Entry entry = (MusicDirectory.Entry) obj; MusicDirectory.Entry entry = (MusicDirectory.Entry) obj;
entry.setCloseness(Util.getStringDistance(query, entry.getTitle())); entry.setCloseness(Util.getStringDistance(query, entry.getTitle()));
} }
} }
// Sort based on the closeness paramater // Sort based on the closeness paramater
Collections.sort(results, new Comparator<Object>() { Collections.sort(results, new Comparator<Object>() {
@Override @Override
public int compare(Object lhs, Object rhs) { public int compare(Object lhs, Object rhs) {
// Get the closeness of the two objects // Get the closeness of the two objects
int left, right; int left, right;
boolean leftArtist = lhs instanceof Artist; boolean leftArtist = lhs instanceof Artist;
boolean rightArtist = rhs instanceof Artist; boolean rightArtist = rhs instanceof Artist;
if (leftArtist) { if (leftArtist) {
left = ((Artist) lhs).getCloseness(); left = ((Artist) lhs).getCloseness();
} else { } else {
left = ((MusicDirectory.Entry) lhs).getCloseness(); left = ((MusicDirectory.Entry) lhs).getCloseness();
} }
if (rightArtist) { if (rightArtist) {
right = ((Artist) rhs).getCloseness(); right = ((Artist) rhs).getCloseness();
} else { } else {
right = ((MusicDirectory.Entry) rhs).getCloseness(); right = ((MusicDirectory.Entry) rhs).getCloseness();
} }
if (left == right) { if (left == right) {
if(leftArtist && rightArtist) { if(leftArtist && rightArtist) {
return 0; return 0;
} else if(leftArtist) { } else if(leftArtist) {
return -1; return -1;
} else if(rightArtist) { } else if(rightArtist) {
return 1; return 1;
} else { } else {
return 0; return 0;
} }
} else if (left > right) { } else if (left > right) {
return 1; return 1;
} else { } else {
return -1; return -1;
} }
} }
}); });
// Done sorting, add results to cursor // Done sorting, add results to cursor
for(Object obj: results) { for(Object obj: results) {
if(obj instanceof Artist) { if(obj instanceof Artist) {
Artist artist = (Artist) obj; Artist artist = (Artist) obj;
String icon = RESOURCE_PREFIX + R.drawable.ic_action_artist; String icon = RESOURCE_PREFIX + R.drawable.ic_action_artist;
cursor.addRow(new Object[]{artist.getId().hashCode(), artist.getName(), null, "ar-" + artist.getId(), artist.getName(), icon}); cursor.addRow(new Object[]{artist.getId().hashCode(), artist.getName(), null, "ar-" + artist.getId(), artist.getName(), icon});
} else { } else {
MusicDirectory.Entry entry = (MusicDirectory.Entry) obj; MusicDirectory.Entry entry = (MusicDirectory.Entry) obj;
if(entry.isDirectory()) { if(entry.isDirectory()) {
String icon = RESOURCE_PREFIX + R.drawable.ic_action_album; String icon = RESOURCE_PREFIX + R.drawable.ic_action_album;
cursor.addRow(new Object[]{entry.getId().hashCode(), entry.getTitle(), entry.getArtist(), entry.getId(), entry.getTitle(), icon}); cursor.addRow(new Object[]{entry.getId().hashCode(), entry.getTitle(), entry.getArtist(), entry.getId(), entry.getTitle(), icon});
} else { } else {
String icon = RESOURCE_PREFIX + R.drawable.ic_action_song; String icon = RESOURCE_PREFIX + R.drawable.ic_action_song;
String id; String id;
if(Util.isTagBrowsing(getContext())) { if(Util.isTagBrowsing(getContext())) {
id = entry.getAlbumId(); id = entry.getAlbumId();
} else { } else {
id = entry.getParent(); id = entry.getParent();
} }
String artistDisplay; String artistDisplay;
if(entry.getArtist() == null) { if(entry.getArtist() == null) {
if(entry.getAlbum() != null) { if(entry.getAlbum() != null) {
artistDisplay = entry.getAlbumDisplay(); artistDisplay = entry.getAlbumDisplay();
} else { } else {
artistDisplay = ""; artistDisplay = "";
} }
} else if(entry.getAlbum() != null) { } else if(entry.getAlbum() != null) {
artistDisplay = entry.getArtist() + " - " + entry.getAlbumDisplay(); artistDisplay = entry.getArtist() + " - " + entry.getAlbumDisplay();
} else { } else {
artistDisplay = entry.getArtist(); artistDisplay = entry.getArtist();
} }
cursor.addRow(new Object[]{entry.getId().hashCode(), entry.getTitle(), artistDisplay, "so-" + id, entry.getTitle(), icon}); cursor.addRow(new Object[]{entry.getId().hashCode(), entry.getTitle(), artistDisplay, "so-" + id, entry.getTitle(), icon});
} }
} }
} }
return cursor; return cursor;
} }
@Override @Override
public boolean onCreate() { public boolean onCreate() {
return false; return false;
} }
@Override @Override
public String getType(Uri uri) { public String getType(Uri uri) {
return null; return null;
} }
@Override @Override
public Uri insert(Uri uri, ContentValues contentValues) { public Uri insert(Uri uri, ContentValues contentValues) {
return null; return null;
} }
@Override @Override
public int delete(Uri uri, String s, String[] strings) { public int delete(Uri uri, String s, String[] strings) {
return 0; return 0;
} }
@Override @Override
public int update(Uri uri, ContentValues contentValues, String s, String[] strings) { public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {
return 0; return 0;
} }
} }

View File

@ -21,8 +21,8 @@ package net.nullsum.audinaut.provider;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
public class AudinautWidget4x1 extends AudinautWidgetProvider { public class AudinautWidget4x1 extends AudinautWidgetProvider {
@Override @Override
protected int getLayout() { protected int getLayout() {
return R.layout.appwidget4x1; return R.layout.appwidget4x1;
} }
} }

View File

@ -21,8 +21,8 @@ package net.nullsum.audinaut.provider;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
public class AudinautWidget4x2 extends AudinautWidgetProvider { public class AudinautWidget4x2 extends AudinautWidgetProvider {
@Override @Override
protected int getLayout() { protected int getLayout() {
return R.layout.appwidget4x2; return R.layout.appwidget4x2;
} }
} }

View File

@ -21,8 +21,8 @@ package net.nullsum.audinaut.provider;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
public class AudinautWidget4x3 extends AudinautWidgetProvider { public class AudinautWidget4x3 extends AudinautWidgetProvider {
@Override @Override
protected int getLayout() { protected int getLayout() {
return R.layout.appwidget4x3; return R.layout.appwidget4x3;
} }
} }

View File

@ -21,8 +21,8 @@ package net.nullsum.audinaut.provider;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
public class AudinautWidget4x4 extends AudinautWidgetProvider { public class AudinautWidget4x4 extends AudinautWidgetProvider {
@Override @Override
protected int getLayout() { protected int getLayout() {
return R.layout.appwidget4x4; return R.layout.appwidget4x4;
} }
} }

View File

@ -60,44 +60,44 @@ import net.nullsum.audinaut.util.Util;
*/ */
public class AudinautWidgetProvider extends AppWidgetProvider { public class AudinautWidgetProvider extends AppWidgetProvider {
private static final String TAG = AudinautWidgetProvider.class.getSimpleName(); private static final String TAG = AudinautWidgetProvider.class.getSimpleName();
private static AudinautWidget4x1 instance4x1; private static AudinautWidget4x1 instance4x1;
private static AudinautWidget4x2 instance4x2; private static AudinautWidget4x2 instance4x2;
private static AudinautWidget4x3 instance4x3; private static AudinautWidget4x3 instance4x3;
private static AudinautWidget4x4 instance4x4; private static AudinautWidget4x4 instance4x4;
public static synchronized void notifyInstances(Context context, DownloadService service, boolean playing) { public static synchronized void notifyInstances(Context context, DownloadService service, boolean playing) {
if(instance4x1 == null) { if(instance4x1 == null) {
instance4x1 = new AudinautWidget4x1(); instance4x1 = new AudinautWidget4x1();
} }
if(instance4x2 == null) { if(instance4x2 == null) {
instance4x2 = new AudinautWidget4x2(); instance4x2 = new AudinautWidget4x2();
} }
if(instance4x3 == null) { if(instance4x3 == null) {
instance4x3 = new AudinautWidget4x3(); instance4x3 = new AudinautWidget4x3();
} }
if(instance4x4 == null) { if(instance4x4 == null) {
instance4x4 = new AudinautWidget4x4(); instance4x4 = new AudinautWidget4x4();
} }
instance4x1.notifyChange(context, service, playing); instance4x1.notifyChange(context, service, playing);
instance4x2.notifyChange(context, service, playing); instance4x2.notifyChange(context, service, playing);
instance4x3.notifyChange(context, service, playing); instance4x3.notifyChange(context, service, playing);
instance4x4.notifyChange(context, service, playing); instance4x4.notifyChange(context, service, playing);
} }
@Override @Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
defaultAppWidget(context, appWidgetIds); defaultAppWidget(context, appWidgetIds);
} }
@Override @Override
public void onEnabled(Context context) { public void onEnabled(Context context) {
notifyInstances(context, DownloadService.getInstance(), false); notifyInstances(context, DownloadService.getInstance(), false);
} }
protected int getLayout() { protected int getLayout() {
return 0; return 0;
} }
/** /**
* Initialize given widgets to default state, where we launch Subsonic on default click * Initialize given widgets to default state, where we launch Subsonic on default click
@ -108,12 +108,12 @@ public class AudinautWidgetProvider extends AppWidgetProvider {
final RemoteViews views = new RemoteViews(context.getPackageName(), getLayout()); final RemoteViews views = new RemoteViews(context.getPackageName(), getLayout());
views.setTextViewText(R.id.artist, res.getText(R.string.widget_initial_text)); views.setTextViewText(R.id.artist, res.getText(R.string.widget_initial_text));
if(getLayout() == R.layout.appwidget4x2) { if(getLayout() == R.layout.appwidget4x2) {
views.setTextViewText(R.id.album, ""); views.setTextViewText(R.id.album, "");
} }
linkButtons(context, views, false); linkButtons(context, views, false);
performUpdate(context, null, appWidgetIds, false); performUpdate(context, null, appWidgetIds, false);
} }
private void pushUpdate(Context context, int[] appWidgetIds, RemoteViews views) { private void pushUpdate(Context context, int[] appWidgetIds, RemoteViews views) {
@ -151,20 +151,20 @@ public class AudinautWidgetProvider extends AppWidgetProvider {
final Resources res = context.getResources(); final Resources res = context.getResources();
final RemoteViews views = new RemoteViews(context.getPackageName(), getLayout()); final RemoteViews views = new RemoteViews(context.getPackageName(), getLayout());
if(playing) { if(playing) {
views.setViewVisibility(R.id.widget_root, View.VISIBLE); views.setViewVisibility(R.id.widget_root, View.VISIBLE);
} else { } else {
// Hide widget // Hide widget
SharedPreferences prefs = Util.getPreferences(context); SharedPreferences prefs = Util.getPreferences(context);
if(prefs.getBoolean(Constants.PREFERENCES_KEY_HIDE_WIDGET, false)) { if(prefs.getBoolean(Constants.PREFERENCES_KEY_HIDE_WIDGET, false)) {
views.setViewVisibility(R.id.widget_root, View.GONE); views.setViewVisibility(R.id.widget_root, View.GONE);
} }
} }
// Get Entry from current playing DownloadFile // Get Entry from current playing DownloadFile
MusicDirectory.Entry currentPlaying = null; MusicDirectory.Entry currentPlaying = null;
if(service == null) { if(service == null) {
// Deserialize from playling list to setup // Deserialize from playling list to setup
try { try {
PlayerQueue state = FileUtil.deserialize(context, DownloadServiceLifecycleSupport.FILENAME_DOWNLOADS_SER, PlayerQueue.class); PlayerQueue state = FileUtil.deserialize(context, DownloadServiceLifecycleSupport.FILENAME_DOWNLOADS_SER, PlayerQueue.class);
if (state != null && state.currentPlayingIndex != -1) { if (state != null && state.currentPlayingIndex != -1) {
@ -174,12 +174,12 @@ public class AudinautWidgetProvider extends AppWidgetProvider {
Log.e(TAG, "Failed to grab current playing", e); Log.e(TAG, "Failed to grab current playing", e);
} }
} else { } else {
currentPlaying = service.getCurrentPlaying() == null ? null : service.getCurrentPlaying().getSong(); currentPlaying = service.getCurrentPlaying() == null ? null : service.getCurrentPlaying().getSong();
} }
String title = currentPlaying == null ? null : currentPlaying.getTitle(); String title = currentPlaying == null ? null : currentPlaying.getTitle();
CharSequence artist = currentPlaying == null ? null : currentPlaying.getArtist(); CharSequence artist = currentPlaying == null ? null : currentPlaying.getArtist();
CharSequence album = currentPlaying == null ? null : currentPlaying.getAlbum(); CharSequence album = currentPlaying == null ? null : currentPlaying.getAlbum();
CharSequence errorState = null; CharSequence errorState = null;
// Show error message? // Show error message?
@ -195,19 +195,19 @@ public class AudinautWidgetProvider extends AppWidgetProvider {
if (errorState != null) { if (errorState != null) {
// Show error state to user // Show error state to user
views.setTextViewText(R.id.title,null); views.setTextViewText(R.id.title,null);
views.setTextViewText(R.id.artist, errorState); views.setTextViewText(R.id.artist, errorState);
views.setTextViewText(R.id.album, ""); views.setTextViewText(R.id.album, "");
if(getLayout() != R.layout.appwidget4x1) { if(getLayout() != R.layout.appwidget4x1) {
views.setImageViewResource(R.id.appwidget_coverart, R.drawable.appwidget_art_default); views.setImageViewResource(R.id.appwidget_coverart, R.drawable.appwidget_art_default);
} }
} else { } else {
// No error, so show normal titles // No error, so show normal titles
views.setTextViewText(R.id.title, title); views.setTextViewText(R.id.title, title);
views.setTextViewText(R.id.artist, artist); views.setTextViewText(R.id.artist, artist);
if(getLayout() != R.layout.appwidget4x1) { if(getLayout() != R.layout.appwidget4x1) {
views.setTextViewText(R.id.album, album); views.setTextViewText(R.id.album, album);
} }
} }
// Set correct drawable for pause state // Set correct drawable for pause state
@ -220,10 +220,10 @@ public class AudinautWidgetProvider extends AppWidgetProvider {
// Set the cover art // Set the cover art
try { try {
boolean large = false; boolean large = false;
if(getLayout() != R.layout.appwidget4x1 && getLayout() != R.layout.appwidget4x2) { if(getLayout() != R.layout.appwidget4x1 && getLayout() != R.layout.appwidget4x2) {
large = true; large = true;
} }
ImageLoader imageLoader = SubsonicActivity.getStaticImageLoader(context); ImageLoader imageLoader = SubsonicActivity.getStaticImageLoader(context);
Bitmap bitmap = imageLoader == null ? null : imageLoader.getCachedImage(context, currentPlaying, large); Bitmap bitmap = imageLoader == null ? null : imageLoader.getCachedImage(context, currentPlaying, large);
if (bitmap == null) { if (bitmap == null) {
@ -276,9 +276,9 @@ public class AudinautWidgetProvider extends AppWidgetProvider {
* @param playerActive @param playerActive True if player is active in background. Launch {@link net.nullsum.audinaut.activity.SubsonicFragmentActivity}. * @param playerActive @param playerActive True if player is active in background. Launch {@link net.nullsum.audinaut.activity.SubsonicFragmentActivity}.
*/ */
private void linkButtons(Context context, RemoteViews views, boolean playerActive) { private void linkButtons(Context context, RemoteViews views, boolean playerActive) {
Intent intent = new Intent(context, SubsonicFragmentActivity.class); Intent intent = new Intent(context, SubsonicFragmentActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true); intent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.appwidget_coverart, pendingIntent); views.setOnClickPendingIntent(R.id.appwidget_coverart, pendingIntent);
views.setOnClickPendingIntent(R.id.appwidget_top, pendingIntent); views.setOnClickPendingIntent(R.id.appwidget_top, pendingIntent);
@ -286,19 +286,19 @@ public class AudinautWidgetProvider extends AppWidgetProvider {
// Emulate media button clicks. // Emulate media button clicks.
intent = new Intent("Audinaut.PLAY_PAUSE"); intent = new Intent("Audinaut.PLAY_PAUSE");
intent.setComponent(new ComponentName(context, DownloadService.class)); intent.setComponent(new ComponentName(context, DownloadService.class));
intent.setAction(DownloadService.CMD_TOGGLEPAUSE); intent.setAction(DownloadService.CMD_TOGGLEPAUSE);
pendingIntent = PendingIntent.getService(context, 0, intent, 0); pendingIntent = PendingIntent.getService(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.control_play, pendingIntent); views.setOnClickPendingIntent(R.id.control_play, pendingIntent);
intent = new Intent("Audinaut.NEXT"); // Use a unique action name to ensure a different PendingIntent to be created. intent = new Intent("Audinaut.NEXT"); // Use a unique action name to ensure a different PendingIntent to be created.
intent.setComponent(new ComponentName(context, DownloadService.class)); intent.setComponent(new ComponentName(context, DownloadService.class));
intent.setAction(DownloadService.CMD_NEXT); intent.setAction(DownloadService.CMD_NEXT);
pendingIntent = PendingIntent.getService(context, 0, intent, 0); pendingIntent = PendingIntent.getService(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.control_next, pendingIntent); views.setOnClickPendingIntent(R.id.control_next, pendingIntent);
intent = new Intent("Audinaut.PREVIOUS"); // Use a unique action name to ensure a different PendingIntent to be created. intent = new Intent("Audinaut.PREVIOUS"); // Use a unique action name to ensure a different PendingIntent to be created.
intent.setComponent(new ComponentName(context, DownloadService.class)); intent.setComponent(new ComponentName(context, DownloadService.class));
intent.setAction(DownloadService.CMD_PREVIOUS); intent.setAction(DownloadService.CMD_PREVIOUS);
pendingIntent = PendingIntent.getService(context, 0, intent, 0); pendingIntent = PendingIntent.getService(context, 0, intent, 0);
views.setOnClickPendingIntent(R.id.control_previous, pendingIntent); views.setOnClickPendingIntent(R.id.control_previous, pendingIntent);
} }

View File

@ -7,41 +7,41 @@ import android.util.Log;
import net.nullsum.audinaut.service.DownloadService; import net.nullsum.audinaut.service.DownloadService;
public class A2dpIntentReceiver extends BroadcastReceiver { public class A2dpIntentReceiver extends BroadcastReceiver {
private static final String PLAYSTATUS_RESPONSE = "com.android.music.playstatusresponse"; private static final String PLAYSTATUS_RESPONSE = "com.android.music.playstatusresponse";
private String TAG = A2dpIntentReceiver.class.getSimpleName(); private String TAG = A2dpIntentReceiver.class.getSimpleName();
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
Log.i(TAG, "GOT INTENT " + intent); Log.i(TAG, "GOT INTENT " + intent);
DownloadService downloadService = DownloadService.getInstance(); DownloadService downloadService = DownloadService.getInstance();
if (downloadService != null){ if (downloadService != null){
Intent avrcpIntent = new Intent(PLAYSTATUS_RESPONSE); Intent avrcpIntent = new Intent(PLAYSTATUS_RESPONSE);
avrcpIntent.putExtra("duration", (long) downloadService.getPlayerDuration()); avrcpIntent.putExtra("duration", (long) downloadService.getPlayerDuration());
avrcpIntent.putExtra("position", (long) downloadService.getPlayerPosition()); avrcpIntent.putExtra("position", (long) downloadService.getPlayerPosition());
avrcpIntent.putExtra("ListSize", (long) downloadService.getSongs().size()); avrcpIntent.putExtra("ListSize", (long) downloadService.getSongs().size());
switch (downloadService.getPlayerState()){ switch (downloadService.getPlayerState()){
case STARTED: case STARTED:
avrcpIntent.putExtra("playing", true); avrcpIntent.putExtra("playing", true);
break; break;
case STOPPED: case STOPPED:
avrcpIntent.putExtra("playing", false); avrcpIntent.putExtra("playing", false);
break; break;
case PAUSED: case PAUSED:
avrcpIntent.putExtra("playing", false); avrcpIntent.putExtra("playing", false);
break; break;
case COMPLETED: case COMPLETED:
avrcpIntent.putExtra("playing", false); avrcpIntent.putExtra("playing", false);
break; break;
default: default:
return; return;
} }
context.sendBroadcast(avrcpIntent); context.sendBroadcast(avrcpIntent);
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson Copyright 2014 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.receiver; package net.nullsum.audinaut.receiver;
@ -28,24 +28,24 @@ import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
public class AudioNoisyReceiver extends BroadcastReceiver { public class AudioNoisyReceiver extends BroadcastReceiver {
private static final String TAG = AudioNoisyReceiver.class.getSimpleName(); private static final String TAG = AudioNoisyReceiver.class.getSimpleName();
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
DownloadService downloadService = DownloadService.getInstance(); DownloadService downloadService = DownloadService.getInstance();
// Don't do anything if downloadService is not started // Don't do anything if downloadService is not started
if(downloadService == null) { if(downloadService == null) {
return; return;
} }
if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals (intent.getAction ())) { if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals (intent.getAction ())) {
if((downloadService.getPlayerState() == PlayerState.STARTED || downloadService.getPlayerState() == PlayerState.PAUSED_TEMP)) { if((downloadService.getPlayerState() == PlayerState.STARTED || downloadService.getPlayerState() == PlayerState.PAUSED_TEMP)) {
SharedPreferences prefs = Util.getPreferences(downloadService); SharedPreferences prefs = Util.getPreferences(downloadService);
int pausePref = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_PAUSE_DISCONNECT, "0")); int pausePref = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_PAUSE_DISCONNECT, "0"));
if(pausePref == 0) { if(pausePref == 0) {
downloadService.pause(); downloadService.pause();
} }
} }
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.receiver; package net.nullsum.audinaut.receiver;
@ -23,12 +23,12 @@ import net.nullsum.audinaut.service.HeadphoneListenerService;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
public class BootReceiver extends BroadcastReceiver { public class BootReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if(Util.shouldStartOnHeadphones(context)) { if(Util.shouldStartOnHeadphones(context)) {
Intent serviceIntent = new Intent(); Intent serviceIntent = new Intent();
serviceIntent.setClassName(context.getPackageName(), HeadphoneListenerService.class.getName()); serviceIntent.setClassName(context.getPackageName(), HeadphoneListenerService.class.getName());
context.startService(serviceIntent); context.startService(serviceIntent);
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.receiver; package net.nullsum.audinaut.receiver;
@ -24,17 +24,17 @@ import net.nullsum.audinaut.service.DownloadService;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
public class HeadphonePlugReceiver extends BroadcastReceiver { public class HeadphonePlugReceiver extends BroadcastReceiver {
private static final String TAG = HeadphonePlugReceiver.class.getSimpleName(); private static final String TAG = HeadphonePlugReceiver.class.getSimpleName();
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if(Intent.ACTION_HEADSET_PLUG.equals(intent.getAction())) { if(Intent.ACTION_HEADSET_PLUG.equals(intent.getAction())) {
int headphoneState = intent.getIntExtra("state", -1); int headphoneState = intent.getIntExtra("state", -1);
if(headphoneState == 1 && Util.shouldStartOnHeadphones(context)) { if(headphoneState == 1 && Util.shouldStartOnHeadphones(context)) {
Intent start = new Intent(context, DownloadService.class); Intent start = new Intent(context, DownloadService.class);
start.setAction(DownloadService.START_PLAY); start.setAction(DownloadService.START_PLAY);
context.startService(start); context.startService(start);
} }
} }
} }
} }

View File

@ -36,22 +36,22 @@ public class MediaButtonIntentReceiver extends BroadcastReceiver {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
KeyEvent event = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT); KeyEvent event = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT);
if(DownloadService.getInstance() == null && (event.getKeyCode() == KeyEvent.KEYCODE_MEDIA_STOP || if(DownloadService.getInstance() == null && (event.getKeyCode() == KeyEvent.KEYCODE_MEDIA_STOP ||
event.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) { event.getKeyCode() == KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE || event.getKeyCode() == KeyEvent.KEYCODE_HEADSETHOOK)) {
Log.w(TAG, "Ignore keycode event because downloadService is off"); Log.w(TAG, "Ignore keycode event because downloadService is off");
return; return;
} }
Log.i(TAG, "Got MEDIA_BUTTON key event: " + event); Log.i(TAG, "Got MEDIA_BUTTON key event: " + event);
Intent serviceIntent = new Intent(context, DownloadService.class); Intent serviceIntent = new Intent(context, DownloadService.class);
serviceIntent.putExtra(Intent.EXTRA_KEY_EVENT, event); serviceIntent.putExtra(Intent.EXTRA_KEY_EVENT, event);
context.startService(serviceIntent); context.startService(serviceIntent);
if (isOrderedBroadcast()) { if (isOrderedBroadcast()) {
try { try {
abortBroadcast(); abortBroadcast();
} catch (Exception x) { } catch (Exception x) {
// Ignored. // Ignored.
} }
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson Copyright 2014 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.receiver; package net.nullsum.audinaut.receiver;
@ -25,22 +25,22 @@ import net.nullsum.audinaut.service.DownloadService;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
public class PlayActionReceiver extends BroadcastReceiver { public class PlayActionReceiver extends BroadcastReceiver {
private static final String TAG = PlayActionReceiver.class.getSimpleName(); private static final String TAG = PlayActionReceiver.class.getSimpleName();
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if(intent.hasExtra(Constants.TASKER_EXTRA_BUNDLE)) { if(intent.hasExtra(Constants.TASKER_EXTRA_BUNDLE)) {
Bundle data = intent.getBundleExtra(Constants.TASKER_EXTRA_BUNDLE); Bundle data = intent.getBundleExtra(Constants.TASKER_EXTRA_BUNDLE);
Boolean startShuffled = data.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE); Boolean startShuffled = data.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE);
Intent start = new Intent(context, DownloadService.class); Intent start = new Intent(context, DownloadService.class);
start.setAction(DownloadService.START_PLAY); start.setAction(DownloadService.START_PLAY);
start.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, startShuffled); start.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, startShuffled);
start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, data.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR)); start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, data.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR));
start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, data.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR)); start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, data.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR));
start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, data.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE)); start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, data.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE));
start.putExtra(Constants.PREFERENCES_KEY_OFFLINE, data.getInt(Constants.PREFERENCES_KEY_OFFLINE)); start.putExtra(Constants.PREFERENCES_KEY_OFFLINE, data.getInt(Constants.PREFERENCES_KEY_OFFLINE));
context.startService(start); context.startService(start);
} }
} }
} }

View File

@ -53,378 +53,378 @@ import static net.nullsum.audinaut.domain.PlayerState.PREPARING;
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class DownloadServiceLifecycleSupport { public class DownloadServiceLifecycleSupport {
private static final String TAG = DownloadServiceLifecycleSupport.class.getSimpleName(); private static final String TAG = DownloadServiceLifecycleSupport.class.getSimpleName();
public static final String FILENAME_DOWNLOADS_SER = "downloadstate2.ser"; public static final String FILENAME_DOWNLOADS_SER = "downloadstate2.ser";
private static final int DEBOUNCE_TIME = 200; private static final int DEBOUNCE_TIME = 200;
private final DownloadService downloadService; private final DownloadService downloadService;
private Looper eventLooper; private Looper eventLooper;
private Handler eventHandler; private Handler eventHandler;
private BroadcastReceiver ejectEventReceiver; private BroadcastReceiver ejectEventReceiver;
private PhoneStateListener phoneStateListener; private PhoneStateListener phoneStateListener;
private boolean externalStorageAvailable= true; private boolean externalStorageAvailable= true;
private ReentrantLock lock = new ReentrantLock(); private ReentrantLock lock = new ReentrantLock();
private final AtomicBoolean setup = new AtomicBoolean(false); private final AtomicBoolean setup = new AtomicBoolean(false);
private long lastPressTime = 0; private long lastPressTime = 0;
private SilentBackgroundTask<Void> currentSavePlayQueueTask = null; private SilentBackgroundTask<Void> currentSavePlayQueueTask = null;
private Date lastChange = null; private Date lastChange = null;
/** /**
* This receiver manages the intent that could come from other applications. * This receiver manages the intent that could come from other applications.
*/ */
private BroadcastReceiver intentReceiver = new BroadcastReceiver() { private BroadcastReceiver intentReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(final Context context, final Intent intent) { public void onReceive(final Context context, final Intent intent) {
eventHandler.post(new Runnable() { eventHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
String action = intent.getAction(); String action = intent.getAction();
Log.i(TAG, "intentReceiver.onReceive: " + action); Log.i(TAG, "intentReceiver.onReceive: " + action);
if (DownloadService.CMD_PLAY.equals(action)) { if (DownloadService.CMD_PLAY.equals(action)) {
downloadService.play(); downloadService.play();
} else if (DownloadService.CMD_NEXT.equals(action)) { } else if (DownloadService.CMD_NEXT.equals(action)) {
downloadService.next(); downloadService.next();
} else if (DownloadService.CMD_PREVIOUS.equals(action)) { } else if (DownloadService.CMD_PREVIOUS.equals(action)) {
downloadService.previous(); downloadService.previous();
} else if (DownloadService.CMD_TOGGLEPAUSE.equals(action)) { } else if (DownloadService.CMD_TOGGLEPAUSE.equals(action)) {
downloadService.togglePlayPause(); downloadService.togglePlayPause();
} else if (DownloadService.CMD_PAUSE.equals(action)) { } else if (DownloadService.CMD_PAUSE.equals(action)) {
downloadService.pause(); downloadService.pause();
} else if (DownloadService.CMD_STOP.equals(action)) { } else if (DownloadService.CMD_STOP.equals(action)) {
downloadService.pause(); downloadService.pause();
downloadService.seekTo(0); downloadService.seekTo(0);
} }
} }
}); });
} }
}; };
public DownloadServiceLifecycleSupport(DownloadService downloadService) { public DownloadServiceLifecycleSupport(DownloadService downloadService) {
this.downloadService = downloadService; this.downloadService = downloadService;
} }
public void onCreate() { public void onCreate() {
new Thread(new Runnable() { new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
Looper.prepare(); Looper.prepare();
eventLooper = Looper.myLooper(); eventLooper = Looper.myLooper();
eventHandler = new Handler(eventLooper); eventHandler = new Handler(eventLooper);
// Deserialize queue before starting looper // Deserialize queue before starting looper
try { try {
lock.lock(); lock.lock();
deserializeDownloadQueueNow(); deserializeDownloadQueueNow();
// Wait until PREPARING is done to mark lifecycle as ready to receive events // Wait until PREPARING is done to mark lifecycle as ready to receive events
while(downloadService.getPlayerState() == PREPARING) { while(downloadService.getPlayerState() == PREPARING) {
Util.sleepQuietly(50L); Util.sleepQuietly(50L);
} }
setup.set(true); setup.set(true);
} finally { } finally {
lock.unlock(); lock.unlock();
} }
Looper.loop(); Looper.loop();
} }
}, "DownloadServiceLifecycleSupport").start(); }, "DownloadServiceLifecycleSupport").start();
// Stop when SD card is ejected. // Stop when SD card is ejected.
ejectEventReceiver = new BroadcastReceiver() { ejectEventReceiver = new BroadcastReceiver() {
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
externalStorageAvailable = Intent.ACTION_MEDIA_MOUNTED.equals(intent.getAction()); externalStorageAvailable = Intent.ACTION_MEDIA_MOUNTED.equals(intent.getAction());
if (!externalStorageAvailable) { if (!externalStorageAvailable) {
Log.i(TAG, "External media is ejecting. Stopping playback."); Log.i(TAG, "External media is ejecting. Stopping playback.");
downloadService.reset(); downloadService.reset();
} else { } else {
Log.i(TAG, "External media is available."); Log.i(TAG, "External media is available.");
} }
} }
}; };
IntentFilter ejectFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT); IntentFilter ejectFilter = new IntentFilter(Intent.ACTION_MEDIA_EJECT);
ejectFilter.addAction(Intent.ACTION_MEDIA_MOUNTED); ejectFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
ejectFilter.addDataScheme("file"); ejectFilter.addDataScheme("file");
downloadService.registerReceiver(ejectEventReceiver, ejectFilter); downloadService.registerReceiver(ejectEventReceiver, ejectFilter);
// React to media buttons. // React to media buttons.
Util.registerMediaButtonEventReceiver(downloadService); Util.registerMediaButtonEventReceiver(downloadService);
// Pause temporarily on incoming phone calls. // Pause temporarily on incoming phone calls.
phoneStateListener = new MyPhoneStateListener(); phoneStateListener = new MyPhoneStateListener();
// Android 6.0 removes requirement for android.Manifest.permission.READ_PHONE_STATE; // Android 6.0 removes requirement for android.Manifest.permission.READ_PHONE_STATE;
TelephonyManager telephonyManager = (TelephonyManager) downloadService.getSystemService(Context.TELEPHONY_SERVICE); TelephonyManager telephonyManager = (TelephonyManager) downloadService.getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
// Register the handler for outside intents. // Register the handler for outside intents.
IntentFilter commandFilter = new IntentFilter(); IntentFilter commandFilter = new IntentFilter();
commandFilter.addAction(DownloadService.CMD_PLAY); commandFilter.addAction(DownloadService.CMD_PLAY);
commandFilter.addAction(DownloadService.CMD_TOGGLEPAUSE); commandFilter.addAction(DownloadService.CMD_TOGGLEPAUSE);
commandFilter.addAction(DownloadService.CMD_PAUSE); commandFilter.addAction(DownloadService.CMD_PAUSE);
commandFilter.addAction(DownloadService.CMD_STOP); commandFilter.addAction(DownloadService.CMD_STOP);
commandFilter.addAction(DownloadService.CMD_PREVIOUS); commandFilter.addAction(DownloadService.CMD_PREVIOUS);
commandFilter.addAction(DownloadService.CMD_NEXT); commandFilter.addAction(DownloadService.CMD_NEXT);
commandFilter.addAction(DownloadService.CANCEL_DOWNLOADS); commandFilter.addAction(DownloadService.CANCEL_DOWNLOADS);
downloadService.registerReceiver(intentReceiver, commandFilter); downloadService.registerReceiver(intentReceiver, commandFilter);
new CacheCleaner(downloadService, downloadService).clean(); new CacheCleaner(downloadService, downloadService).clean();
} }
public boolean isInitialized() { public boolean isInitialized() {
return setup.get(); return setup.get();
} }
public void onStart(final Intent intent) { public void onStart(final Intent intent) {
if (intent != null) { if (intent != null) {
final String action = intent.getAction(); final String action = intent.getAction();
if(eventHandler == null) { if(eventHandler == null) {
Util.sleepQuietly(100L); Util.sleepQuietly(100L);
} }
if(eventHandler == null) { if(eventHandler == null) {
return; return;
} }
eventHandler.post(new Runnable() { eventHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
if(!setup.get()) { if(!setup.get()) {
lock.lock(); lock.lock();
lock.unlock(); lock.unlock();
} }
if(DownloadService.START_PLAY.equals(action)) { if(DownloadService.START_PLAY.equals(action)) {
int offlinePref = intent.getIntExtra(Constants.PREFERENCES_KEY_OFFLINE, 0); int offlinePref = intent.getIntExtra(Constants.PREFERENCES_KEY_OFFLINE, 0);
if(offlinePref != 0) { if(offlinePref != 0) {
boolean offline = (offlinePref == 2); boolean offline = (offlinePref == 2);
Util.setOffline(downloadService, offline); Util.setOffline(downloadService, offline);
if (offline) { if (offline) {
downloadService.clearIncomplete(); downloadService.clearIncomplete();
} else { } else {
downloadService.checkDownloads(); downloadService.checkDownloads();
} }
} }
if(intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, false)) { if(intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, false)) {
// Add shuffle parameters // Add shuffle parameters
SharedPreferences.Editor editor = Util.getPreferences(downloadService).edit(); SharedPreferences.Editor editor = Util.getPreferences(downloadService).edit();
String startYear = intent.getStringExtra(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR); String startYear = intent.getStringExtra(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR);
if(startYear != null) { if(startYear != null) {
editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, startYear); editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, startYear);
} }
String endYear = intent.getStringExtra(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR); String endYear = intent.getStringExtra(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR);
if(endYear != null) { if(endYear != null) {
editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, endYear); editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, endYear);
} }
String genre = intent.getStringExtra(Constants.PREFERENCES_KEY_SHUFFLE_GENRE); String genre = intent.getStringExtra(Constants.PREFERENCES_KEY_SHUFFLE_GENRE);
if(genre != null) { if(genre != null) {
editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, genre); editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, genre);
} }
editor.apply(); editor.apply();
downloadService.clear(); downloadService.clear();
downloadService.setShufflePlayEnabled(true); downloadService.setShufflePlayEnabled(true);
} else { } else {
downloadService.start(); downloadService.start();
} }
} else if(DownloadService.CMD_TOGGLEPAUSE.equals(action)) { } else if(DownloadService.CMD_TOGGLEPAUSE.equals(action)) {
downloadService.togglePlayPause(); downloadService.togglePlayPause();
} else if(DownloadService.CMD_NEXT.equals(action)) { } else if(DownloadService.CMD_NEXT.equals(action)) {
downloadService.next(); downloadService.next();
} else if(DownloadService.CMD_PREVIOUS.equals(action)) { } else if(DownloadService.CMD_PREVIOUS.equals(action)) {
downloadService.previous(); downloadService.previous();
} else if(DownloadService.CANCEL_DOWNLOADS.equals(action)) { } else if(DownloadService.CANCEL_DOWNLOADS.equals(action)) {
downloadService.clearBackground(); downloadService.clearBackground();
} else if(intent.getExtras() != null) { } else if(intent.getExtras() != null) {
final KeyEvent event = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT); final KeyEvent event = (KeyEvent) intent.getExtras().get(Intent.EXTRA_KEY_EVENT);
if (event != null) { if (event != null) {
handleKeyEvent(event); handleKeyEvent(event);
} }
} }
} }
}); });
} }
} }
public void onDestroy() { public void onDestroy() {
serializeDownloadQueue(); serializeDownloadQueue();
eventLooper.quit(); eventLooper.quit();
downloadService.unregisterReceiver(ejectEventReceiver); downloadService.unregisterReceiver(ejectEventReceiver);
downloadService.unregisterReceiver(intentReceiver); downloadService.unregisterReceiver(intentReceiver);
TelephonyManager telephonyManager = (TelephonyManager) downloadService.getSystemService(Context.TELEPHONY_SERVICE); TelephonyManager telephonyManager = (TelephonyManager) downloadService.getSystemService(Context.TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE); telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
} }
public boolean isExternalStorageAvailable() { public boolean isExternalStorageAvailable() {
return externalStorageAvailable; return externalStorageAvailable;
} }
public void serializeDownloadQueue() { public void serializeDownloadQueue() {
serializeDownloadQueue(true); serializeDownloadQueue(true);
} }
public void serializeDownloadQueue(final boolean serializeRemote) { public void serializeDownloadQueue(final boolean serializeRemote) {
if(!setup.get()) { if(!setup.get()) {
return; return;
} }
final List<DownloadFile> songs = new ArrayList<DownloadFile>(downloadService.getSongs()); final List<DownloadFile> songs = new ArrayList<DownloadFile>(downloadService.getSongs());
eventHandler.post(new Runnable() { eventHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
if(lock.tryLock()) { if(lock.tryLock()) {
try { try {
serializeDownloadQueueNow(songs, serializeRemote); serializeDownloadQueueNow(songs, serializeRemote);
} finally { } finally {
lock.unlock(); lock.unlock();
} }
} }
} }
}); });
} }
public void serializeDownloadQueueNow(List<DownloadFile> songs, boolean serializeRemote) { public void serializeDownloadQueueNow(List<DownloadFile> songs, boolean serializeRemote) {
final PlayerQueue state = new PlayerQueue(); final PlayerQueue state = new PlayerQueue();
for (DownloadFile downloadFile : songs) { for (DownloadFile downloadFile : songs) {
state.songs.add(downloadFile.getSong()); state.songs.add(downloadFile.getSong());
} }
for (DownloadFile downloadFile : downloadService.getToDelete()) { for (DownloadFile downloadFile : downloadService.getToDelete()) {
state.toDelete.add(downloadFile.getSong()); state.toDelete.add(downloadFile.getSong());
} }
state.currentPlayingIndex = downloadService.getCurrentPlayingIndex(); state.currentPlayingIndex = downloadService.getCurrentPlayingIndex();
state.currentPlayingPosition = downloadService.getPlayerPosition(); state.currentPlayingPosition = downloadService.getPlayerPosition();
DownloadFile currentPlaying = downloadService.getCurrentPlaying(); DownloadFile currentPlaying = downloadService.getCurrentPlaying();
if(currentPlaying != null) { if(currentPlaying != null) {
state.renameCurrent = currentPlaying.isWorkDone() && !currentPlaying.isCompleteFileAvailable(); state.renameCurrent = currentPlaying.isWorkDone() && !currentPlaying.isCompleteFileAvailable();
} }
state.changed = lastChange = new Date(); state.changed = lastChange = new Date();
Log.i(TAG, "Serialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition); Log.i(TAG, "Serialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition);
FileUtil.serialize(downloadService, state, FILENAME_DOWNLOADS_SER); FileUtil.serialize(downloadService, state, FILENAME_DOWNLOADS_SER);
} }
public void post(Runnable runnable) { public void post(Runnable runnable) {
eventHandler.post(runnable); eventHandler.post(runnable);
} }
private void deserializeDownloadQueueNow() { private void deserializeDownloadQueueNow() {
PlayerQueue state = FileUtil.deserialize(downloadService, FILENAME_DOWNLOADS_SER, PlayerQueue.class); PlayerQueue state = FileUtil.deserialize(downloadService, FILENAME_DOWNLOADS_SER, PlayerQueue.class);
if (state == null) { if (state == null) {
return; return;
} }
Log.i(TAG, "Deserialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition); Log.i(TAG, "Deserialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition);
// Rename first thing before anything else starts // Rename first thing before anything else starts
if(state.renameCurrent && state.currentPlayingIndex != -1 && state.currentPlayingIndex < state.songs.size()) { if(state.renameCurrent && state.currentPlayingIndex != -1 && state.currentPlayingIndex < state.songs.size()) {
DownloadFile currentPlaying = new DownloadFile(downloadService, state.songs.get(state.currentPlayingIndex), false); DownloadFile currentPlaying = new DownloadFile(downloadService, state.songs.get(state.currentPlayingIndex), false);
currentPlaying.renamePartial(); currentPlaying.renamePartial();
} }
downloadService.restore(state.songs, state.toDelete, state.currentPlayingIndex, state.currentPlayingPosition); downloadService.restore(state.songs, state.toDelete, state.currentPlayingIndex, state.currentPlayingPosition);
if(state != null) { if(state != null) {
lastChange = state.changed; lastChange = state.changed;
} }
} }
public Date getLastChange() { public Date getLastChange() {
return lastChange; return lastChange;
} }
public void handleKeyEvent(KeyEvent event) { public void handleKeyEvent(KeyEvent event) {
if(event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() > 0) { if(event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() > 0) {
switch (event.getKeyCode()) { switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_MEDIA_PREVIOUS: case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
downloadService.fastForward(); downloadService.fastForward();
break; break;
case KeyEvent.KEYCODE_MEDIA_NEXT: case KeyEvent.KEYCODE_MEDIA_NEXT:
downloadService.rewind(); downloadService.rewind();
break; break;
} }
} else if(event.getAction() == KeyEvent.ACTION_UP) { } else if(event.getAction() == KeyEvent.ACTION_UP) {
switch (event.getKeyCode()) { switch (event.getKeyCode()) {
case KeyEvent.KEYCODE_HEADSETHOOK: case KeyEvent.KEYCODE_HEADSETHOOK:
case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
if(lastPressTime < (System.currentTimeMillis() - 500)) { if(lastPressTime < (System.currentTimeMillis() - 500)) {
lastPressTime = System.currentTimeMillis(); lastPressTime = System.currentTimeMillis();
downloadService.togglePlayPause(); downloadService.togglePlayPause();
} else { } else {
downloadService.next(false, true); downloadService.next(false, true);
} }
break; break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS: case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
if(lastPressTime < (System.currentTimeMillis() - DEBOUNCE_TIME)) { if(lastPressTime < (System.currentTimeMillis() - DEBOUNCE_TIME)) {
lastPressTime = System.currentTimeMillis(); lastPressTime = System.currentTimeMillis();
downloadService.previous(); downloadService.previous();
} }
break; break;
case KeyEvent.KEYCODE_MEDIA_NEXT: case KeyEvent.KEYCODE_MEDIA_NEXT:
if(lastPressTime < (System.currentTimeMillis() - DEBOUNCE_TIME)) { if(lastPressTime < (System.currentTimeMillis() - DEBOUNCE_TIME)) {
lastPressTime = System.currentTimeMillis(); lastPressTime = System.currentTimeMillis();
downloadService.next(); downloadService.next();
} }
break; break;
case KeyEvent.KEYCODE_MEDIA_REWIND: case KeyEvent.KEYCODE_MEDIA_REWIND:
downloadService.rewind(); downloadService.rewind();
break; break;
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
downloadService.fastForward(); downloadService.fastForward();
break; break;
case KeyEvent.KEYCODE_MEDIA_STOP: case KeyEvent.KEYCODE_MEDIA_STOP:
downloadService.stop(); downloadService.stop();
break; break;
case KeyEvent.KEYCODE_MEDIA_PLAY: case KeyEvent.KEYCODE_MEDIA_PLAY:
if(downloadService.getPlayerState() != PlayerState.STARTED) { if(downloadService.getPlayerState() != PlayerState.STARTED) {
downloadService.start(); downloadService.start();
} }
break; break;
case KeyEvent.KEYCODE_MEDIA_PAUSE: case KeyEvent.KEYCODE_MEDIA_PAUSE:
downloadService.pause(); downloadService.pause();
default: default:
break; break;
} }
} }
} }
/** /**
* Logic taken from packages/apps/Music. Will pause when an incoming * Logic taken from packages/apps/Music. Will pause when an incoming
* call rings or if a call (incoming or outgoing) is connected. * call rings or if a call (incoming or outgoing) is connected.
*/ */
private class MyPhoneStateListener extends PhoneStateListener { private class MyPhoneStateListener extends PhoneStateListener {
private boolean resumeAfterCall; private boolean resumeAfterCall;
@Override @Override
public void onCallStateChanged(final int state, String incomingNumber) { public void onCallStateChanged(final int state, String incomingNumber) {
eventHandler.post(new Runnable() { eventHandler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
switch (state) { switch (state) {
case TelephonyManager.CALL_STATE_RINGING: case TelephonyManager.CALL_STATE_RINGING:
case TelephonyManager.CALL_STATE_OFFHOOK: case TelephonyManager.CALL_STATE_OFFHOOK:
if (downloadService.getPlayerState() == PlayerState.STARTED) { if (downloadService.getPlayerState() == PlayerState.STARTED) {
resumeAfterCall = true; resumeAfterCall = true;
downloadService.pause(true); downloadService.pause(true);
} }
break; break;
case TelephonyManager.CALL_STATE_IDLE: case TelephonyManager.CALL_STATE_IDLE:
if (resumeAfterCall) { if (resumeAfterCall) {
resumeAfterCall = false; resumeAfterCall = false;
if(downloadService.getPlayerState() == PlayerState.PAUSED_TEMP) { if(downloadService.getPlayerState() == PlayerState.PAUSED_TEMP) {
downloadService.start(); downloadService.start();
} }
} }
break; break;
default: default:
break; break;
} }
} }
}); });
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.service; package net.nullsum.audinaut.service;
@ -27,40 +27,40 @@ import net.nullsum.audinaut.util.Util;
* Created by Scott on 4/6/2015. * Created by Scott on 4/6/2015.
*/ */
public class HeadphoneListenerService extends Service { public class HeadphoneListenerService extends Service {
private HeadphonePlugReceiver receiver; private HeadphonePlugReceiver receiver;
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
receiver = new HeadphonePlugReceiver(); receiver = new HeadphonePlugReceiver();
registerReceiver(receiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG)); registerReceiver(receiver, new IntentFilter(Intent.ACTION_HEADSET_PLUG));
} }
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
return null; return null;
} }
@Override @Override
public int onStartCommand(Intent intent, int flags, int startId) { public int onStartCommand(Intent intent, int flags, int startId) {
if(!Util.shouldStartOnHeadphones(this)) { if(!Util.shouldStartOnHeadphones(this)) {
stopSelf(); stopSelf();
} }
return Service.START_STICKY; return Service.START_STICKY;
} }
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
try { try {
if(receiver != null) { if(receiver != null) {
unregisterReceiver(receiver); unregisterReceiver(receiver);
} }
} catch(Exception e) { } catch(Exception e) {
// Don't care // Don't care
} }
} }
} }

View File

@ -36,24 +36,24 @@ import net.nullsum.audinaut.util.Util;
*/ */
public class MediaStoreService { public class MediaStoreService {
private static final String TAG = MediaStoreService.class.getSimpleName(); private static final String TAG = MediaStoreService.class.getSimpleName();
private static final Uri ALBUM_ART_URI = Uri.parse("content://media/external/audio/albumart"); private static final Uri ALBUM_ART_URI = Uri.parse("content://media/external/audio/albumart");
private final Context context; private final Context context;
public MediaStoreService(Context context) { public MediaStoreService(Context context) {
this.context = context; this.context = context;
} }
public void saveInMediaStore(DownloadFile downloadFile) { public void saveInMediaStore(DownloadFile downloadFile) {
MusicDirectory.Entry song = downloadFile.getSong(); MusicDirectory.Entry song = downloadFile.getSong();
File songFile = downloadFile.getCompleteFile(); File songFile = downloadFile.getCompleteFile();
// Delete existing row in case the song has been downloaded before. // Delete existing row in case the song has been downloaded before.
deleteFromMediaStore(downloadFile); deleteFromMediaStore(downloadFile);
ContentResolver contentResolver = context.getContentResolver(); ContentResolver contentResolver = context.getContentResolver();
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.TITLE, song.getTitle()); values.put(MediaStore.MediaColumns.TITLE, song.getTitle());
values.put(MediaStore.MediaColumns.DATA, songFile.getAbsolutePath()); values.put(MediaStore.MediaColumns.DATA, songFile.getAbsolutePath());
values.put(MediaStore.Audio.AudioColumns.ARTIST, song.getArtist()); values.put(MediaStore.Audio.AudioColumns.ARTIST, song.getArtist());
@ -84,68 +84,68 @@ public class MediaStoreService {
} }
cursor.close(); cursor.close();
} }
public void deleteFromMediaStore(DownloadFile downloadFile) { public void deleteFromMediaStore(DownloadFile downloadFile) {
ContentResolver contentResolver = context.getContentResolver(); ContentResolver contentResolver = context.getContentResolver();
MusicDirectory.Entry song = downloadFile.getSong(); MusicDirectory.Entry song = downloadFile.getSong();
File file = downloadFile.getCompleteFile(); File file = downloadFile.getCompleteFile();
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
int n = contentResolver.delete(uri, int n = contentResolver.delete(uri,
MediaStore.MediaColumns.DATA + "=?", MediaStore.MediaColumns.DATA + "=?",
new String[]{file.getAbsolutePath()}); new String[]{file.getAbsolutePath()});
if (n > 0) { if (n > 0) {
Log.i(TAG, "Deleting media store row for " + song); Log.i(TAG, "Deleting media store row for " + song);
} }
} }
public void deleteFromMediaStore(File file) { public void deleteFromMediaStore(File file) {
ContentResolver contentResolver = context.getContentResolver(); ContentResolver contentResolver = context.getContentResolver();
Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
int n = contentResolver.delete(uri, int n = contentResolver.delete(uri,
MediaStore.MediaColumns.DATA + "=?", MediaStore.MediaColumns.DATA + "=?",
new String[]{file.getAbsolutePath()}); new String[]{file.getAbsolutePath()});
if (n > 0) { if (n > 0) {
Log.i(TAG, "Deleting media store row for " + file); Log.i(TAG, "Deleting media store row for " + file);
} }
} }
public void renameInMediaStore(File start, File end) { public void renameInMediaStore(File start, File end) {
ContentResolver contentResolver = context.getContentResolver(); ContentResolver contentResolver = context.getContentResolver();
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(MediaStore.MediaColumns.DATA, end.getAbsolutePath()); values.put(MediaStore.MediaColumns.DATA, end.getAbsolutePath());
int n = contentResolver.update(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, int n = contentResolver.update(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
values, values,
MediaStore.MediaColumns.DATA + "=?", MediaStore.MediaColumns.DATA + "=?",
new String[]{start.getAbsolutePath()}); new String[]{start.getAbsolutePath()});
if (n > 0) { if (n > 0) {
Log.i(TAG, "Rename media store row for " + start + " to " + end); Log.i(TAG, "Rename media store row for " + start + " to " + end);
} }
} }
private void insertAlbumArt(int albumId, DownloadFile downloadFile) { private void insertAlbumArt(int albumId, DownloadFile downloadFile) {
ContentResolver contentResolver = context.getContentResolver(); ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = contentResolver.query(Uri.withAppendedPath(ALBUM_ART_URI, String.valueOf(albumId)), null, null, null, null); Cursor cursor = contentResolver.query(Uri.withAppendedPath(ALBUM_ART_URI, String.valueOf(albumId)), null, null, null, null);
if (!cursor.moveToFirst()) { if (!cursor.moveToFirst()) {
// No album art found, add it. // No album art found, add it.
File albumArtFile = FileUtil.getAlbumArtFile(context, downloadFile.getSong()); File albumArtFile = FileUtil.getAlbumArtFile(context, downloadFile.getSong());
if (albumArtFile.exists()) { if (albumArtFile.exists()) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(MediaStore.Audio.AlbumColumns.ALBUM_ID, albumId); values.put(MediaStore.Audio.AlbumColumns.ALBUM_ID, albumId);
values.put(MediaStore.MediaColumns.DATA, albumArtFile.getPath()); values.put(MediaStore.MediaColumns.DATA, albumArtFile.getPath());
contentResolver.insert(ALBUM_ART_URI, values); contentResolver.insert(ALBUM_ART_URI, values);
Log.i(TAG, "Added album art: " + albumArtFile); Log.i(TAG, "Added album art: " + albumArtFile);
} }
} }
cursor.close(); cursor.close();
} }
} }

View File

@ -50,9 +50,9 @@ public interface MusicService {
MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception; MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception; MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception; MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
SearchResult search(SearchCritera criteria, Context context, ProgressListener progressListener) throws Exception; SearchResult search(SearchCritera criteria, Context context, ProgressListener progressListener) throws Exception;
@ -62,40 +62,40 @@ public interface MusicService {
void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context, ProgressListener progressListener) throws Exception; void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context, ProgressListener progressListener) throws Exception;
void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception; void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception;
void addToPlaylist(String id, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception; void addToPlaylist(String id, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception;
void removeFromPlaylist(String id, List<Integer> toRemove, Context context, ProgressListener progressListener) throws Exception; void removeFromPlaylist(String id, List<Integer> toRemove, Context context, ProgressListener progressListener) throws Exception;
void overwritePlaylist(String id, String name, int toRemove, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception; void overwritePlaylist(String id, String name, int toRemove, List<MusicDirectory.Entry> toAdd, Context context, ProgressListener progressListener) throws Exception;
void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception; void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getAlbumList(String type, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception; MusicDirectory getAlbumList(String type, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getAlbumList(String type, String extra, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception; MusicDirectory getAlbumList(String type, String extra, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getSongList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception; MusicDirectory getSongList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception; MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getRandomSongs(int size, String folder, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception; MusicDirectory getRandomSongs(int size, String folder, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception;
Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, ProgressListener progressListener, SilentBackgroundTask task) throws Exception; Bitmap getCoverArt(Context context, MusicDirectory.Entry entry, int size, ProgressListener progressListener, SilentBackgroundTask task) throws Exception;
Response getDownloadInputStream(Context context, MusicDirectory.Entry song, long offset, int maxBitrate, SilentBackgroundTask task) throws Exception; Response getDownloadInputStream(Context context, MusicDirectory.Entry song, long offset, int maxBitrate, SilentBackgroundTask task) throws Exception;
List<Genre> getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception; List<Genre> getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception; MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception;
User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception; User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception;
Bitmap getBitmap(String url, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception; Bitmap getBitmap(String url, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception;
void savePlayQueue(List<MusicDirectory.Entry> songs, MusicDirectory.Entry currentPlaying, int position, Context context, ProgressListener progressListener) throws Exception; void savePlayQueue(List<MusicDirectory.Entry> songs, MusicDirectory.Entry currentPlaying, int position, Context context, ProgressListener progressListener) throws Exception;
PlayerQueue getPlayQueue(Context context, ProgressListener progressListener) throws Exception; PlayerQueue getPlayQueue(Context context, ProgressListener progressListener) throws Exception;
void setInstance(Integer instance) throws Exception; void setInstance(Integer instance) throws Exception;
} }

View File

@ -62,19 +62,19 @@ import java.util.SortedSet;
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class OfflineMusicService implements MusicService { public class OfflineMusicService implements MusicService {
private static final String TAG = OfflineMusicService.class.getSimpleName(); private static final String TAG = OfflineMusicService.class.getSimpleName();
private static final String ERRORMSG = "Not available in offline mode"; private static final String ERRORMSG = "Not available in offline mode";
private static final Random random = new Random(); private static final Random random = new Random();
@Override @Override
public void ping(Context context, ProgressListener progressListener) throws Exception { public void ping(Context context, ProgressListener progressListener) throws Exception {
} }
@Override @Override
public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception { public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
List<Artist> artists = new ArrayList<Artist>(); List<Artist> artists = new ArrayList<Artist>();
List<Entry> entries = new ArrayList<>(); List<Entry> entries = new ArrayList<>();
File root = FileUtil.getMusicDirectory(context); File root = FileUtil.getMusicDirectory(context);
for (File file : FileUtil.listFiles(root)) { for (File file : FileUtil.listFiles(root)) {
if (file.isDirectory()) { if (file.isDirectory()) {
@ -84,47 +84,47 @@ public class OfflineMusicService implements MusicService {
artist.setName(file.getName()); artist.setName(file.getName());
artists.add(artist); artists.add(artist);
} else if(!file.getName().equals("albumart.jpg") && !file.getName().equals(".nomedia")) { } else if(!file.getName().equals("albumart.jpg") && !file.getName().equals(".nomedia")) {
entries.add(createEntry(context, file)); entries.add(createEntry(context, file));
} }
} }
Indexes indexes = new Indexes(0L, Collections.<Artist>emptyList(), artists, entries); Indexes indexes = new Indexes(0L, Collections.<Artist>emptyList(), artists, entries);
return indexes; return indexes;
} }
@Override @Override
public MusicDirectory getMusicDirectory(String id, String artistName, boolean refresh, Context context, ProgressListener progressListener) throws Exception { public MusicDirectory getMusicDirectory(String id, String artistName, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
return getMusicDirectory(id, artistName, refresh, context, progressListener, false); return getMusicDirectory(id, artistName, refresh, context, progressListener, false);
} }
private MusicDirectory getMusicDirectory(String id, String artistName, boolean refresh, Context context, ProgressListener progressListener, boolean isPodcast) throws Exception { private MusicDirectory getMusicDirectory(String id, String artistName, boolean refresh, Context context, ProgressListener progressListener, boolean isPodcast) throws Exception {
File dir = new File(id); File dir = new File(id);
MusicDirectory result = new MusicDirectory(); MusicDirectory result = new MusicDirectory();
result.setName(dir.getName()); result.setName(dir.getName());
Set<String> names = new HashSet<String>(); Set<String> names = new HashSet<String>();
for (File file : FileUtil.listMediaFiles(dir)) { for (File file : FileUtil.listMediaFiles(dir)) {
String name = getName(file); String name = getName(file);
if (name != null & !names.contains(name)) { if (name != null & !names.contains(name)) {
names.add(name); names.add(name);
result.addChild(createEntry(context, file, name, true, isPodcast)); result.addChild(createEntry(context, file, name, true, isPodcast));
} }
} }
result.sortChildren(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_CUSTOM_SORT_ENABLED, true)); result.sortChildren(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_CUSTOM_SORT_ENABLED, true));
return result; return result;
} }
@Override @Override
public MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { public MusicDirectory getArtist(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { public MusicDirectory getAlbum(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
private String getName(File file) { private String getName(File file) {
String name = file.getName(); String name = file.getName();
if (file.isDirectory()) { if (file.isDirectory()) {
return name; return name;
@ -138,401 +138,401 @@ public class OfflineMusicService implements MusicService {
return FileUtil.getBaseName(name); return FileUtil.getBaseName(name);
} }
private Entry createEntry(Context context, File file) { private Entry createEntry(Context context, File file) {
return createEntry(context, file, getName(file)); return createEntry(context, file, getName(file));
} }
private Entry createEntry(Context context, File file, String name) { private Entry createEntry(Context context, File file, String name) {
return createEntry(context, file, name, true); return createEntry(context, file, name, true);
} }
private Entry createEntry(Context context, File file, String name, boolean load) { private Entry createEntry(Context context, File file, String name, boolean load) {
return createEntry(context, file, name, load, false); return createEntry(context, file, name, load, false);
} }
private Entry createEntry(Context context, File file, String name, boolean load, boolean isPodcast) { private Entry createEntry(Context context, File file, String name, boolean load, boolean isPodcast) {
Entry entry; Entry entry;
entry = new Entry(); entry = new Entry();
entry.setDirectory(file.isDirectory()); entry.setDirectory(file.isDirectory());
entry.setId(file.getPath()); entry.setId(file.getPath());
entry.setParent(file.getParent()); entry.setParent(file.getParent());
entry.setSize(file.length()); entry.setSize(file.length());
String root = FileUtil.getMusicDirectory(context).getPath(); String root = FileUtil.getMusicDirectory(context).getPath();
if(!file.getParentFile().getParentFile().getPath().equals(root)) { if(!file.getParentFile().getParentFile().getPath().equals(root)) {
entry.setGrandParent(file.getParentFile().getParent()); entry.setGrandParent(file.getParentFile().getParent());
} }
entry.setPath(file.getPath().replaceFirst("^" + root + "/" , "")); entry.setPath(file.getPath().replaceFirst("^" + root + "/" , ""));
String title = name; String title = name;
if (file.isFile()) { if (file.isFile()) {
File artistFolder = file.getParentFile().getParentFile(); File artistFolder = file.getParentFile().getParentFile();
File albumFolder = file.getParentFile(); File albumFolder = file.getParentFile();
if(artistFolder.getPath().equals(root)) { if(artistFolder.getPath().equals(root)) {
entry.setArtist(albumFolder.getName()); entry.setArtist(albumFolder.getName());
} else { } else {
entry.setArtist(artistFolder.getName()); entry.setArtist(artistFolder.getName());
} }
entry.setAlbum(albumFolder.getName()); entry.setAlbum(albumFolder.getName());
int index = name.indexOf('-'); int index = name.indexOf('-');
if(index != -1) { if(index != -1) {
try { try {
entry.setTrack(Integer.parseInt(name.substring(0, index))); entry.setTrack(Integer.parseInt(name.substring(0, index)));
title = title.substring(index + 1); title = title.substring(index + 1);
} catch(Exception e) { } catch(Exception e) {
// Failed parseInt, just means track filled out // Failed parseInt, just means track filled out
} }
} }
if(load) { if(load) {
entry.loadMetadata(file); entry.loadMetadata(file);
}
}
entry.setTitle(title);
entry.setSuffix(FileUtil.getExtension(file.getName().replace(".complete", "")));
File albumArt = FileUtil.getAlbumArtFile(context, entry);
if (albumArt.exists()) {
entry.setCoverArt(albumArt.getPath());
}
return entry;
}
@Override
public Bitmap getCoverArt(Context context, Entry entry, int size, ProgressListener progressListener, SilentBackgroundTask task) throws Exception {
try {
return FileUtil.getAlbumArtBitmap(context, entry, size);
} catch(Exception e) {
return null;
}
}
@Override
public Response getDownloadInputStream(Context context, Entry song, long offset, int maxBitrate, SilentBackgroundTask task) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public SearchResult search(SearchCritera criteria, Context context, ProgressListener progressListener) throws Exception {
List<Artist> artists = new ArrayList<Artist>();
List<Entry> albums = new ArrayList<Entry>();
List<Entry> songs = new ArrayList<Entry>();
File root = FileUtil.getMusicDirectory(context);
int closeness = 0;
for (File artistFile : FileUtil.listFiles(root)) {
String artistName = artistFile.getName();
if (artistFile.isDirectory()) {
if((closeness = matchCriteria(criteria, artistName)) > 0) {
Artist artist = new Artist();
artist.setId(artistFile.getPath());
artist.setIndex(artistFile.getName().substring(0, 1));
artist.setName(artistName);
artist.setCloseness(closeness);
artists.add(artist);
}
recursiveAlbumSearch(artistName, artistFile, criteria, context, albums, songs);
} }
} }
Collections.sort(artists, new Comparator<Artist>() { entry.setTitle(title);
public int compare(Artist lhs, Artist rhs) { entry.setSuffix(FileUtil.getExtension(file.getName().replace(".complete", "")));
if(lhs.getCloseness() == rhs.getCloseness()) {
return 0;
}
else if(lhs.getCloseness() > rhs.getCloseness()) {
return -1;
}
else {
return 1;
}
}
});
Collections.sort(albums, new Comparator<Entry>() {
public int compare(Entry lhs, Entry rhs) {
if(lhs.getCloseness() == rhs.getCloseness()) {
return 0;
}
else if(lhs.getCloseness() > rhs.getCloseness()) {
return -1;
}
else {
return 1;
}
}
});
Collections.sort(songs, new Comparator<Entry>() {
public int compare(Entry lhs, Entry rhs) {
if(lhs.getCloseness() == rhs.getCloseness()) {
return 0;
}
else if(lhs.getCloseness() > rhs.getCloseness()) {
return -1;
}
else {
return 1;
}
}
});
// Respect counts in search criteria File albumArt = FileUtil.getAlbumArtFile(context, entry);
int artistCount = Math.min(artists.size(), criteria.getArtistCount()); if (albumArt.exists()) {
int albumCount = Math.min(albums.size(), criteria.getAlbumCount()); entry.setCoverArt(albumArt.getPath());
int songCount = Math.min(songs.size(), criteria.getSongCount()); }
artists = artists.subList(0, artistCount); return entry;
albums = albums.subList(0, albumCount);
songs = songs.subList(0, songCount);
return new SearchResult(artists, albums, songs);
} }
private void recursiveAlbumSearch(String artistName, File file, SearchCritera criteria, Context context, List<Entry> albums, List<Entry> songs) { @Override
int closeness; public Bitmap getCoverArt(Context context, Entry entry, int size, ProgressListener progressListener, SilentBackgroundTask task) throws Exception {
for(File albumFile : FileUtil.listMediaFiles(file)) { try {
if(albumFile.isDirectory()) { return FileUtil.getAlbumArtBitmap(context, entry, size);
String albumName = getName(albumFile); } catch(Exception e) {
if((closeness = matchCriteria(criteria, albumName)) > 0) { return null;
Entry album = createEntry(context, albumFile, albumName); }
album.setArtist(artistName); }
album.setCloseness(closeness);
albums.add(album);
}
for(File songFile : FileUtil.listMediaFiles(albumFile)) { @Override
String songName = getName(songFile); public Response getDownloadInputStream(Context context, Entry song, long offset, int maxBitrate, SilentBackgroundTask task) throws Exception {
if(songName == null) { throw new OfflineException(ERRORMSG);
continue; }
}
if(songFile.isDirectory()) { @Override
recursiveAlbumSearch(artistName, songFile, criteria, context, albums, songs); public List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
} throw new OfflineException(ERRORMSG);
else if((closeness = matchCriteria(criteria, songName)) > 0){ }
Entry song = createEntry(context, albumFile, songName);
song.setArtist(artistName); @Override
song.setAlbum(albumName); public SearchResult search(SearchCritera criteria, Context context, ProgressListener progressListener) throws Exception {
song.setCloseness(closeness); List<Artist> artists = new ArrayList<Artist>();
songs.add(song); List<Entry> albums = new ArrayList<Entry>();
} List<Entry> songs = new ArrayList<Entry>();
} File root = FileUtil.getMusicDirectory(context);
} int closeness = 0;
else { for (File artistFile : FileUtil.listFiles(root)) {
String songName = getName(albumFile); String artistName = artistFile.getName();
if((closeness = matchCriteria(criteria, songName)) > 0) { if (artistFile.isDirectory()) {
Entry song = createEntry(context, albumFile, songName); if((closeness = matchCriteria(criteria, artistName)) > 0) {
song.setArtist(artistName); Artist artist = new Artist();
song.setAlbum(songName); artist.setId(artistFile.getPath());
song.setCloseness(closeness); artist.setIndex(artistFile.getName().substring(0, 1));
songs.add(song); artist.setName(artistName);
} artist.setCloseness(closeness);
} artists.add(artist);
} }
}
private int matchCriteria(SearchCritera criteria, String name) { recursiveAlbumSearch(artistName, artistFile, criteria, context, albums, songs);
if (criteria.getPattern().matcher(name).matches()) { }
return Util.getStringDistance( }
criteria.getQuery().toLowerCase(),
name.toLowerCase()); Collections.sort(artists, new Comparator<Artist>() {
} else { public int compare(Artist lhs, Artist rhs) {
return 0; if(lhs.getCloseness() == rhs.getCloseness()) {
} return 0;
} }
else if(lhs.getCloseness() > rhs.getCloseness()) {
return -1;
}
else {
return 1;
}
}
});
Collections.sort(albums, new Comparator<Entry>() {
public int compare(Entry lhs, Entry rhs) {
if(lhs.getCloseness() == rhs.getCloseness()) {
return 0;
}
else if(lhs.getCloseness() > rhs.getCloseness()) {
return -1;
}
else {
return 1;
}
}
});
Collections.sort(songs, new Comparator<Entry>() {
public int compare(Entry lhs, Entry rhs) {
if(lhs.getCloseness() == rhs.getCloseness()) {
return 0;
}
else if(lhs.getCloseness() > rhs.getCloseness()) {
return -1;
}
else {
return 1;
}
}
});
// Respect counts in search criteria
int artistCount = Math.min(artists.size(), criteria.getArtistCount());
int albumCount = Math.min(albums.size(), criteria.getAlbumCount());
int songCount = Math.min(songs.size(), criteria.getSongCount());
artists = artists.subList(0, artistCount);
albums = albums.subList(0, albumCount);
songs = songs.subList(0, songCount);
return new SearchResult(artists, albums, songs);
}
private void recursiveAlbumSearch(String artistName, File file, SearchCritera criteria, Context context, List<Entry> albums, List<Entry> songs) {
int closeness;
for(File albumFile : FileUtil.listMediaFiles(file)) {
if(albumFile.isDirectory()) {
String albumName = getName(albumFile);
if((closeness = matchCriteria(criteria, albumName)) > 0) {
Entry album = createEntry(context, albumFile, albumName);
album.setArtist(artistName);
album.setCloseness(closeness);
albums.add(album);
}
for(File songFile : FileUtil.listMediaFiles(albumFile)) {
String songName = getName(songFile);
if(songName == null) {
continue;
}
if(songFile.isDirectory()) {
recursiveAlbumSearch(artistName, songFile, criteria, context, albums, songs);
}
else if((closeness = matchCriteria(criteria, songName)) > 0){
Entry song = createEntry(context, albumFile, songName);
song.setArtist(artistName);
song.setAlbum(albumName);
song.setCloseness(closeness);
songs.add(song);
}
}
}
else {
String songName = getName(albumFile);
if((closeness = matchCriteria(criteria, songName)) > 0) {
Entry song = createEntry(context, albumFile, songName);
song.setArtist(artistName);
song.setAlbum(songName);
song.setCloseness(closeness);
songs.add(song);
}
}
}
}
private int matchCriteria(SearchCritera criteria, String name) {
if (criteria.getPattern().matcher(name).matches()) {
return Util.getStringDistance(
criteria.getQuery().toLowerCase(),
name.toLowerCase());
} else {
return 0;
}
}
@Override @Override
public List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception { public List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
List<Playlist> playlists = new ArrayList<Playlist>(); List<Playlist> playlists = new ArrayList<Playlist>();
File root = FileUtil.getPlaylistDirectory(context); File root = FileUtil.getPlaylistDirectory(context);
String lastServer = null; String lastServer = null;
boolean removeServer = true; boolean removeServer = true;
for (File folder : FileUtil.listFiles(root)) { for (File folder : FileUtil.listFiles(root)) {
if(folder.isDirectory()) { if(folder.isDirectory()) {
String server = folder.getName(); String server = folder.getName();
SortedSet<File> fileList = FileUtil.listFiles(folder); SortedSet<File> fileList = FileUtil.listFiles(folder);
for(File file: fileList) { for(File file: fileList) {
if(FileUtil.isPlaylistFile(file)) { if(FileUtil.isPlaylistFile(file)) {
String id = file.getName(); String id = file.getName();
String filename = FileUtil.getBaseName(id); String filename = FileUtil.getBaseName(id);
String name = server + ": " + filename; String name = server + ": " + filename;
Playlist playlist = new Playlist(server, name); Playlist playlist = new Playlist(server, name);
playlist.setComment(filename); playlist.setComment(filename);
Reader reader = null; Reader reader = null;
BufferedReader buffer = null; BufferedReader buffer = null;
int songCount = 0; int songCount = 0;
try { try {
reader = new FileReader(file); reader = new FileReader(file);
buffer = new BufferedReader(reader); buffer = new BufferedReader(reader);
String line = buffer.readLine(); String line = buffer.readLine();
while( (line = buffer.readLine()) != null ){ while( (line = buffer.readLine()) != null ){
// No matter what, end file can't have .complete in it // No matter what, end file can't have .complete in it
line = line.replace(".complete", ""); line = line.replace(".complete", "");
File entryFile = new File(line); File entryFile = new File(line);
// Don't add file to playlist if it doesn't exist as cached or pinned! // Don't add file to playlist if it doesn't exist as cached or pinned!
File checkFile = entryFile; File checkFile = entryFile;
if(!checkFile.exists()) { if(!checkFile.exists()) {
// If normal file doens't exist, check if .complete version does // If normal file doens't exist, check if .complete version does
checkFile = new File(entryFile.getParent(), FileUtil.getBaseName(entryFile.getName()) checkFile = new File(entryFile.getParent(), FileUtil.getBaseName(entryFile.getName())
+ ".complete." + FileUtil.getExtension(entryFile.getName())); + ".complete." + FileUtil.getExtension(entryFile.getName()));
} }
String entryName = getName(entryFile); String entryName = getName(entryFile);
if(checkFile.exists() && entryName != null){ if(checkFile.exists() && entryName != null){
songCount++; songCount++;
} }
} }
playlist.setSongCount(Integer.toString(songCount)); playlist.setSongCount(Integer.toString(songCount));
} catch(Exception e) { } catch(Exception e) {
Log.w(TAG, "Failed to count songs in playlist", e); Log.w(TAG, "Failed to count songs in playlist", e);
} finally { } finally {
Util.close(buffer); Util.close(buffer);
Util.close(reader); Util.close(reader);
} }
if(songCount > 0) { if(songCount > 0) {
playlists.add(playlist); playlists.add(playlist);
} }
} }
} }
if(!server.equals(lastServer) && fileList.size() > 0) { if(!server.equals(lastServer) && fileList.size() > 0) {
if(lastServer != null) { if(lastServer != null) {
removeServer = false; removeServer = false;
} }
lastServer = server; lastServer = server;
} }
} else { } else {
// Delete legacy playlist files // Delete legacy playlist files
try { try {
folder.delete(); folder.delete();
} catch(Exception e) { } catch(Exception e) {
Log.w(TAG, "Failed to delete old playlist file: " + folder.getName()); Log.w(TAG, "Failed to delete old playlist file: " + folder.getName());
} }
} }
} }
if(removeServer) { if(removeServer) {
for(Playlist playlist: playlists) { for(Playlist playlist: playlists) {
playlist.setName(playlist.getName().substring(playlist.getId().length() + 2)); playlist.setName(playlist.getName().substring(playlist.getId().length() + 2));
} }
} }
return playlists; return playlists;
} }
@Override @Override
public MusicDirectory getPlaylist(boolean refresh, String id, String name, Context context, ProgressListener progressListener) throws Exception { public MusicDirectory getPlaylist(boolean refresh, String id, String name, Context context, ProgressListener progressListener) throws Exception {
DownloadService downloadService = DownloadService.getInstance(); DownloadService downloadService = DownloadService.getInstance();
if (downloadService == null) { if (downloadService == null) {
return new MusicDirectory(); return new MusicDirectory();
} }
Reader reader = null; Reader reader = null;
BufferedReader buffer = null; BufferedReader buffer = null;
try { try {
int firstIndex = name.indexOf(id); int firstIndex = name.indexOf(id);
if(firstIndex != -1) { if(firstIndex != -1) {
name = name.substring(id.length() + 2); name = name.substring(id.length() + 2);
} }
File playlistFile = FileUtil.getPlaylistFile(context, id, name); File playlistFile = FileUtil.getPlaylistFile(context, id, name);
reader = new FileReader(playlistFile); reader = new FileReader(playlistFile);
buffer = new BufferedReader(reader); buffer = new BufferedReader(reader);
MusicDirectory playlist = new MusicDirectory(); MusicDirectory playlist = new MusicDirectory();
String line = buffer.readLine(); String line = buffer.readLine();
if(!"#EXTM3U".equals(line)) return playlist; if(!"#EXTM3U".equals(line)) return playlist;
while( (line = buffer.readLine()) != null ){ while( (line = buffer.readLine()) != null ){
// No matter what, end file can't have .complete in it // No matter what, end file can't have .complete in it
line = line.replace(".complete", ""); line = line.replace(".complete", "");
File entryFile = new File(line); File entryFile = new File(line);
// Don't add file to playlist if it doesn't exist as cached or pinned! // Don't add file to playlist if it doesn't exist as cached or pinned!
File checkFile = entryFile; File checkFile = entryFile;
if(!checkFile.exists()) { if(!checkFile.exists()) {
// If normal file doens't exist, check if .complete version does // If normal file doens't exist, check if .complete version does
checkFile = new File(entryFile.getParent(), FileUtil.getBaseName(entryFile.getName()) checkFile = new File(entryFile.getParent(), FileUtil.getBaseName(entryFile.getName())
+ ".complete." + FileUtil.getExtension(entryFile.getName())); + ".complete." + FileUtil.getExtension(entryFile.getName()));
} }
String entryName = getName(entryFile); String entryName = getName(entryFile);
if(checkFile.exists() && entryName != null){ if(checkFile.exists() && entryName != null){
playlist.addChild(createEntry(context, entryFile, entryName, false)); playlist.addChild(createEntry(context, entryFile, entryName, false));
} }
} }
return playlist; return playlist;
} finally { } finally {
Util.close(buffer); Util.close(buffer);
Util.close(reader); Util.close(reader);
} }
} }
@Override @Override
public void createPlaylist(String id, String name, List<Entry> entries, Context context, ProgressListener progressListener) throws Exception { public void createPlaylist(String id, String name, List<Entry> entries, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception { public void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public void addToPlaylist(String id, List<Entry> toAdd, Context context, ProgressListener progressListener) throws Exception { public void addToPlaylist(String id, List<Entry> toAdd, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public void removeFromPlaylist(String id, List<Integer> toRemove, Context context, ProgressListener progressListener) throws Exception { public void removeFromPlaylist(String id, List<Integer> toRemove, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public void overwritePlaylist(String id, String name, int toRemove, List<Entry> toAdd, Context context, ProgressListener progressListener) throws Exception { public void overwritePlaylist(String id, String name, int toRemove, List<Entry> toAdd, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception { public void updatePlaylist(String id, String name, String comment, boolean pub, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public MusicDirectory getAlbumList(String type, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception { public MusicDirectory getAlbumList(String type, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public MusicDirectory getAlbumList(String type, String extra, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception { public MusicDirectory getAlbumList(String type, String extra, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public MusicDirectory getSongList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception { public MusicDirectory getSongList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception { public MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public List<Genre> getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception { public List<Genre> getGenres(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception { public MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public MusicDirectory getRandomSongs(int size, String folder, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception { public MusicDirectory getRandomSongs(int size, String folder, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception {
File root = FileUtil.getMusicDirectory(context); File root = FileUtil.getMusicDirectory(context);
List<File> children = new LinkedList<File>(); List<File> children = new LinkedList<File>();
@ -550,29 +550,29 @@ public class OfflineMusicService implements MusicService {
return result; return result;
} }
@Override @Override
public User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception { public User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public Bitmap getBitmap(String url, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception { public Bitmap getBitmap(String url, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public void savePlayQueue(List<Entry> songs, Entry currentPlaying, int position, Context context, ProgressListener progressListener) throws Exception { public void savePlayQueue(List<Entry> songs, Entry currentPlaying, int position, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public PlayerQueue getPlayQueue(Context context, ProgressListener progressListener) throws Exception { public PlayerQueue getPlayQueue(Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
@Override @Override
public void setInstance(Integer instance) throws Exception{ public void setInstance(Integer instance) throws Exception{
throw new OfflineException(ERRORMSG); throw new OfflineException(ERRORMSG);
} }
private void listFilesRecursively(File parent, List<File> children) { private void listFilesRecursively(File parent, List<File> children) {

View File

@ -45,10 +45,10 @@ public class EntryListParser extends MusicDirectoryEntryParser {
if (eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
String name = getElementName(); String name = getElementName();
if ("album".equals(name)) { if ("album".equals(name)) {
MusicDirectory.Entry entry = parseEntry(""); MusicDirectory.Entry entry = parseEntry("");
if(get("isDir") == null) { if(get("isDir") == null) {
entry.setDirectory(true); entry.setDirectory(true);
} }
dir.addChild(entry); dir.addChild(entry);
} else if ("song".equals(name)) { } else if ("song".equals(name)) {
MusicDirectory.Entry entry = parseEntry(""); MusicDirectory.Entry entry = parseEntry("");

View File

@ -29,8 +29,8 @@ import java.io.InputStream;
public class ErrorParser extends AbstractParser { public class ErrorParser extends AbstractParser {
public ErrorParser(Context context, int instance) { public ErrorParser(Context context, int instance) {
super(context, instance); super(context, instance);
} }
public void parse(InputStream inputStream) throws Exception { public void parse(InputStream inputStream) throws Exception {

View File

@ -53,13 +53,13 @@ public class IndexesParser extends MusicDirectoryEntryParser {
List<Artist> artists = new ArrayList<Artist>(); List<Artist> artists = new ArrayList<Artist>();
List<Artist> shortcuts = new ArrayList<Artist>(); List<Artist> shortcuts = new ArrayList<Artist>();
List<MusicDirectory.Entry> entries = new ArrayList<MusicDirectory.Entry>(); List<MusicDirectory.Entry> entries = new ArrayList<MusicDirectory.Entry>();
Long lastModified = null; Long lastModified = null;
int eventType; int eventType;
String index = "#"; String index = "#";
String ignoredArticles = null; String ignoredArticles = null;
boolean changed = false; boolean changed = false;
Map<String, Artist> artistList = new HashMap<String, Artist>(); Map<String, Artist> artistList = new HashMap<String, Artist>();
do { do {
eventType = nextParseEvent(); eventType = nextParseEvent();
@ -68,7 +68,7 @@ public class IndexesParser extends MusicDirectoryEntryParser {
if ("indexes".equals(name) || "artists".equals(name)) { if ("indexes".equals(name) || "artists".equals(name)) {
changed = true; changed = true;
lastModified = getLong("lastModified"); lastModified = getLong("lastModified");
ignoredArticles = get("ignoredArticles"); ignoredArticles = get("ignoredArticles");
} else if ("index".equals(name)) { } else if ("index".equals(name)) {
index = get("name"); index = get("name");
@ -78,14 +78,14 @@ public class IndexesParser extends MusicDirectoryEntryParser {
artist.setName(get("name")); artist.setName(get("name"));
artist.setIndex(index); artist.setIndex(index);
// Combine the id's for the two artists // Combine the id's for the two artists
if(artistList.containsKey(artist.getName())) { if(artistList.containsKey(artist.getName())) {
Artist originalArtist = artistList.get(artist.getName()); Artist originalArtist = artistList.get(artist.getName());
originalArtist.setId(originalArtist.getId() + ";" + artist.getId()); originalArtist.setId(originalArtist.getId() + ";" + artist.getId());
} else { } else {
artistList.put(artist.getName(), artist); artistList.put(artist.getName(), artist);
artists.add(artist); artists.add(artist);
} }
if (artists.size() % 10 == 0) { if (artists.size() % 10 == 0) {
String msg = getContext().getResources().getString(R.string.parser_artist_count, artists.size()); String msg = getContext().getResources().getString(R.string.parser_artist_count, artists.size());
@ -97,10 +97,10 @@ public class IndexesParser extends MusicDirectoryEntryParser {
shortcut.setName(get("name")); shortcut.setName(get("name"));
shortcut.setIndex("*"); shortcut.setIndex("*");
shortcuts.add(shortcut); shortcuts.add(shortcut);
} else if("child".equals(name)) { } else if("child".equals(name)) {
MusicDirectory.Entry entry = parseEntry(""); MusicDirectory.Entry entry = parseEntry("");
entries.add(entry); entries.add(entry);
} else if ("error".equals(name)) { } else if ("error".equals(name)) {
handleError(); handleError();
} }
} }
@ -108,11 +108,11 @@ public class IndexesParser extends MusicDirectoryEntryParser {
validate(); validate();
if(ignoredArticles != null) { if(ignoredArticles != null) {
SharedPreferences.Editor prefs = Util.getPreferences(context).edit(); SharedPreferences.Editor prefs = Util.getPreferences(context).edit();
prefs.putString(Constants.CACHE_KEY_IGNORE, ignoredArticles); prefs.putString(Constants.CACHE_KEY_IGNORE, ignoredArticles);
prefs.apply(); prefs.apply();
} }
if (!changed) { if (!changed) {
return null; return null;

View File

@ -33,21 +33,21 @@ public class MusicDirectoryEntryParser extends AbstractParser {
protected MusicDirectory.Entry parseEntry(String artist) { protected MusicDirectory.Entry parseEntry(String artist) {
MusicDirectory.Entry entry = new MusicDirectory.Entry(); MusicDirectory.Entry entry = new MusicDirectory.Entry();
entry.setId(get("id")); entry.setId(get("id"));
entry.setParent(get("parent")); entry.setParent(get("parent"));
entry.setArtistId(get("artistId")); entry.setArtistId(get("artistId"));
entry.setTitle(get("title")); entry.setTitle(get("title"));
if(entry.getTitle() == null) { if(entry.getTitle() == null) {
entry.setTitle(get("name")); entry.setTitle(get("name"));
} }
entry.setDirectory(getBoolean("isDir")); entry.setDirectory(getBoolean("isDir"));
entry.setCoverArt(get("coverArt")); entry.setCoverArt(get("coverArt"));
entry.setArtist(get("artist")); entry.setArtist(get("artist"));
entry.setYear(getInteger("year")); entry.setYear(getInteger("year"));
entry.setGenre(get("genre")); entry.setGenre(get("genre"));
entry.setAlbum(get("album")); entry.setAlbum(get("album"));
if (!entry.isDirectory()) { if (!entry.isDirectory()) {
entry.setAlbumId(get("albumId")); entry.setAlbumId(get("albumId"));
entry.setTrack(getInteger("track")); entry.setTrack(getInteger("track"));
entry.setContentType(get("contentType")); entry.setContentType(get("contentType"));
entry.setSuffix(get("suffix")); entry.setSuffix(get("suffix"));
@ -57,23 +57,23 @@ public class MusicDirectoryEntryParser extends AbstractParser {
entry.setDuration(getInteger("duration")); entry.setDuration(getInteger("duration"));
entry.setBitRate(getInteger("bitRate")); entry.setBitRate(getInteger("bitRate"));
entry.setPath(get("path")); entry.setPath(get("path"));
entry.setDiscNumber(getInteger("discNumber")); entry.setDiscNumber(getInteger("discNumber"));
String type = get("type"); String type = get("type");
} else if(!"".equals(artist)) { } else if(!"".equals(artist)) {
entry.setPath(artist + "/" + entry.getTitle()); entry.setPath(artist + "/" + entry.getTitle());
} }
return entry; return entry;
} }
protected MusicDirectory.Entry parseArtist() { protected MusicDirectory.Entry parseArtist() {
MusicDirectory.Entry entry = new MusicDirectory.Entry(); MusicDirectory.Entry entry = new MusicDirectory.Entry();
entry.setId(get("id")); entry.setId(get("id"));
entry.setTitle(get("name")); entry.setTitle(get("name"));
entry.setPath(entry.getTitle()); entry.setPath(entry.getTitle());
entry.setDirectory(true); entry.setDirectory(true);
return entry; return entry;
} }
} }

View File

@ -49,52 +49,52 @@ public class MusicDirectoryParser extends MusicDirectoryEntryParser {
MusicDirectory dir = new MusicDirectory(); MusicDirectory dir = new MusicDirectory();
int eventType; int eventType;
boolean isArtist = false; boolean isArtist = false;
Map<String, Entry> titleMap = new HashMap<String, Entry>(); Map<String, Entry> titleMap = new HashMap<String, Entry>();
do { do {
eventType = nextParseEvent(); eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
String name = getElementName(); String name = getElementName();
if ("child".equals(name) || "song".equals(name)) { if ("child".equals(name) || "song".equals(name)) {
Entry entry = parseEntry(artist); Entry entry = parseEntry(artist);
entry.setGrandParent(dir.getParent()); entry.setGrandParent(dir.getParent());
// Only check for songs // Only check for songs
if(!entry.isDirectory()) { if(!entry.isDirectory()) {
// Check if duplicates // Check if duplicates
String disc = (entry.getDiscNumber() != null) ? Integer.toString(entry.getDiscNumber()) : ""; String disc = (entry.getDiscNumber() != null) ? Integer.toString(entry.getDiscNumber()) : "";
String track = (entry.getTrack() != null) ? Integer.toString(entry.getTrack()) : ""; String track = (entry.getTrack() != null) ? Integer.toString(entry.getTrack()) : "";
String duplicateId = disc + "-" + track + "-" + entry.getTitle(); String duplicateId = disc + "-" + track + "-" + entry.getTitle();
Entry duplicate = titleMap.get(duplicateId); Entry duplicate = titleMap.get(duplicateId);
if (duplicate != null) { if (duplicate != null) {
// Check if the first already has been rebased or not // Check if the first already has been rebased or not
if (duplicate.getTitle().equals(entry.getTitle())) { if (duplicate.getTitle().equals(entry.getTitle())) {
duplicate.rebaseTitleOffPath(); duplicate.rebaseTitleOffPath();
} }
// Rebase if this is the second instance of this title found // Rebase if this is the second instance of this title found
entry.rebaseTitleOffPath(); entry.rebaseTitleOffPath();
} else { } else {
titleMap.put(duplicateId, entry); titleMap.put(duplicateId, entry);
} }
} }
dir.addChild(entry); dir.addChild(entry);
} else if ("directory".equals(name) || "artist".equals(name) || ("album".equals(name) && !isArtist)) { } else if ("directory".equals(name) || "artist".equals(name) || ("album".equals(name) && !isArtist)) {
dir.setName(get("name")); dir.setName(get("name"));
dir.setId(get("id")); dir.setId(get("id"));
if(Util.isTagBrowsing(context, instance)) { if(Util.isTagBrowsing(context, instance)) {
dir.setParent(get("artistId")); dir.setParent(get("artistId"));
} else { } else {
dir.setParent(get("parent")); dir.setParent(get("parent"));
} }
isArtist = true; isArtist = true;
} else if("album".equals(name)) { } else if("album".equals(name)) {
Entry entry = parseEntry(artist); Entry entry = parseEntry(artist);
entry.setDirectory(true); entry.setDirectory(true);
dir.addChild(entry); dir.addChild(entry);
} else if ("error".equals(name)) { } else if ("error".equals(name)) {
handleError(); handleError();
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.service.parser; package net.nullsum.audinaut.service.parser;
@ -30,54 +30,54 @@ import net.nullsum.audinaut.domain.PlayerQueue;
import net.nullsum.audinaut.util.ProgressListener; import net.nullsum.audinaut.util.ProgressListener;
public class PlayQueueParser extends MusicDirectoryEntryParser { public class PlayQueueParser extends MusicDirectoryEntryParser {
private static final String TAG = PlayQueueParser.class.getSimpleName(); private static final String TAG = PlayQueueParser.class.getSimpleName();
public PlayQueueParser(Context context, int instance) { public PlayQueueParser(Context context, int instance) {
super(context, instance); super(context, instance);
} }
public PlayerQueue parse(InputStream inputStream, ProgressListener progressListener) throws Exception { public PlayerQueue parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream); init(inputStream);
PlayerQueue state = new PlayerQueue(); PlayerQueue state = new PlayerQueue();
String currentId = null; String currentId = null;
int eventType; int eventType;
do { do {
eventType = nextParseEvent(); eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
String name = getElementName(); String name = getElementName();
if("playQueue".equals(name)) { if("playQueue".equals(name)) {
currentId = get("current"); currentId = get("current");
state.currentPlayingPosition = getInteger("position"); state.currentPlayingPosition = getInteger("position");
try { try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH);
dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
state.changed = dateFormat.parse(get("changed")); state.changed = dateFormat.parse(get("changed"));
} catch (ParseException e) { } catch (ParseException e) {
state.changed = null; state.changed = null;
} }
} else if ("entry".equals(name)) { } else if ("entry".equals(name)) {
MusicDirectory.Entry entry = parseEntry(""); MusicDirectory.Entry entry = parseEntry("");
// Only add songs // Only add songs
state.songs.add(entry); state.songs.add(entry);
} else if ("error".equals(name)) { } else if ("error".equals(name)) {
handleError(); handleError();
} }
} }
} while (eventType != XmlPullParser.END_DOCUMENT); } while (eventType != XmlPullParser.END_DOCUMENT);
if(currentId != null) { if(currentId != null) {
for (MusicDirectory.Entry entry : state.songs) { for (MusicDirectory.Entry entry : state.songs) {
if (entry.getId().equals(currentId)) { if (entry.getId().equals(currentId)) {
state.currentPlayingIndex = state.songs.indexOf(entry); state.currentPlayingIndex = state.songs.indexOf(entry);
} }
} }
} else { } else {
state.currentPlayingIndex = 0; state.currentPlayingIndex = 0;
state.currentPlayingPosition = 0; state.currentPlayingPosition = 0;
} }
validate(); validate();
return state; return state;
} }
} }

View File

@ -32,8 +32,8 @@ import java.io.InputStream;
public class PlaylistParser extends MusicDirectoryEntryParser { public class PlaylistParser extends MusicDirectoryEntryParser {
public PlaylistParser(Context context, int instance) { public PlaylistParser(Context context, int instance) {
super(context, instance); super(context, instance);
} }
public MusicDirectory parse(InputStream inputStream, ProgressListener progressListener) throws Exception { public MusicDirectory parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream); init(inputStream);
@ -49,9 +49,9 @@ public class PlaylistParser extends MusicDirectoryEntryParser {
} else if ("error".equals(name)) { } else if ("error".equals(name)) {
handleError(); handleError();
} else if ("playlist".equals(name)) { } else if ("playlist".equals(name)) {
dir.setName(get("name")); dir.setName(get("name"));
dir.setId(get("id")); dir.setId(get("id"));
} }
} }
} while (eventType != XmlPullParser.END_DOCUMENT); } while (eventType != XmlPullParser.END_DOCUMENT);

View File

@ -34,8 +34,8 @@ import java.util.List;
public class PlaylistsParser extends AbstractParser { public class PlaylistsParser extends AbstractParser {
public PlaylistsParser(Context context, int instance) { public PlaylistsParser(Context context, int instance) {
super(context, instance); super(context, instance);
} }
public List<Playlist> parse(InputStream inputStream, ProgressListener progressListener) throws Exception { public List<Playlist> parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream); init(inputStream);
@ -49,13 +49,13 @@ public class PlaylistsParser extends AbstractParser {
if ("playlist".equals(tag)) { if ("playlist".equals(tag)) {
String id = get("id"); String id = get("id");
String name = get("name"); String name = get("name");
String owner = get("owner"); String owner = get("owner");
String comment = get("comment"); String comment = get("comment");
String songCount = get("songCount"); String songCount = get("songCount");
String pub = get("public"); String pub = get("public");
String created = get("created"); String created = get("created");
String changed = get("changed"); String changed = get("changed");
Integer duration = getInteger("duration"); Integer duration = getInteger("duration");
result.add(new Playlist(id, name, owner, comment, songCount, pub, created, changed, duration)); result.add(new Playlist(id, name, owner, comment, songCount, pub, created, changed, duration));
} else if ("error".equals(tag)) { } else if ("error".equals(tag)) {
handleError(); handleError();

View File

@ -32,8 +32,8 @@ import java.io.InputStream;
public class RandomSongsParser extends MusicDirectoryEntryParser { public class RandomSongsParser extends MusicDirectoryEntryParser {
public RandomSongsParser(Context context, int instance) { public RandomSongsParser(Context context, int instance) {
super(context, instance); super(context, instance);
} }
public MusicDirectory parse(InputStream inputStream, ProgressListener progressListener) throws Exception { public MusicDirectory parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream); init(inputStream);

View File

@ -36,8 +36,8 @@ import java.util.ArrayList;
public class SearchResult2Parser extends MusicDirectoryEntryParser { public class SearchResult2Parser extends MusicDirectoryEntryParser {
public SearchResult2Parser(Context context, int instance) { public SearchResult2Parser(Context context, int instance) {
super(context, instance); super(context, instance);
} }
public SearchResult parse(InputStream inputStream, ProgressListener progressListener) throws Exception { public SearchResult parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream); init(inputStream);
@ -56,8 +56,8 @@ public class SearchResult2Parser extends MusicDirectoryEntryParser {
artist.setName(get("name")); artist.setName(get("name"));
artists.add(artist); artists.add(artist);
} else if ("album".equals(name)) { } else if ("album".equals(name)) {
MusicDirectory.Entry entry = parseEntry(""); MusicDirectory.Entry entry = parseEntry("");
entry.setDirectory(true); entry.setDirectory(true);
albums.add(entry); albums.add(entry);
} else if ("song".equals(name)) { } else if ("song".equals(name)) {
songs.add(parseEntry("")); songs.add(parseEntry(""));

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson Copyright 2014 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.service.parser; package net.nullsum.audinaut.service.parser;
@ -33,76 +33,76 @@ import net.nullsum.audinaut.service.MusicServiceFactory;
import net.nullsum.audinaut.util.ProgressListener; import net.nullsum.audinaut.util.ProgressListener;
public class UserParser extends AbstractParser { public class UserParser extends AbstractParser {
private static final String TAG = UserParser.class.getSimpleName(); private static final String TAG = UserParser.class.getSimpleName();
public UserParser(Context context, int instance) { public UserParser(Context context, int instance) {
super(context, instance); super(context, instance);
} }
public List<User> parse(InputStream inputStream, ProgressListener progressListener) throws Exception { public List<User> parse(InputStream inputStream, ProgressListener progressListener) throws Exception {
init(inputStream); init(inputStream);
List<User> result = new ArrayList<User>(); List<User> result = new ArrayList<User>();
List<MusicFolder> musicFolders = null; List<MusicFolder> musicFolders = null;
User user = null; User user = null;
int eventType; int eventType;
String tagName = null; String tagName = null;
do { do {
eventType = nextParseEvent(); eventType = nextParseEvent();
if (eventType == XmlPullParser.START_TAG) { if (eventType == XmlPullParser.START_TAG) {
tagName = getElementName(); tagName = getElementName();
if ("user".equals(tagName)) { if ("user".equals(tagName)) {
user = new User(); user = new User();
user.setUsername(get("username")); user.setUsername(get("username"));
user.setEmail(get("email")); user.setEmail(get("email"));
for(String role: User.ROLES) { for(String role: User.ROLES) {
parseSetting(user, role); parseSetting(user, role);
} }
result.add(user); result.add(user);
} else if ("error".equals(tagName)) { } else if ("error".equals(tagName)) {
handleError(); handleError();
} }
} else if(eventType == XmlPullParser.TEXT) { } else if(eventType == XmlPullParser.TEXT) {
if("folder".equals(tagName)) { if("folder".equals(tagName)) {
String id = getText(); String id = getText();
if(musicFolders == null) { if(musicFolders == null) {
musicFolders = getMusicFolders(); musicFolders = getMusicFolders();
} }
if(user != null) { if(user != null) {
if(user.getMusicFolderSettings() == null) { if(user.getMusicFolderSettings() == null) {
for (MusicFolder musicFolder : musicFolders) { for (MusicFolder musicFolder : musicFolders) {
user.addMusicFolder(musicFolder); user.addMusicFolder(musicFolder);
} }
} }
for(Setting musicFolder: user.getMusicFolderSettings()) { for(Setting musicFolder: user.getMusicFolderSettings()) {
if(musicFolder.getName().equals(id)) { if(musicFolder.getName().equals(id)) {
musicFolder.setValue(true); musicFolder.setValue(true);
break; break;
} }
} }
} }
} }
} }
} while (eventType != XmlPullParser.END_DOCUMENT); } while (eventType != XmlPullParser.END_DOCUMENT);
validate(); validate();
return result; return result;
} }
private List<MusicFolder> getMusicFolders() throws Exception{ private List<MusicFolder> getMusicFolders() throws Exception{
MusicService musicService = MusicServiceFactory.getMusicService(context); MusicService musicService = MusicServiceFactory.getMusicService(context);
return musicService.getMusicFolders(false, context, null); return musicService.getMusicFolders(false, context, null);
} }
private void parseSetting(User user, String name) { private void parseSetting(User user, String name) {
String value = get(name); String value = get(name);
if(value != null) { if(value != null) {
user.addSetting(name, "true".equals(value)); user.addSetting(name, "true".equals(value));
} }
} }
} }

View File

@ -34,57 +34,57 @@ import android.os.IBinder;
*/ */
public class AuthenticatorService extends Service { public class AuthenticatorService extends Service {
private SubsonicAuthenticator authenticator; private SubsonicAuthenticator authenticator;
@Override @Override
public void onCreate() { public void onCreate() {
authenticator = new SubsonicAuthenticator(this); authenticator = new SubsonicAuthenticator(this);
} }
@Override @Override
public IBinder onBind(Intent intent) { public IBinder onBind(Intent intent) {
return authenticator.getIBinder(); return authenticator.getIBinder();
} }
private class SubsonicAuthenticator extends AbstractAccountAuthenticator { private class SubsonicAuthenticator extends AbstractAccountAuthenticator {
public SubsonicAuthenticator(Context context) { public SubsonicAuthenticator(Context context) {
super(context); super(context);
} }
@Override @Override
public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) { public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
return null; return null;
} }
@Override @Override
public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
return null; return null;
} }
@Override @Override
public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException { public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
return null; return null;
} }
@Override @Override
public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
return null; return null;
} }
@Override @Override
public String getAuthTokenLabel(String authTokenType) { public String getAuthTokenLabel(String authTokenType) {
return null; return null;
} }
@Override @Override
public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
return null; return null;
} }
@Override @Override
public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException { public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
return null; return null;
} }
} }
} }

View File

@ -32,71 +32,71 @@ import java.util.List;
* @author Scott * @author Scott
*/ */
public class Updater { public class Updater {
protected String TAG = Updater.class.getSimpleName(); protected String TAG = Updater.class.getSimpleName();
protected int version; protected int version;
protected Context context; protected Context context;
public Updater(int version) { public Updater(int version) {
// 5.2 should show as 520 instead of 52 // 5.2 should show as 520 instead of 52
if(version < 100) { if(version < 100) {
version *= 10; version *= 10;
} }
this.version = version; this.version = version;
} }
public void checkUpdates(Context context) { public void checkUpdates(Context context) {
this.context = context; this.context = context;
List<Updater> updaters = new ArrayList<Updater>(); List<Updater> updaters = new ArrayList<Updater>();
updaters.add(new UpdaterSongPress()); updaters.add(new UpdaterSongPress());
SharedPreferences prefs = Util.getPreferences(context); SharedPreferences prefs = Util.getPreferences(context);
int lastVersion = prefs.getInt(Constants.LAST_VERSION, 0); int lastVersion = prefs.getInt(Constants.LAST_VERSION, 0);
if(lastVersion == 0) { if(lastVersion == 0) {
SharedPreferences.Editor editor = prefs.edit(); SharedPreferences.Editor editor = prefs.edit();
editor.putInt(Constants.LAST_VERSION, version); editor.putInt(Constants.LAST_VERSION, version);
editor.apply(); editor.apply();
} }
else if(version > lastVersion) { else if(version > lastVersion) {
SharedPreferences.Editor editor = prefs.edit(); SharedPreferences.Editor editor = prefs.edit();
editor.putInt(Constants.LAST_VERSION, version); editor.putInt(Constants.LAST_VERSION, version);
editor.apply(); editor.apply();
Log.i(TAG, "Updating from version " + lastVersion + " to " + version); Log.i(TAG, "Updating from version " + lastVersion + " to " + version);
for(Updater updater: updaters) { for(Updater updater: updaters) {
if(updater.shouldUpdate(lastVersion)) { if(updater.shouldUpdate(lastVersion)) {
new BackgroundUpdate(context, updater).execute(); new BackgroundUpdate(context, updater).execute();
} }
} }
} }
} }
public String getName() { public String getName() {
return this.TAG; return this.TAG;
} }
private class BackgroundUpdate extends SilentBackgroundTask<Void> { private class BackgroundUpdate extends SilentBackgroundTask<Void> {
private final Updater updater; private final Updater updater;
public BackgroundUpdate(Context context, Updater updater) { public BackgroundUpdate(Context context, Updater updater) {
super(context); super(context);
this.updater = updater; this.updater = updater;
} }
@Override @Override
protected Void doInBackground() { protected Void doInBackground() {
try { try {
updater.update(context); updater.update(context);
} catch(Exception e) { } catch(Exception e) {
Log.w(TAG, "Failed to run update for " + updater.getName()); Log.w(TAG, "Failed to run update for " + updater.getName());
} }
return null; return null;
} }
} }
public boolean shouldUpdate(int version) { public boolean shouldUpdate(int version) {
return this.version > version; return this.version > version;
} }
public void update(Context context) { public void update(Context context) {
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2016 (C) Scott Jackson Copyright 2016 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.updates; package net.nullsum.audinaut.updates;
@ -22,21 +22,21 @@ import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
public class UpdaterSongPress extends Updater { public class UpdaterSongPress extends Updater {
public UpdaterSongPress() { public UpdaterSongPress() {
super(521); super(521);
TAG = this.getClass().getSimpleName(); TAG = this.getClass().getSimpleName();
} }
@Override @Override
public void update(Context context) { public void update(Context context) {
SharedPreferences prefs = Util.getPreferences(context); SharedPreferences prefs = Util.getPreferences(context);
boolean playNowAfter = prefs.getBoolean("playNowAfter", true); boolean playNowAfter = prefs.getBoolean("playNowAfter", true);
// Migrate the old preference so behavior stays the same // Migrate the old preference so behavior stays the same
if(playNowAfter == false) { if(playNowAfter == false) {
SharedPreferences.Editor editor = prefs.edit(); SharedPreferences.Editor editor = prefs.edit();
editor.putString(Constants.PREFERENCES_KEY_SONG_PRESS_ACTION, "single"); editor.putString(Constants.PREFERENCES_KEY_SONG_PRESS_ACTION, "single");
editor.apply(); editor.apply();
} }
} }
} }

View File

@ -45,62 +45,62 @@ public abstract class BackgroundTask<T> implements ProgressListener {
private static final String TAG = BackgroundTask.class.getSimpleName(); private static final String TAG = BackgroundTask.class.getSimpleName();
private final Context context; private final Context context;
protected AtomicBoolean cancelled = new AtomicBoolean(false); protected AtomicBoolean cancelled = new AtomicBoolean(false);
protected OnCancelListener cancelListener; protected OnCancelListener cancelListener;
protected Runnable onCompletionListener = null; protected Runnable onCompletionListener = null;
protected Task task; protected Task task;
private static final int DEFAULT_CONCURRENCY = 8; private static final int DEFAULT_CONCURRENCY = 8;
private static final Collection<Thread> threads = Collections.synchronizedCollection(new ArrayList<Thread>()); private static final Collection<Thread> threads = Collections.synchronizedCollection(new ArrayList<Thread>());
protected static final BlockingQueue<BackgroundTask.Task> queue = new LinkedBlockingQueue<BackgroundTask.Task>(10); protected static final BlockingQueue<BackgroundTask.Task> queue = new LinkedBlockingQueue<BackgroundTask.Task>(10);
private static Handler handler = null; private static Handler handler = null;
static { static {
try { try {
handler = new Handler(Looper.getMainLooper()); handler = new Handler(Looper.getMainLooper());
} catch(Exception e) { } catch(Exception e) {
// Not called from main thread // Not called from main thread
} }
} }
public BackgroundTask(Context context) { public BackgroundTask(Context context) {
this.context = context; this.context = context;
if(threads.size() < DEFAULT_CONCURRENCY) { if(threads.size() < DEFAULT_CONCURRENCY) {
for(int i = threads.size(); i < DEFAULT_CONCURRENCY; i++) { for(int i = threads.size(); i < DEFAULT_CONCURRENCY; i++) {
Thread thread = new Thread(new TaskRunnable(), String.format("BackgroundTask_%d", i)); Thread thread = new Thread(new TaskRunnable(), String.format("BackgroundTask_%d", i));
threads.add(thread); threads.add(thread);
thread.start(); thread.start();
} }
} }
if(handler == null) { if(handler == null) {
try { try {
handler = new Handler(Looper.getMainLooper()); handler = new Handler(Looper.getMainLooper());
} catch(Exception e) { } catch(Exception e) {
// Not called from main thread // Not called from main thread
} }
} }
} }
public static void stopThreads() { public static void stopThreads() {
for(Thread thread: threads) { for(Thread thread: threads) {
thread.interrupt(); thread.interrupt();
} }
threads.clear(); threads.clear();
queue.clear(); queue.clear();
} }
protected Activity getActivity() { protected Activity getActivity() {
return (context instanceof Activity) ? ((Activity) context) : null; return (context instanceof Activity) ? ((Activity) context) : null;
} }
protected Context getContext() { protected Context getContext() {
return context; return context;
} }
protected Handler getHandler() { protected Handler getHandler() {
return handler; return handler;
} }
public abstract void execute(); public abstract void execute();
protected abstract T doInBackground() throws Throwable; protected abstract T doInBackground() throws Throwable;
@ -108,10 +108,10 @@ public abstract class BackgroundTask<T> implements ProgressListener {
protected void error(Throwable error) { protected void error(Throwable error) {
Log.w(TAG, "Got exception: " + error, error); Log.w(TAG, "Got exception: " + error, error);
Activity activity = getActivity(); Activity activity = getActivity();
if(activity != null) { if(activity != null) {
new ErrorDialog(activity, getErrorMessage(error), true); new ErrorDialog(activity, getErrorMessage(error), true);
} }
} }
protected String getErrorMessage(Throwable error) { protected String getErrorMessage(Throwable error) {
@ -139,33 +139,33 @@ public abstract class BackgroundTask<T> implements ProgressListener {
return error.getClass().getSimpleName(); return error.getClass().getSimpleName();
} }
public void cancel() { public void cancel() {
if(cancelled.compareAndSet(false, true)) { if(cancelled.compareAndSet(false, true)) {
if(isRunning()) { if(isRunning()) {
if(cancelListener != null) { if(cancelListener != null) {
cancelListener.onCancel(); cancelListener.onCancel();
} else { } else {
task.cancel(); task.cancel();
} }
} }
task = null; task = null;
} }
} }
public boolean isCancelled() { public boolean isCancelled() {
return cancelled.get(); return cancelled.get();
} }
public void setOnCancelListener(OnCancelListener listener) { public void setOnCancelListener(OnCancelListener listener) {
cancelListener = listener; cancelListener = listener;
} }
public boolean isRunning() { public boolean isRunning() {
if(task == null) { if(task == null) {
return false; return false;
} else { } else {
return task.isRunning(); return task.isRunning();
} }
} }
@Override @Override
public abstract void updateProgress(final String message); public abstract void updateProgress(final String message);
@ -175,151 +175,151 @@ public abstract class BackgroundTask<T> implements ProgressListener {
updateProgress(context.getResources().getString(messageId)); updateProgress(context.getResources().getString(messageId));
} }
@Override @Override
public void updateCache(int changeCode) { public void updateCache(int changeCode) {
} }
public void setOnCompletionListener(Runnable onCompletionListener) { public void setOnCompletionListener(Runnable onCompletionListener) {
this.onCompletionListener = onCompletionListener; this.onCompletionListener = onCompletionListener;
} }
protected class Task { protected class Task {
private Thread thread; private Thread thread;
private AtomicBoolean taskStart = new AtomicBoolean(false); private AtomicBoolean taskStart = new AtomicBoolean(false);
private void execute() throws Exception { private void execute() throws Exception {
// Don't run if cancelled already // Don't run if cancelled already
if(isCancelled()) { if(isCancelled()) {
return; return;
} }
try { try {
thread = Thread.currentThread(); thread = Thread.currentThread();
taskStart.set(true); taskStart.set(true);
final T result = doInBackground(); final T result = doInBackground();
if(isCancelled()) { if(isCancelled()) {
taskStart.set(false); taskStart.set(false);
return; return;
} }
if(handler != null) { if(handler != null) {
handler.post(new Runnable() { handler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
if (!isCancelled()) { if (!isCancelled()) {
try { try {
onDone(result); onDone(result);
} catch (Throwable t) { } catch (Throwable t) {
if(!isCancelled()) { if(!isCancelled()) {
try { try {
onError(t); onError(t);
} catch(Exception e) { } catch(Exception e) {
// Don't care // Don't care
} }
} }
} }
} }
taskStart.set(false); taskStart.set(false);
} }
}); });
} else { } else {
taskStart.set(false); taskStart.set(false);
} }
} catch(InterruptedException interrupt) { } catch(InterruptedException interrupt) {
if(taskStart.get()) { if(taskStart.get()) {
// Don't exit root thread if task cancelled // Don't exit root thread if task cancelled
throw interrupt; throw interrupt;
} }
} catch(final Throwable t) { } catch(final Throwable t) {
if(isCancelled()) { if(isCancelled()) {
taskStart.set(false); taskStart.set(false);
return; return;
} }
if(handler != null) { if(handler != null) {
handler.post(new Runnable() { handler.post(new Runnable() {
@Override @Override
public void run() { public void run() {
if(!isCancelled()) { if(!isCancelled()) {
try { try {
onError(t); onError(t);
} catch(Exception e) { } catch(Exception e) {
// Don't care // Don't care
} }
} }
taskStart.set(false); taskStart.set(false);
} }
}); });
} else { } else {
taskStart.set(false); taskStart.set(false);
} }
} finally { } finally {
thread = null; thread = null;
} }
} }
public void cancel() { public void cancel() {
if(taskStart.compareAndSet(true, false)) { if(taskStart.compareAndSet(true, false)) {
if (thread != null) { if (thread != null) {
thread.interrupt(); thread.interrupt();
} }
} }
} }
public boolean isCancelled() { public boolean isCancelled() {
if(Thread.interrupted()) { if(Thread.interrupted()) {
return true; return true;
} else if(BackgroundTask.this.isCancelled()) { } else if(BackgroundTask.this.isCancelled()) {
return true; return true;
} else { } else {
return false; return false;
} }
} }
public void onDone(T result) { public void onDone(T result) {
done(result); done(result);
if(onCompletionListener != null) { if(onCompletionListener != null) {
onCompletionListener.run(); onCompletionListener.run();
} }
} }
public void onError(Throwable t) { public void onError(Throwable t) {
error(t); error(t);
} }
public boolean isRunning() { public boolean isRunning() {
return taskStart.get(); return taskStart.get();
} }
} }
private class TaskRunnable implements Runnable { private class TaskRunnable implements Runnable {
private boolean running = true; private boolean running = true;
public TaskRunnable() { public TaskRunnable() {
} }
@Override @Override
public void run() { public void run() {
Looper.prepare(); Looper.prepare();
while(running) { while(running) {
try { try {
Task task = queue.take(); Task task = queue.take();
task.execute(); task.execute();
} catch(InterruptedException stop) { } catch(InterruptedException stop) {
Log.e(TAG, "Thread died"); Log.e(TAG, "Thread died");
running = false; running = false;
threads.remove(Thread.currentThread()); threads.remove(Thread.currentThread());
} catch(Throwable t) { } catch(Throwable t) {
Log.e(TAG, "Unexpected crash in BackgroundTask thread", t); Log.e(TAG, "Unexpected crash in BackgroundTask thread", t);
} }
} }
} }
} }
public static interface OnCancelListener { public static interface OnCancelListener {
void onCancel(); void onCancel();
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of ServerProxy. This file is part of ServerProxy.
SocketProxy is free software: you can redistribute it and/or modify SocketProxy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson Copyright 2014 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
@ -18,11 +18,11 @@ package net.nullsum.audinaut.util;
import java.io.File; import java.io.File;
public interface BufferFile { public interface BufferFile {
File getFile(); File getFile();
Long getContentLength(); Long getContentLength();
long getEstimatedSize(); long getEstimatedSize();
boolean isWorkDone(); boolean isWorkDone();
void onStart(); void onStart();
void onStop(); void onStop();
void onResume(); void onResume();
} }

View File

@ -23,60 +23,60 @@ import android.content.Context;
import net.nullsum.audinaut.util.FileProxy; import net.nullsum.audinaut.util.FileProxy;
public class BufferProxy extends FileProxy { public class BufferProxy extends FileProxy {
private static final String TAG = BufferProxy.class.getSimpleName(); private static final String TAG = BufferProxy.class.getSimpleName();
protected BufferFile progress; protected BufferFile progress;
public BufferProxy(Context context) { public BufferProxy(Context context) {
super(context); super(context);
} }
protected ProxyTask getTask(Socket client) { protected ProxyTask getTask(Socket client) {
return new BufferFileTask(client); return new BufferFileTask(client);
} }
public void setBufferFile(BufferFile progress) { public void setBufferFile(BufferFile progress) {
this.progress = progress; this.progress = progress;
} }
protected class BufferFileTask extends StreamFileTask { protected class BufferFileTask extends StreamFileTask {
public BufferFileTask(Socket client) { public BufferFileTask(Socket client) {
super(client); super(client);
} }
@Override @Override
File getFile(String path) { File getFile(String path) {
return progress.getFile(); return progress.getFile();
} }
@Override @Override
Long getContentLength() { Long getContentLength() {
Long contentLength = progress.getContentLength(); Long contentLength = progress.getContentLength();
if(contentLength == null && progress.isWorkDone()) { if(contentLength == null && progress.isWorkDone()) {
contentLength = file.length(); contentLength = file.length();
} }
return contentLength; return contentLength;
} }
@Override @Override
long getFileSize() { long getFileSize() {
return progress.getEstimatedSize(); return progress.getEstimatedSize();
} }
@Override @Override
public void onStart() { public void onStart() {
progress.onStart(); progress.onStart();
} }
@Override @Override
public void onStop() { public void onStop() {
progress.onStop(); progress.onStop();
} }
@Override @Override
public void onResume() { public void onResume() {
progress.onResume(); progress.onResume();
} }
@Override @Override
public boolean isWorkDone() { public boolean isWorkDone() {
return progress.isWorkDone() && cbSkip >= file.length(); return progress.isWorkDone() && cbSkip >= file.length();
} }
} }
} }

View File

@ -25,28 +25,28 @@ import java.util.*;
public class CacheCleaner { public class CacheCleaner {
private static final String TAG = CacheCleaner.class.getSimpleName(); private static final String TAG = CacheCleaner.class.getSimpleName();
private static final long MIN_FREE_SPACE = 500 * 1024L * 1024L; private static final long MIN_FREE_SPACE = 500 * 1024L * 1024L;
private static final long MAX_COVER_ART_SPACE = 100 * 1024L * 1024L; private static final long MAX_COVER_ART_SPACE = 100 * 1024L * 1024L;
private final Context context; private final Context context;
private final DownloadService downloadService; private final DownloadService downloadService;
private final MediaStoreService mediaStore; private final MediaStoreService mediaStore;
public CacheCleaner(Context context, DownloadService downloadService) { public CacheCleaner(Context context, DownloadService downloadService) {
this.context = context; this.context = context;
this.downloadService = downloadService; this.downloadService = downloadService;
this.mediaStore = new MediaStoreService(context); this.mediaStore = new MediaStoreService(context);
} }
public void clean() { public void clean() {
new BackgroundCleanup(context).execute(); new BackgroundCleanup(context).execute();
}
public void cleanSpace() {
new BackgroundSpaceCleanup(context).execute();
}
public void cleanPlaylists(List<Playlist> playlists) {
new BackgroundPlaylistsCleanup(context, playlists).execute();
} }
public void cleanSpace() {
new BackgroundSpaceCleanup(context).execute();
}
public void cleanPlaylists(List<Playlist> playlists) {
new BackgroundPlaylistsCleanup(context, playlists).execute();
}
private void deleteEmptyDirs(List<File> dirs, Set<File> undeletable) { private void deleteEmptyDirs(List<File> dirs, Set<File> undeletable) {
for (File dir : dirs) { for (File dir : dirs) {
@ -58,12 +58,12 @@ public class CacheCleaner {
} }
} }
private long getMinimumDelete(List<File> files, List<File> pinned) { private long getMinimumDelete(List<File> files, List<File> pinned) {
if(files.size() == 0) { if(files.size() == 0) {
return 0L; return 0L;
} }
long cacheSizeBytes = Util.getCacheSizeMB(context) * 1024L * 1024L; long cacheSizeBytes = Util.getCacheSizeMB(context) * 1024L * 1024L;
long bytesUsedBySubsonic = 0L; long bytesUsedBySubsonic = 0L;
for (File file : files) { for (File file : files) {
@ -73,7 +73,7 @@ public class CacheCleaner {
bytesUsedBySubsonic += file.length(); bytesUsedBySubsonic += file.length();
} }
// Ensure that file system is not more than 95% full. // Ensure that file system is not more than 95% full.
StatFs stat = new StatFs(files.get(0).getPath()); StatFs stat = new StatFs(files.get(0).getPath());
long bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize(); long bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize();
long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize(); long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
@ -89,8 +89,8 @@ public class CacheCleaner {
Log.i(TAG, "Cache size before : " + Util.formatBytes(bytesUsedBySubsonic)); Log.i(TAG, "Cache size before : " + Util.formatBytes(bytesUsedBySubsonic));
Log.i(TAG, "Minimum to delete : " + Util.formatBytes(bytesToDelete)); Log.i(TAG, "Minimum to delete : " + Util.formatBytes(bytesToDelete));
return bytesToDelete; return bytesToDelete;
} }
private void deleteFiles(List<File> files, Set<File> undeletable, long bytesToDelete, boolean deletePartials) { private void deleteFiles(List<File> files, Set<File> undeletable, long bytesToDelete, boolean deletePartials) {
if (files.isEmpty()) { if (files.isEmpty()) {
@ -99,14 +99,14 @@ public class CacheCleaner {
long bytesDeleted = 0L; long bytesDeleted = 0L;
for (File file : files) { for (File file : files) {
if(!deletePartials && bytesDeleted > bytesToDelete) break; if(!deletePartials && bytesDeleted > bytesToDelete) break;
if (bytesToDelete > bytesDeleted || (deletePartials && (file.getName().endsWith(".partial") || file.getName().contains(".partial.")))) { if (bytesToDelete > bytesDeleted || (deletePartials && (file.getName().endsWith(".partial") || file.getName().contains(".partial.")))) {
if (!undeletable.contains(file) && !file.getName().equals(Constants.ALBUM_ART_FILE)) { if (!undeletable.contains(file) && !file.getName().equals(Constants.ALBUM_ART_FILE)) {
long size = file.length(); long size = file.length();
if (Util.delete(file)) { if (Util.delete(file)) {
bytesDeleted += size; bytesDeleted += size;
mediaStore.deleteFromMediaStore(file); mediaStore.deleteFromMediaStore(file);
} }
} }
} }
@ -122,8 +122,8 @@ public class CacheCleaner {
if (isCacheFile) { if (isCacheFile) {
files.add(file); files.add(file);
} else { } else {
pinned.add(file); pinned.add(file);
} }
} else { } else {
// Depth-first // Depth-first
for (File child : FileUtil.listFiles(file)) { for (File child : FileUtil.listFiles(file)) {
@ -160,133 +160,133 @@ public class CacheCleaner {
return undeletable; return undeletable;
} }
private void cleanupCoverArt(Context context) { private void cleanupCoverArt(Context context) {
File dir = FileUtil.getAlbumArtDirectory(context); File dir = FileUtil.getAlbumArtDirectory(context);
List<File> files = new ArrayList<File>(); List<File> files = new ArrayList<File>();
long bytesUsed = 0L; long bytesUsed = 0L;
for(File file: dir.listFiles()) { for(File file: dir.listFiles()) {
if(file.isFile()) { if(file.isFile()) {
files.add(file); files.add(file);
bytesUsed += file.length(); bytesUsed += file.length();
} }
} }
// Don't waste time sorting if under limit already // Don't waste time sorting if under limit already
if(bytesUsed < MAX_COVER_ART_SPACE) { if(bytesUsed < MAX_COVER_ART_SPACE) {
return; return;
} }
sortByAscendingModificationTime(files); sortByAscendingModificationTime(files);
long bytesDeleted = 0L; long bytesDeleted = 0L;
for(File file: files) { for(File file: files) {
// End as soon as the space used is below the threshold // End as soon as the space used is below the threshold
if(bytesUsed < MAX_COVER_ART_SPACE) { if(bytesUsed < MAX_COVER_ART_SPACE) {
break; break;
} }
long bytes = file.length(); long bytes = file.length();
if(file.delete()) { if(file.delete()) {
bytesUsed -= bytes; bytesUsed -= bytes;
bytesDeleted += bytes; bytesDeleted += bytes;
} }
} }
Log.i(TAG, "Deleted " + Util.formatBytes(bytesDeleted) + " worth of cover art"); Log.i(TAG, "Deleted " + Util.formatBytes(bytesDeleted) + " worth of cover art");
} }
private class BackgroundCleanup extends SilentBackgroundTask<Void> { private class BackgroundCleanup extends SilentBackgroundTask<Void> {
public BackgroundCleanup(Context context) { public BackgroundCleanup(Context context) {
super(context); super(context);
} }
@Override @Override
protected Void doInBackground() { protected Void doInBackground() {
if (downloadService == null) { if (downloadService == null) {
Log.e(TAG, "DownloadService not set. Aborting cache cleaning."); Log.e(TAG, "DownloadService not set. Aborting cache cleaning.");
return null; return null;
} }
try { try {
List<File> files = new ArrayList<File>(); List<File> files = new ArrayList<File>();
List<File> pinned = new ArrayList<File>(); List<File> pinned = new ArrayList<File>();
List<File> dirs = new ArrayList<File>(); List<File> dirs = new ArrayList<File>();
findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, pinned, dirs); findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, pinned, dirs);
sortByAscendingModificationTime(files); sortByAscendingModificationTime(files);
Set<File> undeletable = findUndeletableFiles(); Set<File> undeletable = findUndeletableFiles();
deleteFiles(files, undeletable, getMinimumDelete(files, pinned), true); deleteFiles(files, undeletable, getMinimumDelete(files, pinned), true);
deleteEmptyDirs(dirs, undeletable); deleteEmptyDirs(dirs, undeletable);
// Make sure cover art directory does not grow too large // Make sure cover art directory does not grow too large
cleanupCoverArt(context); cleanupCoverArt(context);
} catch (RuntimeException x) { } catch (RuntimeException x) {
Log.e(TAG, "Error in cache cleaning.", x); Log.e(TAG, "Error in cache cleaning.", x);
} }
return null; return null;
} }
} }
private class BackgroundSpaceCleanup extends SilentBackgroundTask<Void> { private class BackgroundSpaceCleanup extends SilentBackgroundTask<Void> {
public BackgroundSpaceCleanup(Context context) { public BackgroundSpaceCleanup(Context context) {
super(context); super(context);
} }
@Override @Override
protected Void doInBackground() { protected Void doInBackground() {
if (downloadService == null) { if (downloadService == null) {
Log.e(TAG, "DownloadService not set. Aborting cache cleaning."); Log.e(TAG, "DownloadService not set. Aborting cache cleaning.");
return null; return null;
} }
try { try {
List<File> files = new ArrayList<File>(); List<File> files = new ArrayList<File>();
List<File> pinned = new ArrayList<File>(); List<File> pinned = new ArrayList<File>();
List<File> dirs = new ArrayList<File>(); List<File> dirs = new ArrayList<File>();
findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, pinned, dirs); findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, pinned, dirs);
long bytesToDelete = getMinimumDelete(files, pinned); long bytesToDelete = getMinimumDelete(files, pinned);
if(bytesToDelete > 0L) { if(bytesToDelete > 0L) {
sortByAscendingModificationTime(files); sortByAscendingModificationTime(files);
Set<File> undeletable = findUndeletableFiles(); Set<File> undeletable = findUndeletableFiles();
deleteFiles(files, undeletable, bytesToDelete, false); deleteFiles(files, undeletable, bytesToDelete, false);
} }
} catch (RuntimeException x) { } catch (RuntimeException x) {
Log.e(TAG, "Error in cache cleaning.", x); Log.e(TAG, "Error in cache cleaning.", x);
} }
return null; return null;
} }
} }
private class BackgroundPlaylistsCleanup extends SilentBackgroundTask<Void> { private class BackgroundPlaylistsCleanup extends SilentBackgroundTask<Void> {
private final List<Playlist> playlists; private final List<Playlist> playlists;
public BackgroundPlaylistsCleanup(Context context, List<Playlist> playlists) { public BackgroundPlaylistsCleanup(Context context, List<Playlist> playlists) {
super(context); super(context);
this.playlists = playlists; this.playlists = playlists;
} }
@Override @Override
protected Void doInBackground() { protected Void doInBackground() {
try { try {
String server = Util.getServerName(context); String server = Util.getServerName(context);
SortedSet<File> playlistFiles = FileUtil.listFiles(FileUtil.getPlaylistDirectory(context, server)); SortedSet<File> playlistFiles = FileUtil.listFiles(FileUtil.getPlaylistDirectory(context, server));
for (Playlist playlist : playlists) { for (Playlist playlist : playlists) {
playlistFiles.remove(FileUtil.getPlaylistFile(context, server, playlist.getName())); playlistFiles.remove(FileUtil.getPlaylistFile(context, server, playlist.getName()));
} }
for(File playlist : playlistFiles) { for(File playlist : playlistFiles) {
playlist.delete(); playlist.delete();
} }
} catch (RuntimeException x) { } catch (RuntimeException x) {
Log.e(TAG, "Error in playlist cache cleaning.", x); Log.e(TAG, "Error in playlist cache cleaning.", x);
} }
return null; return null;
} }
} }
} }

View File

@ -29,13 +29,13 @@ public final class Constants {
public static final String REST_PROTOCOL_VERSION_SUBSONIC = "1.13.0"; public static final String REST_PROTOCOL_VERSION_SUBSONIC = "1.13.0";
public static final String REST_CLIENT_ID = "Audinaut"; public static final String REST_CLIENT_ID = "Audinaut";
public static final String LAST_VERSION = "subsonic.version"; public static final String LAST_VERSION = "subsonic.version";
// Names for intent extras. // Names for intent extras.
public static final String INTENT_EXTRA_NAME_ID = "subsonic.id"; public static final String INTENT_EXTRA_NAME_ID = "subsonic.id";
public static final String INTENT_EXTRA_NAME_NAME = "subsonic.name"; public static final String INTENT_EXTRA_NAME_NAME = "subsonic.name";
public static final String INTENT_EXTRA_NAME_DIRECTORY = "subsonic.directory"; public static final String INTENT_EXTRA_NAME_DIRECTORY = "subsonic.directory";
public static final String INTENT_EXTRA_NAME_CHILD_ID = "subsonic.child.id"; public static final String INTENT_EXTRA_NAME_CHILD_ID = "subsonic.child.id";
public static final String INTENT_EXTRA_NAME_ARTIST = "subsonic.artist"; public static final String INTENT_EXTRA_NAME_ARTIST = "subsonic.artist";
public static final String INTENT_EXTRA_NAME_TITLE = "subsonic.title"; public static final String INTENT_EXTRA_NAME_TITLE = "subsonic.title";
public static final String INTENT_EXTRA_NAME_AUTOPLAY = "subsonic.playall"; public static final String INTENT_EXTRA_NAME_AUTOPLAY = "subsonic.playall";
@ -44,131 +44,131 @@ public final class Constants {
public static final String INTENT_EXTRA_NAME_PLAYLIST_NAME = "subsonic.playlist.name"; public static final String INTENT_EXTRA_NAME_PLAYLIST_NAME = "subsonic.playlist.name";
public static final String INTENT_EXTRA_NAME_PLAYLIST_OWNER = "subsonic.playlist.isOwner"; public static final String INTENT_EXTRA_NAME_PLAYLIST_OWNER = "subsonic.playlist.isOwner";
public static final String INTENT_EXTRA_NAME_ALBUM_LIST_TYPE = "subsonic.albumlisttype"; public static final String INTENT_EXTRA_NAME_ALBUM_LIST_TYPE = "subsonic.albumlisttype";
public static final String INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA = "subsonic.albumlistextra"; public static final String INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA = "subsonic.albumlistextra";
public static final String INTENT_EXTRA_NAME_ALBUM_LIST_SIZE = "subsonic.albumlistsize"; public static final String INTENT_EXTRA_NAME_ALBUM_LIST_SIZE = "subsonic.albumlistsize";
public static final String INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET = "subsonic.albumlistoffset"; public static final String INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET = "subsonic.albumlistoffset";
public static final String INTENT_EXTRA_NAME_SHUFFLE = "subsonic.shuffle"; public static final String INTENT_EXTRA_NAME_SHUFFLE = "subsonic.shuffle";
public static final String INTENT_EXTRA_REQUEST_SEARCH = "subsonic.requestsearch"; public static final String INTENT_EXTRA_REQUEST_SEARCH = "subsonic.requestsearch";
public static final String INTENT_EXTRA_NAME_EXIT = "subsonic.exit" ; public static final String INTENT_EXTRA_NAME_EXIT = "subsonic.exit" ;
public static final String INTENT_EXTRA_NAME_DOWNLOAD = "subsonic.download"; public static final String INTENT_EXTRA_NAME_DOWNLOAD = "subsonic.download";
public static final String INTENT_EXTRA_NAME_DOWNLOAD_VIEW = "subsonic.download_view"; public static final String INTENT_EXTRA_NAME_DOWNLOAD_VIEW = "subsonic.download_view";
public static final String INTENT_EXTRA_VIEW_ALBUM = "subsonic.view_album"; public static final String INTENT_EXTRA_VIEW_ALBUM = "subsonic.view_album";
public static final String INTENT_EXTRA_NAME_SHARE = "subsonic.share"; public static final String INTENT_EXTRA_NAME_SHARE = "subsonic.share";
public static final String INTENT_EXTRA_FRAGMENT_TYPE = "fragmentType"; public static final String INTENT_EXTRA_FRAGMENT_TYPE = "fragmentType";
public static final String INTENT_EXTRA_REFRESH_LISTINGS = "refreshListings"; public static final String INTENT_EXTRA_REFRESH_LISTINGS = "refreshListings";
public static final String INTENT_EXTRA_SEARCH_SONG = "searchSong"; public static final String INTENT_EXTRA_SEARCH_SONG = "searchSong";
public static final String INTENT_EXTRA_TOP_TRACKS = "topTracks"; public static final String INTENT_EXTRA_TOP_TRACKS = "topTracks";
public static final String INTENT_EXTRA_PLAY_LAST = "playLast"; public static final String INTENT_EXTRA_PLAY_LAST = "playLast";
public static final String INTENT_EXTRA_ENTRY = "passedEntry"; public static final String INTENT_EXTRA_ENTRY = "passedEntry";
// Preferences keys. // Preferences keys.
public static final String PREFERENCES_KEY_SERVER_KEY = "server"; public static final String PREFERENCES_KEY_SERVER_KEY = "server";
public static final String PREFERENCES_KEY_SERVER_COUNT = "serverCount"; public static final String PREFERENCES_KEY_SERVER_COUNT = "serverCount";
public static final String PREFERENCES_KEY_SERVER_ADD = "serverAdd"; public static final String PREFERENCES_KEY_SERVER_ADD = "serverAdd";
public static final String PREFERENCES_KEY_SERVER_REMOVE = "serverRemove"; public static final String PREFERENCES_KEY_SERVER_REMOVE = "serverRemove";
public static final String PREFERENCES_KEY_SERVER_INSTANCE = "serverInstanceId"; public static final String PREFERENCES_KEY_SERVER_INSTANCE = "serverInstanceId";
public static final String PREFERENCES_KEY_SERVER_NAME = "serverName"; public static final String PREFERENCES_KEY_SERVER_NAME = "serverName";
public static final String PREFERENCES_KEY_SERVER_URL = "serverUrl"; public static final String PREFERENCES_KEY_SERVER_URL = "serverUrl";
public static final String PREFERENCES_KEY_SERVER_INTERNAL_URL = "serverInternalUrl"; public static final String PREFERENCES_KEY_SERVER_INTERNAL_URL = "serverInternalUrl";
public static final String PREFERENCES_KEY_SERVER_LOCAL_NETWORK_SSID = "serverLocalNetworkSSID"; public static final String PREFERENCES_KEY_SERVER_LOCAL_NETWORK_SSID = "serverLocalNetworkSSID";
public static final String PREFERENCES_KEY_TEST_CONNECTION = "serverTestConnection"; public static final String PREFERENCES_KEY_TEST_CONNECTION = "serverTestConnection";
public static final String PREFERENCES_KEY_OPEN_BROWSER = "openBrowser"; public static final String PREFERENCES_KEY_OPEN_BROWSER = "openBrowser";
public static final String PREFERENCES_KEY_MUSIC_FOLDER_ID = "musicFolderId"; public static final String PREFERENCES_KEY_MUSIC_FOLDER_ID = "musicFolderId";
public static final String PREFERENCES_KEY_USERNAME = "username"; public static final String PREFERENCES_KEY_USERNAME = "username";
public static final String PREFERENCES_KEY_PASSWORD = "password"; public static final String PREFERENCES_KEY_PASSWORD = "password";
public static final String PREFERENCES_KEY_INSTALL_TIME = "installTime"; public static final String PREFERENCES_KEY_INSTALL_TIME = "installTime";
public static final String PREFERENCES_KEY_THEME = "theme"; public static final String PREFERENCES_KEY_THEME = "theme";
public static final String PREFERENCES_KEY_FULL_SCREEN = "fullScreen"; public static final String PREFERENCES_KEY_FULL_SCREEN = "fullScreen";
public static final String PREFERENCES_KEY_DISPLAY_TRACK = "displayTrack"; public static final String PREFERENCES_KEY_DISPLAY_TRACK = "displayTrack";
public static final String PREFERENCES_KEY_MAX_BITRATE_WIFI = "maxBitrateWifi"; public static final String PREFERENCES_KEY_MAX_BITRATE_WIFI = "maxBitrateWifi";
public static final String PREFERENCES_KEY_MAX_BITRATE_MOBILE = "maxBitrateMobile"; public static final String PREFERENCES_KEY_MAX_BITRATE_MOBILE = "maxBitrateMobile";
public static final String PREFERENCES_KEY_NETWORK_TIMEOUT = "networkTimeout"; public static final String PREFERENCES_KEY_NETWORK_TIMEOUT = "networkTimeout";
public static final String PREFERENCES_KEY_CACHE_SIZE = "cacheSize"; public static final String PREFERENCES_KEY_CACHE_SIZE = "cacheSize";
public static final String PREFERENCES_KEY_CACHE_LOCATION = "cacheLocation"; public static final String PREFERENCES_KEY_CACHE_LOCATION = "cacheLocation";
public static final String PREFERENCES_KEY_PRELOAD_COUNT_WIFI = "preloadCountWifi"; public static final String PREFERENCES_KEY_PRELOAD_COUNT_WIFI = "preloadCountWifi";
public static final String PREFERENCES_KEY_PRELOAD_COUNT_MOBILE = "preloadCountMobile"; public static final String PREFERENCES_KEY_PRELOAD_COUNT_MOBILE = "preloadCountMobile";
public static final String PREFERENCES_KEY_HIDE_MEDIA = "hideMedia"; public static final String PREFERENCES_KEY_HIDE_MEDIA = "hideMedia";
public static final String PREFERENCES_KEY_MEDIA_BUTTONS = "mediaButtons"; public static final String PREFERENCES_KEY_MEDIA_BUTTONS = "mediaButtons";
public static final String PREFERENCES_KEY_SCREEN_LIT_ON_DOWNLOAD = "screenLitOnDownload"; public static final String PREFERENCES_KEY_SCREEN_LIT_ON_DOWNLOAD = "screenLitOnDownload";
public static final String PREFERENCES_KEY_REPEAT_MODE = "repeatMode"; public static final String PREFERENCES_KEY_REPEAT_MODE = "repeatMode";
public static final String PREFERENCES_KEY_WIFI_REQUIRED_FOR_DOWNLOAD = "wifiRequiredForDownload"; public static final String PREFERENCES_KEY_WIFI_REQUIRED_FOR_DOWNLOAD = "wifiRequiredForDownload";
public static final String PREFERENCES_KEY_RANDOM_SIZE = "randomSize"; public static final String PREFERENCES_KEY_RANDOM_SIZE = "randomSize";
public static final String PREFERENCES_KEY_OFFLINE = "offline"; public static final String PREFERENCES_KEY_OFFLINE = "offline";
public static final String PREFERENCES_KEY_TEMP_LOSS = "tempLoss"; public static final String PREFERENCES_KEY_TEMP_LOSS = "tempLoss";
public static final String PREFERENCES_KEY_SHUFFLE_START_YEAR = "startYear"; public static final String PREFERENCES_KEY_SHUFFLE_START_YEAR = "startYear";
public static final String PREFERENCES_KEY_SHUFFLE_END_YEAR = "endYear"; public static final String PREFERENCES_KEY_SHUFFLE_END_YEAR = "endYear";
public static final String PREFERENCES_KEY_SHUFFLE_GENRE = "genre"; public static final String PREFERENCES_KEY_SHUFFLE_GENRE = "genre";
public static final String PREFERENCES_KEY_KEEP_SCREEN_ON = "keepScreenOn"; public static final String PREFERENCES_KEY_KEEP_SCREEN_ON = "keepScreenOn";
public static final String PREFERENCES_EQUALIZER_ON = "equalizerOn"; public static final String PREFERENCES_EQUALIZER_ON = "equalizerOn";
public static final String PREFERENCES_EQUALIZER_SETTINGS = "equalizerSettings"; public static final String PREFERENCES_EQUALIZER_SETTINGS = "equalizerSettings";
public static final String PREFERENCES_KEY_PERSISTENT_NOTIFICATION = "persistentNotification"; public static final String PREFERENCES_KEY_PERSISTENT_NOTIFICATION = "persistentNotification";
public static final String PREFERENCES_KEY_GAPLESS_PLAYBACK = "gaplessPlayback"; public static final String PREFERENCES_KEY_GAPLESS_PLAYBACK = "gaplessPlayback";
public static final String PREFERENCES_KEY_REMOVE_PLAYED = "removePlayed"; public static final String PREFERENCES_KEY_REMOVE_PLAYED = "removePlayed";
public static final String PREFERENCES_KEY_KEEP_PLAYED_CNT = "keepPlayedCount"; public static final String PREFERENCES_KEY_KEEP_PLAYED_CNT = "keepPlayedCount";
public static final String PREFERENCES_KEY_SHUFFLE_MODE = "shuffleMode2"; public static final String PREFERENCES_KEY_SHUFFLE_MODE = "shuffleMode2";
public static final String PREFERENCES_KEY_SHUFFLE_MODE_EXTRA = "shuffleModeExtra"; public static final String PREFERENCES_KEY_SHUFFLE_MODE_EXTRA = "shuffleModeExtra";
public static final String PREFERENCES_KEY_SYNC_ENABLED = "syncEnabled"; public static final String PREFERENCES_KEY_SYNC_ENABLED = "syncEnabled";
public static final String PREFERENCES_KEY_SYNC_INTERVAL = "syncInterval"; public static final String PREFERENCES_KEY_SYNC_INTERVAL = "syncInterval";
public static final String PREFERENCES_KEY_SYNC_WIFI = "syncWifi"; public static final String PREFERENCES_KEY_SYNC_WIFI = "syncWifi";
public static final String PREFERENCES_KEY_SYNC_NOTIFICATION = "syncNotification"; public static final String PREFERENCES_KEY_SYNC_NOTIFICATION = "syncNotification";
public static final String PREFERENCES_KEY_SYNC_MOST_RECENT = "syncMostRecent"; public static final String PREFERENCES_KEY_SYNC_MOST_RECENT = "syncMostRecent";
public static final String PREFERENCES_KEY_PAUSE_DISCONNECT = "pauseOnDisconnect"; public static final String PREFERENCES_KEY_PAUSE_DISCONNECT = "pauseOnDisconnect";
public static final String PREFERENCES_KEY_HIDE_WIDGET = "hideWidget"; public static final String PREFERENCES_KEY_HIDE_WIDGET = "hideWidget";
public static final String PREFERENCES_KEY_CUSTOM_SORT_ENABLED = "customSortEnabled"; public static final String PREFERENCES_KEY_CUSTOM_SORT_ENABLED = "customSortEnabled";
public static final String PREFERENCES_KEY_SHARED_ENABLED = "sharedEnabled"; public static final String PREFERENCES_KEY_SHARED_ENABLED = "sharedEnabled";
public static final String PREFERENCES_KEY_OPEN_TO_TAB = "openToTab"; public static final String PREFERENCES_KEY_OPEN_TO_TAB = "openToTab";
// public static final String PREFERENCES_KEY_PLAY_NOW_AFTER = "playNowAfter"; // public static final String PREFERENCES_KEY_PLAY_NOW_AFTER = "playNowAfter";
public static final String PREFERENCES_KEY_SONG_PRESS_ACTION = "songPressAction"; public static final String PREFERENCES_KEY_SONG_PRESS_ACTION = "songPressAction";
public static final String PREFERENCES_KEY_LARGE_ALBUM_ART = "largeAlbumArt"; public static final String PREFERENCES_KEY_LARGE_ALBUM_ART = "largeAlbumArt";
public static final String PREFERENCES_KEY_PLAYLIST_NAME = "suggestedPlaylistName"; public static final String PREFERENCES_KEY_PLAYLIST_NAME = "suggestedPlaylistName";
public static final String PREFERENCES_KEY_PLAYLIST_ID = "suggestedPlaylistId"; public static final String PREFERENCES_KEY_PLAYLIST_ID = "suggestedPlaylistId";
public static final String PREFERENCES_KEY_RECENT_COUNT = "mostRecentCount"; public static final String PREFERENCES_KEY_RECENT_COUNT = "mostRecentCount";
public static final String PREFERENCES_KEY_REPLAY_GAIN = "replayGain"; public static final String PREFERENCES_KEY_REPLAY_GAIN = "replayGain";
public static final String PREFERENCES_KEY_REPLAY_GAIN_BUMP = "replayGainBump2"; public static final String PREFERENCES_KEY_REPLAY_GAIN_BUMP = "replayGainBump2";
public static final String PREFERENCES_KEY_REPLAY_GAIN_UNTAGGED = "replayGainUntagged2"; public static final String PREFERENCES_KEY_REPLAY_GAIN_UNTAGGED = "replayGainUntagged2";
public static final String PREFERENCES_KEY_REPLAY_GAIN_TYPE= "replayGainType"; public static final String PREFERENCES_KEY_REPLAY_GAIN_TYPE= "replayGainType";
public static final String PREFERENCES_KEY_ALBUMS_PER_FOLDER = "albumsPerFolder"; public static final String PREFERENCES_KEY_ALBUMS_PER_FOLDER = "albumsPerFolder";
public static final String PREFERENCES_KEY_FIRST_LEVEL_ARTIST = "firstLevelArtist"; public static final String PREFERENCES_KEY_FIRST_LEVEL_ARTIST = "firstLevelArtist";
public static final String PREFERENCES_KEY_START_ON_HEADPHONES = "startOnHeadphones"; public static final String PREFERENCES_KEY_START_ON_HEADPHONES = "startOnHeadphones";
public static final String PREFERENCES_KEY_COLOR_ACTION_BAR = "colorActionBar"; public static final String PREFERENCES_KEY_COLOR_ACTION_BAR = "colorActionBar";
public static final String PREFERENCES_KEY_SHUFFLE_BY_ALBUM = "shuffleByAlbum"; public static final String PREFERENCES_KEY_SHUFFLE_BY_ALBUM = "shuffleByAlbum";
public static final String PREFERENCES_KEY_RESUME_PLAY_QUEUE_NEVER = "neverResumePlayQueue"; public static final String PREFERENCES_KEY_RESUME_PLAY_QUEUE_NEVER = "neverResumePlayQueue";
public static final String PREFERENCES_KEY_BATCH_MODE = "batchMode"; public static final String PREFERENCES_KEY_BATCH_MODE = "batchMode";
public static final String PREFERENCES_KEY_HEADS_UP_NOTIFICATION = "headsUpNotification"; public static final String PREFERENCES_KEY_HEADS_UP_NOTIFICATION = "headsUpNotification";
public static final String OFFLINE_STAR_COUNT = "starCount"; public static final String OFFLINE_STAR_COUNT = "starCount";
public static final String OFFLINE_STAR_ID = "starID"; public static final String OFFLINE_STAR_ID = "starID";
public static final String OFFLINE_STAR_SEARCH = "starTitle"; public static final String OFFLINE_STAR_SEARCH = "starTitle";
public static final String OFFLINE_STAR_SETTING = "starSetting"; public static final String OFFLINE_STAR_SETTING = "starSetting";
public static final String CACHE_KEY_IGNORE = "ignoreArticles"; public static final String CACHE_KEY_IGNORE = "ignoreArticles";
public static final String CACHE_AUDIO_SESSION_ID = "audioSessionId"; public static final String CACHE_AUDIO_SESSION_ID = "audioSessionId";
public static final String CACHE_BLOCK_TOKEN_USE = "blockTokenUse"; public static final String CACHE_BLOCK_TOKEN_USE = "blockTokenUse";
public static final String MAIN_BACK_STACK = "backStackIds"; public static final String MAIN_BACK_STACK = "backStackIds";
public static final String MAIN_BACK_STACK_SIZE = "backStackIdsSize"; public static final String MAIN_BACK_STACK_SIZE = "backStackIdsSize";
public static final String MAIN_NOW_PLAYING = "nowPlayingId"; public static final String MAIN_NOW_PLAYING = "nowPlayingId";
public static final String MAIN_NOW_PLAYING_SECONDARY = "nowPlayingSecondaryId"; public static final String MAIN_NOW_PLAYING_SECONDARY = "nowPlayingSecondaryId";
public static final String MAIN_SLIDE_PANEL_STATE = "slidePanelState"; public static final String MAIN_SLIDE_PANEL_STATE = "slidePanelState";
public static final String FRAGMENT_LIST = "fragmentList"; public static final String FRAGMENT_LIST = "fragmentList";
public static final String FRAGMENT_LIST2 = "fragmentList2"; public static final String FRAGMENT_LIST2 = "fragmentList2";
public static final String FRAGMENT_EXTRA = "fragmentExtra"; public static final String FRAGMENT_EXTRA = "fragmentExtra";
public static final String FRAGMENT_DOWNLOAD_FLIPPER = "fragmentDownloadFlipper"; public static final String FRAGMENT_DOWNLOAD_FLIPPER = "fragmentDownloadFlipper";
public static final String FRAGMENT_NAME = "fragmentName"; public static final String FRAGMENT_NAME = "fragmentName";
public static final String FRAGMENT_POSITION = "fragmentPosition"; public static final String FRAGMENT_POSITION = "fragmentPosition";
// Name of the preferences file. // Name of the preferences file.
public static final String PREFERENCES_FILE_NAME = "net.nullsum.audinaut_preferences"; public static final String PREFERENCES_FILE_NAME = "net.nullsum.audinaut_preferences";
public static final String OFFLINE_SYNC_NAME = "net.nullsum.audinaut.offline"; public static final String OFFLINE_SYNC_NAME = "net.nullsum.audinaut.offline";
public static final String OFFLINE_SYNC_DEFAULT = "syncDefaults"; public static final String OFFLINE_SYNC_DEFAULT = "syncDefaults";
// Account prefs // Account prefs
public static final String SYNC_ACCOUNT_NAME = "Subsonic Account"; public static final String SYNC_ACCOUNT_NAME = "Subsonic Account";
public static final String SYNC_ACCOUNT_TYPE = "Audinaut"; public static final String SYNC_ACCOUNT_TYPE = "Audinaut";
public static final String SYNC_ACCOUNT_PLAYLIST_AUTHORITY = "net.nullsum.audinaut.playlists.provider"; public static final String SYNC_ACCOUNT_PLAYLIST_AUTHORITY = "net.nullsum.audinaut.playlists.provider";
public static final String SYNC_ACCOUNT_MOST_RECENT_AUTHORITY = "net.nullsum.audinaut.mostrecent.provider"; public static final String SYNC_ACCOUNT_MOST_RECENT_AUTHORITY = "net.nullsum.audinaut.mostrecent.provider";
public static final String TASKER_EXTRA_BUNDLE = "com.twofortyfouram.locale.intent.extra.BUNDLE"; public static final String TASKER_EXTRA_BUNDLE = "com.twofortyfouram.locale.intent.extra.BUNDLE";
public static final String ALBUM_ART_FILE = "albumart.jpg"; public static final String ALBUM_ART_FILE = "albumart.jpg";

View File

@ -15,100 +15,100 @@ import net.nullsum.audinaut.view.SongView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
public class DownloadFileItemHelperCallback extends ItemTouchHelper.SimpleCallback { public class DownloadFileItemHelperCallback extends ItemTouchHelper.SimpleCallback {
private static final String TAG = DownloadFileItemHelperCallback.class.getSimpleName(); private static final String TAG = DownloadFileItemHelperCallback.class.getSimpleName();
private SubsonicFragment fragment; private SubsonicFragment fragment;
private boolean mainList; private boolean mainList;
private BackgroundTask pendingTask = null; private BackgroundTask pendingTask = null;
private Deque pendingOperations = new ArrayDeque(); private Deque pendingOperations = new ArrayDeque();
public DownloadFileItemHelperCallback(SubsonicFragment fragment, boolean mainList) { public DownloadFileItemHelperCallback(SubsonicFragment fragment, boolean mainList) {
super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT); super(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT);
this.fragment = fragment; this.fragment = fragment;
this.mainList = mainList; this.mainList = mainList;
} }
@Override @Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder fromHolder, RecyclerView.ViewHolder toHolder) { public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder fromHolder, RecyclerView.ViewHolder toHolder) {
int from = fromHolder.getAdapterPosition(); int from = fromHolder.getAdapterPosition();
int to = toHolder.getAdapterPosition(); int to = toHolder.getAdapterPosition();
getSectionAdapter().moveItem(from, to); getSectionAdapter().moveItem(from, to);
synchronized (pendingOperations) { synchronized (pendingOperations) {
pendingOperations.add(new Pair<>(from, to)); pendingOperations.add(new Pair<>(from, to));
updateDownloadService(); updateDownloadService();
} }
return true; return true;
} }
@Override @Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
SongView songView = (SongView) ((UpdateView.UpdateViewHolder) viewHolder).getUpdateView(); SongView songView = (SongView) ((UpdateView.UpdateViewHolder) viewHolder).getUpdateView();
DownloadFile downloadFile = songView.getDownloadFile(); DownloadFile downloadFile = songView.getDownloadFile();
getSectionAdapter().removeItem(downloadFile); getSectionAdapter().removeItem(downloadFile);
synchronized (pendingOperations) { synchronized (pendingOperations) {
pendingOperations.add(downloadFile); pendingOperations.add(downloadFile);
updateDownloadService(); updateDownloadService();
} }
} }
public DownloadService getDownloadService() { public DownloadService getDownloadService() {
return fragment.getDownloadService(); return fragment.getDownloadService();
} }
public SectionAdapter getSectionAdapter() { public SectionAdapter getSectionAdapter() {
return fragment.getCurrentAdapter(); return fragment.getCurrentAdapter();
} }
private void updateDownloadService() { private void updateDownloadService() {
if(pendingTask == null) { if(pendingTask == null) {
final DownloadService downloadService = getDownloadService(); final DownloadService downloadService = getDownloadService();
if(downloadService == null) { if(downloadService == null) {
return; return;
} }
pendingTask = new SilentBackgroundTask<Void>(downloadService) { pendingTask = new SilentBackgroundTask<Void>(downloadService) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
boolean running = true; boolean running = true;
while(running) { while(running) {
Object nextOperation = null; Object nextOperation = null;
synchronized (pendingOperations) { synchronized (pendingOperations) {
if(!pendingOperations.isEmpty()) { if(!pendingOperations.isEmpty()) {
nextOperation = pendingOperations.remove(); nextOperation = pendingOperations.remove();
} }
} }
if(nextOperation != null) { if(nextOperation != null) {
if(nextOperation instanceof Pair) { if(nextOperation instanceof Pair) {
Pair<Integer, Integer> swap = (Pair) nextOperation; Pair<Integer, Integer> swap = (Pair) nextOperation;
downloadService.swap(mainList, swap.getFirst(), swap.getSecond()); downloadService.swap(mainList, swap.getFirst(), swap.getSecond());
} else if(nextOperation instanceof DownloadFile) { } else if(nextOperation instanceof DownloadFile) {
DownloadFile downloadFile = (DownloadFile) nextOperation; DownloadFile downloadFile = (DownloadFile) nextOperation;
if(mainList) { if(mainList) {
downloadService.remove(downloadFile); downloadService.remove(downloadFile);
} else { } else {
downloadService.removeBackground(downloadFile); downloadService.removeBackground(downloadFile);
} }
} }
} else { } else {
running = false; running = false;
} }
} }
synchronized (pendingOperations) { synchronized (pendingOperations) {
pendingTask = null; pendingTask = null;
// Start a task if this is non-empty. Means someone added while we were running operations // Start a task if this is non-empty. Means someone added while we were running operations
if(!pendingOperations.isEmpty()) { if(!pendingOperations.isEmpty()) {
updateDownloadService(); updateDownloadService();
} }
} }
return null; return null;
} }
}; };
pendingTask.execute(); pendingTask.execute();
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
@ -32,71 +32,71 @@ import java.util.WeakHashMap;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
public class DrawableTint { public class DrawableTint {
private static final Map<Integer, Integer> attrMap = new HashMap<>(); private static final Map<Integer, Integer> attrMap = new HashMap<>();
private static final WeakHashMap<Integer, Drawable> tintedDrawables = new WeakHashMap<>(); private static final WeakHashMap<Integer, Drawable> tintedDrawables = new WeakHashMap<>();
public static Drawable getTintedDrawable(Context context, @DrawableRes int drawableRes) { public static Drawable getTintedDrawable(Context context, @DrawableRes int drawableRes) {
return getTintedDrawable(context, drawableRes, R.attr.colorAccent); return getTintedDrawable(context, drawableRes, R.attr.colorAccent);
} }
public static Drawable getTintedDrawable(Context context, @DrawableRes int drawableRes, @AttrRes int colorAttr) { public static Drawable getTintedDrawable(Context context, @DrawableRes int drawableRes, @AttrRes int colorAttr) {
if(tintedDrawables.containsKey(drawableRes)) { if(tintedDrawables.containsKey(drawableRes)) {
return tintedDrawables.get(drawableRes); return tintedDrawables.get(drawableRes);
} }
int color = getColorRes(context, colorAttr); int color = getColorRes(context, colorAttr);
Drawable background = context.getResources().getDrawable(drawableRes); Drawable background = context.getResources().getDrawable(drawableRes);
background.setColorFilter(color, PorterDuff.Mode.SRC_IN); background.setColorFilter(color, PorterDuff.Mode.SRC_IN);
tintedDrawables.put(drawableRes, background); tintedDrawables.put(drawableRes, background);
return background; return background;
} }
public static Drawable getTintedDrawableFromColor(Context context, @DrawableRes int drawableRes, @ColorRes int colorRes) { public static Drawable getTintedDrawableFromColor(Context context, @DrawableRes int drawableRes, @ColorRes int colorRes) {
if(tintedDrawables.containsKey(drawableRes)) { if(tintedDrawables.containsKey(drawableRes)) {
return tintedDrawables.get(drawableRes); return tintedDrawables.get(drawableRes);
} }
int color = context.getResources().getColor(colorRes); int color = context.getResources().getColor(colorRes);
Drawable background = context.getResources().getDrawable(drawableRes); Drawable background = context.getResources().getDrawable(drawableRes);
background.setColorFilter(color, PorterDuff.Mode.SRC_IN); background.setColorFilter(color, PorterDuff.Mode.SRC_IN);
tintedDrawables.put(drawableRes, background); tintedDrawables.put(drawableRes, background);
return background; return background;
} }
public static int getColorRes(Context context, @AttrRes int colorAttr) { public static int getColorRes(Context context, @AttrRes int colorAttr) {
int color; int color;
if(attrMap.containsKey(colorAttr)) { if(attrMap.containsKey(colorAttr)) {
color = attrMap.get(colorAttr); color = attrMap.get(colorAttr);
} else { } else {
TypedValue typedValue = new TypedValue(); TypedValue typedValue = new TypedValue();
Resources.Theme theme = context.getTheme(); Resources.Theme theme = context.getTheme();
theme.resolveAttribute(colorAttr, typedValue, true); theme.resolveAttribute(colorAttr, typedValue, true);
color = typedValue.data; color = typedValue.data;
attrMap.put(colorAttr, color); attrMap.put(colorAttr, color);
} }
return color; return color;
} }
public static int getDrawableRes(Context context, @AttrRes int drawableAttr) { public static int getDrawableRes(Context context, @AttrRes int drawableAttr) {
if(attrMap.containsKey(drawableAttr)) { if(attrMap.containsKey(drawableAttr)) {
return attrMap.get(drawableAttr); return attrMap.get(drawableAttr);
} else { } else {
int[] attrs = new int[]{drawableAttr}; int[] attrs = new int[]{drawableAttr};
TypedArray typedArray = context.obtainStyledAttributes(attrs); TypedArray typedArray = context.obtainStyledAttributes(attrs);
@DrawableRes int drawableRes = typedArray.getResourceId(0, 0); @DrawableRes int drawableRes = typedArray.getResourceId(0, 0);
typedArray.recycle(); typedArray.recycle();
attrMap.put(drawableAttr, drawableRes); attrMap.put(drawableAttr, drawableRes);
return drawableRes; return drawableRes;
} }
} }
public static Drawable getTintedAttrDrawable(Context context, @AttrRes int drawableAttr, @AttrRes int colorAttr) { public static Drawable getTintedAttrDrawable(Context context, @AttrRes int drawableAttr, @AttrRes int colorAttr) {
if(tintedDrawables.containsKey(drawableAttr)) { if(tintedDrawables.containsKey(drawableAttr)) {
return getTintedDrawable(context, attrMap.get(drawableAttr), colorAttr); return getTintedDrawable(context, attrMap.get(drawableAttr), colorAttr);
} }
@DrawableRes int drawableRes = getDrawableRes(context, drawableAttr); @DrawableRes int drawableRes = getDrawableRes(context, drawableAttr);
return getTintedDrawable(context, drawableRes, colorAttr); return getTintedDrawable(context, drawableRes, colorAttr);
} }
public static void wipeTintCache() { public static void wipeTintCache() {
attrMap.clear(); attrMap.clear();
tintedDrawables.clear(); tintedDrawables.clear();
} }
} }

View File

@ -1,20 +1,20 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2016 (C) Scott Jackson Copyright 2016 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
public final class EnvironmentVariables { public final class EnvironmentVariables {
public static final String PASTEBIN_DEV_KEY = ""; public static final String PASTEBIN_DEV_KEY = "";
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of ServerProxy. This file is part of ServerProxy.
SocketProxy is free software: you can redistribute it and/or modify SocketProxy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson Copyright 2014 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
@ -29,191 +29,191 @@ import android.util.Log;
import net.nullsum.audinaut.util.ServerProxy; import net.nullsum.audinaut.util.ServerProxy;
public class FileProxy extends ServerProxy { public class FileProxy extends ServerProxy {
private static final String TAG = FileProxy.class.getSimpleName(); private static final String TAG = FileProxy.class.getSimpleName();
public FileProxy(Context context) { public FileProxy(Context context) {
super(context); super(context);
} }
protected ProxyTask getTask(Socket client) { protected ProxyTask getTask(Socket client) {
return new StreamFileTask(client); return new StreamFileTask(client);
} }
protected class StreamFileTask extends ProxyTask { protected class StreamFileTask extends ProxyTask {
File file; File file;
public StreamFileTask(Socket client) { public StreamFileTask(Socket client) {
super(client); super(client);
} }
@Override @Override
public boolean processRequest() { public boolean processRequest() {
if(!super.processRequest()) { if(!super.processRequest()) {
return false; return false;
} }
Log.i(TAG, "Processing request for file " + path); Log.i(TAG, "Processing request for file " + path);
file = getFile(path); file = getFile(path);
if (!file.exists()) { if (!file.exists()) {
Log.e(TAG, "File " + path + " does not exist"); Log.e(TAG, "File " + path + " does not exist");
return false; return false;
} }
// Make sure to not try to read past where the file is downloaded // Make sure to not try to read past where the file is downloaded
if(cbSkip != 0 && cbSkip >= file.length()) { if(cbSkip != 0 && cbSkip >= file.length()) {
return false; return false;
} }
return true; return true;
} }
File getFile(String path) { File getFile(String path) {
return new File(path); return new File(path);
} }
Long getContentLength() { Long getContentLength() {
return file.length(); return file.length();
} }
long getFileSize() { long getFileSize() {
return file.length(); return file.length();
} }
@Override @Override
public void run() { public void run() {
Long contentLength = getContentLength(); Long contentLength = getContentLength();
// Create HTTP header // Create HTTP header
String headers; String headers;
if(cbSkip == 0) { if(cbSkip == 0) {
headers = "HTTP/1.0 200 OK\r\n"; headers = "HTTP/1.0 200 OK\r\n";
} else { } else {
headers = "HTTP/1.0 206 OK\r\n"; headers = "HTTP/1.0 206 OK\r\n";
headers += "Content-Range: bytes " + cbSkip + "-" + (file.length() - 1) + "/"; headers += "Content-Range: bytes " + cbSkip + "-" + (file.length() - 1) + "/";
if(contentLength == null) { if(contentLength == null) {
headers += "*"; headers += "*";
} else { } else {
headers += contentLength; headers += contentLength;
} }
headers += "\r\n"; headers += "\r\n";
Log.i(TAG, "Streaming starts from: " + cbSkip); Log.i(TAG, "Streaming starts from: " + cbSkip);
} }
String name = file.getPath(); String name = file.getPath();
int index = name.lastIndexOf('.'); int index = name.lastIndexOf('.');
String ext = ""; String ext = "";
if(index != -1) { if(index != -1) {
ext = name.substring(index + 1).toLowerCase(); ext = name.substring(index + 1).toLowerCase();
} }
if("mp3".equals(ext)) { if("mp3".equals(ext)) {
headers += "Content-Type: audio/mpeg\r\n"; headers += "Content-Type: audio/mpeg\r\n";
} else { } else {
headers += "Content-Type: " + "application/octet-stream" + "\r\n"; headers += "Content-Type: " + "application/octet-stream" + "\r\n";
} }
long fileSize; long fileSize;
if(contentLength == null) { if(contentLength == null) {
fileSize = getFileSize(); fileSize = getFileSize();
} else { } else {
fileSize = contentLength; fileSize = contentLength;
if(cbSkip > 0) { if(cbSkip > 0) {
headers += "Content-Length: " + (fileSize - cbSkip) + "\r\n"; headers += "Content-Length: " + (fileSize - cbSkip) + "\r\n";
} else { } else {
headers += "Content-Length: " + fileSize + "\r\n"; headers += "Content-Length: " + fileSize + "\r\n";
} }
headers += "Accept-Ranges: bytes \r\n"; headers += "Accept-Ranges: bytes \r\n";
} }
Log.i(TAG, "Streaming fileSize: " + fileSize); Log.i(TAG, "Streaming fileSize: " + fileSize);
headers += "Connection: close\r\n"; headers += "Connection: close\r\n";
headers += "\r\n"; headers += "\r\n";
long cbToSend = fileSize - cbSkip; long cbToSend = fileSize - cbSkip;
OutputStream output = null; OutputStream output = null;
byte[] buff = new byte[64 * 1024]; byte[] buff = new byte[64 * 1024];
try { try {
output = new BufferedOutputStream(client.getOutputStream(), 32*1024); output = new BufferedOutputStream(client.getOutputStream(), 32*1024);
output.write(headers.getBytes()); output.write(headers.getBytes());
// Make sure to have file lock // Make sure to have file lock
onStart(); onStart();
// Loop as long as there's stuff to send // Loop as long as there's stuff to send
while (isRunning && !client.isClosed()) { while (isRunning && !client.isClosed()) {
onResume(); onResume();
// See if there's more to send // See if there's more to send
int cbSentThisBatch = 0; int cbSentThisBatch = 0;
if (file.exists()) { if (file.exists()) {
FileInputStream input = new FileInputStream(file); FileInputStream input = new FileInputStream(file);
input.skip(cbSkip); input.skip(cbSkip);
int cbToSendThisBatch = input.available(); int cbToSendThisBatch = input.available();
while (cbToSendThisBatch > 0) { while (cbToSendThisBatch > 0) {
int cbToRead = Math.min(cbToSendThisBatch, buff.length); int cbToRead = Math.min(cbToSendThisBatch, buff.length);
int cbRead = input.read(buff, 0, cbToRead); int cbRead = input.read(buff, 0, cbToRead);
if (cbRead == -1) { if (cbRead == -1) {
break; break;
} }
cbToSendThisBatch -= cbRead; cbToSendThisBatch -= cbRead;
cbToSend -= cbRead; cbToSend -= cbRead;
output.write(buff, 0, cbRead); output.write(buff, 0, cbRead);
output.flush(); output.flush();
cbSkip += cbRead; cbSkip += cbRead;
cbSentThisBatch += cbRead; cbSentThisBatch += cbRead;
} }
input.close(); input.close();
} }
// Done regardless of whether or not it thinks it is // Done regardless of whether or not it thinks it is
if(isWorkDone()) { if(isWorkDone()) {
break; break;
} }
// If we did nothing this batch, block for a second // If we did nothing this batch, block for a second
if (cbSentThisBatch == 0) { if (cbSentThisBatch == 0) {
Log.d(TAG, "Blocking until more data appears (" + cbToSend + ")"); Log.d(TAG, "Blocking until more data appears (" + cbToSend + ")");
Thread.sleep(1000); Thread.sleep(1000);
} }
} }
// Release file lock, use of stream proxy means nothing else is using it // Release file lock, use of stream proxy means nothing else is using it
onStop(); onStop();
} }
catch (SocketException socketException) { catch (SocketException socketException) {
Log.e(TAG, "SocketException() thrown, proxy client has probably closed. This can exit harmlessly"); Log.e(TAG, "SocketException() thrown, proxy client has probably closed. This can exit harmlessly");
// Release file lock, use of stream proxy means nothing else is using it // Release file lock, use of stream proxy means nothing else is using it
onStop(); onStop();
} }
catch (Exception e) { catch (Exception e) {
Log.e(TAG, "Exception thrown from streaming task:"); Log.e(TAG, "Exception thrown from streaming task:");
Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage()); Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
} }
// Cleanup // Cleanup
try { try {
if (output != null) { if (output != null) {
output.close(); output.close();
} }
client.close(); client.close();
} }
catch (IOException e) { catch (IOException e) {
Log.e(TAG, "IOException while cleaning up streaming task:"); Log.e(TAG, "IOException while cleaning up streaming task:");
Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage()); Log.e(TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
} }
} }
public void onStart() { public void onStart() {
} }
public void onStop() { public void onStop() {
} }
public void onResume() { public void onResume() {
} }
public boolean isWorkDone() { public boolean isWorkDone() {
return cbSkip >= file.length(); return cbSkip >= file.length();
} }
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -54,386 +54,386 @@ import net.nullsum.audinaut.service.MusicServiceFactory;
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class ImageLoader { public class ImageLoader {
private static final String TAG = ImageLoader.class.getSimpleName(); private static final String TAG = ImageLoader.class.getSimpleName();
public static final String PLAYLIST_PREFIX = "pl-"; public static final String PLAYLIST_PREFIX = "pl-";
private Context context; private Context context;
private LruCache<String, Bitmap> cache; private LruCache<String, Bitmap> cache;
private Handler handler; private Handler handler;
private Bitmap nowPlaying; private Bitmap nowPlaying;
private Bitmap nowPlayingSmall; private Bitmap nowPlayingSmall;
private final int imageSizeDefault; private final int imageSizeDefault;
private final int imageSizeLarge; private final int imageSizeLarge;
private boolean clearingCache = false; private boolean clearingCache = false;
private final int cacheSize; private final int cacheSize;
private final static int[] COLORS = {0xFF33B5E5, 0xFFAA66CC, 0xFF99CC00, 0xFFFFBB33, 0xFFFF4444}; private final static int[] COLORS = {0xFF33B5E5, 0xFFAA66CC, 0xFF99CC00, 0xFFFFBB33, 0xFFFF4444};
public ImageLoader(Context context) { public ImageLoader(Context context) {
this.context = context; this.context = context;
handler = new Handler(Looper.getMainLooper()); handler = new Handler(Looper.getMainLooper());
final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
cacheSize = maxMemory / 4; cacheSize = maxMemory / 4;
// Determine the density-dependent image sizes. // Determine the density-dependent image sizes.
imageSizeDefault = context.getResources().getDrawable(R.drawable.unknown_album).getIntrinsicHeight(); imageSizeDefault = context.getResources().getDrawable(R.drawable.unknown_album).getIntrinsicHeight();
DisplayMetrics metrics = context.getResources().getDisplayMetrics(); DisplayMetrics metrics = context.getResources().getDisplayMetrics();
imageSizeLarge = Math.round(Math.min(metrics.widthPixels, metrics.heightPixels)); imageSizeLarge = Math.round(Math.min(metrics.widthPixels, metrics.heightPixels));
cache = new LruCache<String, Bitmap>(cacheSize) { cache = new LruCache<String, Bitmap>(cacheSize) {
@Override @Override
protected int sizeOf(String key, Bitmap bitmap) { protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getRowBytes() * bitmap.getHeight() / 1024; return bitmap.getRowBytes() * bitmap.getHeight() / 1024;
} }
@Override @Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldBitmap, Bitmap newBitmap) { protected void entryRemoved(boolean evicted, String key, Bitmap oldBitmap, Bitmap newBitmap) {
if(evicted) { if(evicted) {
if((oldBitmap != nowPlaying && oldBitmap != nowPlayingSmall) || clearingCache) { if((oldBitmap != nowPlaying && oldBitmap != nowPlayingSmall) || clearingCache) {
oldBitmap.recycle(); oldBitmap.recycle();
} else if(oldBitmap != newBitmap) { } else if(oldBitmap != newBitmap) {
cache.put(key, oldBitmap); cache.put(key, oldBitmap);
} }
} }
} }
}; };
} }
public void clearCache() { public void clearCache() {
nowPlaying = null; nowPlaying = null;
nowPlayingSmall = null; nowPlayingSmall = null;
new SilentBackgroundTask<Void>(context) { new SilentBackgroundTask<Void>(context) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
clearingCache = true; clearingCache = true;
cache.evictAll(); cache.evictAll();
clearingCache = false; clearingCache = false;
return null; return null;
} }
}.execute(); }.execute();
} }
public void onLowMemory(float percent) { public void onLowMemory(float percent) {
Log.i(TAG, "Cache size: " + cache.size() + " => " + Math.round(cacheSize * (1 - percent)) + " out of " + cache.maxSize()); Log.i(TAG, "Cache size: " + cache.size() + " => " + Math.round(cacheSize * (1 - percent)) + " out of " + cache.maxSize());
cache.resize(Math.round(cacheSize * (1 - percent))); cache.resize(Math.round(cacheSize * (1 - percent)));
} }
public void onUIVisible() { public void onUIVisible() {
if(cache.maxSize() != cacheSize) { if(cache.maxSize() != cacheSize) {
Log.i(TAG, "Returned to full cache size"); Log.i(TAG, "Returned to full cache size");
cache.resize(cacheSize); cache.resize(cacheSize);
} }
} }
public void setNowPlayingSmall(Bitmap bitmap) { public void setNowPlayingSmall(Bitmap bitmap) {
nowPlayingSmall = bitmap; nowPlayingSmall = bitmap;
} }
private Bitmap getUnknownImage(MusicDirectory.Entry entry, int size) { private Bitmap getUnknownImage(MusicDirectory.Entry entry, int size) {
String key; String key;
int color; int color;
if(entry == null) { if(entry == null) {
key = getKey("unknown", size); key = getKey("unknown", size);
color = COLORS[0]; color = COLORS[0];
return getUnknownImage(key, size, color, null, null); return getUnknownImage(key, size, color, null, null);
} else { } else {
key = getKey(entry.getId() + "unknown", size); key = getKey(entry.getId() + "unknown", size);
String hash; String hash;
if(entry.getAlbum() != null) { if(entry.getAlbum() != null) {
hash = entry.getAlbum(); hash = entry.getAlbum();
} else if(entry.getArtist() != null) { } else if(entry.getArtist() != null) {
hash = entry.getArtist(); hash = entry.getArtist();
} else { } else {
hash = entry.getId(); hash = entry.getId();
} }
color = COLORS[Math.abs(hash.hashCode()) % COLORS.length]; color = COLORS[Math.abs(hash.hashCode()) % COLORS.length];
return getUnknownImage(key, size, color, entry.getAlbum(), entry.getArtist()); return getUnknownImage(key, size, color, entry.getAlbum(), entry.getArtist());
} }
} }
private Bitmap getUnknownImage(String key, int size, int color, String topText, String bottomText) { private Bitmap getUnknownImage(String key, int size, int color, String topText, String bottomText) {
Bitmap bitmap = cache.get(key); Bitmap bitmap = cache.get(key);
if(bitmap == null) { if(bitmap == null) {
bitmap = createUnknownImage(size, color, topText, bottomText); bitmap = createUnknownImage(size, color, topText, bottomText);
cache.put(key, bitmap); cache.put(key, bitmap);
} }
return bitmap; return bitmap;
} }
private Bitmap createUnknownImage(int size, int primaryColor, String topText, String bottomText) { private Bitmap createUnknownImage(int size, int primaryColor, String topText, String bottomText) {
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap); Canvas canvas = new Canvas(bitmap);
Paint color = new Paint(); Paint color = new Paint();
color.setColor(primaryColor); color.setColor(primaryColor);
canvas.drawRect(0, 0, size, size * 2.0f / 3.0f, color); canvas.drawRect(0, 0, size, size * 2.0f / 3.0f, color);
color.setShader(new LinearGradient(0, 0, 0, size / 3.0f, Color.rgb(82, 82, 82), Color.BLACK, Shader.TileMode.MIRROR)); color.setShader(new LinearGradient(0, 0, 0, size / 3.0f, Color.rgb(82, 82, 82), Color.BLACK, Shader.TileMode.MIRROR));
canvas.drawRect(0, size * 2.0f / 3.0f, size, size, color); canvas.drawRect(0, size * 2.0f / 3.0f, size, size, color);
if(topText != null || bottomText != null) { if(topText != null || bottomText != null) {
Paint font = new Paint(); Paint font = new Paint();
font.setFlags(Paint.ANTI_ALIAS_FLAG); font.setFlags(Paint.ANTI_ALIAS_FLAG);
font.setColor(Color.WHITE); font.setColor(Color.WHITE);
font.setTextSize(3.0f + size * 0.07f); font.setTextSize(3.0f + size * 0.07f);
if(topText != null) { if(topText != null) {
canvas.drawText(topText, size * 0.05f, size * 0.6f, font); canvas.drawText(topText, size * 0.05f, size * 0.6f, font);
} }
if(bottomText != null) { if(bottomText != null) {
canvas.drawText(bottomText, size * 0.05f, size * 0.8f, font); canvas.drawText(bottomText, size * 0.05f, size * 0.8f, font);
} }
} }
return bitmap; return bitmap;
} }
public Bitmap getCachedImage(Context context, MusicDirectory.Entry entry, boolean large) { public Bitmap getCachedImage(Context context, MusicDirectory.Entry entry, boolean large) {
int size = large ? imageSizeLarge : imageSizeDefault; int size = large ? imageSizeLarge : imageSizeDefault;
if(entry == null || entry.getCoverArt() == null) { if(entry == null || entry.getCoverArt() == null) {
return getUnknownImage(entry, size); return getUnknownImage(entry, size);
} }
Bitmap bitmap = cache.get(getKey(entry.getCoverArt(), size)); Bitmap bitmap = cache.get(getKey(entry.getCoverArt(), size));
if(bitmap == null || bitmap.isRecycled()) { if(bitmap == null || bitmap.isRecycled()) {
bitmap = FileUtil.getAlbumArtBitmap(context, entry, size); bitmap = FileUtil.getAlbumArtBitmap(context, entry, size);
String key = getKey(entry.getCoverArt(), size); String key = getKey(entry.getCoverArt(), size);
cache.put(key, bitmap); cache.put(key, bitmap);
cache.get(key); cache.get(key);
} }
if(bitmap != null && bitmap.isRecycled()) { if(bitmap != null && bitmap.isRecycled()) {
bitmap = null; bitmap = null;
} }
return bitmap; return bitmap;
} }
public SilentBackgroundTask loadImage(View view, MusicDirectory.Entry entry, boolean large, boolean crossfade) { public SilentBackgroundTask loadImage(View view, MusicDirectory.Entry entry, boolean large, boolean crossfade) {
int size = large ? imageSizeLarge : imageSizeDefault; int size = large ? imageSizeLarge : imageSizeDefault;
return loadImage(view, entry, large, size, crossfade); return loadImage(view, entry, large, size, crossfade);
} }
public SilentBackgroundTask loadImage(View view, MusicDirectory.Entry entry, boolean large, int size, boolean crossfade) { public SilentBackgroundTask loadImage(View view, MusicDirectory.Entry entry, boolean large, int size, boolean crossfade) {
// If we know this a artist, try to load artist info instead // If we know this a artist, try to load artist info instead
if(entry != null && !entry.isAlbum() && !Util.isOffline(context)) { if(entry != null && !entry.isAlbum() && !Util.isOffline(context)) {
SilentBackgroundTask task = new ArtistImageTask(view.getContext(), entry, size, imageSizeLarge, large, view, crossfade); SilentBackgroundTask task = new ArtistImageTask(view.getContext(), entry, size, imageSizeLarge, large, view, crossfade);
task.execute(); task.execute();
return task; return task;
} else if(entry != null && entry.getCoverArt() == null && entry.isDirectory() && !Util.isOffline(context)) { } else if(entry != null && entry.getCoverArt() == null && entry.isDirectory() && !Util.isOffline(context)) {
// Try to lookup child cover art // Try to lookup child cover art
MusicDirectory.Entry firstChild = FileUtil.lookupChild(context, entry, true); MusicDirectory.Entry firstChild = FileUtil.lookupChild(context, entry, true);
if(firstChild != null) { if(firstChild != null) {
entry.setCoverArt(firstChild.getCoverArt()); entry.setCoverArt(firstChild.getCoverArt());
} }
} }
Bitmap bitmap; Bitmap bitmap;
if (entry == null || entry.getCoverArt() == null) { if (entry == null || entry.getCoverArt() == null) {
bitmap = getUnknownImage(entry, size); bitmap = getUnknownImage(entry, size);
setImage(view, Util.createDrawableFromBitmap(context, bitmap), crossfade); setImage(view, Util.createDrawableFromBitmap(context, bitmap), crossfade);
return null; return null;
} }
bitmap = cache.get(getKey(entry.getCoverArt(), size)); bitmap = cache.get(getKey(entry.getCoverArt(), size));
if (bitmap != null && !bitmap.isRecycled()) { if (bitmap != null && !bitmap.isRecycled()) {
final Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap); final Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap);
setImage(view, drawable, crossfade); setImage(view, drawable, crossfade);
if(large) { if(large) {
nowPlaying = bitmap; nowPlaying = bitmap;
} }
return null; return null;
} }
if (!large) { if (!large) {
setImage(view, null, false); setImage(view, null, false);
} }
ImageTask task = new ViewImageTask(view.getContext(), entry, size, imageSizeLarge, large, view, crossfade); ImageTask task = new ViewImageTask(view.getContext(), entry, size, imageSizeLarge, large, view, crossfade);
task.execute(); task.execute();
return task; return task;
} }
public SilentBackgroundTask<Void> loadImage(View view, String url, boolean large) { public SilentBackgroundTask<Void> loadImage(View view, String url, boolean large) {
Bitmap bitmap; Bitmap bitmap;
int size = large ? imageSizeLarge : imageSizeDefault; int size = large ? imageSizeLarge : imageSizeDefault;
if (url == null) { if (url == null) {
String key = getKey(url + "unknown", size); String key = getKey(url + "unknown", size);
int color = COLORS[Math.abs(key.hashCode()) % COLORS.length]; int color = COLORS[Math.abs(key.hashCode()) % COLORS.length];
bitmap = getUnknownImage(key, size, color, null, null); bitmap = getUnknownImage(key, size, color, null, null);
setImage(view, Util.createDrawableFromBitmap(context, bitmap), true); setImage(view, Util.createDrawableFromBitmap(context, bitmap), true);
return null; return null;
} }
bitmap = cache.get(getKey(url, size)); bitmap = cache.get(getKey(url, size));
if (bitmap != null && !bitmap.isRecycled()) { if (bitmap != null && !bitmap.isRecycled()) {
final Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap); final Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap);
setImage(view, drawable, true); setImage(view, drawable, true);
return null; return null;
} }
setImage(view, null, false); setImage(view, null, false);
SilentBackgroundTask<Void> task = new ViewUrlTask(view.getContext(), view, url, size); SilentBackgroundTask<Void> task = new ViewUrlTask(view.getContext(), view, url, size);
task.execute(); task.execute();
return task; return task;
} }
public SilentBackgroundTask loadImage(View view, Playlist playlist, boolean large, boolean crossfade) { public SilentBackgroundTask loadImage(View view, Playlist playlist, boolean large, boolean crossfade) {
MusicDirectory.Entry entry = new MusicDirectory.Entry(); MusicDirectory.Entry entry = new MusicDirectory.Entry();
String id; String id;
if(Util.isOffline(context)) { if(Util.isOffline(context)) {
id = PLAYLIST_PREFIX + playlist.getName(); id = PLAYLIST_PREFIX + playlist.getName();
entry.setTitle(playlist.getComment()); entry.setTitle(playlist.getComment());
} else { } else {
id = PLAYLIST_PREFIX + playlist.getId(); id = PLAYLIST_PREFIX + playlist.getId();
entry.setTitle(playlist.getName()); entry.setTitle(playlist.getName());
} }
entry.setId(id); entry.setId(id);
entry.setCoverArt(id); entry.setCoverArt(id);
// So this isn't treated as a artist // So this isn't treated as a artist
entry.setParent(""); entry.setParent("");
return loadImage(view, entry, large, crossfade); return loadImage(view, entry, large, crossfade);
} }
private String getKey(String coverArtId, int size) { private String getKey(String coverArtId, int size) {
return coverArtId + size; return coverArtId + size;
} }
private void setImage(View view, final Drawable drawable, boolean crossfade) { private void setImage(View view, final Drawable drawable, boolean crossfade) {
if (view instanceof TextView) { if (view instanceof TextView) {
// Cross-fading is not implemented for TextView since it's not in use. It would be easy to add it, though. // Cross-fading is not implemented for TextView since it's not in use. It would be easy to add it, though.
TextView textView = (TextView) view; TextView textView = (TextView) view;
textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null); textView.setCompoundDrawablesWithIntrinsicBounds(drawable, null, null, null);
} else if (view instanceof ImageView) { } else if (view instanceof ImageView) {
final ImageView imageView = (ImageView) view; final ImageView imageView = (ImageView) view;
if (crossfade && drawable != null) { if (crossfade && drawable != null) {
Drawable existingDrawable = imageView.getDrawable(); Drawable existingDrawable = imageView.getDrawable();
if (existingDrawable == null) { if (existingDrawable == null) {
Bitmap emptyImage; Bitmap emptyImage;
if(drawable.getIntrinsicWidth() > 0 && drawable.getIntrinsicHeight() > 0) { if(drawable.getIntrinsicWidth() > 0 && drawable.getIntrinsicHeight() > 0) {
emptyImage = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); emptyImage = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
} else { } else {
emptyImage = Bitmap.createBitmap(imageSizeDefault, imageSizeDefault, Bitmap.Config.ARGB_8888); emptyImage = Bitmap.createBitmap(imageSizeDefault, imageSizeDefault, Bitmap.Config.ARGB_8888);
} }
existingDrawable = new BitmapDrawable(context.getResources(), emptyImage); existingDrawable = new BitmapDrawable(context.getResources(), emptyImage);
} else if(existingDrawable instanceof TransitionDrawable) { } else if(existingDrawable instanceof TransitionDrawable) {
// This should only ever be used if user is skipping through many songs quickly // This should only ever be used if user is skipping through many songs quickly
TransitionDrawable tmp = (TransitionDrawable) existingDrawable; TransitionDrawable tmp = (TransitionDrawable) existingDrawable;
existingDrawable = tmp.getDrawable(tmp.getNumberOfLayers() - 1); existingDrawable = tmp.getDrawable(tmp.getNumberOfLayers() - 1);
} }
if(existingDrawable != null && drawable != null) { if(existingDrawable != null && drawable != null) {
Drawable[] layers = new Drawable[]{existingDrawable, drawable}; Drawable[] layers = new Drawable[]{existingDrawable, drawable};
final TransitionDrawable transitionDrawable = new TransitionDrawable(layers); final TransitionDrawable transitionDrawable = new TransitionDrawable(layers);
imageView.setImageDrawable(transitionDrawable); imageView.setImageDrawable(transitionDrawable);
transitionDrawable.startTransition(250); transitionDrawable.startTransition(250);
// Get rid of transition drawable after transition occurs // Get rid of transition drawable after transition occurs
handler.postDelayed(new Runnable() { handler.postDelayed(new Runnable() {
@Override @Override
public void run() { public void run() {
// Only execute if still on same transition drawable // Only execute if still on same transition drawable
if (imageView.getDrawable() == transitionDrawable) { if (imageView.getDrawable() == transitionDrawable) {
imageView.setImageDrawable(drawable); imageView.setImageDrawable(drawable);
} }
} }
}, 500L); }, 500L);
} else { } else {
imageView.setImageDrawable(drawable); imageView.setImageDrawable(drawable);
} }
} else { } else {
imageView.setImageDrawable(drawable); imageView.setImageDrawable(drawable);
} }
} }
} }
public abstract class ImageTask extends SilentBackgroundTask<Void> { public abstract class ImageTask extends SilentBackgroundTask<Void> {
private final Context mContext; private final Context mContext;
protected final MusicDirectory.Entry mEntry; protected final MusicDirectory.Entry mEntry;
private final int mSize; private final int mSize;
private final int mSaveSize; private final int mSaveSize;
private final boolean mIsNowPlaying; private final boolean mIsNowPlaying;
protected Drawable mDrawable; protected Drawable mDrawable;
public ImageTask(Context context, MusicDirectory.Entry entry, int size, int saveSize, boolean isNowPlaying) { public ImageTask(Context context, MusicDirectory.Entry entry, int size, int saveSize, boolean isNowPlaying) {
super(context); super(context);
mContext = context; mContext = context;
mEntry = entry; mEntry = entry;
mSize = size; mSize = size;
mSaveSize = saveSize; mSaveSize = saveSize;
mIsNowPlaying = isNowPlaying; mIsNowPlaying = isNowPlaying;
} }
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
try { try {
MusicService musicService = MusicServiceFactory.getMusicService(mContext); MusicService musicService = MusicServiceFactory.getMusicService(mContext);
Bitmap bitmap = musicService.getCoverArt(mContext, mEntry, mSize, null, this); Bitmap bitmap = musicService.getCoverArt(mContext, mEntry, mSize, null, this);
if(bitmap != null) { if(bitmap != null) {
String key = getKey(mEntry.getCoverArt(), mSize); String key = getKey(mEntry.getCoverArt(), mSize);
cache.put(key, bitmap); cache.put(key, bitmap);
// Make sure key is the most recently "used" // Make sure key is the most recently "used"
cache.get(key); cache.get(key);
if (mIsNowPlaying) { if (mIsNowPlaying) {
nowPlaying = bitmap; nowPlaying = bitmap;
} }
} else { } else {
bitmap = getUnknownImage(mEntry, mSize); bitmap = getUnknownImage(mEntry, mSize);
} }
mDrawable = Util.createDrawableFromBitmap(mContext, bitmap); mDrawable = Util.createDrawableFromBitmap(mContext, bitmap);
} catch (Throwable x) { } catch (Throwable x) {
Log.e(TAG, "Failed to download album art.", x); Log.e(TAG, "Failed to download album art.", x);
cancelled.set(true); cancelled.set(true);
} }
return null; return null;
} }
} }
private class ViewImageTask extends ImageTask { private class ViewImageTask extends ImageTask {
protected boolean mCrossfade; protected boolean mCrossfade;
private View mView; private View mView;
public ViewImageTask(Context context, MusicDirectory.Entry entry, int size, int saveSize, boolean isNowPlaying, View view, boolean crossfade) { public ViewImageTask(Context context, MusicDirectory.Entry entry, int size, int saveSize, boolean isNowPlaying, View view, boolean crossfade) {
super(context, entry, size, saveSize, isNowPlaying); super(context, entry, size, saveSize, isNowPlaying);
mView = view; mView = view;
mCrossfade = crossfade; mCrossfade = crossfade;
} }
@Override @Override
protected void done(Void result) { protected void done(Void result) {
setImage(mView, mDrawable, mCrossfade); setImage(mView, mDrawable, mCrossfade);
} }
} }
private class ArtistImageTask extends SilentBackgroundTask<Void> { private class ArtistImageTask extends SilentBackgroundTask<Void> {
private final Context mContext; private final Context mContext;
private final MusicDirectory.Entry mEntry; private final MusicDirectory.Entry mEntry;
private final int mSize; private final int mSize;
private final int mSaveSize; private final int mSaveSize;
private final boolean mIsNowPlaying; private final boolean mIsNowPlaying;
private Drawable mDrawable; private Drawable mDrawable;
private boolean mCrossfade; private boolean mCrossfade;
private View mView; private View mView;
private SilentBackgroundTask subTask; private SilentBackgroundTask subTask;
public ArtistImageTask(Context context, MusicDirectory.Entry entry, int size, int saveSize, boolean isNowPlaying, View view, boolean crossfade) { public ArtistImageTask(Context context, MusicDirectory.Entry entry, int size, int saveSize, boolean isNowPlaying, View view, boolean crossfade) {
super(context); super(context);
mContext = context; mContext = context;
mEntry = entry; mEntry = entry;
mSize = size; mSize = size;
mSaveSize = saveSize; mSaveSize = saveSize;
mIsNowPlaying = isNowPlaying; mIsNowPlaying = isNowPlaying;
mView = view; mView = view;
mCrossfade = crossfade; mCrossfade = crossfade;
} }
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
try { try {
MusicService musicService = MusicServiceFactory.getMusicService(mContext); MusicService musicService = MusicServiceFactory.getMusicService(mContext);
// Figure out whether we are going to get a artist image or the standard image // Figure out whether we are going to get a artist image or the standard image
if (mEntry != null && mEntry.getCoverArt() == null && mEntry.isDirectory() && !Util.isOffline(context)) { if (mEntry != null && mEntry.getCoverArt() == null && mEntry.isDirectory() && !Util.isOffline(context)) {
// Try to lookup child cover art // Try to lookup child cover art
MusicDirectory.Entry firstChild = FileUtil.lookupChild(context, mEntry, true); MusicDirectory.Entry firstChild = FileUtil.lookupChild(context, mEntry, true);
@ -451,72 +451,72 @@ public class ImageLoader {
return null; return null;
} }
// Execute whichever way we decided to go // Execute whichever way we decided to go
subTask.doInBackground(); subTask.doInBackground();
} catch (Throwable x) { } catch (Throwable x) {
Log.e(TAG, "Failed to get artist info", x); Log.e(TAG, "Failed to get artist info", x);
cancelled.set(true); cancelled.set(true);
} }
return null; return null;
} }
@Override @Override
public void done(Void result) { public void done(Void result) {
if(subTask != null) { if(subTask != null) {
subTask.done(result); subTask.done(result);
} else if(mDrawable != null) { } else if(mDrawable != null) {
setImage(mView, mDrawable, mCrossfade); setImage(mView, mDrawable, mCrossfade);
} }
} }
} }
private class ViewUrlTask extends SilentBackgroundTask<Void> { private class ViewUrlTask extends SilentBackgroundTask<Void> {
private final Context mContext; private final Context mContext;
private final String mUrl; private final String mUrl;
private final ImageView mView; private final ImageView mView;
private Drawable mDrawable; private Drawable mDrawable;
private int mSize; private int mSize;
public ViewUrlTask(Context context, View view, String url, int size) { public ViewUrlTask(Context context, View view, String url, int size) {
super(context); super(context);
mContext = context; mContext = context;
mView = (ImageView) view; mView = (ImageView) view;
mUrl = url; mUrl = url;
mSize = size; mSize = size;
} }
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
try { try {
MusicService musicService = MusicServiceFactory.getMusicService(mContext); MusicService musicService = MusicServiceFactory.getMusicService(mContext);
Bitmap bitmap = musicService.getBitmap(mUrl, mSize, mContext, null, this); Bitmap bitmap = musicService.getBitmap(mUrl, mSize, mContext, null, this);
if(bitmap != null) { if(bitmap != null) {
String key = getKey(mUrl, mSize); String key = getKey(mUrl, mSize);
cache.put(key, bitmap); cache.put(key, bitmap);
// Make sure key is the most recently "used" // Make sure key is the most recently "used"
cache.get(key); cache.get(key);
mDrawable = Util.createDrawableFromBitmap(mContext, bitmap); mDrawable = Util.createDrawableFromBitmap(mContext, bitmap);
} }
} catch (Throwable x) { } catch (Throwable x) {
Log.e(TAG, "Failed to download from url " + mUrl, x); Log.e(TAG, "Failed to download from url " + mUrl, x);
cancelled.set(true); cancelled.set(true);
} }
return null; return null;
} }
@Override @Override
protected void done(Void result) { protected void done(Void result) {
if(mDrawable != null) { if(mDrawable != null) {
mView.setImageDrawable(mDrawable); mView.setImageDrawable(mDrawable);
} else { } else {
failedToDownload(); failedToDownload();
} }
} }
protected void failedToDownload() { protected void failedToDownload() {
} }
} }
} }

View File

@ -13,61 +13,61 @@ import net.nullsum.audinaut.activity.SubsonicActivity;
public abstract class LoadingTask<T> extends BackgroundTask<T> { public abstract class LoadingTask<T> extends BackgroundTask<T> {
private final Activity tabActivity; private final Activity tabActivity;
private ProgressDialog loading; private ProgressDialog loading;
private final boolean cancellable; private final boolean cancellable;
public LoadingTask(Activity activity) { public LoadingTask(Activity activity) {
super(activity); super(activity);
tabActivity = activity; tabActivity = activity;
this.cancellable = true; this.cancellable = true;
} }
public LoadingTask(Activity activity, final boolean cancellable) { public LoadingTask(Activity activity, final boolean cancellable) {
super(activity); super(activity);
tabActivity = activity; tabActivity = activity;
this.cancellable = cancellable; this.cancellable = cancellable;
} }
@Override @Override
public void execute() { public void execute() {
loading = ProgressDialog.show(tabActivity, "", "Loading. Please Wait...", true, cancellable, new DialogInterface.OnCancelListener() { loading = ProgressDialog.show(tabActivity, "", "Loading. Please Wait...", true, cancellable, new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface dialog) { public void onCancel(DialogInterface dialog) {
cancel(); cancel();
} }
}); });
queue.offer(task = new Task() { queue.offer(task = new Task() {
@Override @Override
public void onDone(T result) { public void onDone(T result) {
if(loading.isShowing()) { if(loading.isShowing()) {
loading.dismiss(); loading.dismiss();
} }
done(result); done(result);
} }
@Override @Override
public void onError(Throwable t) { public void onError(Throwable t) {
if(loading.isShowing()) { if(loading.isShowing()) {
loading.dismiss(); loading.dismiss();
} }
error(t); error(t);
} }
}); });
} }
@Override @Override
public boolean isCancelled() { public boolean isCancelled() {
return (tabActivity instanceof SubsonicActivity && ((SubsonicActivity) tabActivity).isDestroyedCompat()) || cancelled.get(); return (tabActivity instanceof SubsonicActivity && ((SubsonicActivity) tabActivity).isDestroyedCompat()) || cancelled.get();
} }
@Override @Override
public void updateProgress(final String message) { public void updateProgress(final String message) {
if(!cancelled.get()) { if(!cancelled.get()) {
getHandler().post(new Runnable() { getHandler().post(new Runnable() {
@Override @Override
public void run() { public void run() {
loading.setMessage(message); loading.setMessage(message);
} }
}); });
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
@ -31,53 +31,53 @@ import net.nullsum.audinaut.view.SongView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
public final class MenuUtil { public final class MenuUtil {
private final static String TAG = MenuUtil.class.getSimpleName(); private final static String TAG = MenuUtil.class.getSimpleName();
public static void hideMenuItems(Context context, Menu menu, UpdateView updateView) { public static void hideMenuItems(Context context, Menu menu, UpdateView updateView) {
if(!Util.isOffline(context)) { if(!Util.isOffline(context)) {
// If we are looking at a standard song view, get downloadFile to cache what options to show // If we are looking at a standard song view, get downloadFile to cache what options to show
if(updateView instanceof SongView) { if(updateView instanceof SongView) {
SongView songView = (SongView) updateView; SongView songView = (SongView) updateView;
DownloadFile downloadFile = songView.getDownloadFile(); DownloadFile downloadFile = songView.getDownloadFile();
try { try {
if(downloadFile != null) { if(downloadFile != null) {
if(downloadFile.isWorkDone()) { if(downloadFile.isWorkDone()) {
// Remove permanent cache menu if already perma cached // Remove permanent cache menu if already perma cached
if(downloadFile.isSaved()) { if(downloadFile.isSaved()) {
menu.setGroupVisible(R.id.hide_pin, false); menu.setGroupVisible(R.id.hide_pin, false);
} }
// Remove cache option no matter what if already downloaded // Remove cache option no matter what if already downloaded
menu.setGroupVisible(R.id.hide_download, false); menu.setGroupVisible(R.id.hide_download, false);
} else { } else {
// Remove delete option if nothing to delete // Remove delete option if nothing to delete
menu.setGroupVisible(R.id.hide_delete, false); menu.setGroupVisible(R.id.hide_delete, false);
} }
} }
} catch(Exception e) { } catch(Exception e) {
Log.w(TAG, "Failed to lookup downloadFile info", e); Log.w(TAG, "Failed to lookup downloadFile info", e);
} }
} }
// Apply similar logic to album views // Apply similar logic to album views
else if(updateView instanceof AlbumView || updateView instanceof ArtistView || updateView instanceof ArtistEntryView) { else if(updateView instanceof AlbumView || updateView instanceof ArtistView || updateView instanceof ArtistEntryView) {
File folder = null; File folder = null;
if(updateView instanceof AlbumView) { if(updateView instanceof AlbumView) {
folder = ((AlbumView) updateView).getFile(); folder = ((AlbumView) updateView).getFile();
} else if(updateView instanceof ArtistView) { } else if(updateView instanceof ArtistView) {
folder = ((ArtistView) updateView).getFile(); folder = ((ArtistView) updateView).getFile();
} else if(updateView instanceof ArtistEntryView) { } else if(updateView instanceof ArtistEntryView) {
folder = ((ArtistEntryView) updateView).getFile(); folder = ((ArtistEntryView) updateView).getFile();
} }
try { try {
if(folder != null && !folder.exists()) { if(folder != null && !folder.exists()) {
menu.setGroupVisible(R.id.hide_delete, false); menu.setGroupVisible(R.id.hide_delete, false);
} }
} catch(Exception e) { } catch(Exception e) {
Log.w(TAG, "Failed to lookup album directory info", e); Log.w(TAG, "Failed to lookup album directory info", e);
} }
} }
} }
} }
} }

View File

@ -24,5 +24,5 @@ package net.nullsum.audinaut.util;
public interface ProgressListener { public interface ProgressListener {
void updateProgress(String message); void updateProgress(String message);
void updateProgress(int messageId); void updateProgress(int messageId);
void updateCache(int changeCode); void updateCache(int changeCode);
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of ServerProxy. This file is part of ServerProxy.
SocketProxy is free software: you can redistribute it and/or modify SocketProxy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson Copyright 2014 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
@ -40,192 +40,192 @@ import android.net.wifi.WifiManager;
import android.util.Log; import android.util.Log;
public abstract class ServerProxy implements Runnable { public abstract class ServerProxy implements Runnable {
private static final String TAG = ServerProxy.class.getSimpleName(); private static final String TAG = ServerProxy.class.getSimpleName();
private Thread thread; private Thread thread;
protected boolean isRunning; protected boolean isRunning;
private ServerSocket socket; private ServerSocket socket;
private int port; private int port;
private Context context; private Context context;
public ServerProxy(Context context) { public ServerProxy(Context context) {
// Create listening socket // Create listening socket
try { try {
socket = new ServerSocket(0); socket = new ServerSocket(0);
socket.setSoTimeout(5000); socket.setSoTimeout(5000);
port = socket.getLocalPort(); port = socket.getLocalPort();
this.context = context; this.context = context;
} catch (UnknownHostException e) { // impossible } catch (UnknownHostException e) { // impossible
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "IOException initializing server", e); Log.e(TAG, "IOException initializing server", e);
} }
} }
public void start() { public void start() {
if(socket.isBound()) { if(socket.isBound()) {
thread = new Thread(this, "Socket Proxy"); thread = new Thread(this, "Socket Proxy");
thread.start(); thread.start();
} else { } else {
Log.e(TAG, "Attempting to start a non-initialized proxy"); Log.e(TAG, "Attempting to start a non-initialized proxy");
} }
} }
public void stop() { public void stop() {
isRunning = false; isRunning = false;
if(thread != null) { if(thread != null) {
thread.interrupt(); thread.interrupt();
} }
} }
public String getPrivateAddress(String request) { public String getPrivateAddress(String request) {
return getAddress("127.0.0.1", request); return getAddress("127.0.0.1", request);
} }
public String getPublicAddress(String request) { public String getPublicAddress(String request) {
WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE); WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
int ipAddress = wifiManager.getConnectionInfo().getIpAddress(); int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
if (ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN)) { if (ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN)) {
ipAddress = Integer.reverseBytes(ipAddress); ipAddress = Integer.reverseBytes(ipAddress);
} }
byte[] ipByteArray = BigInteger.valueOf(ipAddress).toByteArray(); byte[] ipByteArray = BigInteger.valueOf(ipAddress).toByteArray();
String ipAddressString = null; String ipAddressString = null;
try { try {
ipAddressString = InetAddress.getByAddress(ipByteArray).getHostAddress(); ipAddressString = InetAddress.getByAddress(ipByteArray).getHostAddress();
} catch(UnknownHostException ex) { } catch(UnknownHostException ex) {
Log.e(TAG, "Unable to get host address."); Log.e(TAG, "Unable to get host address.");
} }
return getAddress(ipAddressString, request); return getAddress(ipAddressString, request);
} }
private String getAddress(String host, String request) { private String getAddress(String host, String request) {
try { try {
return String.format("http://%s:%d/%s", host, port, URLEncoder.encode(request, "UTF-8")); return String.format("http://%s:%d/%s", host, port, URLEncoder.encode(request, "UTF-8"));
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
return null; return null;
} }
} }
@Override @Override
public void run() { public void run() {
isRunning = true; isRunning = true;
while (isRunning) { while (isRunning) {
try { try {
Socket client = socket.accept(); Socket client = socket.accept();
if (client == null) { if (client == null) {
continue; continue;
} }
Log.i(TAG, "client connected"); Log.i(TAG, "client connected");
ProxyTask task = getTask(client); ProxyTask task = getTask(client);
if (task.processRequest()) { if (task.processRequest()) {
new Thread(task, "ProxyTask").start(); new Thread(task, "ProxyTask").start();
} }
} catch (SocketTimeoutException e) { } catch (SocketTimeoutException e) {
// Do nothing // Do nothing
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "Error connecting to client", e); Log.e(TAG, "Error connecting to client", e);
} }
} }
Log.i(TAG, "Proxy interrupted. Shutting down."); Log.i(TAG, "Proxy interrupted. Shutting down.");
} }
abstract ProxyTask getTask(Socket client); abstract ProxyTask getTask(Socket client);
protected abstract class ProxyTask implements Runnable { protected abstract class ProxyTask implements Runnable {
protected Socket client; protected Socket client;
protected String path; protected String path;
protected int cbSkip = 0; protected int cbSkip = 0;
protected Map<String, String> requestHeaders = new HashMap<>(); protected Map<String, String> requestHeaders = new HashMap<>();
public ProxyTask(Socket client) { public ProxyTask(Socket client) {
this.client = client; this.client = client;
} }
protected boolean readRequest() { protected boolean readRequest() {
InputStream is; InputStream is;
String firstLine; String firstLine;
BufferedReader reader; BufferedReader reader;
try { try {
is = client.getInputStream(); is = client.getInputStream();
reader = new BufferedReader(new InputStreamReader(is), 8192); reader = new BufferedReader(new InputStreamReader(is), 8192);
firstLine = reader.readLine(); firstLine = reader.readLine();
} catch (IOException e) { } catch (IOException e) {
Log.e(TAG, "Error parsing request", e); Log.e(TAG, "Error parsing request", e);
return false; return false;
} }
if (firstLine == null) { if (firstLine == null) {
Log.i(TAG, "Proxy client closed connection without a request."); Log.i(TAG, "Proxy client closed connection without a request.");
return false; return false;
} }
StringTokenizer st = new StringTokenizer(firstLine); StringTokenizer st = new StringTokenizer(firstLine);
if(!st.hasMoreTokens()) { if(!st.hasMoreTokens()) {
Log.w(TAG, "Unknown request with no tokens"); Log.w(TAG, "Unknown request with no tokens");
return false; return false;
} else if(st.countTokens() < 2) { } else if(st.countTokens() < 2) {
Log.w(TAG, "Unknown request with no uri: \"" + firstLine + '"'); Log.w(TAG, "Unknown request with no uri: \"" + firstLine + '"');
return false; return false;
} }
String method = st.nextToken(); String method = st.nextToken();
String uri = st.nextToken(); String uri = st.nextToken();
String realUri = uri.substring(1); String realUri = uri.substring(1);
// Process path // Process path
try { try {
path = URLDecoder.decode(realUri, "UTF-8"); path = URLDecoder.decode(realUri, "UTF-8");
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unsupported encoding", e); Log.e(TAG, "Unsupported encoding", e);
return false; return false;
} }
// Get all of the headers // Get all of the headers
try { try {
String line; String line;
while((line = reader.readLine()) != null && !"".equals(line)) { while((line = reader.readLine()) != null && !"".equals(line)) {
int index = line.indexOf(':'); int index = line.indexOf(':');
// Ignore headers without ':' or where ':' is the last thing in the string // Ignore headers without ':' or where ':' is the last thing in the string
if(index != -1 && (index + 2) < line.length()) { if(index != -1 && (index + 2) < line.length()) {
String headerName = line.substring(0, index); String headerName = line.substring(0, index);
String headerValue = line.substring(index + 2); String headerValue = line.substring(index + 2);
requestHeaders.put(headerName, headerValue); requestHeaders.put(headerName, headerValue);
} }
} }
} catch(IOException e) { } catch(IOException e) {
// Don't really care once past first line // Don't really care once past first line
} catch(Exception e) { } catch(Exception e) {
Log.w(TAG, "Exception reading request", e); Log.w(TAG, "Exception reading request", e);
} }
return true; return true;
} }
public boolean processRequest() { public boolean processRequest() {
if (!readRequest()) { if (!readRequest()) {
return false; return false;
} }
Log.i(TAG, "Processing request for " + path); Log.i(TAG, "Processing request for " + path);
// Try to get range requested // Try to get range requested
String range = requestHeaders.get("Range"); String range = requestHeaders.get("Range");
if(range != null) { if(range != null) {
int index = range.indexOf("="); int index = range.indexOf("=");
if(index >= 0) { if(index >= 0) {
range = range.substring(index + 1); range = range.substring(index + 1);
index = range.indexOf("-"); index = range.indexOf("-");
if(index > 0) { if(index > 0) {
range = range.substring(0, index); range = range.substring(0, index);
} }
cbSkip = Integer.parseInt(range); cbSkip = Integer.parseInt(range);
} }
} }
return true; return true;
} }
} }
} }

View File

@ -1,20 +1,20 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2009 (C) Sindre Mehus Copyright 2009 (C) Sindre Mehus
*/ */
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
@ -29,16 +29,16 @@ import java.io.IOException;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
public class SettingsBackupAgent extends BackupAgentHelper { public class SettingsBackupAgent extends BackupAgentHelper {
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, Constants.PREFERENCES_FILE_NAME); SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, Constants.PREFERENCES_FILE_NAME);
addHelper("mypreferences", helper); addHelper("mypreferences", helper);
} }
@Override @Override
public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException{ public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException{
super.onRestore(data, appVersionCode, newState); super.onRestore(data, appVersionCode, newState);
Util.getPreferences(this).edit().remove(Constants.PREFERENCES_KEY_CACHE_LOCATION).apply(); Util.getPreferences(this).edit().remove(Constants.PREFERENCES_KEY_CACHE_LOCATION).apply();
} }
} }

View File

@ -40,173 +40,173 @@ import net.nullsum.audinaut.util.FileUtil;
*/ */
public class ShufflePlayBuffer { public class ShufflePlayBuffer {
private static final String TAG = ShufflePlayBuffer.class.getSimpleName(); private static final String TAG = ShufflePlayBuffer.class.getSimpleName();
private static final String CACHE_FILENAME = "shuffleBuffer.ser"; private static final String CACHE_FILENAME = "shuffleBuffer.ser";
private ScheduledExecutorService executorService; private ScheduledExecutorService executorService;
private Runnable runnable; private Runnable runnable;
private boolean firstRun = true; private boolean firstRun = true;
private final ArrayList<MusicDirectory.Entry> buffer = new ArrayList<MusicDirectory.Entry>(); private final ArrayList<MusicDirectory.Entry> buffer = new ArrayList<MusicDirectory.Entry>();
private int lastCount = -1; private int lastCount = -1;
private DownloadService context; private DownloadService context;
private boolean awaitingResults = false; private boolean awaitingResults = false;
private int capacity; private int capacity;
private int refillThreshold; private int refillThreshold;
private SharedPreferences.OnSharedPreferenceChangeListener listener; private SharedPreferences.OnSharedPreferenceChangeListener listener;
private int currentServer; private int currentServer;
private String currentFolder = ""; private String currentFolder = "";
private String genre = ""; private String genre = "";
private String startYear = ""; private String startYear = "";
private String endYear = ""; private String endYear = "";
public ShufflePlayBuffer(DownloadService context) { public ShufflePlayBuffer(DownloadService context) {
this.context = context; this.context = context;
executorService = Executors.newSingleThreadScheduledExecutor(); executorService = Executors.newSingleThreadScheduledExecutor();
runnable = new Runnable() { runnable = new Runnable() {
@Override @Override
public void run() { public void run() {
refill(); refill();
} }
}; };
executorService.scheduleWithFixedDelay(runnable, 1, 10, TimeUnit.SECONDS); executorService.scheduleWithFixedDelay(runnable, 1, 10, TimeUnit.SECONDS);
// Calculate out the capacity and refill threshold based on the user's random size preference // Calculate out the capacity and refill threshold based on the user's random size preference
int shuffleListSize = Math.max(1, Integer.parseInt(Util.getPreferences(context).getString(Constants.PREFERENCES_KEY_RANDOM_SIZE, "20"))); int shuffleListSize = Math.max(1, Integer.parseInt(Util.getPreferences(context).getString(Constants.PREFERENCES_KEY_RANDOM_SIZE, "20")));
// ex: default 20 -> 50 // ex: default 20 -> 50
capacity = shuffleListSize * 5 / 2; capacity = shuffleListSize * 5 / 2;
capacity = Math.min(500, capacity); capacity = Math.min(500, capacity);
// ex: default 20 -> 40 // ex: default 20 -> 40
refillThreshold = capacity * 4 / 5; refillThreshold = capacity * 4 / 5;
} }
public List<MusicDirectory.Entry> get(int size) { public List<MusicDirectory.Entry> get(int size) {
clearBufferIfnecessary(); clearBufferIfnecessary();
// Make sure fetcher is running if needed // Make sure fetcher is running if needed
restart(); restart();
List<MusicDirectory.Entry> result = new ArrayList<MusicDirectory.Entry>(size); List<MusicDirectory.Entry> result = new ArrayList<MusicDirectory.Entry>(size);
synchronized (buffer) { synchronized (buffer) {
boolean removed = false; boolean removed = false;
while (!buffer.isEmpty() && result.size() < size) { while (!buffer.isEmpty() && result.size() < size) {
result.add(buffer.remove(buffer.size() - 1)); result.add(buffer.remove(buffer.size() - 1));
removed = true; removed = true;
} }
// Re-cache if anything is taken out // Re-cache if anything is taken out
if(removed) { if(removed) {
FileUtil.serialize(context, buffer, CACHE_FILENAME); FileUtil.serialize(context, buffer, CACHE_FILENAME);
} }
} }
Log.i(TAG, "Taking " + result.size() + " songs from shuffle play buffer. " + buffer.size() + " remaining."); Log.i(TAG, "Taking " + result.size() + " songs from shuffle play buffer. " + buffer.size() + " remaining.");
if(result.isEmpty()) { if(result.isEmpty()) {
awaitingResults = true; awaitingResults = true;
} }
return result; return result;
} }
public void shutdown() { public void shutdown() {
executorService.shutdown(); executorService.shutdown();
Util.getPreferences(context).unregisterOnSharedPreferenceChangeListener(listener); Util.getPreferences(context).unregisterOnSharedPreferenceChangeListener(listener);
} }
private void restart() { private void restart() {
synchronized(buffer) { synchronized(buffer) {
if(buffer.size() <= refillThreshold && lastCount != 0 && executorService.isShutdown()) { if(buffer.size() <= refillThreshold && lastCount != 0 && executorService.isShutdown()) {
executorService = Executors.newSingleThreadScheduledExecutor(); executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay(runnable, 0, 10, TimeUnit.SECONDS); executorService.scheduleWithFixedDelay(runnable, 0, 10, TimeUnit.SECONDS);
} }
} }
} }
private void refill() { private void refill() {
// Check if active server has changed. // Check if active server has changed.
clearBufferIfnecessary(); clearBufferIfnecessary();
if (buffer != null && (buffer.size() > refillThreshold || (!Util.isNetworkConnected(context) && !Util.isOffline(context)) || lastCount == 0)) { if (buffer != null && (buffer.size() > refillThreshold || (!Util.isNetworkConnected(context) && !Util.isOffline(context)) || lastCount == 0)) {
executorService.shutdown(); executorService.shutdown();
return; return;
} }
try { try {
MusicService service = MusicServiceFactory.getMusicService(context); MusicService service = MusicServiceFactory.getMusicService(context);
// Get capacity based // Get capacity based
int n = capacity - buffer.size(); int n = capacity - buffer.size();
String folder = null; String folder = null;
if(!Util.isTagBrowsing(context)) { if(!Util.isTagBrowsing(context)) {
folder = Util.getSelectedMusicFolderId(context); folder = Util.getSelectedMusicFolderId(context);
} }
MusicDirectory songs = service.getRandomSongs(n, folder, genre, startYear, endYear, context, null); MusicDirectory songs = service.getRandomSongs(n, folder, genre, startYear, endYear, context, null);
synchronized (buffer) { synchronized (buffer) {
lastCount = 0; lastCount = 0;
for(MusicDirectory.Entry entry: songs.getChildren()) { for(MusicDirectory.Entry entry: songs.getChildren()) {
if(!buffer.contains(entry)) { if(!buffer.contains(entry)) {
buffer.add(entry); buffer.add(entry);
lastCount++; lastCount++;
} }
} }
Log.i(TAG, "Refilled shuffle play buffer with " + lastCount + " songs."); Log.i(TAG, "Refilled shuffle play buffer with " + lastCount + " songs.");
// Cache buffer // Cache buffer
FileUtil.serialize(context, buffer, CACHE_FILENAME); FileUtil.serialize(context, buffer, CACHE_FILENAME);
} }
} catch (Exception x) { } catch (Exception x) {
// Give it one more try before quitting // Give it one more try before quitting
if(lastCount != -2) { if(lastCount != -2) {
lastCount = -2; lastCount = -2;
} else if(lastCount == -2) { } else if(lastCount == -2) {
lastCount = 0; lastCount = 0;
} }
Log.w(TAG, "Failed to refill shuffle play buffer.", x); Log.w(TAG, "Failed to refill shuffle play buffer.", x);
} }
if(awaitingResults) { if(awaitingResults) {
awaitingResults = false; awaitingResults = false;
context.checkDownloads(); context.checkDownloads();
} }
} }
private void clearBufferIfnecessary() { private void clearBufferIfnecessary() {
synchronized (buffer) { synchronized (buffer) {
final SharedPreferences prefs = Util.getPreferences(context); final SharedPreferences prefs = Util.getPreferences(context);
if (currentServer != Util.getActiveServer(context) if (currentServer != Util.getActiveServer(context)
|| !Util.equals(currentFolder, Util.getSelectedMusicFolderId(context)) || !Util.equals(currentFolder, Util.getSelectedMusicFolderId(context))
|| (genre != null && !genre.equals(prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, ""))) || (genre != null && !genre.equals(prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, "")))
|| (startYear != null && !startYear.equals(prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, ""))) || (startYear != null && !startYear.equals(prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, "")))
|| (endYear != null && !endYear.equals(prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, "")))) { || (endYear != null && !endYear.equals(prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, "")))) {
lastCount = -1; lastCount = -1;
currentServer = Util.getActiveServer(context); currentServer = Util.getActiveServer(context);
currentFolder = Util.getSelectedMusicFolderId(context); currentFolder = Util.getSelectedMusicFolderId(context);
genre = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, ""); genre = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, "");
startYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, ""); startYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, "");
endYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, ""); endYear = prefs.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, "");
buffer.clear(); buffer.clear();
if(firstRun) { if(firstRun) {
ArrayList cacheList = FileUtil.deserialize(context, CACHE_FILENAME, ArrayList.class); ArrayList cacheList = FileUtil.deserialize(context, CACHE_FILENAME, ArrayList.class);
if(cacheList != null) { if(cacheList != null) {
buffer.addAll(cacheList); buffer.addAll(cacheList);
} }
listener = new SharedPreferences.OnSharedPreferenceChangeListener() { listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override @Override
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
clearBufferIfnecessary(); clearBufferIfnecessary();
restart(); restart();
} }
}; };
prefs.registerOnSharedPreferenceChangeListener(listener); prefs.registerOnSharedPreferenceChangeListener(listener);
firstRun = false; firstRun = false;
} else { } else {
// Clear cache // Clear cache
File file = new File(context.getCacheDir(), CACHE_FILENAME); File file = new File(context.getCacheDir(), CACHE_FILENAME);
file.delete(); file.delete();
} }
} }
} }
} }
} }

View File

@ -30,13 +30,13 @@ public abstract class SilentBackgroundTask<T> extends BackgroundTask<T> {
@Override @Override
public void execute() { public void execute() {
queue.offer(task = new Task()); queue.offer(task = new Task());
} }
@Override @Override
protected void done(T result) { protected void done(T result) {
// Don't do anything unless overriden // Don't do anything unless overriden
} }
@Override @Override
public void updateProgress(int messageId) { public void updateProgress(int messageId) {

View File

@ -1,20 +1,20 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
@ -25,17 +25,17 @@ import net.nullsum.audinaut.service.MusicService;
import net.nullsum.audinaut.service.MusicServiceFactory; import net.nullsum.audinaut.service.MusicServiceFactory;
public abstract class SilentServiceTask<T> extends SilentBackgroundTask<T> { public abstract class SilentServiceTask<T> extends SilentBackgroundTask<T> {
protected MusicService musicService; protected MusicService musicService;
public SilentServiceTask(Context context) { public SilentServiceTask(Context context) {
super(context); super(context);
} }
@Override @Override
protected T doInBackground() throws Throwable { protected T doInBackground() throws Throwable {
musicService = MusicServiceFactory.getMusicService(getContext()); musicService = MusicServiceFactory.getMusicService(getContext());
return doInBackground(musicService); return doInBackground(musicService);
} }
protected abstract T doInBackground(MusicService musicService) throws Throwable; protected abstract T doInBackground(MusicService musicService) throws Throwable;
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
@ -29,235 +29,235 @@ import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.service.DownloadFile; import net.nullsum.audinaut.service.DownloadFile;
public class SongDBHandler extends SQLiteOpenHelper { public class SongDBHandler extends SQLiteOpenHelper {
private static final String TAG = SongDBHandler.class.getSimpleName(); private static final String TAG = SongDBHandler.class.getSimpleName();
private static SongDBHandler dbHandler; private static SongDBHandler dbHandler;
private static final int DATABASE_VERSION = 2; private static final int DATABASE_VERSION = 2;
public static final String DATABASE_NAME = "SongsDB"; public static final String DATABASE_NAME = "SongsDB";
public static final String TABLE_SONGS = "RegisteredSongs"; public static final String TABLE_SONGS = "RegisteredSongs";
public static final String SONGS_ID = "id"; public static final String SONGS_ID = "id";
public static final String SONGS_SERVER_KEY = "serverKey"; public static final String SONGS_SERVER_KEY = "serverKey";
public static final String SONGS_SERVER_ID = "serverId"; public static final String SONGS_SERVER_ID = "serverId";
public static final String SONGS_COMPLETE_PATH = "completePath"; public static final String SONGS_COMPLETE_PATH = "completePath";
public static final String SONGS_LAST_PLAYED = "lastPlayed"; public static final String SONGS_LAST_PLAYED = "lastPlayed";
public static final String SONGS_LAST_COMPLETED = "lastCompleted"; public static final String SONGS_LAST_COMPLETED = "lastCompleted";
private Context context; private Context context;
private SongDBHandler(Context context) { private SongDBHandler(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION); super(context, DATABASE_NAME, null, DATABASE_VERSION);
this.context = context; this.context = context;
} }
@Override @Override
public void onCreate(SQLiteDatabase db) { public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + TABLE_SONGS + " ( " + db.execSQL("CREATE TABLE " + TABLE_SONGS + " ( " +
SONGS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + SONGS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
SONGS_SERVER_KEY + " INTEGER NOT NULL, " + SONGS_SERVER_KEY + " INTEGER NOT NULL, " +
SONGS_SERVER_ID + " TEXT NOT NULL, " + SONGS_SERVER_ID + " TEXT NOT NULL, " +
SONGS_COMPLETE_PATH + " TEXT NOT NULL, " + SONGS_COMPLETE_PATH + " TEXT NOT NULL, " +
SONGS_LAST_PLAYED + " INTEGER, " + SONGS_LAST_PLAYED + " INTEGER, " +
SONGS_LAST_COMPLETED + " INTEGER, " + SONGS_LAST_COMPLETED + " INTEGER, " +
"UNIQUE(" + SONGS_SERVER_KEY + ", " + SONGS_SERVER_ID + "))"); "UNIQUE(" + SONGS_SERVER_KEY + ", " + SONGS_SERVER_ID + "))");
} }
@Override @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_SONGS); db.execSQL("DROP TABLE IF EXISTS " + TABLE_SONGS);
this.onCreate(db); this.onCreate(db);
} }
public synchronized void addSong(DownloadFile downloadFile) { public synchronized void addSong(DownloadFile downloadFile) {
addSong(Util.getMostRecentActiveServer(context), downloadFile); addSong(Util.getMostRecentActiveServer(context), downloadFile);
} }
public synchronized void addSong(int instance, DownloadFile downloadFile) { public synchronized void addSong(int instance, DownloadFile downloadFile) {
SQLiteDatabase db = this.getWritableDatabase(); SQLiteDatabase db = this.getWritableDatabase();
addSong(db, instance, downloadFile); addSong(db, instance, downloadFile);
db.close(); db.close();
} }
protected synchronized void addSong(SQLiteDatabase db, DownloadFile downloadFile) { protected synchronized void addSong(SQLiteDatabase db, DownloadFile downloadFile) {
addSong(db, Util.getMostRecentActiveServer(context), downloadFile); addSong(db, Util.getMostRecentActiveServer(context), downloadFile);
} }
protected synchronized void addSong(SQLiteDatabase db, int instance, DownloadFile downloadFile) { protected synchronized void addSong(SQLiteDatabase db, int instance, DownloadFile downloadFile) {
addSong(db, instance, downloadFile.getSong().getId(), downloadFile.getSaveFile().getAbsolutePath()); addSong(db, instance, downloadFile.getSong().getId(), downloadFile.getSaveFile().getAbsolutePath());
} }
protected synchronized void addSong(SQLiteDatabase db, String id, String absolutePath) { protected synchronized void addSong(SQLiteDatabase db, String id, String absolutePath) {
addSong(db, Util.getMostRecentActiveServer(context), id, absolutePath); addSong(db, Util.getMostRecentActiveServer(context), id, absolutePath);
} }
protected synchronized void addSong(SQLiteDatabase db, int instance, String id, String absolutePath) { protected synchronized void addSong(SQLiteDatabase db, int instance, String id, String absolutePath) {
addSongImpl(db, Util.getRestUrlHash(context, instance), id, absolutePath); addSongImpl(db, Util.getRestUrlHash(context, instance), id, absolutePath);
} }
protected synchronized void addSongImpl(SQLiteDatabase db, int serverKey, String id, String absolutePath) { protected synchronized void addSongImpl(SQLiteDatabase db, int serverKey, String id, String absolutePath) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(SONGS_SERVER_KEY, serverKey); values.put(SONGS_SERVER_KEY, serverKey);
values.put(SONGS_SERVER_ID, id); values.put(SONGS_SERVER_ID, id);
values.put(SONGS_COMPLETE_PATH, absolutePath); values.put(SONGS_COMPLETE_PATH, absolutePath);
db.insertWithOnConflict(TABLE_SONGS, null, values, SQLiteDatabase.CONFLICT_IGNORE); db.insertWithOnConflict(TABLE_SONGS, null, values, SQLiteDatabase.CONFLICT_IGNORE);
} }
public synchronized void addSongs(int instance, List<MusicDirectory.Entry> entries) { public synchronized void addSongs(int instance, List<MusicDirectory.Entry> entries) {
SQLiteDatabase db = this.getWritableDatabase(); SQLiteDatabase db = this.getWritableDatabase();
List<Pair<String, String>> pairs = new ArrayList<>(); List<Pair<String, String>> pairs = new ArrayList<>();
for(MusicDirectory.Entry entry: entries) { for(MusicDirectory.Entry entry: entries) {
pairs.add(new Pair<>(entry.getId(), FileUtil.getSongFile(context, entry).getAbsolutePath())); pairs.add(new Pair<>(entry.getId(), FileUtil.getSongFile(context, entry).getAbsolutePath()));
} }
addSongs(db, instance, pairs); addSongs(db, instance, pairs);
db.close(); db.close();
} }
public synchronized void addSongs(SQLiteDatabase db, int instance, List<Pair<String, String>> entries) { public synchronized void addSongs(SQLiteDatabase db, int instance, List<Pair<String, String>> entries) {
addSongsImpl(db, Util.getRestUrlHash(context, instance), entries); addSongsImpl(db, Util.getRestUrlHash(context, instance), entries);
} }
protected synchronized void addSongsImpl(SQLiteDatabase db, int serverKey, List<Pair<String, String>> entries) { protected synchronized void addSongsImpl(SQLiteDatabase db, int serverKey, List<Pair<String, String>> entries) {
db.beginTransaction(); db.beginTransaction();
try { try {
for (Pair<String, String> entry : entries) { for (Pair<String, String> entry : entries) {
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(SONGS_SERVER_KEY, serverKey); values.put(SONGS_SERVER_KEY, serverKey);
values.put(SONGS_SERVER_ID, entry.getFirst()); values.put(SONGS_SERVER_ID, entry.getFirst());
values.put(SONGS_COMPLETE_PATH, entry.getSecond()); values.put(SONGS_COMPLETE_PATH, entry.getSecond());
// Util.sleepQuietly(10000); // Util.sleepQuietly(10000);
db.insertWithOnConflict(TABLE_SONGS, null, values, SQLiteDatabase.CONFLICT_IGNORE); db.insertWithOnConflict(TABLE_SONGS, null, values, SQLiteDatabase.CONFLICT_IGNORE);
} }
db.setTransactionSuccessful(); db.setTransactionSuccessful();
} catch(Exception e) {} } catch(Exception e) {}
db.endTransaction(); db.endTransaction();
} }
public synchronized void setSongPlayed(DownloadFile downloadFile, boolean submission) { public synchronized void setSongPlayed(DownloadFile downloadFile, boolean submission) {
// TODO: In case of offline want to update all matches // TODO: In case of offline want to update all matches
Pair<Integer, String> pair = getOnlineSongId(downloadFile); Pair<Integer, String> pair = getOnlineSongId(downloadFile);
if(pair == null) { if(pair == null) {
return; return;
} }
int serverKey = pair.getFirst(); int serverKey = pair.getFirst();
String id = pair.getSecond(); String id = pair.getSecond();
// Open and make sure song is in db // Open and make sure song is in db
SQLiteDatabase db = this.getWritableDatabase(); SQLiteDatabase db = this.getWritableDatabase();
addSongImpl(db, serverKey, id, downloadFile.getSaveFile().getAbsolutePath()); addSongImpl(db, serverKey, id, downloadFile.getSaveFile().getAbsolutePath());
// Update song's last played // Update song's last played
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(submission ? SONGS_LAST_COMPLETED : SONGS_LAST_PLAYED, System.currentTimeMillis()); values.put(submission ? SONGS_LAST_COMPLETED : SONGS_LAST_PLAYED, System.currentTimeMillis());
db.update(TABLE_SONGS, values, SONGS_SERVER_KEY + " = ? AND " + SONGS_SERVER_ID + " = ?", new String[]{Integer.toString(serverKey), id}); db.update(TABLE_SONGS, values, SONGS_SERVER_KEY + " = ? AND " + SONGS_SERVER_ID + " = ?", new String[]{Integer.toString(serverKey), id});
db.close(); db.close();
} }
public boolean hasBeenPlayed(MusicDirectory.Entry entry) { public boolean hasBeenPlayed(MusicDirectory.Entry entry) {
Long[] lastPlayed = getLastPlayed(entry); Long[] lastPlayed = getLastPlayed(entry);
return lastPlayed != null && lastPlayed[0] != null && lastPlayed[0] > 0; return lastPlayed != null && lastPlayed[0] != null && lastPlayed[0] > 0;
} }
public boolean hasBeenCompleted(MusicDirectory.Entry entry) { public boolean hasBeenCompleted(MusicDirectory.Entry entry) {
Long[] lastPlayed = getLastPlayed(entry); Long[] lastPlayed = getLastPlayed(entry);
return lastPlayed != null && lastPlayed[1] != null && lastPlayed[1] > 0; return lastPlayed != null && lastPlayed[1] != null && lastPlayed[1] > 0;
} }
public synchronized Long[] getLastPlayed(MusicDirectory.Entry entry) { public synchronized Long[] getLastPlayed(MusicDirectory.Entry entry) {
return getLastPlayed(getOnlineSongId(entry)); return getLastPlayed(getOnlineSongId(entry));
} }
protected synchronized Long[] getLastPlayed(Pair<Integer, String> pair) { protected synchronized Long[] getLastPlayed(Pair<Integer, String> pair) {
if(pair == null) { if(pair == null) {
return null; return null;
} else { } else {
return getLastPlayed(pair.getFirst(), pair.getSecond()); return getLastPlayed(pair.getFirst(), pair.getSecond());
} }
} }
public synchronized Long[] getLastPlayed(int serverKey, String id) { public synchronized Long[] getLastPlayed(int serverKey, String id) {
SQLiteDatabase db = this.getReadableDatabase(); SQLiteDatabase db = this.getReadableDatabase();
String[] columns = {SONGS_LAST_PLAYED, SONGS_LAST_COMPLETED}; String[] columns = {SONGS_LAST_PLAYED, SONGS_LAST_COMPLETED};
Cursor cursor = db.query(TABLE_SONGS, columns, SONGS_SERVER_KEY + " = ? AND " + SONGS_SERVER_ID + " = ?", new String[]{Integer.toString(serverKey), id}, null, null, null, null); Cursor cursor = db.query(TABLE_SONGS, columns, SONGS_SERVER_KEY + " = ? AND " + SONGS_SERVER_ID + " = ?", new String[]{Integer.toString(serverKey), id}, null, null, null, null);
try { try {
cursor.moveToFirst(); cursor.moveToFirst();
Long[] dates = new Long[2]; Long[] dates = new Long[2];
dates[0] = cursor.getLong(0); dates[0] = cursor.getLong(0);
dates[1] = cursor.getLong(1); dates[1] = cursor.getLong(1);
return dates; return dates;
} catch(Exception e) { } catch(Exception e) {
return null; return null;
} }
finally { finally {
cursor.close();
db.close();
}
}
public synchronized Pair<Integer, String> getOnlineSongId(MusicDirectory.Entry entry) {
return getOnlineSongId(Util.getRestUrlHash(context), entry.getId(), FileUtil.getSongFile(context, entry).getAbsolutePath(), Util.isOffline(context) ? false : true);
}
public synchronized Pair<Integer, String> getOnlineSongId(DownloadFile downloadFile) {
return getOnlineSongId(Util.getRestUrlHash(context), downloadFile.getSong().getId(), downloadFile.getSaveFile().getAbsolutePath(), Util.isOffline(context) ? false : true);
}
public synchronized Pair<Integer, String> getOnlineSongId(int serverKey, MusicDirectory.Entry entry) {
return getOnlineSongId(serverKey, new DownloadFile(context, entry, true));
}
public synchronized Pair<Integer, String> getOnlineSongId(int serverKey, DownloadFile downloadFile) {
return getOnlineSongId(serverKey, downloadFile.getSong().getId(), downloadFile.getSaveFile().getAbsolutePath(), true);
}
public synchronized Pair<Integer, String> getOnlineSongId(int serverKey, String id, String savePath, boolean requireServerKey) {
SharedPreferences prefs = Util.getPreferences(context);
String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
if(cacheLocn != null && id.indexOf(cacheLocn) != -1) {
if(requireServerKey) {
return getIdFromPath(serverKey, savePath);
} else {
return getIdFromPath(savePath);
}
} else {
return new Pair<>(serverKey, id);
}
}
public synchronized Pair<Integer, String> getIdFromPath(String path) {
SQLiteDatabase db = this.getReadableDatabase();
String[] columns = {SONGS_SERVER_KEY, SONGS_SERVER_ID};
Cursor cursor = db.query(TABLE_SONGS, columns, SONGS_COMPLETE_PATH + " = ?", new String[] { path }, null, null, SONGS_LAST_PLAYED + " DESC", null);
try {
cursor.moveToFirst();
return new Pair(cursor.getInt(0), cursor.getString(1));
} catch(Exception e) {
return null;
}
finally {
cursor.close(); cursor.close();
db.close(); db.close();
} }
} }
public synchronized Pair<Integer, String> getIdFromPath(int serverKey, String path) {
SQLiteDatabase db = this.getReadableDatabase();
String[] columns = {SONGS_SERVER_KEY, SONGS_SERVER_ID}; public synchronized Pair<Integer, String> getOnlineSongId(MusicDirectory.Entry entry) {
Cursor cursor = db.query(TABLE_SONGS, columns, SONGS_SERVER_KEY + " = ? AND " + SONGS_COMPLETE_PATH + " = ?", new String[] {Integer.toString(serverKey), path }, null, null, null, null); return getOnlineSongId(Util.getRestUrlHash(context), entry.getId(), FileUtil.getSongFile(context, entry).getAbsolutePath(), Util.isOffline(context) ? false : true);
}
public synchronized Pair<Integer, String> getOnlineSongId(DownloadFile downloadFile) {
return getOnlineSongId(Util.getRestUrlHash(context), downloadFile.getSong().getId(), downloadFile.getSaveFile().getAbsolutePath(), Util.isOffline(context) ? false : true);
}
try { public synchronized Pair<Integer, String> getOnlineSongId(int serverKey, MusicDirectory.Entry entry) {
cursor.moveToFirst(); return getOnlineSongId(serverKey, new DownloadFile(context, entry, true));
return new Pair(cursor.getInt(0), cursor.getString(1)); }
} catch(Exception e) { public synchronized Pair<Integer, String> getOnlineSongId(int serverKey, DownloadFile downloadFile) {
return null; return getOnlineSongId(serverKey, downloadFile.getSong().getId(), downloadFile.getSaveFile().getAbsolutePath(), true);
} }
finally { public synchronized Pair<Integer, String> getOnlineSongId(int serverKey, String id, String savePath, boolean requireServerKey) {
SharedPreferences prefs = Util.getPreferences(context);
String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
if(cacheLocn != null && id.indexOf(cacheLocn) != -1) {
if(requireServerKey) {
return getIdFromPath(serverKey, savePath);
} else {
return getIdFromPath(savePath);
}
} else {
return new Pair<>(serverKey, id);
}
}
public synchronized Pair<Integer, String> getIdFromPath(String path) {
SQLiteDatabase db = this.getReadableDatabase();
String[] columns = {SONGS_SERVER_KEY, SONGS_SERVER_ID};
Cursor cursor = db.query(TABLE_SONGS, columns, SONGS_COMPLETE_PATH + " = ?", new String[] { path }, null, null, SONGS_LAST_PLAYED + " DESC", null);
try {
cursor.moveToFirst();
return new Pair(cursor.getInt(0), cursor.getString(1));
} catch(Exception e) {
return null;
}
finally {
cursor.close(); cursor.close();
db.close(); db.close();
} }
} }
public synchronized Pair<Integer, String> getIdFromPath(int serverKey, String path) {
SQLiteDatabase db = this.getReadableDatabase();
public static SongDBHandler getHandler(Context context) { String[] columns = {SONGS_SERVER_KEY, SONGS_SERVER_ID};
if(dbHandler == null) { Cursor cursor = db.query(TABLE_SONGS, columns, SONGS_SERVER_KEY + " = ? AND " + SONGS_COMPLETE_PATH + " = ?", new String[] {Integer.toString(serverKey), path }, null, null, null, null);
dbHandler = new SongDBHandler(context);
}
return dbHandler; try {
} cursor.moveToFirst();
return new Pair(cursor.getInt(0), cursor.getString(1));
} catch(Exception e) {
return null;
}
finally {
cursor.close();
db.close();
}
}
public static SongDBHandler getHandler(Context context) {
if(dbHandler == null) {
dbHandler = new SongDBHandler(context);
}
return dbHandler;
}
} }

View File

@ -18,139 +18,139 @@ import net.nullsum.audinaut.activity.SubsonicFragmentActivity;
* Created by Scott on 11/24/13. * Created by Scott on 11/24/13.
*/ */
public final class SyncUtil { public final class SyncUtil {
private static String TAG = SyncUtil.class.getSimpleName(); private static String TAG = SyncUtil.class.getSimpleName();
private static ArrayList<SyncSet> syncedPlaylists; private static ArrayList<SyncSet> syncedPlaylists;
private static String url; private static String url;
private static void checkRestURL(Context context) { private static void checkRestURL(Context context) {
int instance = Util.getActiveServer(context); int instance = Util.getActiveServer(context);
String newURL = Util.getRestUrl(context, null, instance, false); String newURL = Util.getRestUrl(context, null, instance, false);
if(url == null || !url.equals(newURL)) { if(url == null || !url.equals(newURL)) {
syncedPlaylists = null; syncedPlaylists = null;
url = newURL; url = newURL;
} }
} }
// Playlist sync // Playlist sync
public static boolean isSyncedPlaylist(Context context, String playlistId) { public static boolean isSyncedPlaylist(Context context, String playlistId) {
checkRestURL(context); checkRestURL(context);
if(syncedPlaylists == null) { if(syncedPlaylists == null) {
syncedPlaylists = getSyncedPlaylists(context); syncedPlaylists = getSyncedPlaylists(context);
} }
return syncedPlaylists.contains(new SyncSet(playlistId)); return syncedPlaylists.contains(new SyncSet(playlistId));
} }
public static ArrayList<SyncSet> getSyncedPlaylists(Context context) { public static ArrayList<SyncSet> getSyncedPlaylists(Context context) {
return getSyncedPlaylists(context, Util.getActiveServer(context)); return getSyncedPlaylists(context, Util.getActiveServer(context));
} }
public static ArrayList<SyncSet> getSyncedPlaylists(Context context, int instance) { public static ArrayList<SyncSet> getSyncedPlaylists(Context context, int instance) {
String syncFile = getPlaylistSyncFile(context, instance); String syncFile = getPlaylistSyncFile(context, instance);
ArrayList<SyncSet> playlists = FileUtil.deserializeCompressed(context, syncFile, ArrayList.class); ArrayList<SyncSet> playlists = FileUtil.deserializeCompressed(context, syncFile, ArrayList.class);
if(playlists == null) { if(playlists == null) {
playlists = new ArrayList<SyncSet>(); playlists = new ArrayList<SyncSet>();
// Try to convert old style into new style // Try to convert old style into new style
ArrayList<String> oldPlaylists = FileUtil.deserialize(context, syncFile, ArrayList.class); ArrayList<String> oldPlaylists = FileUtil.deserialize(context, syncFile, ArrayList.class);
// If exists, time to convert! // If exists, time to convert!
if(oldPlaylists != null) { if(oldPlaylists != null) {
for(String id: oldPlaylists) { for(String id: oldPlaylists) {
playlists.add(new SyncSet(id)); playlists.add(new SyncSet(id));
} }
FileUtil.serializeCompressed(context, playlists, syncFile); FileUtil.serializeCompressed(context, playlists, syncFile);
} }
} }
return playlists; return playlists;
} }
public static void setSyncedPlaylists(Context context, int instance, ArrayList<SyncSet> playlists) { public static void setSyncedPlaylists(Context context, int instance, ArrayList<SyncSet> playlists) {
FileUtil.serializeCompressed(context, playlists, getPlaylistSyncFile(context, instance)); FileUtil.serializeCompressed(context, playlists, getPlaylistSyncFile(context, instance));
} }
public static void addSyncedPlaylist(Context context, String playlistId) { public static void addSyncedPlaylist(Context context, String playlistId) {
String playlistFile = getPlaylistSyncFile(context); String playlistFile = getPlaylistSyncFile(context);
ArrayList<SyncSet> playlists = getSyncedPlaylists(context); ArrayList<SyncSet> playlists = getSyncedPlaylists(context);
SyncSet set = new SyncSet(playlistId); SyncSet set = new SyncSet(playlistId);
if(!playlists.contains(set)) { if(!playlists.contains(set)) {
playlists.add(set); playlists.add(set);
} }
FileUtil.serializeCompressed(context, playlists, playlistFile); FileUtil.serializeCompressed(context, playlists, playlistFile);
syncedPlaylists = playlists; syncedPlaylists = playlists;
} }
public static void removeSyncedPlaylist(Context context, String playlistId) { public static void removeSyncedPlaylist(Context context, String playlistId) {
int instance = Util.getActiveServer(context); int instance = Util.getActiveServer(context);
removeSyncedPlaylist(context, playlistId, instance); removeSyncedPlaylist(context, playlistId, instance);
} }
public static void removeSyncedPlaylist(Context context, String playlistId, int instance) { public static void removeSyncedPlaylist(Context context, String playlistId, int instance) {
String playlistFile = getPlaylistSyncFile(context, instance); String playlistFile = getPlaylistSyncFile(context, instance);
ArrayList<SyncSet> playlists = getSyncedPlaylists(context, instance); ArrayList<SyncSet> playlists = getSyncedPlaylists(context, instance);
SyncSet set = new SyncSet(playlistId); SyncSet set = new SyncSet(playlistId);
if(playlists.contains(set)) { if(playlists.contains(set)) {
playlists.remove(set); playlists.remove(set);
FileUtil.serializeCompressed(context, playlists, playlistFile); FileUtil.serializeCompressed(context, playlists, playlistFile);
syncedPlaylists = playlists; syncedPlaylists = playlists;
} }
} }
public static String getPlaylistSyncFile(Context context) { public static String getPlaylistSyncFile(Context context) {
int instance = Util.getActiveServer(context); int instance = Util.getActiveServer(context);
return getPlaylistSyncFile(context, instance); return getPlaylistSyncFile(context, instance);
} }
public static String getPlaylistSyncFile(Context context, int instance) { public static String getPlaylistSyncFile(Context context, int instance) {
return "sync-playlist-" + (Util.getRestUrl(context, null, instance, false)).hashCode() + ".ser"; return "sync-playlist-" + (Util.getRestUrl(context, null, instance, false)).hashCode() + ".ser";
} }
// Most Recently Added // Most Recently Added
public static ArrayList<String> getSyncedMostRecent(Context context, int instance) { public static ArrayList<String> getSyncedMostRecent(Context context, int instance) {
ArrayList<String> list = FileUtil.deserialize(context, getMostRecentSyncFile(context, instance), ArrayList.class); ArrayList<String> list = FileUtil.deserialize(context, getMostRecentSyncFile(context, instance), ArrayList.class);
if(list == null) { if(list == null) {
list = new ArrayList<String>(); list = new ArrayList<String>();
} }
return list; return list;
} }
public static void removeMostRecentSyncFiles(Context context) { public static void removeMostRecentSyncFiles(Context context) {
int total = Util.getServerCount(context); int total = Util.getServerCount(context);
for(int i = 0; i < total; i++) { for(int i = 0; i < total; i++) {
File file = new File(context.getCacheDir(), getMostRecentSyncFile(context, i)); File file = new File(context.getCacheDir(), getMostRecentSyncFile(context, i));
file.delete(); file.delete();
} }
} }
public static String getMostRecentSyncFile(Context context, int instance) { public static String getMostRecentSyncFile(Context context, int instance) {
return "sync-most_recent-" + (Util.getRestUrl(context, null, instance, false)).hashCode() + ".ser"; return "sync-most_recent-" + (Util.getRestUrl(context, null, instance, false)).hashCode() + ".ser";
} }
public static String joinNames(List<String> names) { public static String joinNames(List<String> names) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
for (String val : names) { for (String val : names) {
builder.append(val).append(", "); builder.append(val).append(", ");
} }
builder.setLength(builder.length() - 2); builder.setLength(builder.length() - 2);
return builder.toString(); return builder.toString();
} }
public static class SyncSet implements Serializable { public static class SyncSet implements Serializable {
public String id; public String id;
public List<String> synced; public List<String> synced;
protected SyncSet() { protected SyncSet() {
} }
public SyncSet(String id) { public SyncSet(String id) {
this.id = id; this.id = id;
} }
public SyncSet(String id, List<String> synced) { public SyncSet(String id, List<String> synced) {
this.id = id; this.id = id;
this.synced = synced; this.synced = synced;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if(obj instanceof SyncSet) { if(obj instanceof SyncSet) {
return this.id.equals(((SyncSet)obj).id); return this.id.equals(((SyncSet)obj).id);
} else { } else {
return false; return false;
} }
} }
@Override @Override
public int hashCode() { public int hashCode() {
return id.hashCode(); return id.hashCode();
} }
} }
} }

View File

@ -19,22 +19,22 @@ public abstract class TabBackgroundTask<T> extends BackgroundTask<T> {
public void execute() { public void execute() {
tabFragment.setProgressVisible(true); tabFragment.setProgressVisible(true);
queue.offer(task = new Task() { queue.offer(task = new Task() {
@Override @Override
public void onDone(T result) { public void onDone(T result) {
tabFragment.setProgressVisible(false); tabFragment.setProgressVisible(false);
done(result); done(result);
} }
@Override @Override
public void onError(Throwable t) { public void onError(Throwable t) {
tabFragment.setProgressVisible(false); tabFragment.setProgressVisible(false);
error(t); error(t);
} }
}); });
} }
@Override @Override
public boolean isCancelled() { public boolean isCancelled() {
return !tabFragment.isAdded() || cancelled.get(); return !tabFragment.isAdded() || cancelled.get();
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2016 (C) Scott Jackson Copyright 2016 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
@ -26,73 +26,73 @@ import net.nullsum.audinaut.activity.SettingsActivity;
import net.nullsum.audinaut.activity.SubsonicFragmentActivity; import net.nullsum.audinaut.activity.SubsonicFragmentActivity;
public final class ThemeUtil { public final class ThemeUtil {
public static final String THEME_DARK = "dark"; public static final String THEME_DARK = "dark";
public static final String THEME_BLACK = "black"; public static final String THEME_BLACK = "black";
public static final String THEME_LIGHT = "light"; public static final String THEME_LIGHT = "light";
public static final String THEME_DAY_NIGHT = "day/night"; public static final String THEME_DAY_NIGHT = "day/night";
public static final String THEME_DAY_BLACK_NIGHT = "day/black"; public static final String THEME_DAY_BLACK_NIGHT = "day/black";
public static String getTheme(Context context) { public static String getTheme(Context context) {
SharedPreferences prefs = Util.getPreferences(context); SharedPreferences prefs = Util.getPreferences(context);
String theme = prefs.getString(Constants.PREFERENCES_KEY_THEME, null); String theme = prefs.getString(Constants.PREFERENCES_KEY_THEME, null);
if(THEME_DAY_NIGHT.equals(theme)) { if(THEME_DAY_NIGHT.equals(theme)) {
int currentNightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; int currentNightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
if(currentNightMode == Configuration.UI_MODE_NIGHT_YES) { if(currentNightMode == Configuration.UI_MODE_NIGHT_YES) {
theme = THEME_DARK; theme = THEME_DARK;
} else { } else {
theme = THEME_LIGHT; theme = THEME_LIGHT;
} }
} else if(THEME_DAY_BLACK_NIGHT.equals(theme)) { } else if(THEME_DAY_BLACK_NIGHT.equals(theme)) {
int currentNightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; int currentNightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
if(currentNightMode == Configuration.UI_MODE_NIGHT_YES) { if(currentNightMode == Configuration.UI_MODE_NIGHT_YES) {
theme = THEME_BLACK; theme = THEME_BLACK;
} else { } else {
theme = THEME_LIGHT; theme = THEME_LIGHT;
} }
} }
return theme; return theme;
} }
public static int getThemeRes(Context context) { public static int getThemeRes(Context context) {
return getThemeRes(context, getTheme(context)); return getThemeRes(context, getTheme(context));
} }
public static int getThemeRes(Context context, String theme) { public static int getThemeRes(Context context, String theme) {
if(context instanceof SubsonicFragmentActivity || context instanceof SettingsActivity) { if(context instanceof SubsonicFragmentActivity || context instanceof SettingsActivity) {
if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true)) { if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true)) {
if (THEME_DARK.equals(theme)) { if (THEME_DARK.equals(theme)) {
return R.style.Theme_Audinaut_Dark_No_Actionbar; return R.style.Theme_Audinaut_Dark_No_Actionbar;
} else if (THEME_BLACK.equals(theme)) { } else if (THEME_BLACK.equals(theme)) {
return R.style.Theme_Audinaut_Black_No_Actionbar; return R.style.Theme_Audinaut_Black_No_Actionbar;
} else { } else {
return R.style.Theme_Audinaut_Light_No_Actionbar; return R.style.Theme_Audinaut_Light_No_Actionbar;
} }
} else { } else {
if (THEME_DARK.equals(theme)) { if (THEME_DARK.equals(theme)) {
return R.style.Theme_Audinaut_Dark_No_Color; return R.style.Theme_Audinaut_Dark_No_Color;
} else if (THEME_BLACK.equals(theme)) { } else if (THEME_BLACK.equals(theme)) {
return R.style.Theme_Audinaut_Black_No_Color; return R.style.Theme_Audinaut_Black_No_Color;
} else { } else {
return R.style.Theme_Audinaut_Light_No_Color; return R.style.Theme_Audinaut_Light_No_Color;
} }
} }
} else { } else {
if (THEME_DARK.equals(theme)) { if (THEME_DARK.equals(theme)) {
return R.style.Theme_Audinaut_Dark; return R.style.Theme_Audinaut_Dark;
} else if (THEME_BLACK.equals(theme)) { } else if (THEME_BLACK.equals(theme)) {
return R.style.Theme_Audinaut_Black; return R.style.Theme_Audinaut_Black;
} else { } else {
return R.style.Theme_Audinaut_Light; return R.style.Theme_Audinaut_Light;
} }
} }
} }
public static void setTheme(Context context, String theme) { public static void setTheme(Context context, String theme) {
SharedPreferences.Editor editor = Util.getPreferences(context).edit(); SharedPreferences.Editor editor = Util.getPreferences(context).edit();
editor.putString(Constants.PREFERENCES_KEY_THEME, theme); editor.putString(Constants.PREFERENCES_KEY_THEME, theme);
editor.apply(); editor.apply();
} }
public static void applyTheme(Context context, String theme) { public static void applyTheme(Context context, String theme) {
context.setTheme(getThemeRes(context, theme)); context.setTheme(getThemeRes(context, theme));
} }
} }

View File

@ -1,20 +1,20 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2015 (C) Scott Jackson Copyright 2015 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
@ -43,50 +43,50 @@ import net.nullsum.audinaut.service.OfflineException;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
public final class UpdateHelper { public final class UpdateHelper {
private static final String TAG = UpdateHelper.class.getSimpleName(); private static final String TAG = UpdateHelper.class.getSimpleName();
public static abstract class EntryInstanceUpdater { public static abstract class EntryInstanceUpdater {
private Entry entry; private Entry entry;
protected int metadataUpdate = DownloadService.METADATA_UPDATED_ALL; protected int metadataUpdate = DownloadService.METADATA_UPDATED_ALL;
public EntryInstanceUpdater(Entry entry) { public EntryInstanceUpdater(Entry entry) {
this.entry = entry; this.entry = entry;
} }
public EntryInstanceUpdater(Entry entry, int metadataUpdate) { public EntryInstanceUpdater(Entry entry, int metadataUpdate) {
this.entry = entry; this.entry = entry;
this.metadataUpdate = metadataUpdate; this.metadataUpdate = metadataUpdate;
} }
public abstract void update(Entry found); public abstract void update(Entry found);
public void execute() { public void execute() {
DownloadService downloadService = DownloadService.getInstance(); DownloadService downloadService = DownloadService.getInstance();
if(downloadService != null && !entry.isDirectory()) { if(downloadService != null && !entry.isDirectory()) {
boolean serializeChanges = false; boolean serializeChanges = false;
List<DownloadFile> downloadFiles = downloadService.getDownloads(); List<DownloadFile> downloadFiles = downloadService.getDownloads();
DownloadFile currentPlaying = downloadService.getCurrentPlaying(); DownloadFile currentPlaying = downloadService.getCurrentPlaying();
for(DownloadFile file: downloadFiles) { for(DownloadFile file: downloadFiles) {
Entry check = file.getSong(); Entry check = file.getSong();
if(entry.getId().equals(check.getId())) { if(entry.getId().equals(check.getId())) {
update(check); update(check);
serializeChanges = true; serializeChanges = true;
if(currentPlaying != null && currentPlaying.getSong() != null && currentPlaying.getSong().getId().equals(entry.getId())) { if(currentPlaying != null && currentPlaying.getSong() != null && currentPlaying.getSong().getId().equals(entry.getId())) {
downloadService.onMetadataUpdate(metadataUpdate); downloadService.onMetadataUpdate(metadataUpdate);
} }
} }
} }
if(serializeChanges) { if(serializeChanges) {
downloadService.serializeQueue(); downloadService.serializeQueue();
} }
} }
Entry find = UpdateView.findEntry(entry); Entry find = UpdateView.findEntry(entry);
if(find != null) { if(find != null) {
update(find); update(find);
} }
} }
} }
} }

View File

@ -1,16 +1,16 @@
/* /*
This file is part of Subsonic. This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
Subsonic is distributed in the hope that it will be useful, Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>. along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson Copyright 2014 (C) Scott Jackson
*/ */
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
@ -43,80 +43,80 @@ import net.nullsum.audinaut.adapter.SettingsAdapter;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
public final class UserUtil { public final class UserUtil {
private static final String TAG = UserUtil.class.getSimpleName(); private static final String TAG = UserUtil.class.getSimpleName();
private static final long MIN_VERIFY_DURATION = 1000L * 60L * 60L; private static final long MIN_VERIFY_DURATION = 1000L * 60L * 60L;
private static int instance = -1; private static int instance = -1;
private static int instanceHash = -1; private static int instanceHash = -1;
private static User currentUser; private static User currentUser;
private static long lastVerifiedTime = 0; private static long lastVerifiedTime = 0;
public static void refreshCurrentUser(Context context, boolean forceRefresh) { public static void refreshCurrentUser(Context context, boolean forceRefresh) {
refreshCurrentUser(context, forceRefresh, false); refreshCurrentUser(context, forceRefresh, false);
} }
public static void refreshCurrentUser(Context context, boolean forceRefresh, boolean unAuth) { public static void refreshCurrentUser(Context context, boolean forceRefresh, boolean unAuth) {
currentUser = null; currentUser = null;
if(unAuth) { if(unAuth) {
lastVerifiedTime = 0; lastVerifiedTime = 0;
} }
seedCurrentUser(context, forceRefresh); seedCurrentUser(context, forceRefresh);
} }
public static void seedCurrentUser(Context context) { public static void seedCurrentUser(Context context) {
seedCurrentUser(context, false); seedCurrentUser(context, false);
} }
public static void seedCurrentUser(final Context context, final boolean refresh) { public static void seedCurrentUser(final Context context, final boolean refresh) {
// Only try to seed if online // Only try to seed if online
if(Util.isOffline(context)) { if(Util.isOffline(context)) {
currentUser = null; currentUser = null;
return; return;
} }
final int instance = Util.getActiveServer(context); final int instance = Util.getActiveServer(context);
final int instanceHash = (instance == 0) ? 0 : Util.getRestUrl(context, null).hashCode(); final int instanceHash = (instance == 0) ? 0 : Util.getRestUrl(context, null).hashCode();
if(UserUtil.instance == instance && UserUtil.instanceHash == instanceHash && currentUser != null) { if(UserUtil.instance == instance && UserUtil.instanceHash == instanceHash && currentUser != null) {
return; return;
} else { } else {
UserUtil.instance = instance; UserUtil.instance = instance;
UserUtil.instanceHash = instanceHash; UserUtil.instanceHash = instanceHash;
} }
new SilentBackgroundTask<Void>(context) { new SilentBackgroundTask<Void>(context) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
currentUser = MusicServiceFactory.getMusicService(context).getUser(refresh, getCurrentUsername(context, instance), context, null); currentUser = MusicServiceFactory.getMusicService(context).getUser(refresh, getCurrentUsername(context, instance), context, null);
// If running, redo cast selector // If running, redo cast selector
DownloadService downloadService = DownloadService.getInstance(); DownloadService downloadService = DownloadService.getInstance();
return null; return null;
} }
@Override @Override
protected void done(Void result) { protected void done(Void result) {
if(context instanceof AppCompatActivity) { if(context instanceof AppCompatActivity) {
((AppCompatActivity) context).supportInvalidateOptionsMenu(); ((AppCompatActivity) context).supportInvalidateOptionsMenu();
} }
} }
@Override @Override
protected void error(Throwable error) { protected void error(Throwable error) {
// Don't do anything, supposed to be background pull // Don't do anything, supposed to be background pull
Log.e(TAG, "Failed to seed user information"); Log.e(TAG, "Failed to seed user information");
} }
}.execute(); }.execute();
} }
public static User getCurrentUser() { public static User getCurrentUser() {
return currentUser; return currentUser;
} }
public static String getCurrentUsername(Context context, int instance) { public static String getCurrentUsername(Context context, int instance) {
SharedPreferences prefs = Util.getPreferences(context); SharedPreferences prefs = Util.getPreferences(context);
return prefs.getString(Constants.PREFERENCES_KEY_USERNAME + instance, null); return prefs.getString(Constants.PREFERENCES_KEY_USERNAME + instance, null);
} }
public static String getCurrentUsername(Context context) { public static String getCurrentUsername(Context context) {
return getCurrentUsername(context, Util.getActiveServer(context)); return getCurrentUsername(context, Util.getActiveServer(context));
} }
} }

Some files were not shown because too many files have changed in this diff Show More