IDE-fueled mega refactor

This commit is contained in:
Andrew Rabert 2018-03-24 21:28:28 -04:00
parent 1396ff5e48
commit c7a49ee88e
267 changed files with 6271 additions and 9399 deletions

6
.gitignore vendored
View File

@ -37,11 +37,7 @@ captures/
# Intellij # Intellij
*.iml *.iml
.idea/workspace.xml .idea
.idea/tasks.xml
.idea/gradle.xml
.idea/dictionaries
.idea/libraries
# External native build folder generated in Android Studio 2.2 and later # External native build folder generated in Android Studio 2.2 and later
.externalNativeBuild .externalNativeBuild

4
.idea/misc.xml generated
View File

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
</project>

9
.idea/modules.xml generated
View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/Audinaut.iml" filepath="$PROJECT_DIR$/Audinaut.iml" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
</modules>
</component>
</project>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>

6
.idea/vcs.xml generated
View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -3,10 +3,6 @@
package="net.nullsum.audinaut" package="net.nullsum.audinaut"
android:installLocation="internalOnly"> android:installLocation="internalOnly">
<instrumentation android:name="android.test.InstrumentationTestRunner"
android:targetPackage="net.nullsum.audinaut"
android:label="Tests" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
@ -21,23 +17,40 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" /> <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" android:maxSdkVersion="22"/> <uses-permission
android:name="android.permission.READ_PHONE_STATE"
android:maxSdkVersion="22" />
<uses-feature android:name="android.hardware.touchscreen" android:required="false" /> <uses-feature
<uses-feature android:name="android.hardware.bluetooth" android:required="false" /> android:name="android.hardware.touchscreen"
<uses-feature android:name="android.hardware.microphone" android:required="false" /> android:required="false" />
<uses-feature android:name="android.hardware.wifi" android:required="false" /> <uses-feature
android:name="android.hardware.bluetooth"
android:required="false" />
<uses-feature
android:name="android.hardware.microphone"
android:required="false" />
<uses-feature
android:name="android.hardware.wifi"
android:required="false" />
<supports-screens android:anyDensity="true" android:xlargeScreens="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true"/> <supports-screens
android:anyDensity="true"
android:largeScreens="true"
android:normalScreens="true"
android:smallScreens="true"
android:xlargeScreens="true" />
<application android:label="@string/common.appname" <application
android:backupAgent="net.nullsum.audinaut.util.SettingsBackupAgent" android:backupAgent="net.nullsum.audinaut.util.SettingsBackupAgent"
android:icon="@drawable/launch" android:icon="@drawable/launch"
android:label="@string/common.appname"
android:theme="@style/LaunchScreen"> android:theme="@style/LaunchScreen">
<uses-library android:name="android.test.runner" /> <uses-library android:name="android.test.runner" />
<activity android:name="net.nullsum.audinaut.activity.SubsonicFragmentActivity" <activity
android:name="net.nullsum.audinaut.activity.SubsonicFragmentActivity"
android:configChanges="orientation|keyboardHidden" android:configChanges="orientation|keyboardHidden"
android:launchMode="singleTask"> android:launchMode="singleTask">
<intent-filter> <intent-filter>
@ -46,11 +59,13 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="net.nullsum.audinaut.activity.SettingsActivity" <activity
android:name="net.nullsum.audinaut.activity.SettingsActivity"
android:configChanges="orientation|keyboardHidden" android:configChanges="orientation|keyboardHidden"
android:launchMode="singleTask" /> android:launchMode="singleTask" />
<activity android:name="net.nullsum.audinaut.activity.VoiceQueryReceiverActivity" <activity
android:name="net.nullsum.audinaut.activity.VoiceQueryReceiverActivity"
android:launchMode="singleTask"> android:launchMode="singleTask">
<intent-filter> <intent-filter>
<action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" /> <action android:name="android.media.action.MEDIA_PLAY_FROM_SEARCH" />
@ -58,25 +73,29 @@
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="net.nullsum.audinaut.activity.QueryReceiverActivity" <activity
android:name="net.nullsum.audinaut.activity.QueryReceiverActivity"
android:launchMode="singleTask"> android:launchMode="singleTask">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.SEARCH" /> <action android:name="android.intent.action.SEARCH" />
</intent-filter> </intent-filter>
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable"/> <meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity> </activity>
<activity <activity
android:name="net.nullsum.audinaut.activity.EditPlayActionActivity" android:name="net.nullsum.audinaut.activity.EditPlayActionActivity"
android:label="@string/tasker.start_playing" android:icon="@drawable/launch"
android:icon="@drawable/launch"> android:label="@string/tasker.start_playing">
<intent-filter> <intent-filter>
<action android:name="com.twofortyfouram.locale.intent.action.EDIT_SETTING" /> <action android:name="com.twofortyfouram.locale.intent.action.EDIT_SETTING" />
</intent-filter> </intent-filter>
</activity> </activity>
<service android:name=".service.DownloadService" <service
android:name=".service.DownloadService"
android:label="Audinaut Playback Service" /> android:label="Audinaut Playback Service" />
<service android:name="net.nullsum.audinaut.service.sync.AuthenticatorService"> <service android:name="net.nullsum.audinaut.service.sync.AuthenticatorService">
@ -84,17 +103,18 @@
<action android:name="android.accounts.AccountAuthenticator" /> <action android:name="android.accounts.AccountAuthenticator" />
</intent-filter> </intent-filter>
<meta-data android:name="android.accounts.AccountAuthenticator" <meta-data
android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/authenticator" /> android:resource="@xml/authenticator" />
</service> </service>
<service android:name="net.nullsum.audinaut.service.HeadphoneListenerService" <service
android:name="net.nullsum.audinaut.service.HeadphoneListenerService"
android:label="Audinaut Headphone Listener" /> android:label="Audinaut Headphone Listener" />
<receiver
android:name="net.nullsum.audinaut.receiver.BootReceiver"> <receiver android:name="net.nullsum.audinaut.receiver.BootReceiver">
<intent-filter> <intent-filter>
<action <action android:name="android.intent.action.BOOT_COMPLETED" />
android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter> </intent-filter>
</receiver> </receiver>
@ -116,7 +136,9 @@
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter> </intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget4x1"/> <meta-data
android:name="android.appwidget.provider"
android:resource="@xml/appwidget4x1" />
</receiver> </receiver>
<receiver <receiver
android:name="net.nullsum.audinaut.provider.AudinautWidget4x2" android:name="net.nullsum.audinaut.provider.AudinautWidget4x2"
@ -124,7 +146,9 @@
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter> </intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget4x2"/> <meta-data
android:name="android.appwidget.provider"
android:resource="@xml/appwidget4x2" />
</receiver> </receiver>
<receiver <receiver
android:name="net.nullsum.audinaut.provider.AudinautWidget4x3" android:name="net.nullsum.audinaut.provider.AudinautWidget4x3"
@ -132,7 +156,9 @@
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter> </intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget4x3"/> <meta-data
android:name="android.appwidget.provider"
android:resource="@xml/appwidget4x3" />
</receiver> </receiver>
<receiver <receiver
android:name="net.nullsum.audinaut.provider.AudinautWidget4x4" android:name="net.nullsum.audinaut.provider.AudinautWidget4x4"
@ -140,21 +166,26 @@
<intent-filter> <intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter> </intent-filter>
<meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget4x4"/> <meta-data
android:name="android.appwidget.provider"
android:resource="@xml/appwidget4x4" />
</receiver> </receiver>
<receiver <receiver
android:name="net.nullsum.audinaut.receiver.PlayActionReceiver"> android:name="net.nullsum.audinaut.receiver.PlayActionReceiver"
android:permission="">
<intent-filter> <intent-filter>
<action android:name="com.twofortyfouram.locale.intent.action.FIRE_SETTING" /> <action android:name="com.twofortyfouram.locale.intent.action.FIRE_SETTING" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<provider android:name="net.nullsum.audinaut.provider.AudinautSearchProvider" <provider
android:name="net.nullsum.audinaut.provider.AudinautSearchProvider"
android:authorities="net.nullsum.audinaut.provider.AudinautSearchProvider" /> android:authorities="net.nullsum.audinaut.provider.AudinautSearchProvider" />
<meta-data android:name="android.app.default_searchable" <meta-data
android:name="android.app.default_searchable"
android:value="net.nullsum.audinaut.activity.QueryReceiverActivity" /> android:value="net.nullsum.audinaut.activity.QueryReceiverActivity" />
</application> </application>

View File

@ -16,12 +16,10 @@
package net.nullsum.audinaut.activity; package net.nullsum.audinaut.activity;
import android.app.Activity; import android.app.Activity;
import android.support.v7.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AlertDialog;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
@ -29,13 +27,9 @@ import android.view.View;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.Button; import android.widget.Button;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText; import android.widget.EditText;
import android.widget.Spinner; import android.widget.Spinner;
import java.util.ArrayList;
import java.util.List;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.Genre; import net.nullsum.audinaut.domain.Genre;
import net.nullsum.audinaut.service.MusicService; import net.nullsum.audinaut.service.MusicService;
@ -45,6 +39,9 @@ import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.LoadingTask; import net.nullsum.audinaut.util.LoadingTask;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import java.util.ArrayList;
import java.util.List;
public class EditPlayActionActivity extends SubsonicActivity { public class EditPlayActionActivity extends SubsonicActivity {
private CheckBox shuffleCheckbox; private CheckBox shuffleCheckbox;
private CheckBox startYearCheckbox; private CheckBox startYearCheckbox;
@ -64,36 +61,23 @@ public class EditPlayActionActivity extends SubsonicActivity {
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 = findViewById(R.id.edit_shuffle_checkbox);
shuffleCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { shuffleCheckbox.setOnCheckedChangeListener((view, isChecked) -> {
@Override
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 = findViewById(R.id.edit_start_year_checkbox);
startYearBox = (EditText) findViewById(R.id.edit_start_year); startYearBox = 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((view, isChecked) -> startYearBox.setEnabled(isChecked));
@Override
public void onCheckedChanged(CompoundButton view, boolean isChecked) {
startYearBox.setEnabled(isChecked);
}
});
endYearCheckbox = (CheckBox) findViewById(R.id.edit_end_year_checkbox); endYearCheckbox = findViewById(R.id.edit_end_year_checkbox);
endYearBox = (EditText) findViewById(R.id.edit_end_year); endYearBox = findViewById(R.id.edit_end_year);
endYearCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { endYearCheckbox.setOnCheckedChangeListener((view, isChecked) -> endYearBox.setEnabled(isChecked));
@Override
public void onCheckedChanged(CompoundButton view, boolean isChecked) {
endYearBox.setEnabled(isChecked);
}
});
genreButton = (Button) findViewById(R.id.edit_genre_spinner); genreButton = 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) {
@ -105,7 +89,7 @@ public class EditPlayActionActivity extends SubsonicActivity {
@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 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);
@ -116,14 +100,12 @@ public class EditPlayActionActivity extends SubsonicActivity {
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()]), (dialog, 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();
@ -145,7 +127,7 @@ public class EditPlayActionActivity extends SubsonicActivity {
}); });
genreButton.setText(doNothing); genreButton.setText(doNothing);
offlineSpinner = (Spinner) findViewById(R.id.edit_offline_spinner); offlineSpinner = 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);
@ -238,6 +220,7 @@ public class EditPlayActionActivity extends SubsonicActivity {
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

@ -23,13 +23,9 @@ import android.app.Activity;
import android.app.SearchManager; import android.app.SearchManager;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.provider.SearchRecentSuggestions;
import android.util.Log;
import net.nullsum.audinaut.fragments.SubsonicFragment;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.provider.AudinautSearchProvider;
/** /**
* Receives search queries and forwards to the SearchFragment. * Receives search queries and forwards to the SearchFragment.
@ -38,8 +34,6 @@ import net.nullsum.audinaut.provider.AudinautSearchProvider;
*/ */
public class QueryReceiverActivity extends Activity { public class QueryReceiverActivity extends Activity {
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);
@ -51,7 +45,6 @@ public class QueryReceiverActivity extends Activity {
showResult(intent.getDataString(), intent.getStringExtra(SearchManager.EXTRA_DATA_KEY)); showResult(intent.getDataString(), intent.getStringExtra(SearchManager.EXTRA_DATA_KEY));
} }
finish(); finish();
Util.disablePendingTransition(this);
} }
private void doSearch() { private void doSearch() {
@ -63,6 +56,7 @@ public class QueryReceiverActivity extends Activity {
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);

View File

@ -18,7 +18,6 @@
*/ */
package net.nullsum.audinaut.activity; package net.nullsum.audinaut.activity;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
@ -28,8 +27,6 @@ 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 PreferenceCompatFragment fragment;
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -38,7 +35,7 @@ public class SettingsActivity extends SubsonicActivity {
setContentView(R.layout.settings_activity); setContentView(R.layout.settings_activity);
if (savedInstanceState == null) { if (savedInstanceState == null) {
fragment = new SettingsFragment(); PreferenceCompatFragment 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);
@ -50,7 +47,7 @@ public class SettingsActivity extends SubsonicActivity {
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 = findViewById(R.id.main_toolbar);
setSupportActionBar(mainToolbar); setSupportActionBar(mainToolbar);
} }
} }

View File

@ -18,114 +18,106 @@
*/ */
package net.nullsum.audinaut.activity; package net.nullsum.audinaut.activity;
import android.app.UiModeManager;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.media.AudioManager; import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Environment; import android.os.Environment;
import android.os.Handler; import android.os.Handler;
import android.support.design.widget.NavigationView; import android.support.design.widget.NavigationView;
import android.support.v4.app.ActivityCompat; import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.support.v4.content.ContextCompat;
import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AlertDialog; import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.AppCompatDelegate; import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.animation.AnimationUtils; import android.view.animation.AnimationUtils;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener; import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; import android.widget.TextView;
import net.nullsum.audinaut.R;
import net.nullsum.audinaut.fragments.SubsonicFragment;
import net.nullsum.audinaut.service.DownloadService;
import net.nullsum.audinaut.service.HeadphoneListenerService;
import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.DrawableTint;
import net.nullsum.audinaut.util.ImageLoader;
import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.util.ThemeUtil;
import net.nullsum.audinaut.util.UserUtil;
import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.view.UpdateView;
import java.io.File; import java.io.File;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import net.nullsum.audinaut.R; import static android.Manifest.permission;
import net.nullsum.audinaut.fragments.SubsonicFragment;
import net.nullsum.audinaut.service.DownloadService;
import net.nullsum.audinaut.service.HeadphoneListenerService;
import net.nullsum.audinaut.service.MusicService;
import net.nullsum.audinaut.service.MusicServiceFactory;
import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.DrawableTint;
import net.nullsum.audinaut.util.ImageLoader;
import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.util.ThemeUtil;
import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.view.UpdateView;
import net.nullsum.audinaut.util.UserUtil;
import static android.Manifest.*;
public class SubsonicActivity extends AppCompatActivity implements OnItemSelectedListener { public class SubsonicActivity extends AppCompatActivity implements OnItemSelectedListener {
private static final String TAG = SubsonicActivity.class.getSimpleName(); private static final String TAG = SubsonicActivity.class.getSimpleName();
private static ImageLoader IMAGE_LOADER;
protected static String theme;
protected static boolean fullScreen;
protected static boolean actionbarColored;
private static final int MENU_GROUP_SERVER = 10; private static final int MENU_GROUP_SERVER = 10;
private static final int MENU_ITEM_SERVER_BASE = 100; private static final int MENU_ITEM_SERVER_BASE = 100;
private static final int PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1; private static final int PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1;
private static String theme;
private final List<Runnable> afterServiceAvailable = new ArrayList<>(); private static boolean fullScreen;
private boolean drawerIdle = true; private static boolean actionbarColored;
private boolean destroyed = false; private static ImageLoader IMAGE_LOADER;
private boolean finished = false;
protected List<SubsonicFragment> backStack = new ArrayList<SubsonicFragment>();
protected SubsonicFragment currentFragment;
protected View primaryContainer;
protected View secondaryContainer;
protected boolean touchscreen = true;
protected Handler handler = new Handler();
Spinner actionBarSpinner;
ArrayAdapter<CharSequence> spinnerAdapter;
ViewGroup rootView;
DrawerLayout drawer;
ActionBarDrawerToggle drawerToggle;
NavigationView drawerList;
View drawerHeader;
ImageView drawerHeaderToggle;
TextView drawerServerName;
TextView drawerUserName;
int lastSelectedPosition = 0;
boolean showingTabs = true;
boolean drawerOpen = false;
SharedPreferences.OnSharedPreferenceChangeListener preferencesListener;
static { static {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO); AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO);
} }
final List<SubsonicFragment> backStack = new ArrayList<>();
final Handler handler = new Handler();
private final List<Runnable> afterServiceAvailable = new ArrayList<>();
SubsonicFragment currentFragment;
View secondaryContainer;
DrawerLayout drawer;
ActionBarDrawerToggle drawerToggle;
NavigationView drawerList;
int lastSelectedPosition = 0;
private boolean touchscreen = true;
private Spinner actionBarSpinner;
private ArrayAdapter<CharSequence> spinnerAdapter;
private View drawerHeader;
private ImageView drawerHeaderToggle;
private TextView drawerServerName;
private TextView drawerUserName;
private boolean showingTabs = true;
private boolean drawerOpen = false;
private SharedPreferences.OnSharedPreferenceChangeListener preferencesListener;
private boolean drawerIdle = true;
private boolean destroyed = false;
public synchronized static ImageLoader getStaticImageLoader(Context context) {
if (IMAGE_LOADER == null) {
IMAGE_LOADER = new ImageLoader(context);
}
return IMAGE_LOADER;
}
@Override @Override
protected void onCreate(Bundle bundle) { protected void onCreate(Bundle bundle) {
UiModeManager uiModeManager = (UiModeManager) getSystemService(UI_MODE_SERVICE);
PackageManager pm = getPackageManager(); PackageManager pm = getPackageManager();
if (!pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) { if (!pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN)) {
touchscreen = false; touchscreen = false;
@ -156,9 +148,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
switch (requestCode) { switch (requestCode) {
case PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE: { case PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE: {
// If request is cancelled, the result arrays are empty. // If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (!(grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
} else {
Util.toast(this, R.string.permission_external_storage_failed); Util.toast(this, R.string.permission_external_storage_failed);
finish(); finish();
} }
@ -183,10 +173,10 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
} }
} }
protected void createCustomActionBarView() { private void createCustomActionBarView() {
actionBarSpinner = (Spinner) getLayoutInflater().inflate(R.layout.actionbar_spinner, null); actionBarSpinner = (Spinner) getLayoutInflater().inflate(R.layout.actionbar_spinner, null);
if ((this instanceof SubsonicFragmentActivity || this instanceof SettingsActivity) && (Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true) || ThemeUtil.getThemeRes(this) != R.style.Theme_Audinaut_Light_No_Color)) { if ((this instanceof SubsonicFragmentActivity || this instanceof SettingsActivity) && (Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true) || ThemeUtil.getThemeRes(this) != R.style.Theme_Audinaut_Light_No_Color)) {
actionBarSpinner.setBackgroundDrawable(DrawableTint.getTintedDrawableFromColor(this, R.drawable.abc_spinner_mtrl_am_alpha, android.R.color.white)); actionBarSpinner.setBackground(DrawableTint.getTintedDrawableFromColor(this));
} }
spinnerAdapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item); spinnerAdapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
@ -228,26 +218,18 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
Util.getPreferences(this).unregisterOnSharedPreferenceChangeListener(preferencesListener); Util.getPreferences(this).unregisterOnSharedPreferenceChangeListener(preferencesListener);
} }
@Override
public void finish() {
super.finish();
Util.disablePendingTransition(this);
}
@Override @Override
public void setContentView(int viewId) { public void setContentView(int viewId) {
super.setContentView(R.layout.abstract_activity); super.setContentView(R.layout.abstract_activity);
rootView = (ViewGroup) findViewById(R.id.content_frame); ViewGroup rootView = findViewById(R.id.content_frame);
if (viewId != 0) { if (viewId != 0) {
LayoutInflater layoutInflater = getLayoutInflater(); LayoutInflater layoutInflater = getLayoutInflater();
layoutInflater.inflate(viewId, rootView); layoutInflater.inflate(viewId, rootView);
} }
drawerList = (NavigationView) findViewById(R.id.left_drawer); drawerList = findViewById(R.id.left_drawer);
drawerList.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { drawerList.setNavigationItemSelectedListener(menuItem -> {
@Override
public boolean onNavigationItemSelected(final MenuItem menuItem) {
if (showingTabs) { if (showingTabs) {
// Settings are on a different selectable track // Settings are on a different selectable track
if (menuItem.getItemId() != R.id.drawer_settings && menuItem.getItemId() != R.id.drawer_offline) { if (menuItem.getItemId() != R.id.drawer_settings && menuItem.getItemId() != R.id.drawer_offline) {
@ -281,31 +263,27 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
} }
return false; return false;
}
}); });
drawerHeader = drawerList.inflateHeaderView(R.layout.drawer_header); drawerHeader = drawerList.inflateHeaderView(R.layout.drawer_header);
drawerHeader.setOnClickListener(new View.OnClickListener() { drawerHeader.setOnClickListener(v -> {
@Override
public void onClick(View v) {
if (showingTabs) { if (showingTabs) {
populateServers(); populateServers();
} else { } else {
populateTabs(); populateTabs();
} }
}
}); });
drawerHeaderToggle = (ImageView) drawerHeader.findViewById(R.id.header_select_image); drawerHeaderToggle = drawerHeader.findViewById(R.id.header_select_image);
drawerServerName = (TextView) drawerHeader.findViewById(R.id.header_server_name); drawerServerName = drawerHeader.findViewById(R.id.header_server_name);
drawerUserName = (TextView) drawerHeader.findViewById(R.id.header_user_name); drawerUserName = drawerHeader.findViewById(R.id.header_user_name);
updateDrawerHeader(); updateDrawerHeader();
drawer = (DrawerLayout) findViewById(R.id.drawer_layout); drawer = findViewById(R.id.drawer_layout);
// Pass in toolbar if it exists // Pass in toolbar if it exists
Toolbar toolbar = (Toolbar) findViewById(R.id.main_toolbar); Toolbar toolbar = findViewById(R.id.main_toolbar);
drawerToggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.common_appname, R.string.common_appname) { drawerToggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.common_appname, R.string.common_appname) {
@Override @Override
public void onDrawerClosed(View view) { public void onDrawerClosed(View view) {
@ -324,7 +302,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
if (lastSelectedPosition == R.id.drawer_downloading) { if (lastSelectedPosition == R.id.drawer_downloading) {
downloadingVisible = true; downloadingVisible = true;
} }
setDrawerItemVisible(R.id.drawer_downloading, downloadingVisible); setDrawerItemVisible(downloadingVisible);
drawerIdle = true; drawerIdle = true;
drawerOpen = true; drawerOpen = true;
@ -336,24 +314,13 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
drawerIdle = false; drawerIdle = false;
} }
}; };
drawer.setDrawerListener(drawerToggle); drawer.addDrawerListener(drawerToggle);
drawerToggle.setDrawerIndicatorEnabled(true); drawerToggle.setDrawerIndicatorEnabled(true);
drawer.setOnTouchListener(new View.OnTouchListener() { drawer.setOnTouchListener((v, event) -> drawerIdle && currentFragment != null && currentFragment.getGestureDetector() != null && currentFragment.getGestureDetector().onTouchEvent(event));
public boolean onTouch(View v, MotionEvent event) {
if (drawerIdle && currentFragment != null && currentFragment.getGestureDetector() != null) {
return currentFragment.getGestureDetector().onTouchEvent(event);
} else {
return false;
}
}
});
// Check whether this is a tablet or not // Check whether this is a tablet or not
secondaryContainer = findViewById(R.id.fragment_second_container); secondaryContainer = findViewById(R.id.fragment_second_container);
if(secondaryContainer != null) {
primaryContainer = findViewById(R.id.fragment_container);
}
} }
@Override @Override
@ -370,6 +337,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
savedInstanceState.putInt(Constants.MAIN_BACK_STACK_SIZE, backStack.size() + 1); savedInstanceState.putInt(Constants.MAIN_BACK_STACK_SIZE, backStack.size() + 1);
savedInstanceState.putInt(Constants.FRAGMENT_POSITION, lastSelectedPosition); savedInstanceState.putInt(Constants.FRAGMENT_POSITION, lastSelectedPosition);
} }
@Override @Override
public void onRestoreInstanceState(Bundle savedInstanceState) { public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState); super.onRestoreInstanceState(savedInstanceState);
@ -452,6 +420,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
} }
return true; return true;
} }
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
if (drawerToggle != null && drawerToggle.onOptionsItemSelected(item)) { if (drawerToggle != null && drawerToggle.onOptionsItemSelected(item)) {
@ -464,15 +433,6 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
return getCurrentFragment().onOptionsItemSelected(item); return getCurrentFragment().onOptionsItemSelected(item);
} }
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
boolean isVolumeDown = keyCode == KeyEvent.KEYCODE_VOLUME_DOWN;
boolean isVolumeUp = keyCode == KeyEvent.KEYCODE_VOLUME_UP;
boolean isVolumeAdjust = isVolumeDown || isVolumeUp;
return super.onKeyDown(keyCode, event);
}
@Override @Override
public void setTitle(CharSequence title) { public void setTitle(CharSequence title) {
if (title != null && getSupportActionBar() != null && !title.equals(getSupportActionBar().getTitle())) { if (title != null && getSupportActionBar() != null && !title.equals(getSupportActionBar().getTitle())) {
@ -480,6 +440,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
recreateSpinner(); recreateSpinner();
} }
} }
public void setSubtitle(CharSequence title) { public void setSubtitle(CharSequence title) {
getSupportActionBar().setSubtitle(title); getSupportActionBar().setSubtitle(title);
} }
@ -503,17 +464,10 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
drawerList.getMenu().clear(); drawerList.getMenu().clear();
drawerList.inflateMenu(R.menu.drawer_navigation); drawerList.inflateMenu(R.menu.drawer_navigation);
SharedPreferences prefs = Util.getPreferences(this);
boolean sharedEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_SHARED_ENABLED, true) && !Util.isOffline(this);
MenuItem offlineMenuItem = drawerList.getMenu().findItem(R.id.drawer_offline); MenuItem offlineMenuItem = drawerList.getMenu().findItem(R.id.drawer_offline);
if (Util.isOffline(this)) { if (Util.isOffline(this)) {
if (lastSelectedPosition == 0 || lastSelectedPosition == R.id.drawer_library) { if (lastSelectedPosition == 0 || lastSelectedPosition == R.id.drawer_library) {
String newFragment = Util.openToTab(this); String newFragment = "Artist";
if(newFragment == null || "Library".equals(newFragment)) {
newFragment = "Artist";
}
lastSelectedPosition = getDrawerItemId(newFragment); lastSelectedPosition = getDrawerItemId(newFragment);
drawerItemSelected(newFragment); drawerItemSelected(newFragment);
} }
@ -533,6 +487,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
showingTabs = true; showingTabs = true;
} }
private void populateServers() { private void populateServers() {
drawerList.getMenu().clear(); drawerList.getMenu().clear();
@ -549,21 +504,22 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
showingTabs = false; showingTabs = false;
} }
private void setDrawerItemVisible(int id, boolean visible) {
MenuItem item = drawerList.getMenu().findItem(id); private void setDrawerItemVisible(boolean visible) {
MenuItem item = drawerList.getMenu().findItem(R.id.drawer_downloading);
if (item != null) { if (item != null) {
item.setVisible(visible); item.setVisible(visible);
} }
} }
protected void drawerItemSelected(String fragmentType) { void drawerItemSelected(String fragmentType) {
if (currentFragment != null) { if (currentFragment != null) {
currentFragment.stopActionMode(); currentFragment.stopActionMode();
} }
startFragmentActivity(fragmentType); startFragmentActivity(fragmentType);
} }
public void startFragmentActivity(String fragmentType) { void startFragmentActivity(String fragmentType) {
Intent intent = new Intent(); Intent intent = new Intent();
intent.setClass(SubsonicActivity.this, SubsonicFragmentActivity.class); intent.setClass(SubsonicActivity.this, SubsonicFragmentActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
@ -577,20 +533,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
finish(); finish();
} }
protected void exit() { boolean onBackPressedSupport() {
if(((Object) this).getClass() != SubsonicFragmentActivity.class) {
Intent intent = new Intent(this, SubsonicFragmentActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
Util.startActivityWithoutTransition(this, intent);
} else {
finished = true;
this.stopService(new Intent(this, DownloadService.class));
this.finish();
}
}
public boolean onBackPressedSupport() {
if (drawerOpen) { if (drawerOpen) {
drawer.closeDrawers(); drawer.closeDrawers();
return false; return false;
@ -613,9 +556,10 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
return this.currentFragment; return this.currentFragment;
} }
public void replaceFragment(SubsonicFragment fragment, int tag) { void replaceFragment(SubsonicFragment fragment, int tag) {
replaceFragment(fragment, tag, false); replaceFragment(fragment, tag, false);
} }
public void replaceFragment(SubsonicFragment fragment, int tag, boolean replaceCurrent) { public void replaceFragment(SubsonicFragment fragment, int tag, boolean replaceCurrent) {
SubsonicFragment oldFragment = currentFragment; SubsonicFragment oldFragment = currentFragment;
if (currentFragment != null) { if (currentFragment != null) {
@ -643,9 +587,6 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
if (backStack.size() > 1) { if (backStack.size() > 1) {
// Move old right to left if there is a backstack already // Move old right to left if there is a backstack already
SubsonicFragment newLeftFragment = backStack.get(backStack.size() - 1); SubsonicFragment newLeftFragment = backStack.get(backStack.size() - 1);
if(replaceCurrent) {
// trans.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right);
}
trans.remove(newLeftFragment); trans.remove(newLeftFragment);
// Only move right to left if replaceCurrent is false // Only move right to left if replaceCurrent is false
@ -679,6 +620,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
} }
recreateSpinner(); recreateSpinner();
} }
public void removeCurrent() { public void removeCurrent() {
// Don't try to remove current if there is no backstack to remove from // Don't try to remove current if there is no backstack to remove from
if (backStack.isEmpty()) { if (backStack.isEmpty()) {
@ -735,16 +677,6 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
} }
recreateSpinner(); recreateSpinner();
} }
public void replaceExistingFragment(SubsonicFragment fragment, int tag) {
FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
trans.remove(currentFragment);
trans.add(R.id.fragment_container, fragment, tag + "");
trans.commit();
currentFragment = fragment;
currentFragment.setPrimaryFragment(true);
supportInvalidateOptionsMenu();
}
public void invalidate() { public void invalidate() {
if (currentFragment != null) { if (currentFragment != null) {
@ -759,7 +691,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
supportInvalidateOptionsMenu(); supportInvalidateOptionsMenu();
} }
protected void recreateSpinner() { void recreateSpinner() {
if (currentFragment == null || currentFragment.getTitle() == null) { if (currentFragment == null || currentFragment.getTitle() == null) {
return; return;
} }
@ -801,19 +733,10 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
} }
} }
protected void restart() { private void restart() {
restart(true);
}
protected void restart(boolean resumePosition) {
Intent intent = new Intent(this, this.getClass()); Intent intent = new Intent(this, this.getClass());
intent.putExtras(getIntent()); intent.putExtras(getIntent());
if(resumePosition) {
intent.putExtra(Constants.FRAGMENT_POSITION, lastSelectedPosition); intent.putExtra(Constants.FRAGMENT_POSITION, lastSelectedPosition);
} else {
String fragmentType = Util.openToTab(this);
intent.putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, fragmentType);
intent.putExtra(Constants.FRAGMENT_POSITION, getDrawerItemId(fragmentType));
}
finish(); finish();
Util.startActivityWithoutTransition(this, intent); Util.startActivityWithoutTransition(this, intent);
} }
@ -821,7 +744,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
private void applyTheme() { private void applyTheme() {
theme = ThemeUtil.getTheme(this); theme = ThemeUtil.getTheme(this);
if(theme != null && theme.indexOf("fullscreen") != -1) { if (theme != null && theme.contains("fullscreen")) {
theme = theme.substring(0, theme.indexOf("_fullscreen")); theme = theme.substring(0, theme.indexOf("_fullscreen"));
ThemeUtil.setTheme(this, theme); ThemeUtil.setTheme(this, theme);
} }
@ -829,6 +752,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
ThemeUtil.applyTheme(this, theme); ThemeUtil.applyTheme(this, theme);
actionbarColored = Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true); actionbarColored = Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true);
} }
private void applyFullscreen() { private void applyFullscreen() {
fullScreen = Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_FULL_SCREEN, false); fullScreen = Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_FULL_SCREEN, false);
if (fullScreen) { if (fullScreen) {
@ -851,14 +775,9 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
} }
return IMAGE_LOADER; return IMAGE_LOADER;
} }
public synchronized static ImageLoader getStaticImageLoader(Context context) {
if (IMAGE_LOADER == null) {
IMAGE_LOADER = new ImageLoader(context);
}
return IMAGE_LOADER;
}
public DownloadService getDownloadService() { public DownloadService getDownloadService() {
boolean finished = false;
if (finished) { if (finished) {
return null; return null;
} }
@ -883,6 +802,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
} }
return downloadService; return downloadService;
} }
public void runWhenServiceAvailable(Runnable runnable) { public void runWhenServiceAvailable(Runnable runnable) {
if (getDownloadService() != null) { if (getDownloadService() != null) {
runnable.run(); runnable.run();
@ -891,14 +811,10 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
checkIfServiceAvailable(); checkIfServiceAvailable();
} }
} }
private void checkIfServiceAvailable() { private void checkIfServiceAvailable() {
if (getDownloadService() == null) { if (getDownloadService() == null) {
handler.postDelayed(new Runnable() { handler.postDelayed(this::checkIfServiceAvailable, 50);
@Override
public void run() {
checkIfServiceAvailable();
}
}, 50);
} else if (afterServiceAvailable.size() > 0) { } else if (afterServiceAvailable.size() > 0) {
for (Runnable runnable : afterServiceAvailable) { for (Runnable runnable : afterServiceAvailable) {
handler.post(runnable); handler.post(runnable);
@ -907,10 +823,6 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
} }
} }
public static String getThemeName() {
return theme;
}
public boolean isTouchscreen() { public boolean isTouchscreen() {
return touchscreen; return touchscreen;
} }
@ -918,11 +830,12 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
public void openNowPlaying() { public void openNowPlaying() {
} }
public void closeNowPlaying() { public void closeNowPlaying() {
} }
public void setActiveServer(int instance) { private void setActiveServer(int instance) {
if (Util.getActiveServer(this) != instance) { if (Util.getActiveServer(this) != instance) {
final DownloadService service = getDownloadService(); final DownloadService service = getDownloadService();
if (service != null) { if (service != null) {
@ -937,11 +850,12 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
} }
Util.setActiveServer(this, instance); Util.setActiveServer(this, instance);
invalidate(); invalidate();
UserUtil.refreshCurrentUser(this, false, true); UserUtil.refreshCurrentUser(this);
updateDrawerHeader(); updateDrawerHeader();
} }
} }
public void updateDrawerHeader() {
private void updateDrawerHeader() {
if (Util.isOffline(this)) { if (Util.isOffline(this)) {
drawerServerName.setText(R.string.select_album_offline); drawerServerName.setText(R.string.select_album_offline);
drawerUserName.setText(""); drawerUserName.setText("");
@ -955,7 +869,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
} }
} }
public void toggleOffline() { private void toggleOffline() {
boolean isOffline = Util.isOffline(this); boolean isOffline = Util.isOffline(this);
Util.setOffline(this, !isOffline); Util.setOffline(this, !isOffline);
invalidate(); invalidate();
@ -969,7 +883,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
drawer.closeDrawers(); drawer.closeDrawers();
} }
public int getDrawerItemId(String fragmentType) { int getDrawerItemId(String fragmentType) {
if (fragmentType == null) { if (fragmentType == null) {
return R.id.drawer_library; return R.id.drawer_library;
} }
@ -1013,7 +927,6 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
PackageInfo packageInfo = context.getPackageManager().getPackageInfo("net.nullsum.audinaut", 0); PackageInfo packageInfo = context.getPackageManager().getPackageInfo("net.nullsum.audinaut", 0);
file = new File(Environment.getExternalStorageDirectory(), "audinaut-stacktrace.txt"); file = new File(Environment.getExternalStorageDirectory(), "audinaut-stacktrace.txt");
printWriter = new PrintWriter(file); printWriter = new PrintWriter(file);
printWriter.println("Android API level: " + Build.VERSION.SDK);
printWriter.println("Subsonic version name: " + packageInfo.versionName); printWriter.println("Subsonic version name: " + packageInfo.versionName);
printWriter.println("Subsonic version code: " + packageInfo.versionCode); printWriter.println("Subsonic version code: " + packageInfo.versionCode);
printWriter.println(); printWriter.println();

View File

@ -20,42 +20,28 @@ package net.nullsum.audinaut.activity;
import android.accounts.Account; import android.accounts.Account;
import android.accounts.AccountManager; import android.accounts.AccountManager;
import android.app.Dialog;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction; import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar; import android.support.v7.widget.Toolbar;
import android.util.Log; import android.util.Log;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.sothree.slidinguppanel.SlidingUpPanelLayout.PanelState;
import com.sothree.slidinguppanel.SlidingUpPanelLayout; import com.sothree.slidinguppanel.SlidingUpPanelLayout;
import com.sothree.slidinguppanel.SlidingUpPanelLayout.PanelState;
import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.PlayerQueue;
import net.nullsum.audinaut.domain.PlayerState; import net.nullsum.audinaut.domain.PlayerState;
import net.nullsum.audinaut.fragments.DownloadFragment; import net.nullsum.audinaut.fragments.DownloadFragment;
import net.nullsum.audinaut.fragments.NowPlayingFragment; import net.nullsum.audinaut.fragments.NowPlayingFragment;
@ -66,8 +52,6 @@ import net.nullsum.audinaut.fragments.SelectPlaylistFragment;
import net.nullsum.audinaut.fragments.SubsonicFragment; import net.nullsum.audinaut.fragments.SubsonicFragment;
import net.nullsum.audinaut.service.DownloadFile; import net.nullsum.audinaut.service.DownloadFile;
import net.nullsum.audinaut.service.DownloadService; import net.nullsum.audinaut.service.DownloadService;
import net.nullsum.audinaut.service.MusicService;
import net.nullsum.audinaut.service.MusicServiceFactory;
import net.nullsum.audinaut.updates.Updater; import net.nullsum.audinaut.updates.Updater;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.FileUtil; import net.nullsum.audinaut.util.FileUtil;
@ -75,15 +59,16 @@ import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.util.UserUtil; import net.nullsum.audinaut.util.UserUtil;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import java.io.File;
import java.util.List;
/** /**
* Created by Scott on 10/14/13. * Created by Scott on 10/14/13.
*/ */
public class SubsonicFragmentActivity extends SubsonicActivity implements DownloadService.OnSongChangedListener { public class SubsonicFragmentActivity extends SubsonicActivity implements DownloadService.OnSongChangedListener {
private static String TAG = SubsonicFragmentActivity.class.getSimpleName(); private static final String TAG = SubsonicFragmentActivity.class.getSimpleName();
private static boolean infoDialogDisplayed; private static boolean infoDialogDisplayed;
private static boolean sessionInitialized = false; private static boolean sessionInitialized = false;
private static long ALLOWED_SKEW = 30000L;
private SlidingUpPanelLayout slideUpPanel; private SlidingUpPanelLayout slideUpPanel;
private SlidingUpPanelLayout.PanelSlideListener panelSlideListener; private SlidingUpPanelLayout.PanelSlideListener panelSlideListener;
private boolean isPanelClosing = false; private boolean isPanelClosing = false;
@ -97,9 +82,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
private TextView trackView; private TextView trackView;
private TextView artistView; private TextView artistView;
private ImageButton startButton; private ImageButton startButton;
private long lastBackPressTime = 0;
private DownloadFile currentPlaying; private DownloadFile currentPlaying;
private PlayerState currentState;
private ImageButton previousButton; private ImageButton previousButton;
private ImageButton nextButton; private ImageButton nextButton;
private ImageButton rewindButton; private ImageButton rewindButton;
@ -111,11 +94,9 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
String fragmentType = getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE); String fragmentType = getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE);
boolean firstRun = false; boolean firstRun = false;
if (fragmentType == null) { if (fragmentType == null) {
fragmentType = Util.openToTab(this); fragmentType = "Library";
if (fragmentType != null) {
firstRun = true; firstRun = true;
} }
}
if ("".equals(fragmentType) || fragmentType == null || firstRun) { if ("".equals(fragmentType) || fragmentType == null || firstRun) {
// Initial startup stuff // Initial startup stuff
@ -139,13 +120,9 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
if (findViewById(R.id.fragment_container) != null && savedInstanceState == null) { if (findViewById(R.id.fragment_container) != null && savedInstanceState == null) {
String fragmentType = getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE); String fragmentType = getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE);
if (fragmentType == null) { if (fragmentType == null) {
fragmentType = Util.openToTab(this); fragmentType = "Library";
if(fragmentType != null) {
getIntent().putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, fragmentType); getIntent().putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, fragmentType);
lastSelectedPosition = getDrawerItemId(fragmentType); lastSelectedPosition = getDrawerItemId(fragmentType);
} else {
lastSelectedPosition = R.id.drawer_library;
}
MenuItem item = drawerList.getMenu().findItem(lastSelectedPosition); MenuItem item = drawerList.getMenu().findItem(lastSelectedPosition);
if (item != null) { if (item != null) {
@ -187,7 +164,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
} }
} }
slideUpPanel = (SlidingUpPanelLayout) findViewById(R.id.slide_up_panel); slideUpPanel = findViewById(R.id.slide_up_panel);
panelSlideListener = new SlidingUpPanelLayout.PanelSlideListener() { panelSlideListener = new SlidingUpPanelLayout.PanelSlideListener() {
@Override @Override
public void onPanelSlide(View panel, float slideOffset) { public void onPanelSlide(View panel, float slideOffset) {
@ -232,22 +209,17 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD)) { if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD)) {
// Post this later so it actually runs // Post this later so it actually runs
handler.postDelayed(new Runnable() { handler.postDelayed(this::openNowPlaying, 200);
@Override
public void run() {
openNowPlaying();
}
}, 200);
getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD); getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD);
} }
bottomBar = findViewById(R.id.bottom_bar); bottomBar = findViewById(R.id.bottom_bar);
mainToolbar = (Toolbar) findViewById(R.id.main_toolbar); mainToolbar = findViewById(R.id.main_toolbar);
nowPlayingToolbar = (Toolbar) findViewById(R.id.now_playing_toolbar); nowPlayingToolbar = findViewById(R.id.now_playing_toolbar);
coverArtView = (ImageView) bottomBar.findViewById(R.id.album_art); coverArtView = bottomBar.findViewById(R.id.album_art);
trackView = (TextView) bottomBar.findViewById(R.id.track_name); trackView = bottomBar.findViewById(R.id.track_name);
artistView = (TextView) bottomBar.findViewById(R.id.artist_name); artistView = bottomBar.findViewById(R.id.artist_name);
setSupportActionBar(mainToolbar); setSupportActionBar(mainToolbar);
@ -258,11 +230,8 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
trans.commit(); trans.commit();
} }
rewindButton = (ImageButton) findViewById(R.id.download_rewind); rewindButton = findViewById(R.id.download_rewind);
rewindButton.setOnClickListener(new View.OnClickListener() { rewindButton.setOnClickListener(v -> new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
@Override
public void onClick(View v) {
new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
if (getDownloadService() == null) { if (getDownloadService() == null) {
@ -272,15 +241,10 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
getDownloadService().rewind(); getDownloadService().rewind();
return null; return null;
} }
}.execute(); }.execute());
}
});
previousButton = (ImageButton) findViewById(R.id.download_previous); previousButton = findViewById(R.id.download_previous);
previousButton.setOnClickListener(new View.OnClickListener() { previousButton.setOnClickListener(v -> new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
@Override
public void onClick(View v) {
new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
if (getDownloadService() == null) { if (getDownloadService() == null) {
@ -290,15 +254,10 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
getDownloadService().previous(); getDownloadService().previous();
return null; return null;
} }
}.execute(); }.execute());
}
});
startButton = (ImageButton) findViewById(R.id.download_start); startButton = findViewById(R.id.download_start);
startButton.setOnClickListener(new View.OnClickListener() { startButton.setOnClickListener(v -> new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
@Override
public void onClick(View v) {
new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
PlayerState state = getDownloadService().getPlayerState(); PlayerState state = getDownloadService().getPlayerState();
@ -310,15 +269,10 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
return null; return null;
} }
}.execute(); }.execute());
}
});
nextButton = (ImageButton) findViewById(R.id.download_next); nextButton = findViewById(R.id.download_next);
nextButton.setOnClickListener(new View.OnClickListener() { nextButton.setOnClickListener(v -> new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
@Override
public void onClick(View v) {
new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
if (getDownloadService() == null) { if (getDownloadService() == null) {
@ -328,15 +282,10 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
getDownloadService().next(); getDownloadService().next();
return null; return null;
} }
}.execute(); }.execute());
}
});
fastforwardButton = (ImageButton) findViewById(R.id.download_fastforward); fastforwardButton = findViewById(R.id.download_fastforward);
fastforwardButton.setOnClickListener(new View.OnClickListener() { fastforwardButton.setOnClickListener(v -> new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
@Override
public void onClick(View v) {
new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
if (getDownloadService() == null) { if (getDownloadService() == null) {
@ -346,9 +295,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
getDownloadService().fastForward(); getDownloadService().fastForward();
return null; return null;
} }
}.execute(); }.execute());
}
});
} }
@Override @Override
@ -421,12 +368,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
UserUtil.seedCurrentUser(this); UserUtil.seedCurrentUser(this);
createAccount(); createAccount();
runWhenServiceAvailable(new Runnable() { runWhenServiceAvailable(() -> getDownloadService().addOnSongChangedListener(SubsonicFragmentActivity.this));
@Override
public void run() {
getDownloadService().addOnSongChangedListener(SubsonicFragmentActivity.this, true);
}
});
} }
@Override @Override
@ -447,6 +389,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
} }
savedInstanceState.putInt(Constants.MAIN_SLIDE_PANEL_STATE, slideUpPanel.getPanelState().hashCode()); savedInstanceState.putInt(Constants.MAIN_SLIDE_PANEL_STATE, slideUpPanel.getPanelState().hashCode());
} }
@Override @Override
public void onRestoreInstanceState(Bundle savedInstanceState) { public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState); super.onRestoreInstanceState(savedInstanceState);
@ -484,11 +427,6 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
} }
} }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
return super.onOptionsItemSelected(item);
}
@Override @Override
public void onBackPressed() { public void onBackPressed() {
if (slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED && secondaryFragment == null) { if (slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED && secondaryFragment == null) {
@ -499,7 +437,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
} }
@Override @Override
public boolean onBackPressedSupport() { boolean onBackPressedSupport() {
if (slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) { if (slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) {
removeCurrent(); removeCurrent();
return false; return false;
@ -538,6 +476,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
super.replaceFragment(fragment, tag, replaceCurrent); super.replaceFragment(fragment, tag, replaceCurrent);
} }
} }
@Override @Override
public void removeCurrent() { public void removeCurrent() {
if (slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED && secondaryFragment != null) { if (slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED && secondaryFragment != null) {
@ -610,6 +549,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
public void openNowPlaying() { public void openNowPlaying() {
slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.EXPANDED); slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.EXPANDED);
} }
@Override @Override
public void closeNowPlaying() { public void closeNowPlaying() {
slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
@ -628,14 +568,13 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
} }
} }
public void checkUpdates() { private void checkUpdates() {
try { try {
String version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; String version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
int ver = Integer.parseInt(version.replace(".", "")); int ver = Integer.parseInt(version.replace(".", ""));
Updater updater = new Updater(ver); Updater updater = new Updater(ver);
updater.checkUpdates(this); updater.checkUpdates(this);
} } catch (Exception ignored) {
catch(Exception e) {
} }
} }
@ -649,6 +588,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
sessionInitialized = true; sessionInitialized = true;
} }
private void loadSettings() { private void loadSettings() {
PreferenceManager.setDefaultValues(this, R.xml.settings_appearance, false); PreferenceManager.setDefaultValues(this, R.xml.settings_appearance, false);
PreferenceManager.setDefaultValues(this, R.xml.settings_cache, false); PreferenceManager.setDefaultValues(this, R.xml.settings_cache, false);
@ -703,33 +643,17 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
if (Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_RESUME_PLAY_QUEUE_NEVER, false)) { if (Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_RESUME_PLAY_QUEUE_NEVER, false)) {
return; return;
} }
final SubsonicActivity context = this;
new SilentBackgroundTask<Void>(this) { new SilentBackgroundTask<Void>(this) {
private PlayerQueue playerQueue;
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
try { try {
MusicService musicService = MusicServiceFactory.getMusicService(context);
PlayerQueue remoteState = musicService.getPlayQueue(context, null);
// Make sure we wait until download service is ready // Make sure we wait until download service is ready
DownloadService downloadService = getDownloadService(); DownloadService downloadService = getDownloadService();
while (downloadService == null || !downloadService.isInitialized()) { while (downloadService == null || !downloadService.isInitialized()) {
Util.sleepQuietly(100L); Util.sleepQuietly(100L);
downloadService = getDownloadService(); downloadService = getDownloadService();
} }
// If we had a remote state and it's changed is more recent than our existing state
if(remoteState != null && remoteState.changed != null) {
// Check if changed + 30 seconds since some servers have slight skew
Date remoteChange = new Date(remoteState.changed.getTime() - ALLOWED_SKEW);
Date localChange = downloadService.getLastStateChanged();
if(localChange == null || localChange.before(remoteChange)) {
playerQueue = remoteState;
}
}
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Failed to get playing queue to server", e); Log.e(TAG, "Failed to get playing queue to server", e);
} }
@ -759,27 +683,18 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
return null; return null;
} }
@Override
protected void done(Void result) {
}
}.execute(); }.execute();
} }
private void showInfoDialog() { private void showInfoDialog() {
if (!infoDialogDisplayed) { if (!infoDialogDisplayed) {
infoDialogDisplayed = true; infoDialogDisplayed = true;
if (Util.getRestUrl(this, null).contains("demo.subsonic.org")) { if (Util.getRestUrl(this).contains("demo.subsonic.org")) {
Util.info(this, R.string.main_welcome_title, R.string.main_welcome_text); Util.info(this, R.string.main_welcome_title, R.string.main_welcome_text);
} }
} }
} }
public Toolbar getActiveToolbar() {
return slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED ? nowPlayingToolbar : mainToolbar;
}
@Override @Override
public void onSongChanged(DownloadFile currentPlaying, int currentPlayingIndex) { public void onSongChanged(DownloadFile currentPlaying, int currentPlayingIndex) {
this.currentPlaying = currentPlaying; this.currentPlaying = currentPlaying;
@ -831,7 +746,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
} }
@Override @Override
public void onStateUpdate(DownloadFile downloadFile, PlayerState playerState) { public void onStateUpdate(PlayerState playerState) {
int[] attrs = new int[]{(playerState == PlayerState.STARTED) ? R.attr.actionbar_pause : R.attr.actionbar_start}; int[] attrs = new int[]{(playerState == PlayerState.STARTED) ? R.attr.actionbar_pause : R.attr.actionbar_start};
TypedArray typedArray = this.obtainStyledAttributes(attrs); TypedArray typedArray = this.obtainStyledAttributes(attrs);
startButton.setImageResource(typedArray.getResourceId(0, 0)); startButton.setImageResource(typedArray.getResourceId(0, 0));

View File

@ -24,23 +24,18 @@ import android.app.SearchManager;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.provider.SearchRecentSuggestions;
import android.util.Log;
import net.nullsum.audinaut.fragments.SubsonicFragment;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.provider.AudinautSearchProvider;
/** /**
* Receives voice search queries and forwards to the SearchFragment. * Receives voice search queries and forwards to the SearchFragment.
* * <p>
* http://android-developers.blogspot.com/2010/09/supporting-new-music-voice-action.html * http://android-developers.blogspot.com/2010/09/supporting-new-music-voice-action.html
* *
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class VoiceQueryReceiverActivity extends Activity { public class VoiceQueryReceiverActivity extends Activity {
private static final String TAG = VoiceQueryReceiverActivity.class.getSimpleName();
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
@ -57,6 +52,5 @@ public class VoiceQueryReceiverActivity extends Activity {
Util.startActivityWithoutTransition(VoiceQueryReceiverActivity.this, intent); Util.startActivityWithoutTransition(VoiceQueryReceiverActivity.this, intent);
} }
finish(); finish();
Util.disablePendingTransition(this);
} }
} }

View File

@ -17,12 +17,12 @@ package net.nullsum.audinaut.adapter;
import android.content.Context; import android.content.Context;
import java.util.List;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.util.ImageLoader; import net.nullsum.audinaut.util.ImageLoader;
import net.nullsum.audinaut.view.FastScroller; import net.nullsum.audinaut.view.FastScroller;
import java.util.List;
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);

View File

@ -18,17 +18,12 @@ package net.nullsum.audinaut.adapter;
import android.content.Context; import android.content.Context;
import android.support.v7.widget.PopupMenu; import android.support.v7.widget.PopupMenu;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.TextView; import android.widget.TextView;
import java.io.Serializable;
import java.util.List;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.Artist; import net.nullsum.audinaut.domain.Artist;
import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.MusicDirectory.Entry; import net.nullsum.audinaut.domain.MusicDirectory.Entry;
import net.nullsum.audinaut.domain.MusicFolder; import net.nullsum.audinaut.domain.MusicFolder;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
@ -37,16 +32,14 @@ import net.nullsum.audinaut.view.FastScroller;
import net.nullsum.audinaut.view.SongView; import net.nullsum.audinaut.view.SongView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import java.io.Serializable;
import java.util.List;
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 final int VIEW_TYPE_ARTIST = 4;
public static int VIEW_TYPE_ARTIST = 4; private static final int VIEW_TYPE_SONG = 3;
private final List<MusicFolder> musicFolders;
private List<MusicFolder> musicFolders; private final OnMusicFolderChanged onMusicFolderChanged;
private OnMusicFolderChanged onMusicFolderChanged;
public ArtistAdapter(Context context, List<Serializable> artists, OnItemClickedListener listener) {
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);
@ -62,9 +55,7 @@ public class ArtistAdapter extends SectionAdapter<Serializable> implements FastS
@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(v -> {
@Override
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);
@ -72,9 +63,7 @@ public class ArtistAdapter extends SectionAdapter<Serializable> implements FastS
popup.getMenu().add(musicFolder.getName()); popup.getMenu().add(musicFolder.getName());
} }
popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { popup.setOnMenuItemClickListener(item -> {
@Override
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) {
@ -88,17 +77,16 @@ public class ArtistAdapter extends SectionAdapter<Serializable> implements FastS
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);
} }
@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 = 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) {
@ -114,7 +102,7 @@ public class ArtistAdapter extends SectionAdapter<Serializable> implements FastS
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(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);

View File

@ -16,15 +16,14 @@
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
import android.content.Context; import android.content.Context;
import android.view.ViewGroup;
import java.util.List;
import net.nullsum.audinaut.view.BasicListView; import net.nullsum.audinaut.view.BasicListView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import java.util.List;
public class BasicListAdapter extends SectionAdapter<String> { public class BasicListAdapter extends SectionAdapter<String> {
public static int VIEW_TYPE_LINE = 1; private static final 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);
@ -32,7 +31,7 @@ public class BasicListAdapter extends SectionAdapter<String> {
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(int viewType) {
return new UpdateView.UpdateViewHolder(new BasicListView(context)); return new UpdateView.UpdateViewHolder(new BasicListView(context));
} }

View File

@ -16,8 +16,6 @@
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
import android.content.Context; import android.content.Context;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify; import android.text.util.Linkify;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -25,16 +23,16 @@ import android.view.ViewGroup;
import android.widget.ArrayAdapter; import android.widget.ArrayAdapter;
import android.widget.TextView; import android.widget.TextView;
import java.util.List;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
public class DetailsAdapter extends ArrayAdapter<String> { import java.util.List;
private List<String> headers;
private List<String> details;
public DetailsAdapter(Context context, int layout, List<String> headers, List<String> details) { public class DetailsAdapter extends ArrayAdapter<String> {
super(context, layout, headers); private final List<String> headers;
private final List<String> details;
public DetailsAdapter(Context context, List<String> headers, List<String> details) {
super(context, R.layout.details_item, headers);
this.headers = headers; this.headers = headers;
this.details = details; this.details = details;
@ -49,8 +47,8 @@ public class DetailsAdapter extends ArrayAdapter<String> {
view = convertView; view = convertView;
} }
TextView nameView = (TextView) view.findViewById(R.id.detail_name); TextView nameView = view.findViewById(R.id.detail_name);
TextView detailsView = (TextView) view.findViewById(R.id.detail_value); TextView detailsView = view.findViewById(R.id.detail_value);
nameView.setText(headers.get(position)); nameView.setText(headers.get(position));

View File

@ -18,12 +18,6 @@ package net.nullsum.audinaut.adapter;
import android.content.Context; import android.content.Context;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import java.util.List;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.service.DownloadFile; import net.nullsum.audinaut.service.DownloadFile;
@ -32,8 +26,10 @@ import net.nullsum.audinaut.view.FastScroller;
import net.nullsum.audinaut.view.SongView; import net.nullsum.audinaut.view.SongView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import java.util.List;
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; private static final 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);
@ -42,7 +38,7 @@ public class DownloadFileAdapter extends SectionAdapter<DownloadFile> implements
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(int viewType) {
return new UpdateView.UpdateViewHolder(new SongView(context)); return new UpdateView.UpdateViewHolder(new SongView(context));
} }

View File

@ -18,11 +18,6 @@ package net.nullsum.audinaut.adapter;
import android.content.Context; import android.content.Context;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
@ -34,19 +29,17 @@ import net.nullsum.audinaut.view.SongView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import net.nullsum.audinaut.view.UpdateView.UpdateViewHolder; import net.nullsum.audinaut.view.UpdateView.UpdateViewHolder;
import java.util.List;
public class EntryGridAdapter extends SectionAdapter<Entry> { public class EntryGridAdapter extends SectionAdapter<Entry> {
private static String TAG = EntryGridAdapter.class.getSimpleName(); public static final int VIEW_TYPE_ALBUM_CELL = 1;
public static final int VIEW_TYPE_ALBUM_LINE = 2;
public static int VIEW_TYPE_ALBUM_CELL = 1; public static final int VIEW_TYPE_SONG = 3;
public static int VIEW_TYPE_ALBUM_LINE = 2; private final ImageLoader imageLoader;
public static int VIEW_TYPE_SONG = 3; private final boolean largeAlbums;
private ImageLoader imageLoader;
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;
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);
@ -68,7 +61,7 @@ public class EntryGridAdapter extends SectionAdapter<Entry> {
} }
@Override @Override
public UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateViewHolder onCreateSectionViewHolder(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);
@ -93,9 +86,6 @@ public class EntryGridAdapter extends SectionAdapter<Entry> {
} }
} }
public UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) {
return new UpdateViewHolder(header, false);
}
public void onBindHeaderHolder(UpdateViewHolder holder, String header, int sectionIndex) { public void onBindHeaderHolder(UpdateViewHolder holder, String header, int sectionIndex) {
} }
@ -113,27 +103,16 @@ public class EntryGridAdapter extends SectionAdapter<Entry> {
} }
} }
public void setHeader(View header) { public void setShowArtist() {
this.header = header; this.showArtist = true;
this.singleSectionHeader = true;
}
public View getHeader() {
return header;
} }
public void setShowArtist(boolean showArtist) { public void setShowAlbum() {
this.showArtist = showArtist; this.showAlbum = true;
}
public void setShowAlbum(boolean 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) {
index++;
}
notifyItemRemoved(index); notifyItemRemoved(index);
} }

View File

@ -20,8 +20,6 @@ import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import java.util.List;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.MusicDirectory.Entry; import net.nullsum.audinaut.domain.MusicDirectory.Entry;
@ -32,8 +30,10 @@ import net.nullsum.audinaut.util.ImageLoader;
import net.nullsum.audinaut.util.SilentBackgroundTask; import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import java.util.List;
public class EntryInfiniteGridAdapter extends EntryGridAdapter { public class EntryInfiniteGridAdapter extends EntryGridAdapter {
public static int VIEW_TYPE_LOADING = 4; public static final int VIEW_TYPE_LOADING = 4;
private String type; private String type;
private String extra; private String extra;
@ -51,7 +51,7 @@ public class EntryInfiniteGridAdapter extends EntryGridAdapter {
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);
} }
return super.onCreateViewHolder(parent, viewType); return super.onCreateViewHolder(parent, viewType);
@ -122,7 +122,7 @@ public class EntryInfiniteGridAdapter extends EntryGridAdapter {
}.execute(); }.execute();
} }
protected List<Entry> cacheInBackground() throws Exception { private 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();
@ -130,7 +130,7 @@ public class EntryInfiniteGridAdapter extends EntryGridAdapter {
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.contains(MainFragment.SONGS_LIST_PREFIX)) {
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);
@ -138,7 +138,7 @@ public class EntryInfiniteGridAdapter extends EntryGridAdapter {
return result.getChildren(); return result.getChildren();
} }
protected void appendCachedData(List<Entry> newData) { private 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);
@ -146,7 +146,7 @@ public class EntryInfiniteGridAdapter extends EntryGridAdapter {
} }
} }
protected boolean isLoadingView(int position) { private boolean isLoadingView(int position) {
return !allLoaded && position >= sections.get(0).size(); return !allLoaded && position >= sections.get(0).size();
} }
} }

View File

@ -16,48 +16,31 @@
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
import android.content.Context; import android.content.Context;
import android.util.Log;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.util.DrawableTint; import net.nullsum.audinaut.util.DrawableTint;
import net.nullsum.audinaut.view.BasicHeaderView; 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> { import java.util.ArrayList;
private static final String TAG = ExpandableSectionAdapter.class.getSimpleName(); import java.util.List;
abstract class ExpandableSectionAdapter<T> extends SectionAdapter<T> {
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; private List<List<T>> sectionsExtras;
protected List<List<T>> sectionsExtras;
protected int expandToggleRes;
protected int collapseToggleRes;
protected ExpandableSectionAdapter() {} ExpandableSectionAdapter() {
public ExpandableSectionAdapter(Context context, List<T> section) { }
List<List<T>> sections = new ArrayList<>();
sections.add(section);
init(context, Arrays.asList("Section"), sections, Arrays.asList((Integer) null)); void init(Context context, List<String> headers, List<List<T>> fullSections, List<Integer> sectionsDefaultVisible) {
}
public ExpandableSectionAdapter(Context context, List<String> headers, List<List<T>> sections) {
init(context, headers, sections, null);
}
public ExpandableSectionAdapter(Context context, List<String> headers, List<List<T>> sections, List<Integer> sectionsDefaultVisible) {
init(context, headers, sections, 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;
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++) {
@ -83,9 +66,6 @@ public abstract class ExpandableSectionAdapter<T> extends SectionAdapter<T> {
i++; i++;
} }
expandToggleRes = DrawableTint.getDrawableRes(context, EXPAND_TOGGLE);
collapseToggleRes = DrawableTint.getDrawableRes(context, COLLAPSE_TOGGLE);
} }
@Override @Override
@ -96,39 +76,36 @@ public abstract class ExpandableSectionAdapter<T> extends SectionAdapter<T> {
@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 = 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(v -> {
@Override List<T> visibleSelection1 = sections.get(sectionIndex);
public void onClick(View v) { List<T> sectionExtras1 = sectionsExtras.get(sectionIndex);
List<T> visibleSelection = sections.get(sectionIndex);
List<T> sectionExtras = sectionsExtras.get(sectionIndex);
// Update icon // Update icon
int selectToggleAttr; int selectToggleAttr;
if (!visibleSelection.contains(sectionExtras.get(0))) { if (!visibleSelection1.contains(sectionExtras1.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(visibleSelection1.get(visibleSelection1.size() - 1));
visibleSelection.addAll(sectionExtras); visibleSelection1.addAll(sectionExtras1);
notifyItemRangeInserted(lastIndex, sectionExtras.size()); notifyItemRangeInserted(lastIndex, sectionExtras1.size());
} else { } else {
selectToggleAttr = EXPAND_TOGGLE; selectToggleAttr = EXPAND_TOGGLE;
// Update how many are displayed // Update how many are displayed
visibleSelection.removeAll(sectionExtras); visibleSelection1.removeAll(sectionExtras1);
int lastIndex = getItemPosition(visibleSelection.get(visibleSelection.size() - 1)); int lastIndex = getItemPosition(visibleSelection1.get(visibleSelection1.size() - 1));
notifyItemRangeRemoved(lastIndex, sectionExtras.size()); notifyItemRangeRemoved(lastIndex, sectionExtras1.size());
} }
((ImageView) v).setImageResource(DrawableTint.getDrawableRes(context, selectToggleAttr)); ((ImageView) v).setImageResource(DrawableTint.getDrawableRes(context, selectToggleAttr));
}
}); });
int selectToggleAttr; int selectToggleAttr;

View File

@ -16,7 +16,7 @@
package net.nullsum.audinaut.adapter; package net.nullsum.audinaut.adapter;
import android.content.Context; import android.content.Context;
import android.view.ViewGroup;
import net.nullsum.audinaut.domain.Genre; import net.nullsum.audinaut.domain.Genre;
import net.nullsum.audinaut.view.FastScroller; import net.nullsum.audinaut.view.FastScroller;
import net.nullsum.audinaut.view.GenreView; import net.nullsum.audinaut.view.GenreView;
@ -25,7 +25,7 @@ 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; private static final 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);
@ -33,7 +33,7 @@ public class GenreAdapter extends SectionAdapter<Genre> implements FastScroller.
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(int viewType) {
return new UpdateView.UpdateViewHolder(new GenreView(context)); return new UpdateView.UpdateViewHolder(new GenreView(context));
} }

View File

@ -19,18 +19,16 @@ import android.content.Context;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.CompoundButton;
import java.util.List;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.view.BasicHeaderView; import net.nullsum.audinaut.view.BasicHeaderView;
import net.nullsum.audinaut.view.BasicListView; import net.nullsum.audinaut.view.BasicListView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import java.util.List;
public class MainAdapter extends SectionAdapter<Integer> { public class MainAdapter extends SectionAdapter<Integer> {
public static final int VIEW_TYPE_ALBUM_LIST = 1; private 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);
@ -38,7 +36,7 @@ public class MainAdapter extends SectionAdapter<Integer> {
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(int viewType) {
UpdateView updateView = new BasicListView(context); UpdateView updateView = new BasicListView(context);
return new UpdateView.UpdateViewHolder(updateView); return new UpdateView.UpdateViewHolder(updateView);
} }
@ -63,10 +61,11 @@ public class MainAdapter extends SectionAdapter<Integer> {
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 = view.findViewById(R.id.item_checkbox);
String display; String display;
if ("songs".equals(header)) { if ("songs".equals(header)) {

View File

@ -16,20 +16,19 @@ package net.nullsum.audinaut.adapter;
import android.content.Context; import android.content.Context;
import java.util.List;
import android.view.ViewGroup;
import net.nullsum.audinaut.domain.Playlist; import net.nullsum.audinaut.domain.Playlist;
import net.nullsum.audinaut.util.ImageLoader; import net.nullsum.audinaut.util.ImageLoader;
import net.nullsum.audinaut.view.FastScroller; import net.nullsum.audinaut.view.FastScroller;
import net.nullsum.audinaut.view.PlaylistView; 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 { import java.util.List;
public static int VIEW_TYPE_PLAYLIST = 1;
private ImageLoader imageLoader; public class PlaylistAdapter extends SectionAdapter<Playlist> implements FastScroller.BubbleTextGetter {
private boolean largeCell; private static final int VIEW_TYPE_PLAYLIST = 1;
private final ImageLoader imageLoader;
private final 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);
@ -37,15 +36,9 @@ public class PlaylistAdapter extends SectionAdapter<Playlist> implements FastScr
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) {
super(context, headers, sections);
this.imageLoader = imageLoader;
this.largeCell = largeCell;
this.onItemClickedListener = listener;
}
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(int viewType) {
return new UpdateView.UpdateViewHolder(new PlaylistView(context, imageLoader, largeCell)); return new UpdateView.UpdateViewHolder(new PlaylistView(context, imageLoader, largeCell));
} }

View File

@ -19,38 +19,32 @@ import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.MusicDirectory.Entry; import net.nullsum.audinaut.domain.MusicDirectory.Entry;
import net.nullsum.audinaut.domain.SearchResult; import net.nullsum.audinaut.domain.SearchResult;
import net.nullsum.audinaut.util.DrawableTint;
import net.nullsum.audinaut.util.ImageLoader; import net.nullsum.audinaut.util.ImageLoader;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.view.AlbumView; import net.nullsum.audinaut.view.AlbumView;
import net.nullsum.audinaut.view.ArtistView; import net.nullsum.audinaut.view.ArtistView;
import net.nullsum.audinaut.view.BasicHeaderView;
import net.nullsum.audinaut.view.SongView; import net.nullsum.audinaut.view.SongView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import static net.nullsum.audinaut.adapter.ArtistAdapter.VIEW_TYPE_ARTIST; import static net.nullsum.audinaut.adapter.ArtistAdapter.VIEW_TYPE_ARTIST;
import static net.nullsum.audinaut.adapter.EntryGridAdapter.VIEW_TYPE_ALBUM_CELL; import static net.nullsum.audinaut.adapter.EntryGridAdapter.VIEW_TYPE_ALBUM_CELL;
import static net.nullsum.audinaut.adapter.EntryGridAdapter.VIEW_TYPE_ALBUM_LINE; 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 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;
private final ImageLoader imageLoader;
private final boolean largeAlbums;
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;
@ -82,7 +76,7 @@ public class SearchAdapter extends ExpandableSectionAdapter<Serializable> {
} }
@Override @Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { public UpdateView.UpdateViewHolder onCreateSectionViewHolder(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);

View File

@ -32,10 +32,6 @@ import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.PopupMenu; import android.widget.PopupMenu;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.activity.SubsonicFragmentActivity; import net.nullsum.audinaut.activity.SubsonicFragmentActivity;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
@ -45,51 +41,40 @@ import net.nullsum.audinaut.view.BasicHeaderView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import net.nullsum.audinaut.view.UpdateView.UpdateViewHolder; import net.nullsum.audinaut.view.UpdateView.UpdateViewHolder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
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(); public static final int VIEW_TYPE_HEADER = 0;
public static int VIEW_TYPE_HEADER = 0; private static final String TAG = SectionAdapter.class.getSimpleName();
public static String[] ignoredArticles; private static String[] ignoredArticles;
private final List<T> selected = new ArrayList<>();
private final List<UpdateView> selectedViews = new ArrayList<>();
Context context;
List<String> headers;
List<List<T>> sections;
boolean singleSectionHeader;
OnItemClickedListener<T> onItemClickedListener;
boolean checkable = false;
private ActionMode currentActionMode;
protected Context context; SectionAdapter() {
protected List<String> headers;
protected List<List<T>> sections;
protected boolean singleSectionHeader;
protected OnItemClickedListener<T> onItemClickedListener;
protected List<T> selected = new ArrayList<>();
protected List<UpdateView> selectedViews = new ArrayList<>();
protected ActionMode currentActionMode;
protected boolean checkable = false;
protected SectionAdapter() {}
public SectionAdapter(Context context, List<T> section) {
this(context, section, false);
} }
public SectionAdapter(Context context, List<T> section, boolean singleSectionHeader) {
SectionAdapter(Context context, List<T> section) {
this.context = context; this.context = context;
this.headers = Arrays.asList("Section"); this.headers = Collections.singletonList("Section");
this.sections = new ArrayList<>(); this.sections = new ArrayList<>();
this.sections.add(section); this.sections.add(section);
this.singleSectionHeader = singleSectionHeader; this.singleSectionHeader = false;
} }
public SectionAdapter(Context context, List<String> headers, List<List<T>> sections) {
this(context, headers, sections, true); SectionAdapter(Context context, List<String> headers, List<List<T>> sections) {
}
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 = true;
}
public void replaceExistingData(List<T> section) {
this.sections = new ArrayList<>();
this.sections.add(section);
notifyDataSetChanged();
}
public void replaceExistingData(List<String> headers, List<List<T>> sections) {
this.headers = headers;
this.sections = sections;
notifyDataSetChanged();
} }
@Override @Override
@ -97,15 +82,12 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
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(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(v -> {
@Override
public void onClick(View v) {
T item = holder.getItem(); T item = holder.getItem();
updateView.onClick();
if (currentActionMode != null) { if (currentActionMode != null) {
if (updateView.isCheckable()) { if (updateView.isCheckable()) {
if (selected.contains(item)) { if (selected.contains(item)) {
@ -127,38 +109,27 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
} 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(v -> {
@Override
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(menuItem -> onItemClickedListener.onContextItemSelected(menuItem, updateView, item));
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
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(v -> {
@Override
public boolean onLongClick(View v) {
if (updateView.isCheckable()) { if (updateView.isCheckable()) {
if (currentActionMode == null) { if (currentActionMode == null) {
startActionMode(holder); startActionMode(holder);
@ -167,7 +138,6 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
} }
} }
return true; return true;
}
}); });
} }
} }
@ -286,17 +256,18 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
return -1; return -1;
} }
public UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) { 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) {
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) { 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);
} }
@ -316,6 +287,7 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
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);
@ -341,6 +313,7 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
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);
@ -348,14 +321,6 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
} }
public void clearSelected() { public void clearSelected() {
// TODO: This needs to work with multiple sections
for(T item: selected) {
int index = sections.get(0).indexOf(item);
if(singleSectionHeader) {
index++;
}
}
selected.clear(); selected.clear();
for (UpdateView updateView : selectedViews) { for (UpdateView updateView : selectedViews) {
@ -377,6 +342,7 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
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) {
@ -395,16 +361,18 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
} }
} }
public abstract UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType); protected abstract UpdateView.UpdateViewHolder onCreateSectionViewHolder(int viewType);
public abstract void onBindViewHolder(UpdateViewHolder holder, T item, int viewType);
public abstract int getItemViewType(T item); protected abstract void onBindViewHolder(UpdateViewHolder holder, T item, int viewType);
public void setCheckable(boolean checkable) {
this.checkable = checkable; protected abstract int getItemViewType(T item);
}
public void setChecked(UpdateView updateView, boolean checked) { private void setChecked(UpdateView updateView, boolean checked) {
updateView.setChecked(checked); updateView.setChecked(checked);
} }
public void onCreateActionModeMenu(Menu menu, MenuInflater menuInflater) {}
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();
@ -470,16 +438,18 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
}); });
} }
} }
public void stopActionMode() { public void stopActionMode() {
if (currentActionMode != null) { if (currentActionMode != null) {
currentActionMode.finish(); currentActionMode.finish();
} }
} }
public String getNameIndex(String name) { String getNameIndex(String name) {
return getNameIndex(name, false); return getNameIndex(name, false);
} }
public String getNameIndex(String name, boolean removeIgnoredArticles) {
String getNameIndex(String name, boolean removeIgnoredArticles) {
if (name == null) { if (name == null) {
return "*"; return "*";
} }
@ -510,7 +480,9 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
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,121 +0,0 @@
/*
This file is part of Subsonic.
Subsonic is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Subsonic is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
Copyright 2014 (C) Scott Jackson
*/
package net.nullsum.audinaut.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.User;
import net.nullsum.audinaut.util.ImageLoader;
import net.nullsum.audinaut.util.UserUtil;
import net.nullsum.audinaut.view.BasicHeaderView;
import net.nullsum.audinaut.view.RecyclingImageView;
import net.nullsum.audinaut.view.SettingView;
import net.nullsum.audinaut.view.UpdateView;
import static net.nullsum.audinaut.domain.User.Setting;
public class SettingsAdapter extends SectionAdapter<Setting> {
private static final String TAG = SettingsAdapter.class.getSimpleName();
public final int VIEW_TYPE_SETTING = 1;
public final int VIEW_TYPE_SETTING_HEADER = 2;
private final User user;
private final boolean editable;
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) {
super(context, headers, settingSections, imageLoader != null);
this.user = user;
this.imageLoader = imageLoader;
this.editable = editable;
this.onItemClickedListener = onItemClickedListener;
for(List<Setting> settings: sections) {
for (Setting setting : settings) {
if (setting.getValue()) {
addSelected(setting);
}
}
}
}
@Override
public int getItemViewType(int position) {
int viewType = super.getItemViewType(position);
if(viewType == SectionAdapter.VIEW_TYPE_HEADER) {
if(position == 0 && imageLoader != null) {
return VIEW_TYPE_HEADER;
} else {
return VIEW_TYPE_SETTING_HEADER;
}
} else {
return viewType;
}
}
public void onBindHeaderHolder(UpdateView.UpdateViewHolder holder, String description, int sectionIndex) {
View header = holder.getView();
}
@Override
public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) {
if(viewType == VIEW_TYPE_SETTING_HEADER) {
return new UpdateView.UpdateViewHolder(new BasicHeaderView(context));
} else {
return new UpdateView.UpdateViewHolder(new SettingView(context));
}
}
@Override
public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Setting item, int viewType) {
holder.getUpdateView().setObject(item, editable);
}
@Override
public int getItemViewType(Setting item) {
return VIEW_TYPE_SETTING;
}
@Override
public void setChecked(UpdateView updateView, boolean checked) {
if(updateView instanceof SettingView) {
updateView.setChecked(checked);
}
}
public static SettingsAdapter getSettingsAdapter(Context context, User user, ImageLoader imageLoader, OnItemClickedListener<Setting> onItemClickedListener) {
return getSettingsAdapter(context, user, imageLoader, true, onItemClickedListener);
}
public static SettingsAdapter getSettingsAdapter(Context context, User user, ImageLoader imageLoader, boolean isEditable, OnItemClickedListener<Setting> onItemClickedListener) {
List<String> headers = new ArrayList<>();
List<List<User.Setting>> settingsSections = new ArrayList<>();
settingsSections.add(user.getSettings());
if(user.getMusicFolderSettings() != null) {
settingsSections.add(user.getMusicFolderSettings());
}
return new SettingsAdapter(context, user, headers, settingsSections, imageLoader, isEditable, onItemClickedListener);
}
}

View File

@ -19,14 +19,8 @@
package net.nullsum.audinaut.audiofx; package net.nullsum.audinaut.audiofx;
import android.content.Context; import android.content.Context;
import android.media.MediaPlayer;
import android.media.audiofx.AudioEffect;
import android.media.audiofx.LoudnessEnhancer;
import android.os.Build;
import android.util.Log;
public class AudioEffectsController { public class AudioEffectsController {
private static final String TAG = AudioEffectsController.class.getSimpleName();
private final Context context; private final Context context;
private int audioSessionId = 0; private int audioSessionId = 0;

View File

@ -18,14 +18,15 @@
*/ */
package net.nullsum.audinaut.audiofx; package net.nullsum.audinaut.audiofx;
import java.io.Serializable;
import android.content.Context; import android.content.Context;
import android.media.audiofx.BassBoost; import android.media.audiofx.BassBoost;
import android.media.audiofx.Equalizer; import android.media.audiofx.Equalizer;
import android.util.Log; import android.util.Log;
import net.nullsum.audinaut.util.FileUtil; import net.nullsum.audinaut.util.FileUtil;
import java.io.Serializable;
/** /**
* Backward-compatible wrapper for {@link Equalizer}, which is API Level 9. * Backward-compatible wrapper for {@link Equalizer}, which is API Level 9.
* *
@ -54,7 +55,7 @@ public class EqualizerController {
equalizer = new Equalizer(0, audioSessionId); equalizer = new Equalizer(0, audioSessionId);
bass = new BassBoost(0, audioSessionId); bass = new BassBoost(0, audioSessionId);
loudnessAvailable = true; loudnessAvailable = true;
loudnessEnhancerController = new LoudnessEnhancerController(context, audioSessionId); loudnessEnhancerController = new LoudnessEnhancerController(audioSessionId);
} }
public void saveSettings() { public void saveSettings() {
@ -80,7 +81,7 @@ public class EqualizerController {
} }
} }
public boolean isAvailable() { private boolean isAvailable() {
return equalizer != null && bass != null; return equalizer != null && bass != null;
} }
@ -116,6 +117,7 @@ public class EqualizerController {
} }
return equalizer; return equalizer;
} }
public BassBoost getBassBoost() { public BassBoost getBassBoost() {
if (released) { if (released) {
released = false; released = false;
@ -128,6 +130,7 @@ public class EqualizerController {
} }
return bass; return bass;
} }
public LoudnessEnhancerController getLoudnessEnhancerController() { public LoudnessEnhancerController getLoudnessEnhancerController() {
if (loudnessAvailable && released) { if (loudnessAvailable && released) {
released = false; released = false;
@ -144,7 +147,6 @@ public class EqualizerController {
private static class EqualizerSettings implements Serializable { private static class EqualizerSettings implements Serializable {
private short[] bandLevels; private short[] bandLevels;
private short preset;
private boolean enabled; private boolean enabled;
private short bass; private short bass;
private int loudness; private int loudness;
@ -152,17 +154,13 @@ public class EqualizerController {
public EqualizerSettings() { public EqualizerSettings() {
} }
public EqualizerSettings(Equalizer equalizer, BassBoost boost, LoudnessEnhancerController loudnessEnhancerController) { public EqualizerSettings(Equalizer equalizer, BassBoost boost, LoudnessEnhancerController loudnessEnhancerController) {
enabled = equalizer.getEnabled(); enabled = equalizer.getEnabled();
bandLevels = new short[equalizer.getNumberOfBands()]; bandLevels = new short[equalizer.getNumberOfBands()];
for (short i = 0; i < equalizer.getNumberOfBands(); i++) { for (short i = 0; i < equalizer.getNumberOfBands(); i++) {
bandLevels[i] = equalizer.getBandLevel(i); bandLevels[i] = equalizer.getBandLevel(i);
} }
try {
preset = equalizer.getCurrentPreset();
} catch (Exception x) {
preset = -1;
}
try { try {
bass = boost.getRoundedStrength(); bass = boost.getRoundedStrength();
} catch (Exception e) { } catch (Exception e) {

View File

@ -18,22 +18,16 @@
*/ */
package net.nullsum.audinaut.audiofx; package net.nullsum.audinaut.audiofx;
import android.content.Context;
import android.media.audiofx.LoudnessEnhancer; 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 LoudnessEnhancer enhancer; private LoudnessEnhancer enhancer;
private boolean released = false;
private int audioSessionId = 0;
public LoudnessEnhancerController(Context context, int audioSessionId) { public LoudnessEnhancerController(int audioSessionId) {
this.context = context;
try { try {
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);
@ -55,6 +49,7 @@ public class LoudnessEnhancerController {
public void enable() { public void enable() {
enhancer.setEnabled(true); enhancer.setEnabled(true);
} }
public void disable() { public void disable() {
enhancer.setEnabled(false); enhancer.setEnabled(false);
} }
@ -62,6 +57,7 @@ public class LoudnessEnhancerController {
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);
} }
@ -69,7 +65,6 @@ public class LoudnessEnhancerController {
public void release() { public void release() {
if (isAvailable()) { if (isAvailable()) {
enhancer.release(); enhancer.release();
released = true;
} }
} }

View File

@ -19,26 +19,25 @@
package net.nullsum.audinaut.domain; package net.nullsum.audinaut.domain;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.media.MediaMetadataRetriever; import android.media.MediaMetadataRetriever;
import android.os.Build;
import android.util.Log; import android.util.Log;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.io.File;
import java.io.Serializable;
import java.util.Collections;
import java.util.Comparator;
import java.util.Locale;
import net.nullsum.audinaut.service.DownloadService; import net.nullsum.audinaut.service.DownloadService;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.UpdateHelper; import net.nullsum.audinaut.util.UpdateHelper;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import java.io.File;
import java.io.Serializable;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
*/ */
@ -51,8 +50,9 @@ public class MusicDirectory implements Serializable {
private List<Entry> children; private List<Entry> children;
public MusicDirectory() { public MusicDirectory() {
children = new ArrayList<Entry>(); children = new ArrayList<>();
} }
public MusicDirectory(List<Entry> children) { public MusicDirectory(List<Entry> children) {
this.children = children; this.children = children;
} }
@ -86,6 +86,7 @@ public class MusicDirectory implements Serializable {
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);
} }
@ -103,7 +104,7 @@ public class MusicDirectory implements Serializable {
return children; return children;
} }
List<Entry> result = new ArrayList<Entry>(children.size()); List<Entry> result = new ArrayList<>(children.size());
for (Entry child : children) { for (Entry child : children) {
if (child != null && child.isDirectory() && includeDirs || !child.isDirectory() && includeFiles) { if (child != null && child.isDirectory() && includeDirs || !child.isDirectory() && includeFiles) {
result.add(child); result.add(child);
@ -111,8 +112,9 @@ 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<>();
for (Entry child : children) { for (Entry child : children) {
if (child != null && !child.isDirectory()) { if (child != null && !child.isDirectory()) {
result.add(child); result.add(child);
@ -125,22 +127,17 @@ public class MusicDirectory implements Serializable {
return children.size(); return children.size();
} }
public void shuffleChildren() { public void sortChildren(Context context) {
Collections.shuffle(this.children);
}
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(); for (Entry entry : children) {
while(it.hasNext()) {
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);
@ -184,7 +181,8 @@ public class MusicDirectory implements Serializable {
return metadataUpdated; return metadataUpdated;
} }
public synchronized boolean updateEntriesList(Context context, int instance, MusicDirectory refreshedDirectory) {
public synchronized boolean updateEntriesList(Context context, MusicDirectory refreshedDirectory) {
boolean changed = false; boolean changed = false;
Iterator<Entry> it = children.iterator(); Iterator<Entry> it = children.iterator();
while (it.hasNext()) { while (it.hasNext()) {
@ -207,7 +205,7 @@ public class MusicDirectory implements Serializable {
} }
if (resort) { if (resort) {
this.sortChildren(context, instance); this.sortChildren(context);
} }
return changed; return changed;
@ -218,7 +216,6 @@ public class MusicDirectory implements Serializable {
private String id; private String id;
private String parent; private String parent;
private String grandParent;
private String albumId; private String albumId;
private String artistId; private String artistId;
private boolean directory; private boolean directory;
@ -233,26 +230,25 @@ public class MusicDirectory implements Serializable {
private String transcodedContentType; private String transcodedContentType;
private String transcodedSuffix; private String transcodedSuffix;
private String coverArt; private String coverArt;
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;
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;
} }
public void loadMetadata(File file) { public void loadMetadata(File file) {
@ -289,6 +285,7 @@ public class MusicDirectory implements Serializable {
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();
@ -331,14 +328,6 @@ public class MusicDirectory implements Serializable {
this.parent = parent; this.parent = parent;
} }
public String getGrandParent() {
return grandParent;
}
public void setGrandParent(String grandParent) {
this.grandParent = grandParent;
}
public String getAlbumId() { public String getAlbumId() {
return albumId; return albumId;
} }
@ -379,6 +368,10 @@ public class MusicDirectory implements Serializable {
return getParent() != null || getArtist() != null; return getParent() != null || getArtist() != null;
} }
public void setAlbum(String album) {
this.album = album;
}
public String getAlbumDisplay() { public String getAlbumDisplay() {
if (album != null && title.startsWith("Disc ")) { if (album != null && title.startsWith("Disc ")) {
return album; return album;
@ -387,10 +380,6 @@ public class MusicDirectory implements Serializable {
} }
} }
public void setAlbum(String album) {
this.album = album;
}
public String getArtist() { public String getArtist() {
return artist; return artist;
} }
@ -455,14 +444,6 @@ public class MusicDirectory implements Serializable {
this.transcodedSuffix = transcodedSuffix; this.transcodedSuffix = transcodedSuffix;
} }
public Long getSize() {
return size;
}
public void setSize(Long size) {
this.size = size;
}
public Integer getDuration() { public Integer getDuration() {
return duration; return duration;
} }
@ -506,9 +487,11 @@ public class MusicDirectory implements Serializable {
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;
} }
@ -521,18 +504,6 @@ public class MusicDirectory implements Serializable {
this.closeness = closeness; this.closeness = closeness;
} }
public boolean isOnlineId(Context context) {
try {
String cacheLocation = Util.getPreferences(context).getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
return cacheLocation == null || id == null || id.indexOf(cacheLocation) == -1;
} catch(Exception e) {
Log.w(TAG, "Failed to check online id validity");
// Err on the side of default functionality
return true;
}
}
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (this == o) { if (this == o) {
@ -558,8 +529,8 @@ public class MusicDirectory implements Serializable {
} }
public static class EntryComparator implements Comparator<Entry> { public static class EntryComparator implements Comparator<Entry> {
private boolean byYear; private final boolean byYear;
private Collator collator; private final Collator collator;
public EntryComparator(boolean byYear) { public EntryComparator(boolean byYear) {
this.byYear = byYear; this.byYear = byYear;
@ -567,6 +538,14 @@ public class MusicDirectory implements Serializable {
this.collator.setStrength(Collator.PRIMARY); this.collator.setStrength(Collator.PRIMARY);
} }
public static void sort(List<Entry> entries, boolean byYear) {
try {
Collections.sort(entries, new EntryComparator(byYear));
} catch (Exception e) {
Log.w(TAG, "Failed to sort MusicDirectory");
}
}
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;
@ -601,7 +580,7 @@ public class MusicDirectory implements Serializable {
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 && !Objects.equals(lhsTrack, rhsTrack)) {
return lhsTrack.compareTo(rhsTrack); return lhsTrack.compareTo(rhsTrack);
} else if (lhsTrack != null) { } else if (lhsTrack != null) {
return -1; return -1;
@ -611,16 +590,5 @@ public class MusicDirectory implements Serializable {
return collator.compare(lhs.getTitle(), rhs.getTitle()); return collator.compare(lhs.getTitle(), rhs.getTitle());
} }
public static void sort(List<Entry> entries) {
sort(entries, true);
}
public static void sort(List<Entry> entries, boolean byYear) {
try {
Collections.sort(entries, new EntryComparator(byYear));
} catch (Exception e) {
Log.w(TAG, "Failed to sort MusicDirectory");
}
}
} }
} }

View File

@ -35,16 +35,24 @@ 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;
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 static void sort(List<MusicFolder> musicFolders) {
try {
Collections.sort(musicFolders, new MusicFolderComparator());
} catch (Exception e) {
Log.w(TAG, "Failed to sort music folders", e);
}
}
public String getId() { public String getId() {
return id; return id;
} }
@ -53,13 +61,6 @@ public class MusicFolder implements Serializable {
return name; return name;
} }
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean getEnabled() {
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())) {
@ -69,12 +70,4 @@ public class MusicFolder implements Serializable {
} }
} }
} }
public static void sort(List<MusicFolder> musicFolders) {
try {
Collections.sort(musicFolders, new MusicFolderComparator());
} catch (Exception e) {
Log.w(TAG, "Failed to sort music folders", e);
}
}
} }

View File

@ -17,14 +17,12 @@ package net.nullsum.audinaut.domain;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
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 final List<MusicDirectory.Entry> songs = new ArrayList<>();
public List<MusicDirectory.Entry> toDelete = new ArrayList<MusicDirectory.Entry>(); public final List<MusicDirectory.Entry> toDelete = new ArrayList<>();
public int currentPlayingIndex; public int currentPlayingIndex;
public int currentPlayingPosition; public int currentPlayingPosition;
public boolean renameCurrent = false; public boolean renameCurrent = false;
public Date changed = null;
} }

View File

@ -45,10 +45,12 @@ public class Playlist implements Serializable {
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;
@ -65,10 +67,6 @@ public class Playlist implements Serializable {
return id; return id;
} }
public void setId(String id) {
this.id = id;
}
public String getName() { public String getName() {
return name; return name;
} }
@ -81,10 +79,6 @@ public class Playlist implements Serializable {
return this.owner; return this.owner;
} }
public void setOwner(String owner) {
this.owner = owner;
}
public String getComment() { public String getComment() {
return this.comment; return this.comment;
} }
@ -104,6 +98,7 @@ public class Playlist implements Serializable {
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;
} }
@ -112,7 +107,7 @@ public class Playlist implements Serializable {
return created; return created;
} }
public void setCreated(String created) { private 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);
@ -123,14 +118,12 @@ public class Playlist implements Serializable {
this.created = null; this.created = null;
} }
} }
public void setCreated(Date created) {
this.created = created;
}
public Date getChanged() { public Date getChanged() {
return changed; return changed;
} }
public void setChanged(String changed) {
private 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);
@ -141,16 +134,10 @@ public class Playlist implements Serializable {
this.changed = null; this.changed = null;
} }
} }
public void setChanged(Date changed) {
this.changed = changed;
}
public Integer getDuration() { public Integer getDuration() {
return duration; return duration;
} }
public void setDuration(Integer duration) {
this.duration = duration;
}
@Override @Override
public String toString() { public String toString() {
@ -174,14 +161,14 @@ public class Playlist implements Serializable {
} }
public static class PlaylistComparator implements Comparator<Playlist> { public static class PlaylistComparator implements Comparator<Playlist> {
@Override
public int compare(Playlist playlist1, Playlist playlist2) {
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;
} }
@Override
public int compare(Playlist playlist1, Playlist playlist2) {
return playlist1.getName().compareToIgnoreCase(playlist2.getName());
}
} }
} }

View File

@ -68,24 +68,24 @@ public class SearchCritera {
// * 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 = ".*"; StringBuilder regex = new StringBuilder(".*");
String currentPart = ""; StringBuilder currentPart = new StringBuilder();
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.append(Pattern.quote(currentPart.toString()));
regex += ".*"; regex.append(".*");
currentPart = ""; currentPart = new StringBuilder();
} else { } else {
currentPart += c; currentPart.append(c);
} }
} }
if (currentPart.length() > 0) { if (currentPart.length() > 0) {
regex += Pattern.quote(currentPart); regex.append(Pattern.quote(currentPart.toString()));
} }
regex += ".*"; regex.append(".*");
this.pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); this.pattern = Pattern.compile(regex.toString(), Pattern.CASE_INSENSITIVE);
} }
return this.pattern; return this.pattern;

View File

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

View File

@ -15,21 +15,19 @@
package net.nullsum.audinaut.domain; package net.nullsum.audinaut.domain;
import android.util.Pair;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; 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 SETTINGS = "settingsRole";
public static final String DOWNLOAD = "downloadRole";
public static final String UPLOAD = "uploadRole";
public static final String COVERART = "coverArtRole";
public static final String COMMENT = "commentRole";
public static final String STREAM = "streamRole";
public static final List<String> ROLES = new ArrayList<>(); public static final List<String> ROLES = new ArrayList<>();
private static final String ADMIN = "adminRole";
private static final String SETTINGS = "settingsRole";
private static final String DOWNLOAD = "downloadRole";
private static final String UPLOAD = "uploadRole";
private static final String COVERART = "coverArtRole";
private static final String COMMENT = "commentRole";
private static final String STREAM = "streamRole";
static { static {
ROLES.add(ADMIN); ROLES.add(ADMIN);
@ -41,48 +39,13 @@ public class User implements Serializable {
ROLES.add(COMMENT); ROLES.add(COMMENT);
} }
private String username; private final List<Setting> settings = new ArrayList<>();
private String password;
private String email;
private List<Setting> settings = new ArrayList<Setting>();
private List<Setting> musicFolders; private List<Setting> musicFolders;
public User() { public User() {
} }
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public List<Setting> getSettings() {
return settings;
}
public void setSettings(List<Setting> settings) {
this.settings.clear();
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));
} }
@ -92,15 +55,9 @@ public class User implements Serializable {
musicFolders = new ArrayList<>(); musicFolders = new ArrayList<>();
} }
musicFolders.add(new MusicFolderSetting(musicFolder.getId(), musicFolder.getName(), false)); musicFolders.add(new MusicFolderSetting(musicFolder.getId(), musicFolder.getName()));
}
public void addMusicFolder(MusicFolderSetting musicFolderSetting, boolean defaultValue) {
if(musicFolders == null) {
musicFolders = new ArrayList<>();
} }
musicFolders.add(new MusicFolderSetting(musicFolderSetting.getName(), musicFolderSetting.getLabel(), defaultValue));
}
public List<Setting> getMusicFolderSettings() { public List<Setting> getMusicFolderSettings() {
return musicFolders; return musicFolders;
} }
@ -112,6 +69,7 @@ public class User implements Serializable {
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;
@ -120,22 +78,21 @@ public class User implements Serializable {
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 final String label;
public MusicFolderSetting() { public MusicFolderSetting(String name, String label) {
super(name, false);
}
public MusicFolderSetting(String name, String label, Boolean value) {
super(name, value);
this.label = label; this.label = label;
} }

View File

@ -15,7 +15,6 @@
package net.nullsum.audinaut.fragments; package net.nullsum.audinaut.fragments;
import android.content.DialogInterface;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.support.v7.widget.helper.ItemTouchHelper; import android.support.v7.widget.helper.ItemTouchHelper;
@ -26,13 +25,8 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.adapter.DownloadFileAdapter;
import net.nullsum.audinaut.adapter.SectionAdapter; import net.nullsum.audinaut.adapter.SectionAdapter;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.service.DownloadFile; import net.nullsum.audinaut.service.DownloadFile;
@ -42,9 +36,14 @@ import net.nullsum.audinaut.util.DownloadFileItemHelperCallback;
import net.nullsum.audinaut.util.ProgressListener; import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.util.SilentBackgroundTask; import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.adapter.DownloadFileAdapter;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
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;
@ -69,17 +68,7 @@ public class DownloadFragment extends SelectRecyclerFragment<DownloadFile> imple
super.onResume(); super.onResume();
final Handler handler = new Handler(); final Handler handler = new Handler();
Runnable runnable = new Runnable() { Runnable runnable = () -> handler.post(this::update);
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
update();
}
});
}
};
executorService = Executors.newSingleThreadScheduledExecutor(); executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS); executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS);
@ -105,10 +94,10 @@ public class DownloadFragment extends SelectRecyclerFragment<DownloadFile> imple
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<>();
} }
List<DownloadFile> songList = new ArrayList<DownloadFile>(); List<DownloadFile> songList = new ArrayList<>();
songList.addAll(downloadService.getBackgroundDownloads()); songList.addAll(downloadService.getBackgroundDownloads());
currentRevision = downloadService.getDownloadListUpdateRevision(); currentRevision = downloadService.getDownloadListUpdateRevision();
return songList; return songList;
@ -149,10 +138,7 @@ public class DownloadFragment extends SelectRecyclerFragment<DownloadFile> imple
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, "", (dialog, which) -> new SilentBackgroundTask<Void>(context) {
@Override
public void onClick(DialogInterface dialog, int which) {
new SilentBackgroundTask<Void>(context) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
getDownloadService().clearBackground(); getDownloadService().clearBackground();
@ -163,9 +149,7 @@ public class DownloadFragment extends SelectRecyclerFragment<DownloadFile> imple
protected void done(Void result) { protected void done(Void result) {
update(); update();
} }
}.execute(); }.execute());
}
});
return true; return true;
} }

View File

@ -29,14 +29,10 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.CheckBox; import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.SeekBar; import android.widget.SeekBar;
import android.widget.TextView; import android.widget.TextView;
import java.util.HashMap;
import java.util.Map;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.audiofx.EqualizerController; import net.nullsum.audinaut.audiofx.EqualizerController;
import net.nullsum.audinaut.audiofx.LoudnessEnhancerController; import net.nullsum.audinaut.audiofx.LoudnessEnhancerController;
@ -44,6 +40,9 @@ import net.nullsum.audinaut.service.DownloadService;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import java.util.HashMap;
import java.util.Map;
/** /**
* Created by Scott on 10/27/13. * Created by Scott on 10/27/13.
*/ */
@ -52,7 +51,7 @@ public class EqualizerFragment extends SubsonicFragment {
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<>();
private SeekBar bassBar; private SeekBar bassBar;
private SeekBar loudnessBar; private SeekBar loudnessBar;
private EqualizerController equalizerController; private EqualizerController equalizerController;
@ -81,18 +80,11 @@ public class EqualizerFragment extends SubsonicFragment {
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(view -> presetButton.showContextMenu());
@Override
public void onClick(View view) {
presetButton.showContextMenu();
}
});
CheckBox enabledCheckBox = (CheckBox) rootView.findViewById(R.id.equalizer_enabled); CheckBox enabledCheckBox = rootView.findViewById(R.id.equalizer_enabled);
enabledCheckBox.setChecked(equalizer.getEnabled()); enabledCheckBox.setChecked(equalizer.getEnabled());
enabledCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { enabledCheckBox.setOnCheckedChangeListener((compoundButton, b) -> {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
try { try {
setEqualizerEnabled(b); setEqualizerEnabled(b);
} catch (Exception e) { } catch (Exception e) {
@ -100,7 +92,6 @@ public class EqualizerFragment extends SubsonicFragment {
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);
@ -251,7 +242,7 @@ public class EqualizerFragment extends SubsonicFragment {
} }
private void initEqualizer() { private void initEqualizer() {
LinearLayout layout = (LinearLayout) rootView.findViewById(R.id.equalizer_layout); LinearLayout layout = 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];
@ -265,9 +256,9 @@ public class EqualizerFragment extends SubsonicFragment {
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 = bandBar.findViewById(R.id.equalizer_frequency);
final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level); final TextView levelTextView = bandBar.findViewById(R.id.equalizer_level);
SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar); SeekBar bar = bandBar.findViewById(R.id.equalizer_bar);
freqTextView.setText((equalizer.getCenterFreq(band) / 1000) + " Hz"); freqTextView.setText((equalizer.getCenterFreq(band) / 1000) + " Hz");
@ -306,13 +297,13 @@ public class EqualizerFragment extends SubsonicFragment {
layout.addView(bandBar); layout.addView(bandBar);
} }
LinearLayout specialLayout = (LinearLayout) rootView.findViewById(R.id.special_effects_layout); LinearLayout specialLayout = 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 = bandBar.findViewById(R.id.equalizer_frequency);
final TextView bassTextView = (TextView) bandBar.findViewById(R.id.equalizer_level); final TextView bassTextView = bandBar.findViewById(R.id.equalizer_level);
bassBar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar); bassBar = 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());
@ -359,9 +350,9 @@ public class EqualizerFragment extends SubsonicFragment {
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 = bandBar.findViewById(R.id.equalizer_frequency);
final TextView loudnessTextView = (TextView) bandBar.findViewById(R.id.equalizer_level); final TextView loudnessTextView = bandBar.findViewById(R.id.equalizer_level);
loudnessBar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar); loudnessBar = 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());
@ -409,9 +400,9 @@ public class EqualizerFragment extends SubsonicFragment {
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 = bandBar.findViewById(R.id.equalizer_frequency);
final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level); final TextView levelTextView = bandBar.findViewById(R.id.equalizer_level);
SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar); SeekBar bar = bandBar.findViewById(R.id.equalizer_bar);
freqTextView.setText("Master"); freqTextView.setText("Master");

View File

@ -1,15 +1,7 @@
package net.nullsum.audinaut.fragments; package net.nullsum.audinaut.fragments;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.os.StatFs;
import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
@ -17,32 +9,17 @@ import android.view.MenuItem;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.adapter.MainAdapter; import net.nullsum.audinaut.adapter.MainAdapter;
import net.nullsum.audinaut.adapter.SectionAdapter; import net.nullsum.audinaut.adapter.SectionAdapter;
import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.EnvironmentVariables;
import net.nullsum.audinaut.util.FileUtil;
import net.nullsum.audinaut.util.LoadingTask;
import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.util.UserUtil;
import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.service.MusicService; import net.nullsum.audinaut.service.MusicService;
import net.nullsum.audinaut.service.MusicServiceFactory; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Collections;
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();
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";
@ -63,15 +40,6 @@ public class MainFragment extends SelectRecyclerFragment<Integer> {
onFinishSetupOptionsMenu(menu); onFinishSetupOptionsMenu(menu);
} }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(super.onOptionsItemSelected(item)) {
return true;
}
return false;
}
@Override @Override
public int getOptionsMenu() { public int getOptionsMenu() {
return 0; return 0;
@ -98,7 +66,7 @@ public class MainFragment extends SelectRecyclerFragment<Integer> {
@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 Collections.singletonList(0);
} }
@Override @Override
@ -132,59 +100,6 @@ public class MainFragment extends SelectRecyclerFragment<Integer> {
} }
} }
private void showAboutDialog() {
new LoadingTask<Void>(context) {
Long[] used;
long bytesTotalFs;
long bytesAvailableFs;
@Override
protected Void doInBackground() throws Throwable {
File rootFolder = FileUtil.getMusicDirectory(context);
StatFs stat = new StatFs(rootFolder.getPath());
bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize();
bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize();
used = FileUtil.getUsedSize(context, rootFolder);
return null;
}
@Override
protected void done(Void result) {
List<Integer> headers = new ArrayList<>();
List<String> details = new ArrayList<>();
headers.add(R.string.details_author);
details.add("Andrew Rabert");
headers.add(R.string.details_email);
details.add("ar@nullsum.net");
try {
headers.add(R.string.details_version);
details.add(context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName);
} catch(Exception e) {
details.add("");
}
Resources res = context.getResources();
headers.add(R.string.details_files_cached);
details.add(Long.toString(used[0]));
headers.add(R.string.details_files_permanent);
details.add(Long.toString(used[1]));
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)));
headers.add(R.string.details_available_space);
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);
}
}.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) {
@ -211,7 +126,8 @@ public class MainFragment extends SelectRecyclerFragment<Integer> {
} }
@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) {

View File

@ -14,25 +14,13 @@
*/ */
package net.nullsum.audinaut.fragments; package net.nullsum.audinaut.fragments;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import android.support.v7.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper; import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
import android.view.Display; import android.view.Display;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener; import android.view.GestureDetector.OnGestureListener;
@ -42,19 +30,18 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.WindowManager; import android.view.WindowManager;
import android.view.animation.AnimationUtils; import android.view.animation.AnimationUtils;
import android.widget.EditText;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.SeekBar; import android.widget.SeekBar;
import android.widget.TextView; import android.widget.TextView;
import android.widget.ViewFlipper; import android.widget.ViewFlipper;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.activity.SubsonicFragmentActivity; import net.nullsum.audinaut.activity.SubsonicFragmentActivity;
import net.nullsum.audinaut.adapter.DownloadFileAdapter;
import net.nullsum.audinaut.adapter.SectionAdapter; import net.nullsum.audinaut.adapter.SectionAdapter;
import net.nullsum.audinaut.audiofx.EqualizerController; import net.nullsum.audinaut.audiofx.EqualizerController;
import net.nullsum.audinaut.domain.PlayerState; import net.nullsum.audinaut.domain.PlayerState;
@ -62,26 +49,33 @@ import net.nullsum.audinaut.domain.RepeatMode;
import net.nullsum.audinaut.service.DownloadFile; import net.nullsum.audinaut.service.DownloadFile;
import net.nullsum.audinaut.service.DownloadService; import net.nullsum.audinaut.service.DownloadService;
import net.nullsum.audinaut.service.DownloadService.OnSongChangedListener; import net.nullsum.audinaut.service.DownloadService.OnSongChangedListener;
import net.nullsum.audinaut.service.MusicService;
import net.nullsum.audinaut.service.MusicServiceFactory;
import net.nullsum.audinaut.service.OfflineException;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.DownloadFileItemHelperCallback;
import net.nullsum.audinaut.util.DrawableTint;
import net.nullsum.audinaut.util.FileUtil;
import net.nullsum.audinaut.util.MenuUtil;
import net.nullsum.audinaut.util.SilentBackgroundTask; import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.adapter.DownloadFileAdapter; import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.view.AutoRepeatButton;
import net.nullsum.audinaut.view.FadeOutAnimation; import net.nullsum.audinaut.view.FadeOutAnimation;
import net.nullsum.audinaut.view.FastScroller; import net.nullsum.audinaut.view.FastScroller;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import net.nullsum.audinaut.util.Util;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import static net.nullsum.audinaut.domain.MusicDirectory.Entry; import static net.nullsum.audinaut.domain.MusicDirectory.Entry;
import static net.nullsum.audinaut.domain.PlayerState.*; import static net.nullsum.audinaut.domain.PlayerState.COMPLETED;
import net.nullsum.audinaut.util.*; import static net.nullsum.audinaut.domain.PlayerState.IDLE;
import net.nullsum.audinaut.view.AutoRepeatButton; import static net.nullsum.audinaut.domain.PlayerState.PAUSED;
import java.util.ArrayList; import static net.nullsum.audinaut.domain.PlayerState.STOPPED;
import java.util.concurrent.ScheduledFuture;
public class NowPlayingFragment extends SubsonicFragment implements OnGestureListener, SectionAdapter.OnItemClickedListener<DownloadFile>, OnSongChangedListener { public class NowPlayingFragment extends SubsonicFragment implements OnGestureListener, SectionAdapter.OnItemClickedListener<DownloadFile>, OnSongChangedListener {
private static final String TAG = NowPlayingFragment.class.getSimpleName();
private static final int PERCENTAGE_OF_SCREEN_FOR_SWIPE = 10; private static final int PERCENTAGE_OF_SCREEN_FOR_SWIPE = 10;
private static final int ACTION_PREVIOUS = 1; private static final int ACTION_PREVIOUS = 1;
@ -151,56 +145,46 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
Display d = w.getDefaultDisplay(); Display d = w.getDefaultDisplay();
swipeDistance = (d.getWidth() + d.getHeight()) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100; swipeDistance = (d.getWidth() + d.getHeight()) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100;
swipeVelocity = (d.getWidth() + d.getHeight()) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100; swipeVelocity = (d.getWidth() + d.getHeight()) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100;
gestureScanner = new GestureDetector(this); gestureScanner = new GestureDetector(context, this);
playlistFlipper = (ViewFlipper)rootView.findViewById(R.id.download_playlist_flipper); playlistFlipper = rootView.findViewById(R.id.download_playlist_flipper);
emptyTextView = (TextView)rootView.findViewById(R.id.download_empty); emptyTextView = rootView.findViewById(R.id.download_empty);
songTitleTextView = (TextView)rootView.findViewById(R.id.download_song_title); songTitleTextView = rootView.findViewById(R.id.download_song_title);
albumArtImageView = (ImageView)rootView.findViewById(R.id.download_album_art_image); albumArtImageView = rootView.findViewById(R.id.download_album_art_image);
positionTextView = (TextView)rootView.findViewById(R.id.download_position); positionTextView = rootView.findViewById(R.id.download_position);
durationTextView = (TextView)rootView.findViewById(R.id.download_duration); durationTextView = rootView.findViewById(R.id.download_duration);
statusTextView = (TextView)rootView.findViewById(R.id.download_status); statusTextView = rootView.findViewById(R.id.download_status);
progressBar = (SeekBar)rootView.findViewById(R.id.download_progress_bar); progressBar = rootView.findViewById(R.id.download_progress_bar);
previousButton = (AutoRepeatButton)rootView.findViewById(R.id.download_previous); previousButton = rootView.findViewById(R.id.download_previous);
nextButton = (AutoRepeatButton)rootView.findViewById(R.id.download_next); nextButton = rootView.findViewById(R.id.download_next);
rewindButton = (AutoRepeatButton) rootView.findViewById(R.id.download_rewind); rewindButton = rootView.findViewById(R.id.download_rewind);
fastforwardButton = (AutoRepeatButton) rootView.findViewById(R.id.download_fastforward); fastforwardButton = rootView.findViewById(R.id.download_fastforward);
pauseButton = rootView.findViewById(R.id.download_pause); pauseButton = rootView.findViewById(R.id.download_pause);
stopButton = rootView.findViewById(R.id.download_stop); stopButton = rootView.findViewById(R.id.download_stop);
startButton = rootView.findViewById(R.id.download_start); startButton = rootView.findViewById(R.id.download_start);
repeatButton = (ImageButton)rootView.findViewById(R.id.download_repeat); repeatButton = rootView.findViewById(R.id.download_repeat);
toggleListButton = rootView.findViewById(R.id.download_toggle_list); toggleListButton = rootView.findViewById(R.id.download_toggle_list);
playlistView = (RecyclerView)rootView.findViewById(R.id.download_list); playlistView = rootView.findViewById(R.id.download_list);
FastScroller fastScroller = (FastScroller) rootView.findViewById(R.id.download_fast_scroller); FastScroller fastScroller = rootView.findViewById(R.id.download_fast_scroller);
fastScroller.attachRecyclerView(playlistView); fastScroller.attachRecyclerView(playlistView);
setupLayoutManager(playlistView, false); setupLayoutManager(playlistView, false);
ItemTouchHelper touchHelper = new ItemTouchHelper(new DownloadFileItemHelperCallback(this, true)); ItemTouchHelper touchHelper = new ItemTouchHelper(new DownloadFileItemHelperCallback(this, true));
touchHelper.attachToRecyclerView(playlistView); touchHelper.attachToRecyclerView(playlistView);
View.OnTouchListener touchListener = new View.OnTouchListener() { View.OnTouchListener touchListener = (v, me) -> gestureScanner.onTouchEvent(me);
@Override
public boolean onTouch(View v, MotionEvent me) {
return gestureScanner.onTouchEvent(me);
}
};
pauseButton.setOnTouchListener(touchListener); pauseButton.setOnTouchListener(touchListener);
stopButton.setOnTouchListener(touchListener); stopButton.setOnTouchListener(touchListener);
startButton.setOnTouchListener(touchListener); startButton.setOnTouchListener(touchListener);
emptyTextView.setOnTouchListener(touchListener); emptyTextView.setOnTouchListener(touchListener);
albumArtImageView.setOnTouchListener(new View.OnTouchListener() { albumArtImageView.setOnTouchListener((v, me) -> {
@Override
public boolean onTouch(View v, MotionEvent me) {
if (me.getAction() == MotionEvent.ACTION_DOWN) { if (me.getAction() == MotionEvent.ACTION_DOWN) {
lastY = (int) me.getRawY(); lastY = (int) me.getRawY();
} }
return gestureScanner.onTouchEvent(me); return gestureScanner.onTouchEvent(me);
}
}); });
previousButton.setOnClickListener(new View.OnClickListener() { previousButton.setOnClickListener(view -> {
@Override
public void onClick(View view) {
warnIfStorageUnavailable(); warnIfStorageUnavailable();
new SilentBackgroundTask<Void>(context) { new SilentBackgroundTask<Void>(context) {
@Override @Override
@ -210,17 +194,10 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
} }
}.execute(); }.execute();
setControlsVisible(true); setControlsVisible(true);
}
});
previousButton.setOnRepeatListener(new Runnable() {
public void run() {
changeProgress(true);
}
}); });
previousButton.setOnRepeatListener(() -> changeProgress(true));
nextButton.setOnClickListener(new View.OnClickListener() { nextButton.setOnClickListener(view -> {
@Override
public void onClick(View view) {
warnIfStorageUnavailable(); warnIfStorageUnavailable();
new SilentBackgroundTask<Boolean>(context) { new SilentBackgroundTask<Boolean>(context) {
@Override @Override
@ -230,68 +207,33 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
} }
}.execute(); }.execute();
setControlsVisible(true); setControlsVisible(true);
}
});
nextButton.setOnRepeatListener(new Runnable() {
public void run() {
changeProgress(false);
}
}); });
nextButton.setOnRepeatListener(() -> changeProgress(false));
rewindButton.setOnClickListener(new View.OnClickListener() { rewindButton.setOnClickListener(view -> changeProgress(true));
@Override rewindButton.setOnRepeatListener(() -> changeProgress(true));
public void onClick(View view) {
changeProgress(true);
}
});
rewindButton.setOnRepeatListener(new Runnable() {
public void run() {
changeProgress(true);
}
});
fastforwardButton.setOnClickListener(new View.OnClickListener() { fastforwardButton.setOnClickListener(view -> changeProgress(false));
@Override fastforwardButton.setOnRepeatListener(() -> changeProgress(false));
public void onClick(View view) {
changeProgress(false);
}
});
fastforwardButton.setOnRepeatListener(new Runnable() {
public void run() {
changeProgress(false);
}
});
pauseButton.setOnClickListener(new View.OnClickListener() { pauseButton.setOnClickListener(view -> new SilentBackgroundTask<Void>(context) {
@Override
public void onClick(View view) {
new SilentBackgroundTask<Void>(context) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
getDownloadService().pause(); getDownloadService().pause();
return null; return null;
} }
}.execute(); }.execute());
}
});
stopButton.setOnClickListener(new View.OnClickListener() { stopButton.setOnClickListener(view -> new SilentBackgroundTask<Void>(context) {
@Override
public void onClick(View view) {
new SilentBackgroundTask<Void>(context) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
getDownloadService().reset(); getDownloadService().reset();
return null; return null;
} }
}.execute(); }.execute());
}
});
startButton.setOnClickListener(new View.OnClickListener() { startButton.setOnClickListener(view -> {
@Override
public void onClick(View view) {
warnIfStorageUnavailable(); warnIfStorageUnavailable();
new SilentBackgroundTask<Void>(context) { new SilentBackgroundTask<Void>(context) {
@Override @Override
@ -300,12 +242,9 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
return null; return null;
} }
}.execute(); }.execute();
}
}); });
repeatButton.setOnClickListener(new View.OnClickListener() { repeatButton.setOnClickListener(view -> {
@Override
public void onClick(View view) {
RepeatMode repeatMode = getDownloadService().getRepeatMode().next(); RepeatMode repeatMode = getDownloadService().getRepeatMode().next();
getDownloadService().setRepeatMode(repeatMode); getDownloadService().setRepeatMode(repeatMode);
switch (repeatMode) { switch (repeatMode) {
@ -323,27 +262,20 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
} }
updateRepeatButton(); updateRepeatButton();
setControlsVisible(true); setControlsVisible(true);
}
}); });
toggleListButton.setOnClickListener(new View.OnClickListener() { toggleListButton.setOnClickListener(view -> {
@Override
public void onClick(View view) {
toggleFullscreenAlbumArt(); toggleFullscreenAlbumArt();
setControlsVisible(true); setControlsVisible(true);
}
}); });
View overlay = rootView.findViewById(R.id.download_overlay_buttons); View overlay = rootView.findViewById(R.id.download_overlay_buttons);
final int overlayHeight = overlay != null ? overlay.getHeight() : -1; final int overlayHeight = overlay != null ? overlay.getHeight() : -1;
albumArtImageView.setOnClickListener(new View.OnClickListener() { albumArtImageView.setOnClickListener(view -> {
@Override
public void onClick(View view) {
if (overlayHeight == -1 || lastY < (view.getBottom() - overlayHeight)) { if (overlayHeight == -1 || lastY < (view.getBottom() - overlayHeight)) {
toggleFullscreenAlbumArt(); toggleFullscreenAlbumArt();
setControlsVisible(true); setControlsVisible(true);
} }
}
}); });
progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { progressBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@ -411,11 +343,8 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
@Override @Override
public boolean onOptionsItemSelected(MenuItem menuItem) { public boolean onOptionsItemSelected(MenuItem menuItem) {
if(menuItemSelected(menuItem.getItemId(), null)) { return menuItemSelected(menuItem.getItemId(), null) || super.onOptionsItemSelected(menuItem);
return true;
}
return super.onOptionsItemSelected(menuItem);
} }
@Override @Override
@ -436,17 +365,14 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
@Override @Override
public boolean onContextItemSelected(MenuItem menuItem, UpdateView<DownloadFile> updateView, DownloadFile downloadFile) { public boolean onContextItemSelected(MenuItem menuItem, UpdateView<DownloadFile> updateView, DownloadFile downloadFile) {
if(onContextItemSelected(menuItem, downloadFile.getSong())) { return onContextItemSelected(menuItem, downloadFile.getSong()) || menuItemSelected(menuItem.getItemId(), downloadFile);
return true;
}
return menuItemSelected(menuItem.getItemId(), downloadFile);
} }
private boolean menuItemSelected(int menuItemId, final DownloadFile song) { private boolean menuItemSelected(int menuItemId, final DownloadFile song) {
List<Entry> songs;
switch (menuItemId) { switch (menuItemId) {
case R.id.menu_show_album: case R.id.menu_show_artist: case R.id.menu_show_album:
case R.id.menu_show_artist:
Entry entry = song.getSong(); Entry entry = song.getSong();
Intent intent = new Intent(context, SubsonicFragmentActivity.class); Intent intent = new Intent(context, SubsonicFragmentActivity.class);
@ -454,21 +380,10 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
String albumId; String albumId;
String albumName; String albumName;
if (menuItemId == R.id.menu_show_album) { if (menuItemId == R.id.menu_show_album) {
if(Util.isTagBrowsing(context)) {
albumId = entry.getAlbumId(); albumId = entry.getAlbumId();
} else {
albumId = entry.getParent();
}
albumName = entry.getAlbum(); albumName = entry.getAlbum();
} else { } else {
if(Util.isTagBrowsing(context)) {
albumId = entry.getArtistId(); albumId = entry.getArtistId();
} else {
albumId = entry.getGrandParent();
if(albumId == null) {
intent.putExtra(Constants.INTENT_EXTRA_NAME_CHILD_ID, entry.getParent());
}
}
albumName = entry.getArtist(); albumName = entry.getArtist();
intent.putExtra(Constants.INTENT_EXTRA_NAME_ARTIST, true); intent.putExtra(Constants.INTENT_EXTRA_NAME_ARTIST, true);
} }
@ -501,10 +416,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
Util.startActivityWithoutTransition(context, intent); Util.startActivityWithoutTransition(context, intent);
return true; return true;
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, "", (dialog, which) -> new SilentBackgroundTask<Void>(context) {
@Override
public void onClick(DialogInterface dialog, int which) {
new SilentBackgroundTask<Void>(context) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
getDownloadService().setShufflePlayEnabled(false); getDownloadService().setShufflePlayEnabled(false);
@ -516,9 +428,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
protected void done(Void result) { protected void done(Void result) {
context.closeNowPlaying(); context.closeNowPlaying();
} }
}.execute(); }.execute());
}
});
return true; return true;
case R.id.menu_remove_played: case R.id.menu_remove_played:
if (getDownloadService().isRemovePlayed()) { if (getDownloadService().isRemovePlayed()) {
@ -543,7 +453,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
}.execute(); }.execute();
return true; return true;
case R.id.menu_save_playlist: case R.id.menu_save_playlist:
List<Entry> entries = new LinkedList<Entry>(); List<Entry> entries = new LinkedList<>();
for (DownloadFile downloadFile : getDownloadService().getSongs()) { for (DownloadFile downloadFile : getDownloadService().getSongs()) {
entries.add(downloadFile.getSong()); entries.add(downloadFile.getSong());
} }
@ -568,7 +478,8 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
// Any failed condition will get here // Any failed condition will get here
Util.toast(context, "Failed to start equalizer. Try restarting."); Util.toast(context, "Failed to start equalizer. Try restarting.");
return true; return true;
}case R.id.menu_batch_mode: }
case R.id.menu_batch_mode:
if (Util.isBatchMode(context)) { if (Util.isBatchMode(context)) {
Util.setBatchMode(context, false); Util.setBatchMode(context, false);
songListAdapter.notifyDataSetChanged(); songListAdapter.notifyDataSetChanged();
@ -593,6 +504,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
update(); update();
} }
} }
private void onResumeHandlers() { private void onResumeHandlers() {
executorService = Executors.newSingleThreadScheduledExecutor(); executorService = Executors.newSingleThreadScheduledExecutor();
setControlsVisible(true); setControlsVisible(true);
@ -603,22 +515,17 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
startFlipped = false; startFlipped = false;
} }
updateButtons();
if (currentPlaying == null && downloadService != null && currentPlaying == downloadService.getCurrentPlaying()) { if (currentPlaying == null && downloadService != null && currentPlaying == downloadService.getCurrentPlaying()) {
getImageLoader().loadImage(albumArtImageView, (Entry) null, true, false); getImageLoader().loadImage(albumArtImageView, null, true, false);
} }
context.runWhenServiceAvailable(new Runnable() { context.runWhenServiceAvailable(() -> {
@Override
public void run() {
if (primaryFragment) { if (primaryFragment) {
DownloadService downloadService = getDownloadService(); DownloadService downloadService1 = getDownloadService();
downloadService.addOnSongChangedListener(NowPlayingFragment.this, true); downloadService1.addOnSongChangedListener(NowPlayingFragment.this);
} }
updateRepeatButton(); updateRepeatButton();
updateTitle(); updateTitle();
}
}); });
} }
@ -627,6 +534,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
super.onPause(); super.onPause();
onPauseHandlers(); onPauseHandlers();
} }
private void onPauseHandlers() { private void onPauseHandlers() {
if (executorService != null) { if (executorService != null) {
DownloadService downloadService = getDownloadService(); DownloadService downloadService = getDownloadService();
@ -650,14 +558,15 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
} }
@Override @Override
public void setTitle(int title) { void setTitle(int title) {
this.title = context.getResources().getString(title); this.title = context.getResources().getString(title);
if (this.primaryFragment) { if (this.primaryFragment) {
context.setTitle(this.title); context.setTitle(this.title);
} }
} }
@Override @Override
public void setSubtitle(CharSequence title) { void setSubtitle(CharSequence title) {
this.subtitle = title; this.subtitle = title;
if (this.primaryFragment) { if (this.primaryFragment) {
context.setSubtitle(title); context.setSubtitle(title);
@ -675,22 +584,11 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
} }
final Handler handler = new Handler(); final Handler handler = new Handler();
Runnable runnable = new Runnable() { Runnable runnable = () -> handler.post(() -> setControlsVisible(false));
@Override
public void run() {
handler.post(new Runnable() {
@Override
public void run() {
setControlsVisible(false);
}
});
}
};
hideControlsFuture = executorService.schedule(runnable, 3000L, TimeUnit.MILLISECONDS); hideControlsFuture = executorService.schedule(runnable, 3000L, TimeUnit.MILLISECONDS);
} }
private void setControlsVisible(boolean visible) { private void setControlsVisible(boolean visible) {
DownloadService downloadService = getDownloadService();
try { try {
long duration = 1700L; long duration = 1700L;
FadeOutAnimation.createAndStart(rootView.findViewById(R.id.download_overlay_buttons), !visible, duration); FadeOutAnimation.createAndStart(rootView.findViewById(R.id.download_overlay_buttons), !visible, duration);
@ -698,17 +596,11 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
if (visible) { if (visible) {
scheduleHideControls(); scheduleHideControls();
} }
} catch(Exception e) { } catch (Exception ignored) {
} }
} }
private void updateButtons() {
if(context == null) {
return;
}
}
// Scroll to current playing/downloading. // Scroll to current playing/downloading.
private void scrollToCurrent() { private void scrollToCurrent() {
if (getDownloadService() == null || songListAdapter == null) { if (getDownloadService() == null || songListAdapter == null) {
@ -738,20 +630,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
} }
} }
private int getMinutes(int progress) {
if(progress < 30) {
return progress + 1;
} else if(progress < 49) {
return (progress - 30) * 5 + getMinutes(29);
} else if(progress < 57) {
return (progress - 48) * 30 + getMinutes(48);
} else if(progress < 81) {
return (progress - 56) * 60 + getMinutes(56);
} else {
return (progress - 80) * 150 + getMinutes(80);
}
}
private void toggleFullscreenAlbumArt() { private void toggleFullscreenAlbumArt() {
if (playlistFlipper.getDisplayedChild() == 1) { if (playlistFlipper.getDisplayedChild() == 1) {
playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_down_in)); playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_down_in));
@ -936,7 +814,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
} }
} else { } else {
songTitleTextView.setText(null); songTitleTextView.setText(null);
getImageLoader().loadImage(albumArtImageView, (Entry) null, true, false); getImageLoader().loadImage(albumArtImageView, null, true, false);
setSubtitle(null); setSubtitle(null);
} }
} }
@ -948,8 +826,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
DownloadService downloadService = getDownloadService(); DownloadService downloadService = getDownloadService();
if (downloadService.isShufflePlayEnabled()) { if (downloadService.isShufflePlayEnabled()) {
emptyTextView.setText(R.string.download_shuffle_loading); emptyTextView.setText(R.string.download_shuffle_loading);
} } else {
else {
emptyTextView.setText(R.string.download_empty); emptyTextView.setText(R.string.download_empty);
} }
@ -1006,7 +883,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
} }
@Override @Override
public void onStateUpdate(DownloadFile downloadFile, PlayerState playerState) { public void onStateUpdate(PlayerState playerState) {
switch (playerState) { switch (playerState) {
case DOWNLOADING: case DOWNLOADING:
if (currentPlaying != null) { if (currentPlaying != null) {
@ -1066,7 +943,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
} }
} }
public void updateRepeatButton() { private void updateRepeatButton() {
DownloadService downloadService = getDownloadService(); DownloadService downloadService = getDownloadService();
switch (downloadService.getRepeatMode()) { switch (downloadService.getRepeatMode()) {
case OFF: case OFF:
@ -1082,9 +959,8 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
break; break;
} }
} }
private void updateTitle() {
DownloadService downloadService = getDownloadService();
private void updateTitle() {
String title = context.getResources().getString(R.string.button_bar_now_playing); String title = context.getResources().getString(R.string.button_bar_now_playing);
setTitle(title); setTitle(title);

View File

@ -26,32 +26,33 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ListView; import android.widget.ListView;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public abstract class PreferenceCompatFragment extends SubsonicFragment { public abstract class PreferenceCompatFragment extends SubsonicFragment {
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;
final private Runnable mRequestFocus = new Runnable() {
public void run() {
mList.focusableViewAvailable(mList);
}
};
private PreferenceManager mPreferenceManager; private PreferenceManager mPreferenceManager;
private final 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) {
@ -63,12 +64,6 @@ public abstract class PreferenceCompatFragment extends SubsonicFragment {
} }
}; };
final private Runnable mRequestFocus = new Runnable() {
public void run() {
mList.focusableViewAvailable(mList);
}
};
private void bindPreferences() { private void bindPreferences() {
PreferenceScreen localPreferenceScreen = getPreferenceScreen(); PreferenceScreen localPreferenceScreen = getPreferenceScreen();
if (localPreferenceScreen != null) { if (localPreferenceScreen != null) {
@ -110,13 +105,7 @@ public abstract class PreferenceCompatFragment extends SubsonicFragment {
} }
} }
public void addPreferencesFromIntent(Intent intent) { private PreferenceScreen addPreferencesFromResource(int resId) {
requirePreferenceManager();
PreferenceScreen screen = inflateFromIntent(intent, getPreferenceScreen());
setPreferenceScreen(screen);
}
public PreferenceScreen addPreferencesFromResource(int resId) {
requirePreferenceManager(); requirePreferenceManager();
PreferenceScreen screen = inflateFromResource(getActivity(), resId, getPreferenceScreen()); PreferenceScreen screen = inflateFromResource(getActivity(), resId, getPreferenceScreen());
setPreferenceScreen(screen); setPreferenceScreen(screen);
@ -124,12 +113,9 @@ public abstract class PreferenceCompatFragment extends SubsonicFragment {
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(preference1 -> {
@Override onStartNewFragment(preference1.getKey());
public boolean onPreferenceClick(Preference preference) {
onStartNewFragment(preference.getKey());
return false; return false;
}
}); });
} }
} }
@ -137,19 +123,19 @@ public abstract class PreferenceCompatFragment extends SubsonicFragment {
return screen; return screen;
} }
public Preference findPreference(CharSequence key) { 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() { private ListView getListView() {
ensureList(); ensureList();
return mList; return mList;
} }
public PreferenceManager getPreferenceManager() { PreferenceManager getPreferenceManager() {
return mPreferenceManager; return mPreferenceManager;
} }
@ -226,7 +212,9 @@ public abstract class PreferenceCompatFragment extends SubsonicFragment {
dispatchActivityStop(); dispatchActivityStop();
} }
/** Access methods with visibility private **/ /**
* Access methods with visibility private
**/
private PreferenceManager createPreferenceManager() { private PreferenceManager createPreferenceManager() {
try { try {
@ -248,7 +236,7 @@ public abstract class PreferenceCompatFragment extends SubsonicFragment {
} }
} }
protected void setPreferenceScreen(PreferenceScreen preferenceScreen) { 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);
@ -294,18 +282,7 @@ public abstract class PreferenceCompatFragment extends SubsonicFragment {
} }
} }
private PreferenceScreen inflateFromResource(Context context, int resId, PreferenceScreen rootPreferences) {
private void setFragment(PreferenceFragment preferenceFragment) {
try {
Method m = PreferenceManager.class.getDeclaredMethod("setFragment", PreferenceFragment.class);
m.setAccessible(true);
m.invoke(mPreferenceManager, preferenceFragment);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
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);
@ -317,18 +294,7 @@ public abstract class PreferenceCompatFragment extends SubsonicFragment {
return preferenceScreen; return preferenceScreen;
} }
public PreferenceScreen inflateFromIntent(Intent queryIntent, PreferenceScreen rootPreferences) {
PreferenceScreen preferenceScreen ;
try {
Method m = PreferenceManager.class.getDeclaredMethod("inflateFromIntent", Intent.class, PreferenceScreen.class);
m.setAccessible(true);
preferenceScreen = (PreferenceScreen) m.invoke(mPreferenceManager, queryIntent, rootPreferences);
} catch (Exception e) {
throw new RuntimeException(e);
}
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

@ -1,24 +1,16 @@
package net.nullsum.audinaut.fragments; package net.nullsum.audinaut.fragments;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.view.MenuItemCompat; import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.View;
import android.view.MenuItem; import android.view.MenuItem;
import android.net.Uri; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.adapter.ArtistAdapter; import net.nullsum.audinaut.adapter.ArtistAdapter;
import net.nullsum.audinaut.adapter.EntryGridAdapter; import net.nullsum.audinaut.adapter.EntryGridAdapter;
@ -28,26 +20,30 @@ import net.nullsum.audinaut.domain.Artist;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.SearchCritera; import net.nullsum.audinaut.domain.SearchCritera;
import net.nullsum.audinaut.domain.SearchResult; import net.nullsum.audinaut.domain.SearchResult;
import net.nullsum.audinaut.service.DownloadService;
import net.nullsum.audinaut.service.MusicService; import net.nullsum.audinaut.service.MusicService;
import net.nullsum.audinaut.service.MusicServiceFactory; import net.nullsum.audinaut.service.MusicServiceFactory;
import net.nullsum.audinaut.service.DownloadService;
import net.nullsum.audinaut.util.BackgroundTask; import net.nullsum.audinaut.util.BackgroundTask;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.TabBackgroundTask; import net.nullsum.audinaut.util.TabBackgroundTask;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
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 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; private RecyclerView recyclerView;
protected SearchAdapter adapter; private SearchAdapter adapter;
protected boolean largeAlbums = false; private boolean largeAlbums = false;
private SearchResult searchResult; private SearchResult searchResult;
private boolean skipSearch = false; private boolean skipSearch = false;
@ -79,10 +75,10 @@ public class SearchFragment extends SubsonicFragment implements SectionAdapter.O
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 = rootView.findViewById(R.id.refresh_layout);
refreshLayout.setEnabled(false); refreshLayout.setEnabled(false);
recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_recycler); recyclerView = rootView.findViewById(R.id.fragment_recycler);
setupLayoutManager(recyclerView, largeAlbums); setupLayoutManager(recyclerView, largeAlbums);
registerForContextMenu(recyclerView); registerForContextMenu(recyclerView);
@ -157,7 +153,7 @@ public class SearchFragment extends SubsonicFragment implements SectionAdapter.O
if (entry.isDirectory()) { if (entry.isDirectory()) {
onAlbumSelected(entry, false); onAlbumSelected(entry, false);
} else { } else {
onSongSelected(entry, false, true, true, false); onSongSelected(entry, true);
} }
} }
} }
@ -243,16 +239,14 @@ public class SearchFragment extends SubsonicFragment implements SectionAdapter.O
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 append) {
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(Collections.singletonList(song), false, false, false, false);
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));
} }
@ -285,7 +279,7 @@ public class SearchFragment extends SubsonicFragment implements SectionAdapter.O
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);
} }
} }
} }

View File

@ -1,6 +1,5 @@
package net.nullsum.audinaut.fragments; package net.nullsum.audinaut.fragments;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
@ -29,7 +28,6 @@ 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 List<MusicFolder> musicFolders = null; private List<MusicFolder> musicFolders = null;
private List<Entry> entries; private List<Entry> entries;
@ -93,7 +91,7 @@ public class SelectArtistFragment extends SelectRecyclerFragment<Serializable> i
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)) || 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());
@ -129,7 +127,7 @@ public class SelectArtistFragment extends SelectRecyclerFragment<Serializable> i
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) || 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)) {
@ -167,17 +165,7 @@ public class SelectArtistFragment extends SelectRecyclerFragment<Serializable> i
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)) {
musicFolders = musicService.getMusicFolders(refresh, context, listener);
// Hide folders option if there is only one
if (musicFolders.size() == 1) {
musicFolders = null; musicFolders = null;
Util.setSelectedMusicFolderId(context, null);
}
} else {
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);
@ -204,9 +192,7 @@ public class SelectArtistFragment extends SelectRecyclerFragment<Serializable> i
items.addAll(indexes.getArtists()); items.addAll(indexes.getArtists());
entries = dir.getChildren(false, true); entries = dir.getChildren(false, true);
for(Entry entry: entries) { items.addAll(entries);
items.add(entry);
}
} }
return items; return items;

View File

@ -1,74 +1,57 @@
package net.nullsum.audinaut.fragments; package net.nullsum.audinaut.fragments;
import android.support.v7.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.text.Html;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.Display;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.adapter.AlphabeticalAlbumAdapter; import net.nullsum.audinaut.adapter.AlphabeticalAlbumAdapter;
import net.nullsum.audinaut.adapter.EntryInfiniteGridAdapter;
import net.nullsum.audinaut.adapter.EntryGridAdapter; import net.nullsum.audinaut.adapter.EntryGridAdapter;
import net.nullsum.audinaut.adapter.EntryInfiniteGridAdapter;
import net.nullsum.audinaut.adapter.SectionAdapter; import net.nullsum.audinaut.adapter.SectionAdapter;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.service.CachedMusicService; import net.nullsum.audinaut.service.CachedMusicService;
import net.nullsum.audinaut.service.DownloadService;
import net.nullsum.audinaut.util.DrawableTint;
import net.nullsum.audinaut.util.ImageLoader;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import net.nullsum.audinaut.service.MusicService; import net.nullsum.audinaut.service.MusicService;
import net.nullsum.audinaut.service.MusicServiceFactory; import net.nullsum.audinaut.service.MusicServiceFactory;
import net.nullsum.audinaut.service.OfflineException; import net.nullsum.audinaut.service.OfflineException;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.LoadingTask; import net.nullsum.audinaut.util.LoadingTask;
import net.nullsum.audinaut.util.Pair; import net.nullsum.audinaut.util.Pair;
import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.util.TabBackgroundTask; import net.nullsum.audinaut.util.TabBackgroundTask;
import net.nullsum.audinaut.util.UpdateHelper;
import net.nullsum.audinaut.util.UserUtil;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.view.FastScroller; import net.nullsum.audinaut.view.FastScroller;
import net.nullsum.audinaut.view.GridSpacingDecoration;
import net.nullsum.audinaut.view.MyLeadingMarginSpan2;
import net.nullsum.audinaut.view.RecyclingImageView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Collections;
import java.util.HashSet; import java.util.List;
import java.util.Set;
import static net.nullsum.audinaut.domain.MusicDirectory.Entry; import static net.nullsum.audinaut.domain.MusicDirectory.Entry;
public class SelectDirectoryFragment extends SubsonicFragment implements SectionAdapter.OnItemClickedListener<Entry> { public class SelectDirectoryFragment extends SubsonicFragment implements SectionAdapter.OnItemClickedListener<Entry> {
private static final String TAG = SelectDirectoryFragment.class.getSimpleName(); private String id;
private String name;
private Entry directory;
private String playlistId;
private String playlistName;
private boolean playlistOwner;
private String albumListType;
private String albumListExtra;
private int albumListSize;
private boolean refreshListing = false;
private boolean restoredInstance = false;
private boolean lookupParent = false;
private boolean largeAlbums = false;
private boolean topTracks = false;
private String lookupEntry;
private RecyclerView recyclerView; private RecyclerView recyclerView;
private FastScroller fastScroller; private FastScroller fastScroller;
private EntryGridAdapter entryGridAdapter; private EntryGridAdapter entryGridAdapter;
@ -76,27 +59,6 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
private List<Entry> entries; private List<Entry> entries;
private LoadTask currentTask; private LoadTask currentTask;
private SilentBackgroundTask updateCoverArtTask;
private ImageView coverArtView;
private Entry coverArtRep;
private String coverArtId;
String id;
String name;
Entry directory;
String playlistId;
String playlistName;
boolean playlistOwner;
String albumListType;
String albumListExtra;
int albumListSize;
boolean refreshListing = false;
boolean restoredInstance = false;
boolean lookupParent = false;
boolean largeAlbums = false;
boolean topTracks = false;
String lookupEntry;
public SelectDirectoryFragment() { public SelectDirectoryFragment() {
super(); super();
} }
@ -131,7 +93,6 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
playlistId = args.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID); playlistId = args.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID);
playlistName = args.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME); playlistName = args.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME);
playlistOwner = args.getBoolean(Constants.INTENT_EXTRA_NAME_PLAYLIST_OWNER, false); playlistOwner = args.getBoolean(Constants.INTENT_EXTRA_NAME_PLAYLIST_OWNER, false);
Object shareObj = args.getSerializable(Constants.INTENT_EXTRA_NAME_SHARE);
albumListType = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE); albumListType = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE);
albumListExtra = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA); albumListExtra = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA);
albumListSize = args.getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0); albumListSize = args.getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0);
@ -150,23 +111,23 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
albums = (List<Entry>) args.getSerializable(Constants.FRAGMENT_LIST2); albums = (List<Entry>) args.getSerializable(Constants.FRAGMENT_LIST2);
if (albums == null) { if (albums == null) {
albums = new ArrayList<Entry>(); albums = new ArrayList<>();
} }
} }
} }
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 = rootView.findViewById(R.id.refresh_layout);
refreshLayout.setOnRefreshListener(this); refreshLayout.setOnRefreshListener(this);
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;
} }
recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_recycler); recyclerView = rootView.findViewById(R.id.fragment_recycler);
recyclerView.setHasFixedSize(true); recyclerView.setHasFixedSize(true);
fastScroller = (FastScroller) rootView.findViewById(R.id.fragment_fast_scroller); fastScroller = rootView.findViewById(R.id.fragment_fast_scroller);
setupScrollList(recyclerView); setupScrollList(recyclerView);
setupLayoutManager(recyclerView, largeAlbums); setupLayoutManager(recyclerView, largeAlbums);
@ -208,8 +169,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
} else { } else {
if (Util.isOffline(context)) { if (Util.isOffline(context)) {
menuInflater.inflate(R.menu.select_song_offline, menu); menuInflater.inflate(R.menu.select_song_offline, menu);
} } else {
else {
menuInflater.inflate(R.menu.select_song, menu); menuInflater.inflate(R.menu.select_song, menu);
if (playlistId == null || !playlistOwner) { if (playlistId == null || !playlistOwner) {
@ -240,6 +200,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
recreateContextMenu(menu); recreateContextMenu(menu);
} }
@Override @Override
public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Entry> updateView, Entry entry) { public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Entry> updateView, Entry entry) {
if (onContextItemSelected(menuItem, entry)) { if (onContextItemSelected(menuItem, entry)) {
@ -248,7 +209,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
switch (menuItem.getItemId()) { switch (menuItem.getItemId()) {
case R.id.song_menu_remove_playlist: case R.id.song_menu_remove_playlist:
removeFromPlaylist(playlistId, playlistName, Arrays.<Integer>asList(entries.indexOf(entry))); removeFromPlaylist(playlistId, playlistName, Collections.singletonList(entries.indexOf(entry)));
break; break;
} }
@ -271,7 +232,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
} }
fragment.setArguments(args); fragment.setArguments(args);
replaceFragment(fragment, true); replaceFragment(fragment);
} else { } else {
onSongPress(entries, entry, albumListType == null); onSongPress(entries, entry, albumListType == null);
} }
@ -309,7 +270,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
private void getMusicDirectory(final String id, final String name, final boolean refresh) { private void getMusicDirectory(final String id, final String name, final boolean refresh) {
setTitle(name); setTitle(name);
new LoadTask(refresh) { new LoadTask() {
@Override @Override
protected MusicDirectory load(MusicService service) throws Exception { protected MusicDirectory load(MusicService service) throws Exception {
MusicDirectory dir = getMusicDirectory(id, name, refresh, service, this); MusicDirectory dir = getMusicDirectory(id, name, refresh, service, this);
@ -342,47 +303,10 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
}.execute(); }.execute();
} }
private void getRecursiveMusicDirectory(final String id, final String name, final boolean refresh) {
setTitle(name);
new LoadTask(refresh) {
@Override
protected MusicDirectory load(MusicService service) throws Exception {
MusicDirectory root = getMusicDirectory(id, name, refresh, service, this);
List<Entry> songs = new ArrayList<Entry>();
getSongsRecursively(root, songs);
root.replaceChildren(songs);
return root;
}
private void getSongsRecursively(MusicDirectory parent, List<Entry> songs) throws Exception {
songs.addAll(parent.getChildren(false, true));
for (Entry dir : parent.getChildren(true, false)) {
MusicService musicService = MusicServiceFactory.getMusicService(context);
MusicDirectory musicDirectory;
if(Util.isTagBrowsing(context) && !Util.isOffline(context)) {
musicDirectory = musicService.getAlbum(dir.getId(), dir.getTitle(), false, context, this);
} else {
musicDirectory = musicService.getMusicDirectory(dir.getId(), dir.getTitle(), false, context, this);
}
getSongsRecursively(musicDirectory, songs);
}
}
@Override
protected void done(Pair<MusicDirectory, Boolean> result) {
SelectDirectoryFragment.this.name = result.getFirst().getName();
setTitle(SelectDirectoryFragment.this.name);
super.done(result);
}
}.execute();
}
private void getPlaylist(final String playlistId, final String playlistName, final boolean refresh) { private void getPlaylist(final String playlistId, final String playlistName, final boolean refresh) {
setTitle(playlistName); setTitle(playlistName);
new LoadTask(refresh) { new LoadTask() {
@Override @Override
protected MusicDirectory load(MusicService service) throws Exception { protected MusicDirectory load(MusicService service) throws Exception {
return service.getPlaylist(refresh, playlistId, playlistName, context, this); return service.getPlaylist(refresh, playlistId, playlistName, context, this);
@ -401,7 +325,8 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
setTitle(albumListExtra); setTitle(albumListExtra);
} else if ("alphabeticalByName".equals(albumListType)) { } else if ("alphabeticalByName".equals(albumListType)) {
setTitle(R.string.main_albums_alphabetical); setTitle(R.string.main_albums_alphabetical);
} if (MainFragment.SONGS_NEWEST.equals(albumListType)) { }
if (MainFragment.SONGS_NEWEST.equals(albumListType)) {
setTitle(R.string.main_songs_newest); setTitle(R.string.main_songs_newest);
} else if (MainFragment.SONGS_TOP_PLAYED.equals(albumListType)) { } else if (MainFragment.SONGS_TOP_PLAYED.equals(albumListType)) {
setTitle(R.string.main_songs_top_played); setTitle(R.string.main_songs_top_played);
@ -411,7 +336,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
setTitle(R.string.main_songs_frequent); setTitle(R.string.main_songs_frequent);
} }
new LoadTask(true) { new LoadTask() {
@Override @Override
protected MusicDirectory load(MusicService service) throws Exception { protected MusicDirectory load(MusicService service) throws Exception {
MusicDirectory result; MusicDirectory result;
@ -423,7 +348,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
} }
} else if ("genres".equals(albumListType) || "genres-songs".equals(albumListType)) { } else if ("genres".equals(albumListType) || "genres-songs".equals(albumListType)) {
result = service.getSongsByGenre(albumListExtra, size, 0, context, this); result = service.getSongsByGenre(albumListExtra, size, 0, context, this);
} else if(albumListType.indexOf(MainFragment.SONGS_LIST_PREFIX) != -1) { } else if (albumListType.contains(MainFragment.SONGS_LIST_PREFIX)) {
result = service.getSongList(albumListType, size, 0, context, this); result = service.getSongList(albumListType, size, 0, context, this);
} else { } else {
result = service.getAlbumList(albumListType, size, 0, refresh, context, this); result = service.getAlbumList(albumListType, size, 0, refresh, context, this);
@ -433,58 +358,6 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
}.execute(); }.execute();
} }
private abstract class LoadTask extends TabBackgroundTask<Pair<MusicDirectory, Boolean>> {
private boolean refresh;
public LoadTask(boolean refresh) {
super(SelectDirectoryFragment.this);
this.refresh = refresh;
currentTask = this;
}
protected abstract MusicDirectory load(MusicService service) throws Exception;
@Override
protected Pair<MusicDirectory, Boolean> doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(context);
MusicDirectory dir = load(musicService);
albums = dir.getChildren(true, false);
entries = dir.getChildren();
// This isn't really an artist if no albums on it!
if(albums.size() == 0) {
artist = false;
}
return new Pair<>(dir, true);
}
@Override
protected void done(Pair<MusicDirectory, Boolean> result) {
finishLoading();
currentTask = null;
}
@Override
public void updateCache(int changeCode) {
if(entryGridAdapter != null && changeCode == CachedMusicService.CACHE_UPDATE_LIST) {
entryGridAdapter.notifyDataSetChanged();
} else if(changeCode == CachedMusicService.CACHE_UPDATE_METADATA) {
if(coverArtView != null && coverArtRep != null && !Util.equals(coverArtRep.getCoverArt(), coverArtId)) {
synchronized (coverArtRep) {
if (updateCoverArtTask != null && updateCoverArtTask.isRunning()) {
updateCoverArtTask.cancel();
}
updateCoverArtTask = getImageLoader().loadImage(coverArtView, coverArtRep, false, true);
coverArtId = coverArtRep.getCoverArt();
}
}
}
}
}
@Override @Override
public SectionAdapter<Entry> getCurrentAdapter() { public SectionAdapter<Entry> getCurrentAdapter() {
return entryGridAdapter; return entryGridAdapter;
@ -530,10 +403,6 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
infiniteGridAdapter.setData(albumListType, albumListExtra, albumListSize); infiniteGridAdapter.setData(albumListType, albumListExtra, albumListSize);
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
@Override @Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) { public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
@ -559,10 +428,10 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
entryGridAdapter.setOnItemClickedListener(this); entryGridAdapter.setOnItemClickedListener(this);
// Always show artist if this is not a artist we are viewing // Always show artist if this is not a artist we are viewing
if (!artist) { if (!artist) {
entryGridAdapter.setShowArtist(true); entryGridAdapter.setShowArtist();
} }
if (topTracks) { if (topTracks) {
entryGridAdapter.setShowAlbum(true); entryGridAdapter.setShowAlbum();
} }
int scrollToPosition = -1; int scrollToPosition = -1;
@ -596,12 +465,13 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
protected void playNow(final boolean shuffle, final boolean append, final boolean playNext) { protected void playNow(final boolean shuffle, final boolean append, final boolean playNext) {
List<Entry> songs = getSelectedEntries(); List<Entry> songs = getSelectedEntries();
if (!songs.isEmpty()) { if (!songs.isEmpty()) {
download(songs, append, false, !append, playNext, shuffle); download(songs, append, !append, playNext, shuffle);
entryGridAdapter.clearSelected(); entryGridAdapter.clearSelected();
} else { } else {
playAll(shuffle, append, playNext); playAll(shuffle, append, playNext);
} }
} }
private void playAll(final boolean shuffle, final boolean append, final boolean playNext) { private void playAll(final boolean shuffle, final boolean append, final boolean playNext) {
boolean hasSubFolders = albums != null && !albums.isEmpty(); boolean hasSubFolders = albums != null && !albums.isEmpty();
@ -610,13 +480,13 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
} else if (hasSubFolders && albumListType != null) { } else if (hasSubFolders && albumListType != null) {
downloadRecursively(albums, shuffle, append, playNext); downloadRecursively(albums, shuffle, append, playNext);
} else { } else {
download(entries, append, false, !append, playNext, shuffle); download(entries, append, !append, playNext, shuffle);
} }
} }
private List<Integer> getSelectedIndexes() { private List<Integer> getSelectedIndexes() {
List<Entry> selected = entryGridAdapter.getSelected(); List<Entry> selected = entryGridAdapter.getSelected();
List<Integer> indexes = new ArrayList<Integer>(); List<Integer> indexes = new ArrayList<>();
for (Entry entry : selected) { for (Entry entry : selected) {
indexes.add(entries.indexOf(entry)); indexes.add(entries.indexOf(entry));
@ -634,22 +504,23 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
if (songs.isEmpty()) { if (songs.isEmpty()) {
// Get both songs and albums // Get both songs and albums
downloadRecursively(id, save, false, false, false, true); downloadRecursively(id, save, false, false, false, true, false);
} else { } else {
downloadBackground(save, songs); downloadBackground(save, songs);
} }
} }
@Override @Override
protected void downloadBackground(final boolean save, final List<Entry> entries) { void downloadBackground(final boolean save, final List<Entry> entries) {
if (getDownloadService() == null) { if (getDownloadService() == null) {
return; return;
} }
warnIfStorageUnavailable(); warnIfStorageUnavailable();
RecursiveLoader onValid = new RecursiveLoader(context) { new RecursiveLoader(context) {
@Override @Override
protected Boolean doInBackground() throws Throwable { protected Boolean doInBackground() throws Throwable {
getSongsRecursively(entries, true); getSongsRecursively(entries);
getDownloadService().downloadBackground(songs, save); getDownloadService().downloadBackground(songs, save);
return null; return null;
} }
@ -662,8 +533,8 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
} }
@Override @Override
protected void download(List<Entry> entries, boolean append, boolean save, boolean autoplay, boolean playNext, boolean shuffle) { void download(List<Entry> entries, boolean append, boolean autoplay, boolean playNext, boolean shuffle) {
download(entries, append, save, autoplay, playNext, shuffle, playlistName, playlistId); download(entries, append, autoplay, playNext, shuffle, playlistName, playlistId);
} }
@Override @Override
@ -683,7 +554,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
} }
} }
public void removeFromPlaylist(final String id, final String name, final List<Integer> indexes) { private void removeFromPlaylist(final String id, final String name, final List<Integer> indexes) {
new LoadingTask<Void>(context, true) { new LoadingTask<Void>(context, true) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
@ -714,113 +585,43 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Section
}.execute(); }.execute();
} }
private void showTopTracks() { private abstract class LoadTask extends TabBackgroundTask<Pair<MusicDirectory, Boolean>> {
SubsonicFragment fragment = new SelectDirectoryFragment();
Bundle args = new Bundle(getArguments());
args.putBoolean(Constants.INTENT_EXTRA_TOP_TRACKS, true);
fragment.setArguments(args);
replaceFragment(fragment, true); public LoadTask() {
super(SelectDirectoryFragment.this);
currentTask = this;
} }
private View createHeader() { protected abstract MusicDirectory load(MusicService service) throws Exception;
View header = LayoutInflater.from(context).inflate(R.layout.select_album_header, null, false);
setupCoverArt(header);
setupTextDisplay(header);
return header;
}
private void setupCoverArt(View header) {
setupCoverArtImpl((RecyclingImageView) header.findViewById(R.id.select_album_art));
}
private void setupCoverArtImpl(RecyclingImageView coverArtView) {
final ImageLoader imageLoader = getImageLoader();
if(entries.size() > 0) {
coverArtRep = null;
this.coverArtView = coverArtView;
for (int i = 0; (i < 3) && (coverArtRep == null || coverArtRep.getCoverArt() == null); i++) {
coverArtRep = entries.get(random.nextInt(entries.size()));
}
coverArtView.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View v) { protected Pair<MusicDirectory, Boolean> doInBackground() throws Throwable {
if (coverArtRep == null || coverArtRep.getCoverArt() == null) { MusicService musicService = MusicServiceFactory.getMusicService(context);
return; MusicDirectory dir = load(musicService);
albums = dir.getChildren(true, false);
entries = dir.getChildren();
// This isn't really an artist if no albums on it!
if (albums.size() == 0) {
artist = false;
} }
AlertDialog.Builder builder = new AlertDialog.Builder(context); return new Pair<>(dir, true);
ImageView fullScreenView = new ImageView(context);
imageLoader.loadImage(fullScreenView, coverArtRep, true, true);
builder.setCancelable(true);
AlertDialog imageDialog = builder.create();
// Set view here with unecessary 0's to remove top/bottom border
imageDialog.setView(fullScreenView, 0, 0, 0, 0);
imageDialog.show();
}
});
synchronized (coverArtRep) {
coverArtId = coverArtRep.getCoverArt();
updateCoverArtTask = imageLoader.loadImage(coverArtView, coverArtRep, false, true);
}
} }
coverArtView.setOnInvalidated(new RecyclingImageView.OnInvalidated() {
@Override @Override
public void onInvalidated(RecyclingImageView imageView) { protected void done(Pair<MusicDirectory, Boolean> result) {
setupCoverArtImpl(imageView); finishLoading();
} currentTask = null;
});
}
private void setupTextDisplay(final View header) {
final TextView titleView = (TextView) header.findViewById(R.id.select_album_title);
if(playlistName != null) {
titleView.setText(playlistName);
} else if(name != null) {
titleView.setText(name);
} }
int songCount = 0; @Override
public void updateCache(int changeCode) {
Set<String> artists = new HashSet<String>(); if (entryGridAdapter != null && changeCode == CachedMusicService.CACHE_UPDATE_LIST) {
Set<Integer> years = new HashSet<Integer>(); entryGridAdapter.notifyDataSetChanged();
Integer totalDuration = 0;
for (Entry entry : entries) {
if (!entry.isDirectory()) {
songCount++;
if (entry.getArtist() != null) {
artists.add(entry.getArtist());
}
if(entry.getYear() != null) {
years.add(entry.getYear());
}
Integer duration = entry.getDuration();
if(duration != null) {
totalDuration += duration;
} }
} }
} }
final TextView artistView = (TextView) header.findViewById(R.id.select_album_artist);
if (artists.size() == 1) {
String artistText = artists.iterator().next();
if(years.size() == 1) {
artistText += " - " + years.iterator().next();
}
artistView.setText(artistText);
artistView.setVisibility(View.VISIBLE);
} else {
artistView.setVisibility(View.GONE);
}
TextView songCountView = (TextView) header.findViewById(R.id.select_album_song_count);
TextView songLengthView = (TextView) header.findViewById(R.id.select_album_song_length);
String s = context.getResources().getQuantityString(R.plurals.select_album_n_songs, songCount, songCount);
songCountView.setText(s.toUpperCase());
songLengthView.setText(Util.formatDuration(totalDuration));
}
} }

View File

@ -21,18 +21,17 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.adapter.GenreAdapter;
import net.nullsum.audinaut.adapter.SectionAdapter; import net.nullsum.audinaut.adapter.SectionAdapter;
import net.nullsum.audinaut.domain.Genre; import net.nullsum.audinaut.domain.Genre;
import net.nullsum.audinaut.service.MusicService; import net.nullsum.audinaut.service.MusicService;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.ProgressListener; import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.adapter.GenreAdapter;
import net.nullsum.audinaut.view.UpdateView; 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();
@Override @Override
public int getOptionsMenu() { public int getOptionsMenu() {
@ -68,7 +67,8 @@ public class SelectGenreFragment extends SelectRecyclerFragment<Genre> {
} }
@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) {

View File

@ -1,10 +1,7 @@
package net.nullsum.audinaut.fragments; package net.nullsum.audinaut.fragments;
import android.support.v7.app.AlertDialog;
import android.content.DialogInterface;
import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AlertDialog;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
@ -13,30 +10,26 @@ import android.widget.CheckBox;
import android.widget.EditText; import android.widget.EditText;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.adapter.PlaylistAdapter;
import net.nullsum.audinaut.adapter.SectionAdapter; import net.nullsum.audinaut.adapter.SectionAdapter;
import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.Playlist; import net.nullsum.audinaut.domain.Playlist;
import net.nullsum.audinaut.service.DownloadFile;
import net.nullsum.audinaut.service.MusicService; import net.nullsum.audinaut.service.MusicService;
import net.nullsum.audinaut.service.MusicServiceFactory; import net.nullsum.audinaut.service.MusicServiceFactory;
import net.nullsum.audinaut.service.OfflineException; import net.nullsum.audinaut.service.OfflineException;
import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.util.SyncUtil;
import net.nullsum.audinaut.util.CacheCleaner; import net.nullsum.audinaut.util.CacheCleaner;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.LoadingTask; import net.nullsum.audinaut.util.LoadingTask;
import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.util.SyncUtil;
import net.nullsum.audinaut.util.UserUtil; import net.nullsum.audinaut.util.UserUtil;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.adapter.PlaylistAdapter;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import java.text.DateFormat; import java.text.DateFormat;
import java.util.ArrayList; import java.util.ArrayList;
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();
@Override @Override
public void onCreate(Bundle bundle) { public void onCreate(Bundle bundle) {
@ -50,11 +43,10 @@ public class SelectPlaylistFragment extends SelectRecyclerFragment<Playlist> {
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() && !playlist.getId().contains(".m3u") && !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);
} }
@ -67,11 +59,10 @@ public class SelectPlaylistFragment extends SelectRecyclerFragment<Playlist> {
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;
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());
break; break;
case R.id.playlist_menu_play_now: case R.id.playlist_menu_play_now:
fragment = new SelectDirectoryFragment(); fragment = new SelectDirectoryFragment();
@ -147,7 +138,7 @@ public class SelectPlaylistFragment extends SelectRecyclerFragment<Playlist> {
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().contains(".m3u"))) {
args.putBoolean(Constants.INTENT_EXTRA_NAME_PLAYLIST_OWNER, true); args.putBoolean(Constants.INTENT_EXTRA_NAME_PLAYLIST_OWNER, true);
} }
fragment.setArguments(args); fragment.setArguments(args);
@ -172,10 +163,7 @@ public class SelectPlaylistFragment extends SelectRecyclerFragment<Playlist> {
} }
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(), (dialog, which) -> new LoadingTask<Void>(context, false) {
@Override
public void onClick(DialogInterface dialog, int which) {
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);
@ -201,9 +189,7 @@ public class SelectPlaylistFragment extends SelectRecyclerFragment<Playlist> {
Util.toast(context, msg, false); Util.toast(context, msg, false);
} }
}.execute(); }.execute());
}
});
} }
private void displayPlaylistInfo(final Playlist playlist) { private void displayPlaylistInfo(final Playlist playlist) {
@ -254,9 +240,9 @@ public class SelectPlaylistFragment extends SelectRecyclerFragment<Playlist> {
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 = dialogView.findViewById(R.id.get_playlist_name);
final EditText commentBox = (EditText)dialogView.findViewById(R.id.get_playlist_comment); final EditText commentBox = dialogView.findViewById(R.id.get_playlist_comment);
final CheckBox publicBox = (CheckBox)dialogView.findViewById(R.id.get_playlist_public); final CheckBox publicBox = dialogView.findViewById(R.id.get_playlist_public);
nameBox.setText(playlist.getName()); nameBox.setText(playlist.getName());
commentBox.setText(playlist.getComment()); commentBox.setText(playlist.getComment());
@ -271,10 +257,7 @@ public class SelectPlaylistFragment extends SelectRecyclerFragment<Playlist> {
.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, (dialog, which) -> new LoadingTask<Void>(context, false) {
@Override
public void onClick(DialogInterface dialog, int which) {
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();
@ -307,40 +290,9 @@ public class SelectPlaylistFragment extends SelectRecyclerFragment<Playlist> {
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) {
SyncUtil.addSyncedPlaylist(context, playlist.getId());
downloadPlaylist(playlist.getId(), playlist.getName(), true, true, false, false, true);
}
private void stopSyncPlaylist(final Playlist playlist) {
SyncUtil.removeSyncedPlaylist(context, playlist.getId());
new LoadingTask<Void>(context, false) {
@Override
protected Void doInBackground() throws Throwable {
// Unpin all of the songs in playlist
MusicService musicService = MusicServiceFactory.getMusicService(context);
MusicDirectory root = musicService.getPlaylist(true, playlist.getId(), playlist.getName(), context, this);
for(MusicDirectory.Entry entry: root.getChildren()) {
DownloadFile file = new DownloadFile(context, entry, false);
file.unpin();
}
return null;
}
@Override
protected void done(Void result) {
}
}.execute();
}
} }

View File

@ -15,27 +15,16 @@
package net.nullsum.audinaut.fragments; package net.nullsum.audinaut.fragments;
import android.app.SearchManager;
import android.app.SearchableInfo;
import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.adapter.SectionAdapter; import net.nullsum.audinaut.adapter.SectionAdapter;
import net.nullsum.audinaut.service.MusicService; import net.nullsum.audinaut.service.MusicService;
@ -45,17 +34,21 @@ import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.util.TabBackgroundTask; import net.nullsum.audinaut.util.TabBackgroundTask;
import net.nullsum.audinaut.view.FastScroller; import net.nullsum.audinaut.view.FastScroller;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
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; RecyclerView recyclerView;
protected FastScroller fastScroller; SectionAdapter<T> adapter;
protected SectionAdapter<T> adapter; List<T> objects;
protected UpdateTask currentTask; boolean serialize = true;
protected List<T> objects; boolean largeAlbums = false;
protected boolean serialize = true; boolean pullToRefresh = true;
protected boolean largeAlbums = false; boolean backgroundUpdate = true;
protected boolean pullToRefresh = true; private FastScroller fastScroller;
protected boolean backgroundUpdate = true; private UpdateTask currentTask;
@Override @Override
public void onCreate(Bundle bundle) { public void onCreate(Bundle bundle) {
@ -78,11 +71,11 @@ public abstract class SelectRecyclerFragment<T> extends SubsonicFragment impleme
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 = rootView.findViewById(R.id.refresh_layout);
refreshLayout.setOnRefreshListener(this); refreshLayout.setOnRefreshListener(this);
recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_recycler); recyclerView = rootView.findViewById(R.id.fragment_recycler);
fastScroller = (FastScroller) rootView.findViewById(R.id.fragment_fast_scroller); fastScroller = rootView.findViewById(R.id.fragment_fast_scroller);
setupLayoutManager(); setupLayoutManager();
if (pullToRefresh) { if (pullToRefresh) {
@ -110,11 +103,6 @@ public abstract class SelectRecyclerFragment<T> extends SubsonicFragment impleme
onFinishSetupOptionsMenu(menu); onFinishSetupOptionsMenu(menu);
} }
@Override
public boolean onOptionsItemSelected(MenuItem 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;
@ -128,7 +116,7 @@ public abstract class SelectRecyclerFragment<T> extends SubsonicFragment impleme
} }
@Override @Override
protected void refresh(final boolean refresh) { void refresh(final boolean refresh) {
int titleRes = getTitleResource(); int titleRes = getTitleResource();
if (titleRes != 0) { if (titleRes != 0) {
setTitle(getTitleResource()); setTitle(getTitleResource());
@ -147,7 +135,7 @@ public abstract class SelectRecyclerFragment<T> extends SubsonicFragment impleme
if (backgroundUpdate) { if (backgroundUpdate) {
currentTask.execute(); currentTask.execute();
} else { } else {
objects = new ArrayList<T>(); objects = new ArrayList<>();
try { try {
objects = getObjects(null, refresh, null); objects = getObjects(null, refresh, null);
@ -167,17 +155,20 @@ public abstract class SelectRecyclerFragment<T> extends SubsonicFragment impleme
setupLayoutManager(recyclerView, largeAlbums); setupLayoutManager(recyclerView, largeAlbums);
} }
public abstract int getOptionsMenu(); protected abstract int getOptionsMenu();
public abstract SectionAdapter<T> getAdapter(List<T> objs);
public abstract List<T> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception;
public abstract int getTitleResource();
public void onFinishRefresh() { protected abstract SectionAdapter<T> getAdapter(List<T> objs);
protected abstract List<T> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception;
protected abstract int getTitleResource();
void onFinishRefresh() {
} }
private class UpdateTask extends TabBackgroundTask<List<T>> { private class UpdateTask extends TabBackgroundTask<List<T>> {
private boolean refresh; private final boolean refresh;
public UpdateTask(SubsonicFragment fragment, boolean refresh) { public UpdateTask(SubsonicFragment fragment, boolean refresh) {
super(fragment); super(fragment);
@ -188,7 +179,7 @@ public abstract class SelectRecyclerFragment<T> extends SubsonicFragment impleme
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<>();
try { try {
objects = getObjects(musicService, refresh, this); objects = getObjects(musicService, refresh, this);

View File

@ -20,9 +20,6 @@ import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import java.util.ArrayList;
import java.util.List;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.adapter.BasicListAdapter; import net.nullsum.audinaut.adapter.BasicListAdapter;
import net.nullsum.audinaut.adapter.SectionAdapter; import net.nullsum.audinaut.adapter.SectionAdapter;
@ -31,6 +28,9 @@ import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.ProgressListener; import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import java.util.ArrayList;
import java.util.List;
public class SelectYearFragment extends SelectRecyclerFragment<String> { public class SelectYearFragment extends SelectRecyclerFragment<String> {
public SelectYearFragment() { public SelectYearFragment() {
@ -79,7 +79,8 @@ public class SelectYearFragment extends SelectRecyclerFragment<String> {
} }
@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) {

View File

@ -16,9 +16,8 @@
package net.nullsum.audinaut.fragments; package net.nullsum.audinaut.fragments;
import android.accounts.Account; import android.accounts.Account;
import android.app.backup.BackupManager;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.Uri; import android.net.Uri;
@ -31,21 +30,11 @@ import android.preference.PreferenceCategory;
import android.preference.PreferenceScreen; import android.preference.PreferenceScreen;
import android.text.InputType; import android.text.InputType;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.EditText; import android.widget.EditText;
import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.LinkedHashMap;
import java.util.Map;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.service.DownloadService; import net.nullsum.audinaut.service.DownloadService;
import net.nullsum.audinaut.service.HeadphoneListenerService; import net.nullsum.audinaut.service.HeadphoneListenerService;
@ -59,10 +48,16 @@ import net.nullsum.audinaut.util.Util;
import net.nullsum.audinaut.view.CacheLocationPreference; import net.nullsum.audinaut.view.CacheLocationPreference;
import net.nullsum.audinaut.view.ErrorDialog; import net.nullsum.audinaut.view.ErrorDialog;
import java.io.File;
import java.net.URL;
import java.text.DecimalFormat;
import java.util.LinkedHashMap;
import java.util.Map;
public class SettingsFragment extends PreferenceCompatFragment implements SharedPreferences.OnSharedPreferenceChangeListener { public class SettingsFragment extends PreferenceCompatFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
private final static String TAG = SettingsFragment.class.getSimpleName(); private final static String TAG = SettingsFragment.class.getSimpleName();
private final Map<String, ServerSettings> serverSettings = new LinkedHashMap<String, ServerSettings>(); private final Map<String, ServerSettings> serverSettings = new LinkedHashMap<>();
private boolean testingConnection; private boolean testingConnection;
private ListPreference theme; private ListPreference theme;
private ListPreference maxBitrateWifi; private ListPreference maxBitrateWifi;
@ -74,7 +69,6 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
private ListPreference keepPlayedCount; private ListPreference keepPlayedCount;
private ListPreference tempLoss; private ListPreference tempLoss;
private ListPreference pauseDisconnect; private ListPreference pauseDisconnect;
private Preference addServerPreference;
private PreferenceCategory serversCategory; private PreferenceCategory serversCategory;
private ListPreference songPressAction; private ListPreference songPressAction;
private ListPreference syncInterval; private ListPreference syncInterval;
@ -150,14 +144,11 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
if (Constants.PREFERENCES_KEY_HIDE_MEDIA.equals(key)) { if (Constants.PREFERENCES_KEY_HIDE_MEDIA.equals(key)) {
setHideMedia(sharedPreferences.getBoolean(key, true)); setHideMedia(sharedPreferences.getBoolean(key, true));
} } else if (Constants.PREFERENCES_KEY_MEDIA_BUTTONS.equals(key)) {
else if (Constants.PREFERENCES_KEY_MEDIA_BUTTONS.equals(key)) {
setMediaButtonsEnabled(sharedPreferences.getBoolean(key, true)); setMediaButtonsEnabled(sharedPreferences.getBoolean(key, true));
} } else if (Constants.PREFERENCES_KEY_CACHE_LOCATION.equals(key)) {
else if (Constants.PREFERENCES_KEY_CACHE_LOCATION.equals(key)) {
setCacheLocation(sharedPreferences.getString(key, "")); setCacheLocation(sharedPreferences.getString(key, ""));
} } else if (Constants.PREFERENCES_KEY_SYNC_MOST_RECENT.equals(key)) {
else if(Constants.PREFERENCES_KEY_SYNC_MOST_RECENT.equals(key)) {
SyncUtil.removeMostRecentSyncFiles(context); SyncUtil.removeMostRecentSyncFiles(context);
} else if (Constants.PREFERENCES_KEY_REPLAY_GAIN.equals(key) || Constants.PREFERENCES_KEY_REPLAY_GAIN_BUMP.equals(key) || Constants.PREFERENCES_KEY_REPLAY_GAIN_UNTAGGED.equals(key)) { } else if (Constants.PREFERENCES_KEY_REPLAY_GAIN.equals(key) || Constants.PREFERENCES_KEY_REPLAY_GAIN_BUMP.equals(key) || Constants.PREFERENCES_KEY_REPLAY_GAIN_UNTAGGED.equals(key)) {
DownloadService downloadService = DownloadService.getInstance(); DownloadService downloadService = DownloadService.getInstance();
@ -199,7 +190,7 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
tempLoss = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_TEMP_LOSS); tempLoss = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_TEMP_LOSS);
pauseDisconnect = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_PAUSE_DISCONNECT); pauseDisconnect = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_PAUSE_DISCONNECT);
serversCategory = (PreferenceCategory) this.findPreference(Constants.PREFERENCES_KEY_SERVER_KEY); serversCategory = (PreferenceCategory) this.findPreference(Constants.PREFERENCES_KEY_SERVER_KEY);
addServerPreference = this.findPreference(Constants.PREFERENCES_KEY_SERVER_ADD); Preference addServerPreference = this.findPreference(Constants.PREFERENCES_KEY_SERVER_ADD);
songPressAction = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_SONG_PRESS_ACTION); songPressAction = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_SONG_PRESS_ACTION);
syncInterval = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_INTERVAL); syncInterval = (ListPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_INTERVAL);
syncEnabled = (CheckBoxPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_ENABLED); syncEnabled = (CheckBoxPreference) this.findPreference(Constants.PREFERENCES_KEY_SYNC_ENABLED);
@ -216,13 +207,8 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
serverCount = settings.getInt(Constants.PREFERENCES_KEY_SERVER_COUNT, 1); serverCount = settings.getInt(Constants.PREFERENCES_KEY_SERVER_COUNT, 1);
if (cacheSize != null) { if (cacheSize != null) {
this.findPreference("clearCache").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { this.findPreference("clearCache").setOnPreferenceClickListener(preference -> {
@Override Util.confirmDialog(context, (dialog, which) -> new LoadingTask<Void>(context, false) {
public boolean onPreferenceClick(Preference preference) {
Util.confirmDialog(context, R.string.common_delete, R.string.common_confirm_message_cache, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
new LoadingTask<Void>(context, false) {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
FileUtil.deleteMusicDirectory(context); FileUtil.deleteMusicDirectory(context);
@ -240,43 +226,32 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
protected void error(Throwable error) { protected void error(Throwable error) {
Util.toast(context, getErrorMessage(error), false); Util.toast(context, getErrorMessage(error), false);
} }
}.execute(); }.execute());
}
});
return false; return false;
}
}); });
} }
if (syncEnabled != null) { if (syncEnabled != null) {
this.findPreference(Constants.PREFERENCES_KEY_SYNC_ENABLED).setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { this.findPreference(Constants.PREFERENCES_KEY_SYNC_ENABLED).setOnPreferenceChangeListener((preference, newValue) -> {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
Boolean syncEnabled = (Boolean) newValue; Boolean syncEnabled = (Boolean) newValue;
Account account = new Account(Constants.SYNC_ACCOUNT_NAME, Constants.SYNC_ACCOUNT_TYPE); Account account = new Account(Constants.SYNC_ACCOUNT_NAME, Constants.SYNC_ACCOUNT_TYPE);
ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, syncEnabled); ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, syncEnabled);
return true; return true;
}
}); });
syncInterval.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { syncInterval.setOnPreferenceChangeListener((preference, newValue) -> {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
Integer syncInterval = Integer.parseInt(((String) newValue)); Integer syncInterval = Integer.parseInt(((String) newValue));
Account account = new Account(Constants.SYNC_ACCOUNT_NAME, Constants.SYNC_ACCOUNT_TYPE); Account account = new Account(Constants.SYNC_ACCOUNT_NAME, Constants.SYNC_ACCOUNT_TYPE);
ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, new Bundle(), 60L * syncInterval); ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, new Bundle(), 60L * syncInterval);
return true; return true;
}
}); });
} }
if (serversCategory != null) { if (serversCategory != null) {
addServerPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { addServerPreference.setOnPreferenceClickListener(preference -> {
@Override
public boolean onPreferenceClick(Preference preference) {
serverCount++; serverCount++;
int instance = serverCount; int instance = serverCount;
serversCategory.addPreference(addServer(serverCount)); serversCategory.addPreference(addServer(serverCount));
@ -294,7 +269,6 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
ss.update(); ss.update();
return true; return true;
}
}); });
serversCategory.setOrderingAsAdded(false); serversCategory.setOrderingAsAdded(false);
@ -311,18 +285,8 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
} }
private void scheduleBackup() { private void scheduleBackup() {
try { BackupManager backupManager = new BackupManager(context);
Class managerClass = Class.forName("android.app.backup.BackupManager"); backupManager.dataChanged();
Constructor managerConstructor = managerClass.getConstructor(Context.class);
Object manager = managerConstructor.newInstance(context);
Method m = managerClass.getMethod("dataChanged");
m.invoke(manager);
} catch(ClassNotFoundException e) {
Log.e(TAG, "No backup manager found");
} catch(Throwable t) {
Log.e(TAG, "Scheduling backup failed " + t);
t.printStackTrace();
}
} }
private void update() { private void update() {
@ -396,7 +360,8 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
ss.update(); ss.update();
} }
} }
public void checkForRemoved() {
private void checkForRemoved() {
for (ServerSettings ss : serverSettings.values()) { for (ServerSettings ss : serverSettings.values()) {
if (!ss.update()) { if (!ss.update()) {
serversCategory.removePreference(ss.getScreen()); serversCategory.removePreference(ss.getScreen());
@ -410,9 +375,7 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
screen.setKey(Constants.PREFERENCES_KEY_SERVER_KEY + instance); screen.setKey(Constants.PREFERENCES_KEY_SERVER_KEY + instance);
screen.setOrder(instance); screen.setOrder(instance);
screen.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { screen.setOnPreferenceClickListener(preference -> {
@Override
public boolean onPreferenceClick(Preference preference) {
SettingsFragment newFragment = new SettingsFragment(); SettingsFragment newFragment = new SettingsFragment();
Bundle args = new Bundle(); Bundle args = new Bundle();
@ -421,7 +384,6 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
replaceFragment(newFragment); replaceFragment(newFragment);
return false; return false;
}
}); });
return screen; return screen;
@ -466,12 +428,7 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
Button defaultButton = new Button(getContext()); Button defaultButton = new Button(getContext());
defaultButton.setText(internalSSIDDisplay); defaultButton.setText(internalSSIDDisplay);
defaultButton.setOnClickListener(new View.OnClickListener() { defaultButton.setOnClickListener(v -> editText.setText(internalSSID));
@Override
public void onClick(View v) {
editText.setText(internalSSID);
}
});
root.addView(defaultButton); root.addView(defaultButton);
} }
}; };
@ -502,12 +459,9 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
serverOpenBrowser.setKey(Constants.PREFERENCES_KEY_OPEN_BROWSER); serverOpenBrowser.setKey(Constants.PREFERENCES_KEY_OPEN_BROWSER);
serverOpenBrowser.setPersistent(false); serverOpenBrowser.setPersistent(false);
serverOpenBrowser.setTitle(R.string.settings_server_open_browser); serverOpenBrowser.setTitle(R.string.settings_server_open_browser);
serverOpenBrowser.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { serverOpenBrowser.setOnPreferenceClickListener(preference -> {
@Override
public boolean onPreferenceClick(Preference preference) {
openInBrowser(instance); openInBrowser(instance);
return true; return true;
}
}); });
Preference serverRemoveServerPreference = new Preference(context); Preference serverRemoveServerPreference = new Preference(context);
@ -515,12 +469,8 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
serverRemoveServerPreference.setPersistent(false); serverRemoveServerPreference.setPersistent(false);
serverRemoveServerPreference.setTitle(R.string.settings_servers_remove); serverRemoveServerPreference.setTitle(R.string.settings_servers_remove);
serverRemoveServerPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { serverRemoveServerPreference.setOnPreferenceClickListener(preference -> {
@Override Util.confirmDialog(context, R.string.common_delete, screen.getTitle().toString(), (dialog, which) -> {
public boolean onPreferenceClick(Preference preference) {
Util.confirmDialog(context, R.string.common_delete, screen.getTitle().toString(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
// Reset values to null so when we ask for them again they are new // Reset values to null so when we ask for them again they are new
serverNamePreference.setText(null); serverNamePreference.setText(null);
serverUrlPreference.setText(null); serverUrlPreference.setText(null);
@ -545,23 +495,18 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
SettingsFragment serverSelectionFragment = (SettingsFragment) parentFragment; SettingsFragment serverSelectionFragment = (SettingsFragment) parentFragment;
serverSelectionFragment.checkForRemoved(); serverSelectionFragment.checkForRemoved();
} }
}
}); });
return true; return true;
}
}); });
Preference serverTestConnectionPreference = new Preference(context); Preference serverTestConnectionPreference = new Preference(context);
serverTestConnectionPreference.setKey(Constants.PREFERENCES_KEY_TEST_CONNECTION + instance); serverTestConnectionPreference.setKey(Constants.PREFERENCES_KEY_TEST_CONNECTION + instance);
serverTestConnectionPreference.setPersistent(false); serverTestConnectionPreference.setPersistent(false);
serverTestConnectionPreference.setTitle(R.string.settings_test_connection_title); serverTestConnectionPreference.setTitle(R.string.settings_test_connection_title);
serverTestConnectionPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { serverTestConnectionPreference.setOnPreferenceClickListener(preference -> {
@Override
public boolean onPreferenceClick(Preference preference) {
testConnection(instance); testConnection(instance);
return false; return false;
}
}); });
screen.addPreference(serverNamePreference); screen.addPreference(serverNamePreference);
@ -646,7 +591,7 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
@Override @Override
protected Boolean doInBackground() throws Throwable { protected Boolean doInBackground() throws Throwable {
updateProgress(R.string.settings_testing_connection); updateProgress();
previousInstance = Util.getActiveServer(context); previousInstance = Util.getActiveServer(context);
testingConnection = true; testingConnection = true;
@ -686,7 +631,7 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
SharedPreferences prefs = Util.getPreferences(context); SharedPreferences prefs = Util.getPreferences(context);
String url = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null); String url = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null);
if (url == null) { if (url == null) {
new ErrorDialog(context, R.string.settings_invalid_url, false); new ErrorDialog(context, R.string.settings_invalid_url);
return; return;
} }
Uri uriServer = Uri.parse(url); Uri uriServer = Uri.parse(url);
@ -696,13 +641,13 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
} }
private class ServerSettings { private class ServerSettings {
private int instance; private final int instance;
private EditTextPreference serverName; private final EditTextPreference serverName;
private EditTextPreference serverUrl; private final EditTextPreference serverUrl;
private EditTextPreference serverLocalNetworkSSID; private final EditTextPreference serverLocalNetworkSSID;
private EditTextPreference serverInternalUrl; private final EditTextPreference serverInternalUrl;
private EditTextPreference username; private final EditTextPreference username;
private PreferenceScreen screen; private final PreferenceScreen screen;
private ServerSettings(int instance) { private ServerSettings(int instance) {
this.instance = instance; this.instance = instance;
@ -714,9 +659,7 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
username = (EditTextPreference) SettingsFragment.this.findPreference(Constants.PREFERENCES_KEY_USERNAME + instance); username = (EditTextPreference) SettingsFragment.this.findPreference(Constants.PREFERENCES_KEY_USERNAME + instance);
if (serverName != null) { if (serverName != null) {
serverUrl.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { serverUrl.setOnPreferenceChangeListener((preference, value) -> {
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
try { try {
String url = (String) value; String url = (String) value;
new URL(url); new URL(url);
@ -724,15 +667,12 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
throw new Exception(); throw new Exception();
} }
} catch (Exception x) { } catch (Exception x) {
new ErrorDialog(context, R.string.settings_invalid_url, false); new ErrorDialog(context, R.string.settings_invalid_url);
return false; return false;
} }
return true; return true;
}
}); });
serverInternalUrl.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { serverInternalUrl.setOnPreferenceChangeListener((preference, value) -> {
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
try { try {
String url = (String) value; String url = (String) value;
// Allow blank internal IP address // Allow blank internal IP address
@ -745,23 +685,19 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
throw new Exception(); throw new Exception();
} }
} catch (Exception x) { } catch (Exception x) {
new ErrorDialog(context, R.string.settings_invalid_url, false); new ErrorDialog(context, R.string.settings_invalid_url);
return false; return false;
} }
return true; return true;
}
}); });
username.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { username.setOnPreferenceChangeListener((preference, value) -> {
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
String username = (String) value; String username = (String) value;
if (username == null || !username.equals(username.trim())) { if (username == null || !username.equals(username.trim())) {
new ErrorDialog(context, R.string.settings_invalid_username, false); new ErrorDialog(context, R.string.settings_invalid_username);
return false; return false;
} }
return true; return true;
}
}); });
} }
} }

View File

@ -24,12 +24,6 @@ import android.content.ContentValues;
import android.database.Cursor; import android.database.Cursor;
import android.database.MatrixCursor; import android.database.MatrixCursor;
import android.net.Uri; import android.net.Uri;
import android.util.Log;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.Artist; import net.nullsum.audinaut.domain.Artist;
@ -40,13 +34,16 @@ import net.nullsum.audinaut.service.MusicService;
import net.nullsum.audinaut.service.MusicServiceFactory; import net.nullsum.audinaut.service.MusicServiceFactory;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/** /**
* Provides search suggestions based on recent searches. * Provides search suggestions based on recent searches.
* *
* @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 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",
@ -87,7 +84,7 @@ public class AudinautSearchProvider extends ContentProvider {
} }
// Add all results into one pot // Add all results into one pot
List<Object> results = new ArrayList<Object>(); List<Object> results = new ArrayList<>();
results.addAll(searchResult.getArtists()); results.addAll(searchResult.getArtists());
results.addAll(searchResult.getAlbums()); results.addAll(searchResult.getAlbums());
results.addAll(searchResult.getSongs()); results.addAll(searchResult.getSongs());
@ -104,9 +101,7 @@ public class AudinautSearchProvider extends ContentProvider {
} }
// Sort based on the closeness paramater // Sort based on the closeness paramater
Collections.sort(results, new Comparator<Object>() { Collections.sort(results, (lhs, rhs) -> {
@Override
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;
@ -137,7 +132,6 @@ public class AudinautSearchProvider extends ContentProvider {
} else { } else {
return -1; return -1;
} }
}
}); });
// Done sorting, add results to cursor // Done sorting, add results to cursor
@ -155,11 +149,7 @@ public class AudinautSearchProvider extends ContentProvider {
} 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())) {
id = entry.getAlbumId(); id = entry.getAlbumId();
} else {
id = entry.getParent();
}
String artistDisplay; String artistDisplay;
if (entry.getArtist() == null) { if (entry.getArtist() == null) {

View File

@ -24,8 +24,8 @@ import android.appwidget.AppWidgetProvider;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.Resources;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Bitmap.Config; import android.graphics.Bitmap.Config;
import android.graphics.Canvas; import android.graphics.Canvas;
@ -38,6 +38,7 @@ import android.os.Environment;
import android.util.Log; import android.util.Log;
import android.view.View; import android.view.View;
import android.widget.RemoteViews; import android.widget.RemoteViews;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.activity.SubsonicActivity; import net.nullsum.audinaut.activity.SubsonicActivity;
import net.nullsum.audinaut.activity.SubsonicFragmentActivity; import net.nullsum.audinaut.activity.SubsonicFragmentActivity;
@ -85,6 +86,32 @@ public class AudinautWidgetProvider extends AppWidgetProvider {
instance4x4.notifyChange(context, service, playing); instance4x4.notifyChange(context, service, playing);
} }
/**
* Round the corners of a bitmap for the cover art image
*/
private static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final float roundPx = 10;
// Add extra width to the rect so the right side wont be rounded.
final Rect rect = new Rect(0, 0, bitmap.getWidth() + (int) roundPx, bitmap.getHeight());
final RectF rectF = new RectF(rect);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
@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);
@ -95,7 +122,7 @@ public class AudinautWidgetProvider extends AppWidgetProvider {
notifyInstances(context, DownloadService.getInstance(), false); notifyInstances(context, DownloadService.getInstance(), false);
} }
protected int getLayout() { int getLayout() {
return 0; return 0;
} }
@ -112,7 +139,7 @@ public class AudinautWidgetProvider extends AppWidgetProvider {
views.setTextViewText(R.id.album, ""); views.setTextViewText(R.id.album, "");
} }
linkButtons(context, views, false); linkButtons(context, views);
performUpdate(context, null, appWidgetIds, false); performUpdate(context, null, appWidgetIds, false);
} }
@ -129,7 +156,7 @@ public class AudinautWidgetProvider extends AppWidgetProvider {
/** /**
* Handle a change notification coming over from {@link DownloadService} * Handle a change notification coming over from {@link DownloadService}
*/ */
public void notifyChange(Context context, DownloadService service, boolean playing) { void notifyChange(Context context, DownloadService service, boolean playing) {
if (hasInstances(context)) { if (hasInstances(context)) {
performUpdate(context, service, null, playing); performUpdate(context, service, null, playing);
} }
@ -239,43 +266,15 @@ public class AudinautWidgetProvider extends AppWidgetProvider {
} }
// Link actions buttons to intents // Link actions buttons to intents
linkButtons(context, views, currentPlaying != null); linkButtons(context, views);
pushUpdate(context, appWidgetIds, views); pushUpdate(context, appWidgetIds, views);
} }
/**
* Round the corners of a bitmap for the cover art image
*/
private static Bitmap getRoundedCornerBitmap(Bitmap bitmap) {
Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(output);
final int color = 0xff424242;
final Paint paint = new Paint();
final float roundPx = 10;
// Add extra width to the rect so the right side wont be rounded.
final Rect rect = new Rect(0, 0, bitmap.getWidth() + (int) roundPx, bitmap.getHeight());
final RectF rectF = new RectF(rect);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawRoundRect(rectF, roundPx, roundPx, paint);
paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
/** /**
* Link up various button actions using {@link PendingIntent}. * Link up various button actions using {@link PendingIntent}.
*
* @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) {
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);

View File

@ -4,11 +4,12 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.util.Log; 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 final String TAG = A2dpIntentReceiver.class.getSimpleName();
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {

View File

@ -20,7 +20,6 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.media.AudioManager; import android.media.AudioManager;
import android.util.Log;
import net.nullsum.audinaut.domain.PlayerState; import net.nullsum.audinaut.domain.PlayerState;
import net.nullsum.audinaut.service.DownloadService; import net.nullsum.audinaut.service.DownloadService;
@ -28,7 +27,6 @@ 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();
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {

View File

@ -18,13 +18,11 @@ package net.nullsum.audinaut.receiver;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.util.Log;
import net.nullsum.audinaut.service.DownloadService; 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();
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {

View File

@ -19,13 +19,11 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import net.nullsum.audinaut.service.DownloadService; 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();
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {

View File

@ -18,17 +18,6 @@
*/ */
package net.nullsum.audinaut.service; package net.nullsum.audinaut.service;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.concurrent.TimeUnit;
import okhttp3.Response;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.util.Log; import android.util.Log;
@ -36,41 +25,43 @@ import android.util.Log;
import net.nullsum.audinaut.domain.Artist; import net.nullsum.audinaut.domain.Artist;
import net.nullsum.audinaut.domain.Genre; import net.nullsum.audinaut.domain.Genre;
import net.nullsum.audinaut.domain.Indexes; import net.nullsum.audinaut.domain.Indexes;
import net.nullsum.audinaut.domain.PlayerQueue;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.MusicFolder; import net.nullsum.audinaut.domain.MusicFolder;
import net.nullsum.audinaut.domain.Playlist; import net.nullsum.audinaut.domain.Playlist;
import net.nullsum.audinaut.domain.SearchCritera; import net.nullsum.audinaut.domain.SearchCritera;
import net.nullsum.audinaut.domain.SearchResult; import net.nullsum.audinaut.domain.SearchResult;
import net.nullsum.audinaut.domain.User; import net.nullsum.audinaut.domain.User;
import net.nullsum.audinaut.util.SilentBackgroundTask; import net.nullsum.audinaut.util.FileUtil;
import net.nullsum.audinaut.util.ProgressListener; import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.util.SongDBHandler; import net.nullsum.audinaut.util.SongDBHandler;
import net.nullsum.audinaut.util.TimeLimitedCache; import net.nullsum.audinaut.util.TimeLimitedCache;
import net.nullsum.audinaut.util.FileUtil;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import okhttp3.Response;
import static net.nullsum.audinaut.domain.MusicDirectory.Entry; import static net.nullsum.audinaut.domain.MusicDirectory.Entry;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class CachedMusicService implements MusicService { public class CachedMusicService implements MusicService {
public static final int CACHE_UPDATE_LIST = 1;
private static final int CACHE_UPDATE_METADATA = 2;
private static final String TAG = CachedMusicService.class.getSimpleName(); private static final String TAG = CachedMusicService.class.getSimpleName();
private static final int MUSIC_DIR_CACHE_SIZE = 20;
private static final int TTL_MUSIC_DIR = 5 * 60; // Five minutes
public static final int CACHE_UPDATE_LIST = 1;
public static final int CACHE_UPDATE_METADATA = 2;
private static final int CACHED_LAST_FM = 24 * 60;
private final RESTMusicService musicService; private final RESTMusicService musicService;
private final TimeLimitedCache<Indexes> cachedIndexes = new TimeLimitedCache<Indexes>(60 * 60, TimeUnit.SECONDS); private final TimeLimitedCache<Indexes> cachedIndexes = new TimeLimitedCache<>(60 * 60);
private final TimeLimitedCache<List<Playlist>> cachedPlaylists = new TimeLimitedCache<List<Playlist>>(3600, TimeUnit.SECONDS); private final TimeLimitedCache<List<Playlist>> cachedPlaylists = new TimeLimitedCache<>(3600);
private final TimeLimitedCache<List<MusicFolder>> cachedMusicFolders = new TimeLimitedCache<List<MusicFolder>>(10 * 3600, TimeUnit.SECONDS); private final TimeLimitedCache<List<MusicFolder>> cachedMusicFolders = new TimeLimitedCache<>(10 * 3600);
private String restUrl; private String restUrl;
private String musicFolderId; private String musicFolderId;
private boolean isTagBrowsing = false;
public CachedMusicService(RESTMusicService musicService) { public CachedMusicService(RESTMusicService musicService) {
this.musicService = musicService; this.musicService = musicService;
@ -96,7 +87,7 @@ public class CachedMusicService implements MusicService {
if (result == null) { if (result == null) {
result = musicService.getMusicFolders(refresh, context, progressListener); result = musicService.getMusicFolders(refresh, context, progressListener);
FileUtil.serialize(context, new ArrayList<MusicFolder>(result), getCacheName(context, "musicFolders")); FileUtil.serialize(context, new ArrayList<>(result), getCacheName(context, "musicFolders"));
} }
MusicFolder.sort(result); MusicFolder.sort(result);
@ -114,7 +105,7 @@ public class CachedMusicService implements MusicService {
} }
Indexes result = cachedIndexes.get(); Indexes result = cachedIndexes.get();
if (result == null) { if (result == null) {
String name = Util.isTagBrowsing(context, musicService.getInstance(context)) ? "artists" : "indexes"; String name = "artists";
name = getCacheName(context, name, musicFolderId); name = getCacheName(context, name, musicFolderId);
if (!refresh) { if (!refresh) {
result = FileUtil.deserialize(context, name, Indexes.class); result = FileUtil.deserialize(context, name, Indexes.class);
@ -154,7 +145,7 @@ public class CachedMusicService implements MusicService {
@Override @Override
public void done(Void result) { public void done(Void result) {
if (progressListener != null) { if (progressListener != null) {
if(cached.updateEntriesList(context, musicService.getInstance(context), refreshed)) { if (cached.updateEntriesList(context, refreshed)) {
progressListener.updateCache(CACHE_UPDATE_LIST); progressListener.updateCache(CACHE_UPDATE_LIST);
} }
if (metadataUpdated) { if (metadataUpdated) {
@ -178,7 +169,7 @@ public class CachedMusicService implements MusicService {
// If a cached copy exists to check against, look for removes // If a cached copy exists to check against, look for removes
deleteRemovedEntries(context, dir, cached); deleteRemovedEntries(context, dir, cached);
} }
dir.sortChildren(context, musicService.getInstance(context)); dir.sortChildren(context);
return dir; return dir;
} }
@ -206,7 +197,7 @@ public class CachedMusicService implements MusicService {
@Override @Override
public void done(Void result) { public void done(Void result) {
if (progressListener != null) { if (progressListener != null) {
if(cached.updateEntriesList(context, musicService.getInstance(context), refreshed)) { if (cached.updateEntriesList(context, refreshed)) {
progressListener.updateCache(CACHE_UPDATE_LIST); progressListener.updateCache(CACHE_UPDATE_LIST);
} }
} }
@ -226,7 +217,7 @@ public class CachedMusicService implements MusicService {
// If a cached copy exists to check against, look for removes // If a cached copy exists to check against, look for removes
deleteRemovedEntries(context, dir, cached); deleteRemovedEntries(context, dir, cached);
} }
dir.sortChildren(context, musicService.getInstance(context)); dir.sortChildren(context);
return dir; return dir;
} }
@ -256,7 +247,7 @@ public class CachedMusicService implements MusicService {
@Override @Override
public void done(Void result) { public void done(Void result) {
if (progressListener != null) { if (progressListener != null) {
if(cached.updateEntriesList(context, musicService.getInstance(context), refreshed)) { if (cached.updateEntriesList(context, refreshed)) {
progressListener.updateCache(CACHE_UPDATE_LIST); progressListener.updateCache(CACHE_UPDATE_LIST);
} }
if (metadataUpdated) { if (metadataUpdated) {
@ -280,7 +271,7 @@ public class CachedMusicService implements MusicService {
// If a cached copy exists to check against, look for removes // If a cached copy exists to check against, look for removes
deleteRemovedEntries(context, dir, cached); deleteRemovedEntries(context, dir, cached);
} }
dir.sortChildren(context, musicService.getInstance(context)); dir.sortChildren(context);
return dir; return dir;
} }
@ -321,7 +312,7 @@ public class CachedMusicService implements MusicService {
if (result == null) { if (result == null) {
result = musicService.getPlaylists(refresh, context, progressListener); result = musicService.getPlaylists(refresh, context, progressListener);
FileUtil.serialize(context, new ArrayList<Playlist>(result), getCacheName(context, "playlist")); FileUtil.serialize(context, new ArrayList<>(result), getCacheName(context, "playlist"));
} }
cachedPlaylists.set(result); cachedPlaylists.set(result);
} }
@ -439,24 +430,17 @@ public class CachedMusicService implements MusicService {
String recentlyAddedFile = getCacheName(context, type); String recentlyAddedFile = getCacheName(context, type);
ArrayList<String> recents = FileUtil.deserialize(context, recentlyAddedFile, ArrayList.class); ArrayList<String> recents = FileUtil.deserialize(context, recentlyAddedFile, ArrayList.class);
if (recents == null) { if (recents == null) {
recents = new ArrayList<String>(); recents = new ArrayList<>();
} }
// Add any new items // Add any new items
final int instance = musicService.getInstance(context);
isTagBrowsing = Util.isTagBrowsing(context, instance);
for (final Entry album : dir.getChildren()) { for (final Entry album : dir.getChildren()) {
if (!recents.contains(album.getId())) { if (!recents.contains(album.getId())) {
recents.add(album.getId()); recents.add(album.getId());
String cacheName, parent; String cacheName, parent;
if (isTagBrowsing) {
cacheName = "artist"; cacheName = "artist";
parent = album.getArtistId(); parent = album.getArtistId();
} else {
cacheName = "directory";
parent = album.getParent();
}
// Add album to artist // Add album to artist
if (parent != null) { if (parent != null) {
@ -492,7 +476,7 @@ public class CachedMusicService implements MusicService {
artist.setId(album.getId()); artist.setId(album.getId());
artist.setName(album.getTitle()); artist.setName(album.getTitle());
new IndexesUpdater(context, isTagBrowsing ? "artists" : "indexes") { new IndexesUpdater(context) {
private boolean changed = false; private boolean changed = false;
@Override @Override
@ -585,11 +569,6 @@ public class CachedMusicService implements MusicService {
return musicService.getSongList(type, size, offset, context, progressListener); return musicService.getSongList(type, size, offset, context, progressListener);
} }
@Override
public MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception {
return musicService.getRandomSongs(size, artistId, context, progressListener);
}
@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 {
return musicService.getRandomSongs(size, folder, genre, startYear, endYear, context, progressListener); return musicService.getRandomSongs(size, folder, genre, startYear, endYear, context, progressListener);
@ -615,7 +594,7 @@ public class CachedMusicService implements MusicService {
if (result == null) { if (result == null) {
result = musicService.getGenres(refresh, context, progressListener); result = musicService.getGenres(refresh, context, progressListener);
FileUtil.serialize(context, new ArrayList<Genre>(result), getCacheName(context, "genre")); FileUtil.serialize(context, new ArrayList<>(result), getCacheName(context, "genre"));
} }
return result; return result;
@ -663,21 +642,6 @@ public class CachedMusicService implements MusicService {
return result; return result;
} }
@Override
public Bitmap getBitmap(String url, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception {
return musicService.getBitmap(url, size, context, progressListener, task);
}
@Override
public void savePlayQueue(List<Entry> songs, Entry currentPlaying, int position, Context context, ProgressListener progressListener) throws Exception {
musicService.savePlayQueue(songs, currentPlaying, position, context, progressListener);
}
@Override
public PlayerQueue getPlayQueue(Context context, ProgressListener progressListener) throws Exception {
return musicService.getPlayQueue(context, progressListener);
}
@Override @Override
public void setInstance(Integer instance) throws Exception { public void setInstance(Integer instance) throws Exception {
musicService.setInstance(instance); musicService.setInstance(instance);
@ -687,6 +651,7 @@ public class CachedMusicService implements MusicService {
String s = musicService.getRestUrl(context, null, false) + id; String s = musicService.getRestUrl(context, null, false) + id;
return name + "-" + s.hashCode() + ".ser"; return name + "-" + s.hashCode() + ".ser";
} }
private String getCacheName(Context context, String name) { private String getCacheName(Context context, String name) {
String s = musicService.getRestUrl(context, null, false); String s = musicService.getRestUrl(context, null, false);
return name + "-" + s.hashCode() + ".ser"; return name + "-" + s.hashCode() + ".ser";
@ -694,13 +659,9 @@ public class CachedMusicService implements MusicService {
private void deleteRemovedEntries(Context context, MusicDirectory dir, MusicDirectory cached) { private void deleteRemovedEntries(Context context, MusicDirectory dir, MusicDirectory cached) {
if (cached != null) { if (cached != null) {
List<Entry> oldList = new ArrayList<Entry>(); List<Entry> oldList = new ArrayList<>();
oldList.addAll(cached.getChildren()); oldList.addAll(cached.getChildren());
oldList.removeAll(dir.getChildren());
// Remove all current items from old list
for(Entry entry: dir.getChildren()) {
oldList.remove(entry);
}
// Anything remaining has been removed from server // Anything remaining has been removed from server
MediaStoreService store = new MediaStoreService(context); MediaStoreService store = new MediaStoreService(context);
@ -711,33 +672,55 @@ public class CachedMusicService implements MusicService {
} }
} }
private void updateAllSongs(Context context, MusicDirectory dir) {
List<Entry> songs = dir.getSongs();
if (!songs.isEmpty()) {
SongDBHandler.getHandler(context).addSongs(musicService.getInstance(context), songs);
}
}
private void checkSettingsChanged(Context context) {
int instance = musicService.getInstance(context);
String newUrl = musicService.getRestUrl(context, null, false);
if (!Util.equals(newUrl, restUrl)) {
cachedMusicFolders.clear();
cachedIndexes.clear();
cachedPlaylists.clear();
restUrl = newUrl;
}
String newMusicFolderId = Util.getSelectedMusicFolderId(context, instance);
if (!Util.equals(newMusicFolderId, musicFolderId)) {
cachedIndexes.clear();
musicFolderId = newMusicFolderId;
}
}
private abstract class SerializeUpdater<T> { private abstract class SerializeUpdater<T> {
final Context context; final Context context;
final String cacheName; final String cacheName;
final boolean singleUpdate; final boolean singleUpdate;
public SerializeUpdater(Context context, String cacheName) { public SerializeUpdater(Context context) {
this(context, cacheName, true);
}
public SerializeUpdater(Context context, String cacheName, boolean singleUpdate) {
this.context = context; this.context = context;
this.cacheName = getCacheName(context, cacheName); this.cacheName = getCacheName(context, "playlist");
this.singleUpdate = singleUpdate; this.singleUpdate = true;
} }
public SerializeUpdater(Context context, String cacheName, String id) { public SerializeUpdater(Context context, String cacheName, String id) {
this(context, cacheName, id, true);
}
public SerializeUpdater(Context context, String cacheName, String id, boolean singleUpdate) {
this.context = context; this.context = context;
this.cacheName = getCacheName(context, cacheName, id); this.cacheName = getCacheName(context, cacheName, id);
this.singleUpdate = singleUpdate; this.singleUpdate = true;
} }
public ArrayList<T> getArrayList() { public ArrayList<T> getArrayList() {
return FileUtil.deserialize(context, cacheName, ArrayList.class); return FileUtil.deserialize(context, cacheName, ArrayList.class);
} }
public abstract boolean checkResult(T check); public abstract boolean checkResult(T check);
public abstract void updateResult(List<T> objects, T result); public abstract void updateResult(List<T> objects, T result);
public void save(ArrayList<T> objects) { public void save(ArrayList<T> objects) {
FileUtil.serialize(context, objects, cacheName); FileUtil.serialize(context, objects, cacheName);
} }
@ -747,7 +730,7 @@ public class CachedMusicService implements MusicService {
// Only execute if something to check against // Only execute if something to check against
if (objects != null) { if (objects != null) {
List<T> results = new ArrayList<T>(); List<T> results = new ArrayList<>();
for (T check : objects) { for (T check : objects) {
if (checkResult(check)) { if (checkResult(check)) {
results.add(check); results.add(check);
@ -769,24 +752,12 @@ public class CachedMusicService implements MusicService {
} }
} }
} }
private abstract class UserUpdater extends SerializeUpdater<User> {
String username;
public UserUpdater(Context context, String username) {
super(context, "users");
this.username = username;
}
@Override
public boolean checkResult(User check) {
return username.equals(check.getUsername());
}
}
private abstract class PlaylistUpdater extends SerializeUpdater<Playlist> { private abstract class PlaylistUpdater extends SerializeUpdater<Playlist> {
String id; final String id;
public PlaylistUpdater(Context context, String id) { public PlaylistUpdater(Context context, String id) {
super(context, "playlist"); super(context);
this.id = id; this.id = id;
} }
@ -795,14 +766,12 @@ public class CachedMusicService implements MusicService {
return id.equals(check.getId()); return id.equals(check.getId());
} }
} }
private abstract class MusicDirectoryUpdater extends SerializeUpdater<Entry> { private abstract class MusicDirectoryUpdater extends SerializeUpdater<Entry> {
protected MusicDirectory musicDirectory; MusicDirectory musicDirectory;
public MusicDirectoryUpdater(Context context, String cacheName, String id) { public MusicDirectoryUpdater(Context context, String cacheName, String id) {
super(context, cacheName, id, true); super(context, cacheName, id);
}
public MusicDirectoryUpdater(Context context, String cacheName, String id, boolean singleUpdate) {
super(context, cacheName, id, singleUpdate);
} }
@Override @Override
@ -814,170 +783,18 @@ public class CachedMusicService implements MusicService {
return null; return null;
} }
} }
public void save(ArrayList<Entry> objects) { public void save(ArrayList<Entry> objects) {
musicDirectory.replaceChildren(objects); musicDirectory.replaceChildren(objects);
FileUtil.serialize(context, musicDirectory, cacheName); FileUtil.serialize(context, musicDirectory, cacheName);
} }
} }
private abstract class PlaylistDirectoryUpdater {
Context context;
public PlaylistDirectoryUpdater(Context context) {
this.context = context;
}
public abstract boolean checkResult(Entry check);
public abstract void updateResult(Entry result);
public void execute() {
List<Playlist> playlists = FileUtil.deserialize(context, getCacheName(context, "playlist"), ArrayList.class);
if(playlists == null) {
// No playlist list cache, nothing to update!
return;
}
for(Playlist playlist: playlists) {
new MusicDirectoryUpdater(context, "playlist", playlist.getId(), false) {
@Override
public boolean checkResult(Entry check) {
return PlaylistDirectoryUpdater.this.checkResult(check);
}
@Override
public void updateResult(List<Entry> objects, Entry result) {
PlaylistDirectoryUpdater.this.updateResult(result);
}
}.execute();
}
}
}
private abstract class GenericEntryUpdater {
Context context;
List<Entry> entries;
public GenericEntryUpdater(Context context, Entry entry) {
this.context = context;
this.entries = Arrays.asList(entry);
}
public GenericEntryUpdater(Context context, List<Entry> entries) {
this.context = context;
this.entries = entries;
}
public boolean checkResult(Entry entry, Entry check) {
return entry.getId().equals(check.getId());
}
public abstract void updateResult(Entry result);
public void execute() {
String cacheName, parent;
// Make sure it is up to date
isTagBrowsing = Util.isTagBrowsing(context, musicService.getInstance(context));
// Run through each entry, trying to update the directory it is in
final List<Entry> songs = new ArrayList<Entry>();
for(final Entry entry: entries) {
if(isTagBrowsing) {
// If starring album, needs to reference artist instead
if(entry.isDirectory()) {
if(entry.isAlbum()) {
cacheName = "artist";
parent = entry.getArtistId();
} else {
cacheName = "artists";
parent = null;
}
} else {
cacheName = "album";
parent = entry.getAlbumId();
}
} else {
if(entry.isDirectory() && !entry.isAlbum()) {
cacheName = "indexes";
parent = null;
} else {
cacheName = "directory";
parent = entry.getParent();
}
}
// Parent is only null when it is an artist
if(parent == null) {
new IndexesUpdater(context, cacheName) {
@Override
public boolean checkResult(Artist check) {
return GenericEntryUpdater.this.checkResult(entry, new Entry(check));
}
@Override
public void updateResult(List<Artist> objects, Artist result) {
// Don't try to put anything here, as the Entry update method will not be called since it's a artist!
}
}.execute();
} else {
new MusicDirectoryUpdater(context, cacheName, parent) {
@Override
public boolean checkResult(Entry check) {
return GenericEntryUpdater.this.checkResult(entry, check);
}
@Override
public void updateResult(List<Entry> objects, Entry result) {
GenericEntryUpdater.this.updateResult(result);
}
}.execute();
}
songs.add(entry);
}
// Only run through playlists once and check each song against it
if(songs.size() > 0) {
new PlaylistDirectoryUpdater(context) {
@Override
public boolean checkResult(Entry check) {
for(Entry entry: songs) {
if(GenericEntryUpdater.this.checkResult(entry, check)) {
return true;
}
}
return false;
}
@Override
public void updateResult(Entry result) {
GenericEntryUpdater.this.updateResult(result);
}
}.execute();
}
}
}
private class StarUpdater extends GenericEntryUpdater {
public StarUpdater(Context context, List<Entry> entries) {
super(context, entries);
}
@Override
public boolean checkResult(Entry entry, Entry check) {
if (!entry.getId().equals(check.getId())) {
return false;
}
return true;
}
@Override
public void updateResult(Entry result) {
}
};
private abstract class IndexesUpdater extends SerializeUpdater<Artist> { private abstract class IndexesUpdater extends SerializeUpdater<Artist> {
Indexes indexes; Indexes indexes;
IndexesUpdater(Context context, String name) { IndexesUpdater(Context context) {
super(context, name, Util.getSelectedMusicFolderId(context, musicService.getInstance(context))); super(context, "artists", Util.getSelectedMusicFolderId(context, musicService.getInstance(context)));
} }
@Override @Override
@ -987,7 +804,7 @@ public class CachedMusicService implements MusicService {
return null; return null;
} }
ArrayList<Artist> artists = new ArrayList<Artist>(); ArrayList<Artist> artists = new ArrayList<>();
artists.addAll(indexes.getArtists()); artists.addAll(indexes.getArtists());
artists.addAll(indexes.getShortcuts()); artists.addAll(indexes.getShortcuts());
return artists; return artists;
@ -999,34 +816,4 @@ public class CachedMusicService implements MusicService {
cachedIndexes.set(indexes); cachedIndexes.set(indexes);
} }
} }
protected void updateAllSongs(Context context, MusicDirectory dir) {
List<Entry> songs = dir.getSongs();
if(!songs.isEmpty()) {
SongDBHandler.getHandler(context).addSongs(musicService.getInstance(context), songs);
}
}
private void checkSettingsChanged(Context context) {
int instance = musicService.getInstance(context);
String newUrl = musicService.getRestUrl(context, null, false);
boolean newIsTagBrowsing = Util.isTagBrowsing(context, instance);
if (!Util.equals(newUrl, restUrl) || isTagBrowsing != newIsTagBrowsing) {
cachedMusicFolders.clear();
cachedIndexes.clear();
cachedPlaylists.clear();
restUrl = newUrl;
isTagBrowsing = newIsTagBrowsing;
}
String newMusicFolderId = Util.getSelectedMusicFolderId(context, instance);
if(!Util.equals(newMusicFolderId, musicFolderId)) {
cachedIndexes.clear();
musicFolderId = newMusicFolderId;
}
}
public RESTMusicService getMusicService() {
return musicService;
}
} }

View File

@ -18,13 +18,6 @@
*/ */
package net.nullsum.audinaut.service; package net.nullsum.audinaut.service;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import android.content.Context; import android.content.Context;
import android.net.wifi.WifiManager; import android.net.wifi.WifiManager;
import android.os.PowerManager; import android.os.PowerManager;
@ -38,6 +31,13 @@ import net.nullsum.audinaut.util.FileUtil;
import net.nullsum.audinaut.util.SilentBackgroundTask; import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import okhttp3.Response; import okhttp3.Response;
/** /**
@ -54,16 +54,15 @@ public class DownloadFile implements BufferFile {
private final File saveFile; private final File saveFile;
private final MediaStoreService mediaStoreService; private final MediaStoreService mediaStoreService;
private final boolean save;
private final Long contentLength = null;
private DownloadTask downloadTask; private DownloadTask downloadTask;
private boolean save;
private boolean failedDownload = false; private boolean failedDownload = false;
private int failed = 0; private int failed = 0;
private int bitRate; private int bitRate;
private boolean isPlaying = false; private boolean isPlaying = false;
private boolean saveWhenDone = false; private boolean saveWhenDone = false;
private boolean completeWhenDone = false; private boolean completeWhenDone = false;
private Long contentLength = null;
private long currentSpeed = 0;
private boolean rateLimit = false; private boolean rateLimit = false;
public DownloadFile(Context context, MusicDirectory.Entry song, boolean save) { public DownloadFile(Context context, MusicDirectory.Entry song, boolean save) {
@ -82,14 +81,11 @@ public class DownloadFile implements BufferFile {
public MusicDirectory.Entry getSong() { public MusicDirectory.Entry getSong() {
return song; return song;
} }
public boolean isSong() { public boolean isSong() {
return song.isSong(); return song.isSong();
} }
public Context getContext() {
return context;
}
/** /**
* Returns the effective bit rate. * Returns the effective bit rate.
*/ */
@ -102,6 +98,7 @@ public class DownloadFile implements BufferFile {
} }
return song.getBitRate() == null ? 160 : song.getBitRate(); return song.getBitRate() == null ? 160 : song.getBitRate();
} }
private int getActualBitrate() { private int getActualBitrate() {
int br = Util.getMaxBitrate(context); int br = Util.getMaxBitrate(context);
if (br == 0 && song.getTranscodedSuffix() != null && "mp3".equals(song.getTranscodedSuffix().toLowerCase())) { if (br == 0 && song.getTranscodedSuffix() != null && "mp3".equals(song.getTranscodedSuffix().toLowerCase())) {
@ -124,19 +121,6 @@ public class DownloadFile implements BufferFile {
return contentLength; return contentLength;
} }
public long getCurrentSize() {
if(partialFile.exists()) {
return partialFile.length();
} else {
File file = getCompleteFile();
if(file.exists()) {
return file.length();
} else {
return 0L;
}
}
}
@Override @Override
public long getEstimatedSize() { public long getEstimatedSize() {
if (contentLength != null) { if (contentLength != null) {
@ -155,25 +139,12 @@ public class DownloadFile implements BufferFile {
} }
} }
public long getBytesPerSecond() {
return currentSpeed;
}
public synchronized void download() { public synchronized void download() {
rateLimit = false; rateLimit = false;
preDownload(); preDownload();
downloadTask.execute(); downloadTask.execute();
} }
public synchronized void downloadNow(MusicService musicService) {
rateLimit = true;
preDownload();
downloadTask.setMusicService(musicService);
try {
downloadTask.doInBackground();
} catch(InterruptedException e) {
// This should never be reached
}
}
private void preDownload() { private void preDownload() {
FileUtil.createDirectoryForParent(saveFile); FileUtil.createDirectoryForParent(saveFile);
failedDownload = false; failedDownload = false;
@ -211,9 +182,6 @@ public class DownloadFile implements BufferFile {
return saveFile; return saveFile;
} }
public File getSaveFile() {
return saveFile;
}
public File getPartialFile() { public File getPartialFile() {
return partialFile; return partialFile;
@ -264,6 +232,7 @@ public class DownloadFile implements BufferFile {
public boolean isFailed() { public boolean isFailed() {
return failedDownload; return failedDownload;
} }
public boolean isFailedMax() { public boolean isFailedMax() {
return failed > MAX_FAILURES; return failed > MAX_FAILURES;
} }
@ -317,8 +286,12 @@ public class DownloadFile implements BufferFile {
} }
} }
public void renamePartial() {
Util.renameFile(partialFile, completeFile);
saveToStore();
}
public void setPlaying(boolean isPlaying) { public void setPlaying(boolean isPlaying) {
try {
if (saveWhenDone && !isPlaying) { if (saveWhenDone && !isPlaying) {
Util.renameFile(completeFile, saveFile); Util.renameFile(completeFile, saveFile);
renameInStore(completeFile, saveFile); renameInStore(completeFile, saveFile);
@ -333,23 +306,9 @@ public class DownloadFile implements BufferFile {
} }
completeWhenDone = false; completeWhenDone = false;
} }
} catch(IOException ex) {
Log.w(TAG, "Failed to rename file " + completeFile + " to " + saveFile, ex);
}
this.isPlaying = isPlaying; this.isPlaying = isPlaying;
} }
public void renamePartial() {
try {
Util.renameFile(partialFile, completeFile);
saveToStore();
} catch(IOException ex) {
Log.w(TAG, "Failed to rename file " + partialFile + " to " + completeFile, ex);
}
}
public boolean getPlaying() {
return isPlaying;
}
private void deleteFromStore() { private void deleteFromStore() {
try { try {
@ -358,6 +317,7 @@ public class DownloadFile implements BufferFile {
Log.w(TAG, "Failed to remove from store", e); Log.w(TAG, "Failed to remove from store", e);
} }
} }
private void saveToStore() { private void saveToStore() {
if (!Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_HIDE_MEDIA, false)) { if (!Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_HIDE_MEDIA, false)) {
try { try {
@ -367,6 +327,7 @@ public class DownloadFile implements BufferFile {
} }
} }
} }
private void renameInStore(File start, File end) { private void renameInStore(File start, File end) {
try { try {
mediaStoreService.renameInMediaStore(start, end); mediaStoreService.renameInMediaStore(start, end);
@ -454,7 +415,6 @@ public class DownloadFile implements BufferFile {
Response response = musicService.getDownloadInputStream(context, song, partialFile.length(), bitRate, DownloadTask.this); Response response = musicService.getDownloadInputStream(context, song, partialFile.length(), bitRate, DownloadTask.this);
if (response.header("Content-Length") != null) { if (response.header("Content-Length") != null) {
Log.i(TAG, "Content Length: " + contentLength); Log.i(TAG, "Content Length: " + contentLength);
contentLength = contentLength;
} }
boolean partial = response.code() == 206; boolean partial = response.code() == 206;
@ -549,11 +509,7 @@ public class DownloadFile implements BufferFile {
return "DownloadTask (" + song + ")"; return "DownloadTask (" + song + ")";
} }
public void setMusicService(MusicService musicService) { private void downloadAndSaveCoverArt(MusicService musicService) {
this.musicService = musicService;
}
private void downloadAndSaveCoverArt(MusicService musicService) throws Exception {
try { try {
if (song.getCoverArt() != null) { if (song.getCoverArt() != null) {
// Check if album art already exists, don't want to needlessly load into memory // Check if album art already exists, don't want to needlessly load into memory
@ -602,18 +558,13 @@ public class DownloadFile implements BufferFile {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (now - lastLog > 3000L) { // Only every so often. if (now - lastLog > 3000L) { // Only every so often.
Log.i(TAG, "Downloaded " + Util.formatBytes(count) + " of " + song); Log.i(TAG, "Downloaded " + Util.formatBytes(count) + " of " + song);
currentSpeed = lastCount / ((now - lastLog) / 1000L);
lastLog = now; lastLog = now;
lastCount = 0; lastCount = 0;
// Re-establish every few seconds whether screen is on or not // Re-establish every few seconds whether screen is on or not
if (rateLimit) { if (rateLimit) {
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if(pm.isScreenOn()) { activeLimit = pm.isScreenOn();
activeLimit = true;
} else {
activeLimit = false;
}
} }
} }

View File

@ -18,12 +18,6 @@
*/ */
package net.nullsum.audinaut.service; package net.nullsum.audinaut.service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.atomic.AtomicBoolean;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -36,48 +30,45 @@ import android.telephony.TelephonyManager;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.PlayerQueue; import net.nullsum.audinaut.domain.PlayerQueue;
import net.nullsum.audinaut.domain.PlayerState; import net.nullsum.audinaut.domain.PlayerState;
import net.nullsum.audinaut.util.CacheCleaner; import net.nullsum.audinaut.util.CacheCleaner;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.FileUtil; import net.nullsum.audinaut.util.FileUtil;
import net.nullsum.audinaut.util.Pair;
import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.util.SongDBHandler;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import static net.nullsum.audinaut.domain.PlayerState.PREPARING; 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();
public static final String FILENAME_DOWNLOADS_SER = "downloadstate2.ser"; public static final String FILENAME_DOWNLOADS_SER = "downloadstate2.ser";
private static final String TAG = DownloadServiceLifecycleSupport.class.getSimpleName();
private static final int DEBOUNCE_TIME = 200; private static final int DEBOUNCE_TIME = 200;
private final DownloadService downloadService; private final DownloadService downloadService;
private final AtomicBoolean setup = new AtomicBoolean(false);
private final ReentrantLock lock = new ReentrantLock();
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 final AtomicBoolean setup = new AtomicBoolean(false);
private long lastPressTime = 0; private long lastPressTime = 0;
private SilentBackgroundTask<Void> currentSavePlayQueueTask = 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 final 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(() -> {
@Override
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)) {
@ -94,7 +85,6 @@ public class DownloadServiceLifecycleSupport {
downloadService.pause(); downloadService.pause();
downloadService.seekTo(0); downloadService.seekTo(0);
} }
}
}); });
} }
}; };
@ -105,9 +95,7 @@ public class DownloadServiceLifecycleSupport {
} }
public void onCreate() { public void onCreate() {
new Thread(new Runnable() { new Thread(() -> {
@Override
public void run() {
Looper.prepare(); Looper.prepare();
eventLooper = Looper.myLooper(); eventLooper = Looper.myLooper();
eventHandler = new Handler(eventLooper); eventHandler = new Handler(eventLooper);
@ -128,7 +116,6 @@ public class DownloadServiceLifecycleSupport {
} }
Looper.loop(); Looper.loop();
}
}, "DownloadServiceLifecycleSupport").start(); }, "DownloadServiceLifecycleSupport").start();
// Stop when SD card is ejected. // Stop when SD card is ejected.
@ -188,9 +175,7 @@ public class DownloadServiceLifecycleSupport {
return; return;
} }
eventHandler.post(new Runnable() { eventHandler.post(() -> {
@Override
public void run() {
if (!setup.get()) { if (!setup.get()) {
lock.lock(); lock.lock();
lock.unlock(); lock.unlock();
@ -246,7 +231,6 @@ public class DownloadServiceLifecycleSupport {
handleKeyEvent(event); handleKeyEvent(event);
} }
} }
}
}); });
} }
} }
@ -266,29 +250,23 @@ public class DownloadServiceLifecycleSupport {
} }
public void serializeDownloadQueue() { public void serializeDownloadQueue() {
serializeDownloadQueue(true);
}
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<>(downloadService.getSongs());
eventHandler.post(new Runnable() { eventHandler.post(() -> {
@Override
public void run() {
if (lock.tryLock()) { if (lock.tryLock()) {
try { try {
serializeDownloadQueueNow(songs, serializeRemote); serializeDownloadQueueNow(songs);
} finally { } finally {
lock.unlock(); lock.unlock();
} }
} }
}
}); });
} }
public void serializeDownloadQueueNow(List<DownloadFile> songs, boolean serializeRemote) { private void serializeDownloadQueueNow(List<DownloadFile> songs) {
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());
@ -303,8 +281,6 @@ public class DownloadServiceLifecycleSupport {
if (currentPlaying != null) { if (currentPlaying != null) {
state.renameCurrent = currentPlaying.isWorkDone() && !currentPlaying.isCompleteFileAvailable(); state.renameCurrent = currentPlaying.isWorkDone() && !currentPlaying.isCompleteFileAvailable();
} }
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);
} }
@ -327,17 +303,9 @@ public class DownloadServiceLifecycleSupport {
} }
downloadService.restore(state.songs, state.toDelete, state.currentPlayingIndex, state.currentPlayingPosition); downloadService.restore(state.songs, state.toDelete, state.currentPlayingIndex, state.currentPlayingPosition);
if(state != null) {
lastChange = state.changed;
}
} }
public Date getLastChange() { private void handleKeyEvent(KeyEvent event) {
return lastChange;
}
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:
@ -355,7 +323,7 @@ public class DownloadServiceLifecycleSupport {
lastPressTime = System.currentTimeMillis(); lastPressTime = System.currentTimeMillis();
downloadService.togglePlayPause(); downloadService.togglePlayPause();
} else { } else {
downloadService.next(false, true); downloadService.next(true);
} }
break; break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS: case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
@ -401,9 +369,7 @@ public class DownloadServiceLifecycleSupport {
@Override @Override
public void onCallStateChanged(final int state, String incomingNumber) { public void onCallStateChanged(final int state, String incomingNumber) {
eventHandler.post(new Runnable() { eventHandler.post(() -> {
@Override
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:
@ -423,7 +389,6 @@ public class DownloadServiceLifecycleSupport {
default: default:
break; break;
} }
}
}); });
} }
} }

View File

@ -18,8 +18,6 @@
*/ */
package net.nullsum.audinaut.service; package net.nullsum.audinaut.service;
import java.io.File;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.ContentValues; import android.content.ContentValues;
import android.content.Context; import android.content.Context;
@ -27,9 +25,11 @@ import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.provider.MediaStore; import android.provider.MediaStore;
import android.util.Log; import android.util.Log;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.util.FileUtil; import net.nullsum.audinaut.util.FileUtil;
import net.nullsum.audinaut.util.Util;
import java.io.File;
/** /**
* @author Sindre Mehus * @author Sindre Mehus

View File

@ -18,24 +18,23 @@
*/ */
package net.nullsum.audinaut.service; package net.nullsum.audinaut.service;
import java.util.List;
import okhttp3.Response;
import android.content.Context; import android.content.Context;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import net.nullsum.audinaut.domain.Genre; import net.nullsum.audinaut.domain.Genre;
import net.nullsum.audinaut.domain.Indexes; import net.nullsum.audinaut.domain.Indexes;
import net.nullsum.audinaut.domain.PlayerQueue;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.MusicFolder; import net.nullsum.audinaut.domain.MusicFolder;
import net.nullsum.audinaut.domain.Playlist; import net.nullsum.audinaut.domain.Playlist;
import net.nullsum.audinaut.domain.SearchCritera; import net.nullsum.audinaut.domain.SearchCritera;
import net.nullsum.audinaut.domain.SearchResult; import net.nullsum.audinaut.domain.SearchResult;
import net.nullsum.audinaut.domain.User; import net.nullsum.audinaut.domain.User;
import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.util.ProgressListener; import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.util.SilentBackgroundTask;
import java.util.List;
import okhttp3.Response;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
@ -78,7 +77,6 @@ public interface MusicService {
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 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;
@ -91,11 +89,5 @@ public interface MusicService {
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;
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;
void setInstance(Integer instance) throws Exception; void setInstance(Integer instance) throws Exception;
} }

View File

@ -26,7 +26,7 @@ package net.nullsum.audinaut.service;
*/ */
public class OfflineException extends Exception { public class OfflineException extends Exception {
public OfflineException(String message) { public OfflineException() {
super(message); super(OfflineMusicService.ERRORMSG);
} }
} }

View File

@ -18,30 +18,15 @@
*/ */
package net.nullsum.audinaut.service; package net.nullsum.audinaut.service;
import java.io.File;
import java.io.Reader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.util.Log; import android.util.Log;
import okhttp3.Response;
import net.nullsum.audinaut.domain.Artist; import net.nullsum.audinaut.domain.Artist;
import net.nullsum.audinaut.domain.Genre; import net.nullsum.audinaut.domain.Genre;
import net.nullsum.audinaut.domain.Indexes; import net.nullsum.audinaut.domain.Indexes;
import net.nullsum.audinaut.domain.MusicDirectory.Entry;
import net.nullsum.audinaut.domain.PlayerQueue;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.MusicDirectory.Entry;
import net.nullsum.audinaut.domain.MusicFolder; import net.nullsum.audinaut.domain.MusicFolder;
import net.nullsum.audinaut.domain.Playlist; import net.nullsum.audinaut.domain.Playlist;
import net.nullsum.audinaut.domain.SearchCritera; import net.nullsum.audinaut.domain.SearchCritera;
@ -49,21 +34,31 @@ import net.nullsum.audinaut.domain.SearchResult;
import net.nullsum.audinaut.domain.User; import net.nullsum.audinaut.domain.User;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.FileUtil; import net.nullsum.audinaut.util.FileUtil;
import net.nullsum.audinaut.util.Pair;
import net.nullsum.audinaut.util.ProgressListener; import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.util.SilentBackgroundTask; import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.util.SongDBHandler;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import java.io.*;
import java.util.Comparator; import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.SortedSet; import java.util.SortedSet;
import okhttp3.Response;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class OfflineMusicService implements MusicService { public class OfflineMusicService implements MusicService {
public static final String ERRORMSG = "Not available in offline mode";
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 Random random = new Random(); private static final Random random = new Random();
@Override @Override
@ -73,7 +68,7 @@ public class OfflineMusicService implements MusicService {
@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<>();
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)) {
@ -88,26 +83,26 @@ public class OfflineMusicService implements MusicService {
} }
} }
Indexes indexes = new Indexes(0L, Collections.<Artist>emptyList(), artists, entries); return new Indexes(Collections.emptyList(), artists, entries);
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, context);
} }
private MusicDirectory getMusicDirectory(String id, String artistName, boolean refresh, Context context, ProgressListener progressListener, boolean isPodcast) throws Exception {
private MusicDirectory getMusicDirectory(String id, Context context) 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<>();
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));
} }
} }
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));
@ -116,12 +111,12 @@ public class OfflineMusicService implements MusicService {
@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();
} }
@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();
} }
private String getName(File file) { private String getName(File file) {
@ -141,23 +136,18 @@ public class OfflineMusicService implements MusicService {
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);
}
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());
String root = FileUtil.getMusicDirectory(context).getPath(); String root = FileUtil.getMusicDirectory(context).getPath();
if(!file.getParentFile().getParentFile().getPath().equals(root)) {
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()) {
@ -206,21 +196,21 @@ public class OfflineMusicService implements MusicService {
@Override @Override
public Response getDownloadInputStream(Context context, Entry song, long offset, int maxBitrate, SilentBackgroundTask task) throws Exception { public Response getDownloadInputStream(Context context, Entry song, long offset, int maxBitrate, SilentBackgroundTask task) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException();
} }
@Override @Override
public List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception { public List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG); throw new OfflineException();
} }
@Override @Override
public SearchResult search(SearchCritera criteria, Context context, ProgressListener progressListener) throws Exception { public SearchResult search(SearchCritera criteria, Context context, ProgressListener progressListener) throws Exception {
List<Artist> artists = new ArrayList<Artist>(); List<Artist> artists = new ArrayList<>();
List<Entry> albums = new ArrayList<Entry>(); List<Entry> albums = new ArrayList<>();
List<Entry> songs = new ArrayList<Entry>(); List<Entry> songs = new ArrayList<>();
File root = FileUtil.getMusicDirectory(context); File root = FileUtil.getMusicDirectory(context);
int closeness = 0; int closeness;
for (File artistFile : FileUtil.listFiles(root)) { for (File artistFile : FileUtil.listFiles(root)) {
String artistName = artistFile.getName(); String artistName = artistFile.getName();
if (artistFile.isDirectory()) { if (artistFile.isDirectory()) {
@ -237,44 +227,32 @@ public class OfflineMusicService implements MusicService {
} }
} }
Collections.sort(artists, new Comparator<Artist>() { Collections.sort(artists, (lhs, rhs) -> {
public int compare(Artist lhs, Artist rhs) {
if (lhs.getCloseness() == rhs.getCloseness()) { if (lhs.getCloseness() == rhs.getCloseness()) {
return 0; return 0;
} } else if (lhs.getCloseness() > rhs.getCloseness()) {
else if(lhs.getCloseness() > rhs.getCloseness()) {
return -1; return -1;
} } else {
else {
return 1; return 1;
} }
}
}); });
Collections.sort(albums, new Comparator<Entry>() { Collections.sort(albums, (lhs, rhs) -> {
public int compare(Entry lhs, Entry rhs) {
if (lhs.getCloseness() == rhs.getCloseness()) { if (lhs.getCloseness() == rhs.getCloseness()) {
return 0; return 0;
} } else if (lhs.getCloseness() > rhs.getCloseness()) {
else if(lhs.getCloseness() > rhs.getCloseness()) {
return -1; return -1;
} } else {
else {
return 1; return 1;
} }
}
}); });
Collections.sort(songs, new Comparator<Entry>() { Collections.sort(songs, (lhs, rhs) -> {
public int compare(Entry lhs, Entry rhs) {
if (lhs.getCloseness() == rhs.getCloseness()) { if (lhs.getCloseness() == rhs.getCloseness()) {
return 0; return 0;
} } else if (lhs.getCloseness() > rhs.getCloseness()) {
else if(lhs.getCloseness() > rhs.getCloseness()) {
return -1; return -1;
} } else {
else {
return 1; return 1;
} }
}
}); });
// Respect counts in search criteria // Respect counts in search criteria
@ -308,8 +286,7 @@ public class OfflineMusicService implements MusicService {
if (songFile.isDirectory()) { if (songFile.isDirectory()) {
recursiveAlbumSearch(artistName, songFile, criteria, context, albums, songs); recursiveAlbumSearch(artistName, songFile, criteria, context, albums, songs);
} } else if ((closeness = matchCriteria(criteria, songName)) > 0) {
else if((closeness = matchCriteria(criteria, songName)) > 0){
Entry song = createEntry(context, albumFile, songName); Entry song = createEntry(context, albumFile, songName);
song.setArtist(artistName); song.setArtist(artistName);
song.setAlbum(albumName); song.setAlbum(albumName);
@ -317,8 +294,7 @@ public class OfflineMusicService implements MusicService {
songs.add(song); songs.add(song);
} }
} }
} } else {
else {
String songName = getName(albumFile); String songName = getName(albumFile);
if ((closeness = matchCriteria(criteria, songName)) > 0) { if ((closeness = matchCriteria(criteria, songName)) > 0) {
Entry song = createEntry(context, albumFile, songName); Entry song = createEntry(context, albumFile, songName);
@ -330,6 +306,7 @@ public class OfflineMusicService implements MusicService {
} }
} }
} }
private int matchCriteria(SearchCritera criteria, String name) { private int matchCriteria(SearchCritera criteria, String name) {
if (criteria.getPattern().matcher(name).matches()) { if (criteria.getPattern().matcher(name).matches()) {
return Util.getStringDistance( return Util.getStringDistance(
@ -342,7 +319,7 @@ public class OfflineMusicService implements MusicService {
@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<>();
File root = FileUtil.getPlaylistDirectory(context); File root = FileUtil.getPlaylistDirectory(context);
String lastServer = null; String lastServer = null;
boolean removeServer = true; boolean removeServer = true;
@ -474,68 +451,63 @@ public class OfflineMusicService implements MusicService {
@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();
} }
@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();
} }
@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();
} }
@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();
} }
@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();
} }
@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();
} }
@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();
} }
@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();
} }
@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();
}
@Override
public MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception {
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();
} }
@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();
} }
@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<>();
listFilesRecursively(root, children); listFilesRecursively(root, children);
MusicDirectory result = new MusicDirectory(); MusicDirectory result = new MusicDirectory();
@ -552,27 +524,12 @@ public class OfflineMusicService implements MusicService {
@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();
}
@Override
public Bitmap getBitmap(String url, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public void savePlayQueue(List<Entry> songs, Entry currentPlaying, int position, Context context, ProgressListener progressListener) throws Exception {
throw new OfflineException(ERRORMSG);
}
@Override
public PlayerQueue getPlayQueue(Context context, ProgressListener progressListener) throws Exception {
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();
} }
private void listFilesRecursively(File parent, List<File> children) { private void listFilesRecursively(File parent, List<File> children) {

View File

@ -18,28 +18,19 @@
*/ */
package net.nullsum.audinaut.service; package net.nullsum.audinaut.service;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.FormBody;
import okhttp3.FormBody.Builder;
import okhttp3.RequestBody;
import okhttp3.Call;
import okhttp3.Credentials;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.util.Log; import android.util.Log;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.domain.Genre;
import net.nullsum.audinaut.domain.*; import net.nullsum.audinaut.domain.Indexes;
import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.MusicFolder;
import net.nullsum.audinaut.domain.Playlist;
import net.nullsum.audinaut.domain.SearchCritera;
import net.nullsum.audinaut.domain.SearchResult;
import net.nullsum.audinaut.domain.User;
import net.nullsum.audinaut.fragments.MainFragment; import net.nullsum.audinaut.fragments.MainFragment;
import net.nullsum.audinaut.service.parser.EntryListParser; import net.nullsum.audinaut.service.parser.EntryListParser;
import net.nullsum.audinaut.service.parser.ErrorParser; import net.nullsum.audinaut.service.parser.ErrorParser;
@ -47,29 +38,39 @@ import net.nullsum.audinaut.service.parser.GenreParser;
import net.nullsum.audinaut.service.parser.IndexesParser; import net.nullsum.audinaut.service.parser.IndexesParser;
import net.nullsum.audinaut.service.parser.MusicDirectoryParser; import net.nullsum.audinaut.service.parser.MusicDirectoryParser;
import net.nullsum.audinaut.service.parser.MusicFoldersParser; import net.nullsum.audinaut.service.parser.MusicFoldersParser;
import net.nullsum.audinaut.service.parser.PlayQueueParser;
import net.nullsum.audinaut.service.parser.PlaylistParser; import net.nullsum.audinaut.service.parser.PlaylistParser;
import net.nullsum.audinaut.service.parser.PlaylistsParser; import net.nullsum.audinaut.service.parser.PlaylistsParser;
import net.nullsum.audinaut.service.parser.RandomSongsParser; import net.nullsum.audinaut.service.parser.RandomSongsParser;
import net.nullsum.audinaut.service.parser.SearchResult2Parser; import net.nullsum.audinaut.service.parser.SearchResult2Parser;
import net.nullsum.audinaut.service.parser.UserParser; import net.nullsum.audinaut.service.parser.UserParser;
import net.nullsum.audinaut.util.BackgroundTask;
import net.nullsum.audinaut.util.Pair;
import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.FileUtil; import net.nullsum.audinaut.util.FileUtil;
import net.nullsum.audinaut.util.Pair;
import net.nullsum.audinaut.util.ProgressListener; import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.util.SongDBHandler; import net.nullsum.audinaut.util.SongDBHandler;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.concurrent.TimeUnit;
import okhttp3.FormBody;
import okhttp3.FormBody.Builder;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class RESTMusicService implements MusicService { public class RESTMusicService implements MusicService {
private static OkHttpClient client = new OkHttpClient();
private static final String TAG = RESTMusicService.class.getSimpleName(); private static final String TAG = RESTMusicService.class.getSimpleName();
private static final OkHttpClient client = new OkHttpClient();
private Integer instance; private Integer instance;
@Override @Override
@ -93,7 +94,7 @@ public class RESTMusicService implements MusicService {
.build(); .build();
try (Response response = client.newCall(request).execute()) { try (Response response = client.newCall(request).execute()) {
return new MusicFoldersParser(context, getInstance(context)).parse(response.body().byteStream(), progressListener); return new MusicFoldersParser(context, getInstance(context)).parse(response.body().byteStream());
} }
} }
@ -123,8 +124,8 @@ public class RESTMusicService implements MusicService {
public MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { public MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
SharedPreferences prefs = Util.getPreferences(context); SharedPreferences prefs = Util.getPreferences(context);
String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
if(cacheLocn != null && id.indexOf(cacheLocn) != -1) { if (cacheLocn != null && id.contains(cacheLocn)) {
String search = Util.parseOfflineIDSearch(context, id, cacheLocn); String search = Util.parseOfflineIDSearch(id, cacheLocn);
SearchCritera critera = new SearchCritera(search, 1, 1, 0); SearchCritera critera = new SearchCritera(search, 1, 1, 0);
SearchResult result = search(critera, context, progressListener); SearchResult result = search(critera, context, progressListener);
if (result.getArtists().size() == 1) { if (result.getArtists().size() == 1) {
@ -137,7 +138,7 @@ public class RESTMusicService implements MusicService {
MusicDirectory dir = null; MusicDirectory dir = null;
int index, start = 0; int index, start = 0;
while ((index = id.indexOf(';', start)) != -1) { while ((index = id.indexOf(';', start)) != -1) {
MusicDirectory extra = getMusicDirectoryImpl(id.substring(start, index), name, refresh, context, progressListener); MusicDirectory extra = getMusicDirectoryImpl(id.substring(start, index), name, context);
if (dir == null) { if (dir == null) {
dir = extra; dir = extra;
} else { } else {
@ -146,7 +147,7 @@ public class RESTMusicService implements MusicService {
start = index + 1; start = index + 1;
} }
MusicDirectory extra = getMusicDirectoryImpl(id.substring(start), name, refresh, context, progressListener); MusicDirectory extra = getMusicDirectoryImpl(id.substring(start), name, context);
if (dir == null) { if (dir == null) {
dir = extra; dir = extra;
} else { } else {
@ -156,7 +157,7 @@ public class RESTMusicService implements MusicService {
return dir; return dir;
} }
private MusicDirectory getMusicDirectoryImpl(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception { private MusicDirectory getMusicDirectoryImpl(String id, String name, Context context) throws Exception {
String url = getRestUrl(context, "getMusicDirectory"); String url = getRestUrl(context, "getMusicDirectory");
RequestBody formBody = new FormBody.Builder() RequestBody formBody = new FormBody.Builder()
@ -169,7 +170,7 @@ public class RESTMusicService implements MusicService {
.build(); .build();
try (Response response = client.newCall(request).execute()) { try (Response response = client.newCall(request).execute()) {
return new MusicDirectoryParser(context, getInstance(context)).parse(name, response.body().byteStream(), progressListener); return new MusicDirectoryParser(context, getInstance(context)).parse(name, response.body().byteStream());
} }
} }
@ -187,7 +188,7 @@ public class RESTMusicService implements MusicService {
.build(); .build();
try (Response response = client.newCall(request).execute()) { try (Response response = client.newCall(request).execute()) {
return new MusicDirectoryParser(context, getInstance(context)).parse(name, response.body().byteStream(), progressListener); return new MusicDirectoryParser(context, getInstance(context)).parse(name, response.body().byteStream());
} }
} }
@ -205,7 +206,7 @@ public class RESTMusicService implements MusicService {
.build(); .build();
try (Response response = client.newCall(request).execute()) { try (Response response = client.newCall(request).execute()) {
return new MusicDirectoryParser(context, getInstance(context)).parse(name, response.body().byteStream(), progressListener); return new MusicDirectoryParser(context, getInstance(context)).parse(name, response.body().byteStream());
} }
} }
@ -228,7 +229,7 @@ public class RESTMusicService implements MusicService {
.build(); .build();
try (Response response = client.newCall(request).execute()) { try (Response response = client.newCall(request).execute()) {
return new SearchResult2Parser(context, getInstance(context)).parse(response.body().byteStream(), progressListener); return new SearchResult2Parser(context, getInstance(context)).parse(response.body().byteStream());
} }
} }
@ -246,7 +247,7 @@ public class RESTMusicService implements MusicService {
.build(); .build();
try (Response response = client.newCall(request).execute()) { try (Response response = client.newCall(request).execute()) {
return new PlaylistParser(context, getInstance(context)).parse(response.body().byteStream(), progressListener); return new PlaylistParser(context, getInstance(context)).parse(response.body().byteStream());
} }
} }
@ -259,7 +260,7 @@ public class RESTMusicService implements MusicService {
.build(); .build();
try (Response response = client.newCall(request).execute()) { try (Response response = client.newCall(request).execute()) {
return new PlaylistsParser(context, getInstance(context)).parse(response.body().byteStream(), progressListener); return new PlaylistsParser(context, getInstance(context)).parse(response.body().byteStream());
} }
} }
@ -432,7 +433,7 @@ public class RESTMusicService implements MusicService {
.build(); .build();
try (Response response = client.newCall(request).execute()) { try (Response response = client.newCall(request).execute()) {
return new EntryListParser(context, getInstance(context)).parse(response.body().byteStream(), progressListener); return new EntryListParser(context, getInstance(context)).parse(response.body().byteStream());
} }
} }
@ -472,7 +473,7 @@ public class RESTMusicService implements MusicService {
.build(); .build();
try (Response response = client.newCall(request).execute()) { try (Response response = client.newCall(request).execute()) {
return new EntryListParser(context, getInstance(context)).parse(response.body().byteStream(), progressListener); return new EntryListParser(context, getInstance(context)).parse(response.body().byteStream());
} }
} }
@ -510,27 +511,7 @@ public class RESTMusicService implements MusicService {
.build(); .build();
try (Response response = client.newCall(request).execute()) { try (Response response = client.newCall(request).execute()) {
return new EntryListParser(context, getInstance(context)).parse(response.body().byteStream(), progressListener); return new EntryListParser(context, getInstance(context)).parse(response.body().byteStream());
}
}
@Override
public MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception {
Builder builder= new FormBody.Builder();
builder.add("id", artistId);
builder.add("count", Integer.toString(size));
String url = getRestUrl(context, "getSimilarSongs2");
RequestBody formBody = builder.build();
Request request = new Request.Builder()
.url(url)
.post(formBody)
.build();
try (Response response = client.newCall(request).execute()) {
return new RandomSongsParser(context, getInstance(context)).parse(response.body().byteStream(), progressListener);
} }
} }
@ -539,9 +520,6 @@ public class RESTMusicService implements MusicService {
Builder builder = new FormBody.Builder(); Builder builder = new FormBody.Builder();
builder.add("size", Integer.toString(size)); builder.add("size", Integer.toString(size));
if (musicFolderId != null && !"".equals(musicFolderId) && !Util.isTagBrowsing(context, getInstance(context))) {
builder.add("musicFolderId", musicFolderId);
}
if (genre != null && !"".equals(genre)) { if (genre != null && !"".equals(genre)) {
builder.add("genre", genre); builder.add("genre", genre);
} }
@ -578,7 +556,7 @@ public class RESTMusicService implements MusicService {
.build(); .build();
try (Response response = client.newCall(request).execute()) { try (Response response = client.newCall(request).execute()) {
return new RandomSongsParser(context, getInstance(context)).parse(response.body().byteStream(), progressListener); return new RandomSongsParser(context, getInstance(context)).parse(response.body().byteStream());
} }
} }
@ -659,8 +637,7 @@ public class RESTMusicService implements MusicService {
Request request = requestBuilder.build(); Request request = requestBuilder.build();
Response response = eagerClient.newCall(request).execute(); return eagerClient.newCall(request).execute();
return response;
} }
@ -673,7 +650,7 @@ public class RESTMusicService implements MusicService {
.build(); .build();
try (Response response = client.newCall(request).execute()) { try (Response response = client.newCall(request).execute()) {
return new GenreParser(context, getInstance(context)).parse(response.body().byteStream(), progressListener); return new GenreParser(context, getInstance(context)).parse(response.body().byteStream());
} }
} }
@ -703,7 +680,7 @@ public class RESTMusicService implements MusicService {
.build(); .build();
try (Response response = client.newCall(request).execute()) { try (Response response = client.newCall(request).execute()) {
return new RandomSongsParser(context, getInstance(context)).parse(response.body().byteStream(), progressListener); return new RandomSongsParser(context, getInstance(context)).parse(response.body().byteStream());
} }
} }
@ -721,7 +698,7 @@ public class RESTMusicService implements MusicService {
.build(); .build();
try (Response response = client.newCall(request).execute()) { try (Response response = client.newCall(request).execute()) {
List<User> users = new UserParser(context, getInstance(context)).parse(response.body().byteStream(), progressListener); List<User> users = new UserParser(context, getInstance(context)).parse(response.body().byteStream());
if (users.size() > 0) { if (users.size() > 0) {
// Should only have returned one anyways // Should only have returned one anyways
return users.get(0); return users.get(0);
@ -731,91 +708,15 @@ public class RESTMusicService implements MusicService {
} }
} }
@Override
public Bitmap getBitmap(String method, int size, Context context, ProgressListener progressListener, SilentBackgroundTask task) throws Exception {
// Synchronize on the url so that we don't download concurrently
synchronized (method) {
// Use cached file, if existing.
Bitmap bitmap = FileUtil.getMiscBitmap(context, method, size);
if(bitmap != null) {
return bitmap;
}
String url = getRestUrl(context, method);
Request request = new Request.Builder()
.url(url)
.build();
try (Response response = client.newCall(request).execute()) {
InputStream in = response.body().byteStream();
byte[] bytes = Util.toByteArray(in);
if(task != null && task.isCancelled()) {
// Handle case where partial is downloaded and cancelled
return null;
}
OutputStream out = null;
try {
out = new FileOutputStream(FileUtil.getMiscFile(context, url));
out.write(bytes);
} finally {
Util.close(out);
}
return FileUtil.getSampledBitmap(bytes, size, false);
}
}
}
@Override
public void savePlayQueue(List<MusicDirectory.Entry> songs, MusicDirectory.Entry currentPlaying, int position, Context context, ProgressListener progressListener) throws Exception {
String url = getRestUrl(context, "savePlayQueue");
Builder builder= new FormBody.Builder();
builder.add("current", currentPlaying.getId());
builder.add("position", Integer.toString(position));
for(MusicDirectory.Entry song: songs) {
builder.add("id", song.getId());
}
RequestBody formBody = builder.build();
Request request = new Request.Builder()
.url(url)
.post(formBody)
.build();
try (Response response = client.newCall(request).execute()) {
new ErrorParser(context, getInstance(context)).parse(response.body().byteStream());
}
}
@Override
public PlayerQueue getPlayQueue(Context context, ProgressListener progressListener) throws Exception {
String url = getRestUrl(context, "getPlayQueue");
Request request = new Request.Builder()
.url(url)
.build();
try (Response response = client.newCall(request).execute()) {
return new PlayQueueParser(context, getInstance(context)).parse(response.body().byteStream(), progressListener);
}
}
private String getOfflineSongId(String id, Context context, ProgressListener progressListener) throws Exception { private String getOfflineSongId(String id, Context context, ProgressListener progressListener) throws Exception {
SharedPreferences prefs = Util.getPreferences(context); SharedPreferences prefs = Util.getPreferences(context);
String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null); String cacheLocn = prefs.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, null);
if(cacheLocn != null && id.indexOf(cacheLocn) != -1) { if (cacheLocn != null && id.contains(cacheLocn)) {
Pair<Integer, String> cachedSongId = SongDBHandler.getHandler(context).getIdFromPath(Util.getRestUrlHash(context, getInstance(context)), id); Pair<Integer, String> cachedSongId = SongDBHandler.getHandler(context).getIdFromPath(Util.getRestUrlHash(context, getInstance(context)), id);
if (cachedSongId != null) { if (cachedSongId != null) {
id = cachedSongId.getSecond(); id = cachedSongId.getSecond();
} else { } else {
String searchCriteria = Util.parseOfflineIDSearch(context, id, cacheLocn); String searchCriteria = Util.parseOfflineIDSearch(id, cacheLocn);
SearchCritera critera = new SearchCritera(searchCriteria, 0, 0, 1); SearchCritera critera = new SearchCritera(searchCriteria, 0, 0, 1);
SearchResult result = search(critera, context, progressListener); SearchResult result = search(critera, context, progressListener);
if (result.getSongs().size() == 1) { if (result.getSongs().size() == 1) {

View File

@ -18,41 +18,41 @@
*/ */
package net.nullsum.audinaut.service.parser; package net.nullsum.audinaut.service.parser;
import java.io.IOException;
import java.io.InputStream;
import org.xmlpull.v1.XmlPullParser;
import android.content.Context; import android.content.Context;
import android.util.Log; import android.util.Log;
import android.util.Xml; import android.util.Xml;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.util.ProgressListener; import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import org.xmlpull.v1.XmlPullParser;
import java.io.IOException;
import java.io.InputStream;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public abstract class AbstractParser { abstract class AbstractParser {
private static final String TAG = AbstractParser.class.getSimpleName(); private static final String TAG = AbstractParser.class.getSimpleName();
private static final String SUBSONIC_RESPONSE = "subsonic-response"; private static final String SUBSONIC_RESPONSE = "subsonic-response";
private static final String SUBSONIC = "subsonic";
protected final Context context; final Context context;
protected final int instance; private final int instance;
private XmlPullParser parser; private XmlPullParser parser;
private boolean rootElementFound; private boolean rootElementFound;
public AbstractParser(Context context, int instance) { AbstractParser(Context context, int instance) {
this.context = context; this.context = context;
this.instance = instance; this.instance = instance;
} }
protected Context getContext() { Context getContext() {
return context; return context;
} }
protected void handleError() throws Exception { void handleError() throws Exception {
int code = getInteger("code"); int code = getInteger("code");
String message; String message;
switch (code) { switch (code) {
@ -69,7 +69,7 @@ public abstract class AbstractParser {
message = context.getResources().getString(R.string.parser_not_authenticated); message = context.getResources().getString(R.string.parser_not_authenticated);
break; break;
case 41: case 41:
Util.setBlockTokenUse(context, instance, true); Util.setBlockTokenUse(context, instance);
// Throw IOException so RESTMusicService knows to retry // Throw IOException so RESTMusicService knows to retry
throw new IOException(); throw new IOException();
@ -80,34 +80,28 @@ public abstract class AbstractParser {
message = get("message"); message = get("message");
break; break;
} }
throw new SubsonicRESTException(code, message); throw new SubsonicRESTException(message);
} }
protected void updateProgress(ProgressListener progressListener, int messageId) { void updateProgress(ProgressListener progressListener, String message) {
if (progressListener != null) {
progressListener.updateProgress(messageId);
}
}
protected void updateProgress(ProgressListener progressListener, String message) {
if (progressListener != null) { if (progressListener != null) {
progressListener.updateProgress(message); progressListener.updateProgress(message);
} }
} }
protected String getText() { String getText() {
return parser.getText(); return parser.getText();
} }
protected String get(String name) { String get(String name) {
return parser.getAttributeValue(null, name); return parser.getAttributeValue(null, name);
} }
protected boolean getBoolean(String name) { boolean getBoolean() {
return "true".equals(get(name)); return "true".equals(get("isDir"));
} }
protected Integer getInteger(String name) { Integer getInteger(String name) {
String s = get(name); String s = get(name);
try { try {
return (s == null || "".equals(s)) ? null : Integer.valueOf(s); return (s == null || "".equals(s)) ? null : Integer.valueOf(s);
@ -117,40 +111,25 @@ public abstract class AbstractParser {
} }
} }
protected Long getLong(String name) { void init(InputStream inputStream) throws Exception {
String s = get(name);
return s == null ? null : Long.valueOf(s);
}
protected Float getFloat(String name) {
String s = get(name);
return s == null ? null : Float.valueOf(s);
}
protected void init(InputStream inputStream) throws Exception {
parser = Xml.newPullParser(); parser = Xml.newPullParser();
parser.setInput(inputStream, "UTF-8"); parser.setInput(inputStream, "UTF-8");
rootElementFound = false; rootElementFound = false;
} }
protected int nextParseEvent() throws Exception { int nextParseEvent() throws Exception {
try {
return parser.next(); return parser.next();
} catch(Exception e) {
throw e;
}
} }
protected String getElementName() { String getElementName() {
String name = parser.getName(); String name = parser.getName();
if (SUBSONIC_RESPONSE.equals(name)) { if (SUBSONIC_RESPONSE.equals(name)) {
rootElementFound = true; rootElementFound = true;
String version = get("version");
} }
return name; return name;
} }
protected void validate() throws Exception { void validate() throws Exception {
if (!rootElementFound) { if (!rootElementFound) {
throw new Exception(context.getResources().getString(R.string.background_task_parse_error)); throw new Exception(context.getResources().getString(R.string.background_task_parse_error));
} }

View File

@ -19,9 +19,9 @@
package net.nullsum.audinaut.service.parser; package net.nullsum.audinaut.service.parser;
import android.content.Context; import android.content.Context;
import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import java.io.InputStream; import java.io.InputStream;
@ -35,7 +35,7 @@ public class EntryListParser extends MusicDirectoryEntryParser {
super(context, instance); super(context, instance);
} }
public MusicDirectory parse(InputStream inputStream, ProgressListener progressListener) throws Exception { public MusicDirectory parse(InputStream inputStream) throws Exception {
init(inputStream); init(inputStream);
MusicDirectory dir = new MusicDirectory(); MusicDirectory dir = new MusicDirectory();

View File

@ -19,6 +19,7 @@
package net.nullsum.audinaut.service.parser; package net.nullsum.audinaut.service.parser;
import android.content.Context; import android.content.Context;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import java.io.InputStream; import java.io.InputStream;

View File

@ -20,34 +20,29 @@ package net.nullsum.audinaut.service.parser;
import android.content.Context; import android.content.Context;
import android.text.Html; import android.text.Html;
import android.util.Log;
import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.Genre; import net.nullsum.audinaut.domain.Genre;
import net.nullsum.audinaut.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
/** /**
* @author Joshua Bahnsen * @author Joshua Bahnsen
*/ */
public class GenreParser extends AbstractParser { public class GenreParser extends AbstractParser {
private static final String TAG = GenreParser.class.getSimpleName();
public GenreParser(Context context, int instance) { public GenreParser(Context context, int instance) {
super(context, instance); super(context, instance);
} }
public List<Genre> parse(InputStream inputStream, ProgressListener progressListener) throws Exception { public List<Genre> parse(InputStream inputStream) throws Exception {
init(inputStream); init(inputStream);
List<Genre> result = new ArrayList<Genre>(); List<Genre> result = new ArrayList<>();
Genre genre = null; Genre genre = null;
@ -80,12 +75,7 @@ public class GenreParser extends AbstractParser {
validate(); validate();
Collections.sort(result, new Comparator<Genre>() { Collections.sort(result, (genre1, genre2) -> genre1.getName().compareTo(genre2.getName()));
@Override
public int compare(Genre genre1, Genre genre2) {
return genre1.getName().compareTo(genre2.getName());
}
});
return result; return result;
} }
} }

View File

@ -18,25 +18,26 @@
*/ */
package net.nullsum.audinaut.service.parser; package net.nullsum.audinaut.service.parser;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import org.xmlpull.v1.XmlPullParser;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.util.Log;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.Artist; import net.nullsum.audinaut.domain.Artist;
import net.nullsum.audinaut.domain.Indexes; import net.nullsum.audinaut.domain.Indexes;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.util.ProgressListener;
import android.util.Log;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import org.xmlpull.v1.XmlPullParser;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
*/ */
@ -51,15 +52,14 @@ public class IndexesParser extends MusicDirectoryEntryParser {
long t0 = System.currentTimeMillis(); long t0 = System.currentTimeMillis();
init(inputStream); init(inputStream);
List<Artist> artists = new ArrayList<Artist>(); List<Artist> artists = new ArrayList<>();
List<Artist> shortcuts = new ArrayList<Artist>(); List<Artist> shortcuts = new ArrayList<>();
List<MusicDirectory.Entry> entries = new ArrayList<MusicDirectory.Entry>(); List<MusicDirectory.Entry> entries = new ArrayList<>();
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<>();
do { do {
eventType = nextParseEvent(); eventType = nextParseEvent();
@ -67,7 +67,6 @@ public class IndexesParser extends MusicDirectoryEntryParser {
String name = getElementName(); String name = getElementName();
if ("indexes".equals(name) || "artists".equals(name)) { if ("indexes".equals(name) || "artists".equals(name)) {
changed = true; changed = true;
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");
@ -124,6 +123,6 @@ public class IndexesParser extends MusicDirectoryEntryParser {
String msg = getContext().getResources().getString(R.string.parser_artist_count, artists.size()); String msg = getContext().getResources().getString(R.string.parser_artist_count, artists.size());
updateProgress(progressListener, msg); updateProgress(progressListener, msg);
return new Indexes(lastModified == null ? 0L : lastModified, shortcuts, artists, entries); return new Indexes(shortcuts, artists, entries);
} }
} }

View File

@ -25,12 +25,12 @@ import net.nullsum.audinaut.domain.MusicDirectory;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class MusicDirectoryEntryParser extends AbstractParser { class MusicDirectoryEntryParser extends AbstractParser {
public MusicDirectoryEntryParser(Context context, int instance) { MusicDirectoryEntryParser(Context context, int instance) {
super(context, instance); super(context, instance);
} }
protected MusicDirectory.Entry parseEntry(String artist) { 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"));
@ -39,7 +39,7 @@ public class MusicDirectoryEntryParser extends AbstractParser {
if (entry.getTitle() == null) { if (entry.getTitle() == null) {
entry.setTitle(get("name")); entry.setTitle(get("name"));
} }
entry.setDirectory(getBoolean("isDir")); entry.setDirectory(getBoolean());
entry.setCoverArt(get("coverArt")); entry.setCoverArt(get("coverArt"));
entry.setArtist(get("artist")); entry.setArtist(get("artist"));
entry.setYear(getInteger("year")); entry.setYear(getInteger("year"));
@ -53,27 +53,14 @@ public class MusicDirectoryEntryParser extends AbstractParser {
entry.setSuffix(get("suffix")); entry.setSuffix(get("suffix"));
entry.setTranscodedContentType(get("transcodedContentType")); entry.setTranscodedContentType(get("transcodedContentType"));
entry.setTranscodedSuffix(get("transcodedSuffix")); entry.setTranscodedSuffix(get("transcodedSuffix"));
entry.setSize(getLong("size"));
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");
} 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() {
MusicDirectory.Entry entry = new MusicDirectory.Entry();
entry.setId(get("id"));
entry.setTitle(get("name"));
entry.setPath(entry.getTitle());
entry.setDirectory(true);
return entry;
}
} }

View File

@ -19,45 +19,39 @@
package net.nullsum.audinaut.service.parser; package net.nullsum.audinaut.service.parser;
import android.content.Context; import android.content.Context;
import android.util.Log;
import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.ProgressListener;
import net.nullsum.audinaut.util.Util;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static net.nullsum.audinaut.domain.MusicDirectory.*; import static net.nullsum.audinaut.domain.MusicDirectory.Entry;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public class MusicDirectoryParser extends MusicDirectoryEntryParser { public class MusicDirectoryParser extends MusicDirectoryEntryParser {
private static final String TAG = MusicDirectoryParser.class.getSimpleName();
public MusicDirectoryParser(Context context, int instance) { public MusicDirectoryParser(Context context, int instance) {
super(context, instance); super(context, instance);
} }
public MusicDirectory parse(String artist, InputStream inputStream, ProgressListener progressListener) throws Exception { public MusicDirectory parse(String artist, InputStream inputStream) throws Exception {
init(inputStream); init(inputStream);
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<>();
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());
// Only check for songs // Only check for songs
if (!entry.isDirectory()) { if (!entry.isDirectory()) {
@ -84,11 +78,7 @@ public class MusicDirectoryParser extends MusicDirectoryEntryParser {
} 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)) {
dir.setParent(get("artistId")); dir.setParent(get("artistId"));
} else {
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);

View File

@ -18,16 +18,15 @@
*/ */
package net.nullsum.audinaut.service.parser; package net.nullsum.audinaut.service.parser;
import java.io.InputStream; import android.content.Context;
import java.util.ArrayList;
import java.util.List; import net.nullsum.audinaut.domain.MusicFolder;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import android.content.Context; import java.io.InputStream;
import net.nullsum.audinaut.R; import java.util.ArrayList;
import net.nullsum.audinaut.domain.MusicFolder; import java.util.List;
import net.nullsum.audinaut.util.ProgressListener;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
@ -38,10 +37,10 @@ public class MusicFoldersParser extends AbstractParser {
super(context, instance); super(context, instance);
} }
public List<MusicFolder> parse(InputStream inputStream, ProgressListener progressListener) throws Exception { public List<MusicFolder> parse(InputStream inputStream) throws Exception {
init(inputStream); init(inputStream);
List<MusicFolder> result = new ArrayList<MusicFolder>(); List<MusicFolder> result = new ArrayList<>();
int eventType; int eventType;
do { do {
eventType = nextParseEvent(); eventType = nextParseEvent();

View File

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

View File

@ -19,9 +19,9 @@
package net.nullsum.audinaut.service.parser; package net.nullsum.audinaut.service.parser;
import android.content.Context; import android.content.Context;
import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import java.io.InputStream; import java.io.InputStream;
@ -35,7 +35,7 @@ public class PlaylistParser extends MusicDirectoryEntryParser {
super(context, instance); super(context, instance);
} }
public MusicDirectory parse(InputStream inputStream, ProgressListener progressListener) throws Exception { public MusicDirectory parse(InputStream inputStream) throws Exception {
init(inputStream); init(inputStream);
MusicDirectory dir = new MusicDirectory(); MusicDirectory dir = new MusicDirectory();

View File

@ -21,7 +21,7 @@ package net.nullsum.audinaut.service.parser;
import android.content.Context; import android.content.Context;
import net.nullsum.audinaut.domain.Playlist; import net.nullsum.audinaut.domain.Playlist;
import net.nullsum.audinaut.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import java.io.InputStream; import java.io.InputStream;
@ -37,10 +37,10 @@ public class PlaylistsParser extends AbstractParser {
super(context, instance); super(context, instance);
} }
public List<Playlist> parse(InputStream inputStream, ProgressListener progressListener) throws Exception { public List<Playlist> parse(InputStream inputStream) throws Exception {
init(inputStream); init(inputStream);
List<Playlist> result = new ArrayList<Playlist>(); List<Playlist> result = new ArrayList<>();
int eventType; int eventType;
do { do {
eventType = nextParseEvent(); eventType = nextParseEvent();

View File

@ -19,9 +19,9 @@
package net.nullsum.audinaut.service.parser; package net.nullsum.audinaut.service.parser;
import android.content.Context; import android.content.Context;
import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import java.io.InputStream; import java.io.InputStream;
@ -35,7 +35,7 @@ public class RandomSongsParser extends MusicDirectoryEntryParser {
super(context, instance); super(context, instance);
} }
public MusicDirectory parse(InputStream inputStream, ProgressListener progressListener) throws Exception { public MusicDirectory parse(InputStream inputStream) throws Exception {
init(inputStream); init(inputStream);
MusicDirectory dir = new MusicDirectory(); MusicDirectory dir = new MusicDirectory();

View File

@ -19,16 +19,16 @@
package net.nullsum.audinaut.service.parser; package net.nullsum.audinaut.service.parser;
import android.content.Context; import android.content.Context;
import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.Artist;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.SearchResult; import net.nullsum.audinaut.domain.SearchResult;
import net.nullsum.audinaut.domain.Artist;
import net.nullsum.audinaut.util.ProgressListener;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
import java.io.InputStream; import java.io.InputStream;
import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
@ -39,12 +39,12 @@ public class SearchResult2Parser extends MusicDirectoryEntryParser {
super(context, instance); super(context, instance);
} }
public SearchResult parse(InputStream inputStream, ProgressListener progressListener) throws Exception { public SearchResult parse(InputStream inputStream) throws Exception {
init(inputStream); init(inputStream);
List<Artist> artists = new ArrayList<Artist>(); List<Artist> artists = new ArrayList<>();
List<MusicDirectory.Entry> albums = new ArrayList<MusicDirectory.Entry>(); List<MusicDirectory.Entry> albums = new ArrayList<>();
List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(); List<MusicDirectory.Entry> songs = new ArrayList<>();
int eventType; int eventType;
do { do {
eventType = nextParseEvent(); eventType = nextParseEvent();

View File

@ -4,16 +4,10 @@ package net.nullsum.audinaut.service.parser;
* @author Sindre Mehus * @author Sindre Mehus
* @version $Id$ * @version $Id$
*/ */
public class SubsonicRESTException extends Exception { class SubsonicRESTException extends Exception {
private final int code; public SubsonicRESTException(String message) {
public SubsonicRESTException(int code, String message) {
super(message); super(message);
this.code = code;
} }
public int getCode() {
return code;
}
} }

View File

@ -16,7 +16,12 @@
package net.nullsum.audinaut.service.parser; package net.nullsum.audinaut.service.parser;
import android.content.Context; import android.content.Context;
import android.util.Log;
import net.nullsum.audinaut.domain.MusicFolder;
import net.nullsum.audinaut.domain.User;
import net.nullsum.audinaut.domain.User.Setting;
import net.nullsum.audinaut.service.MusicService;
import net.nullsum.audinaut.service.MusicServiceFactory;
import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParser;
@ -24,24 +29,15 @@ import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import net.nullsum.audinaut.domain.MusicFolder;
import net.nullsum.audinaut.domain.User;
import net.nullsum.audinaut.domain.User.MusicFolderSetting;
import net.nullsum.audinaut.domain.User.Setting;
import net.nullsum.audinaut.service.MusicService;
import net.nullsum.audinaut.service.MusicServiceFactory;
import net.nullsum.audinaut.util.ProgressListener;
public class UserParser extends AbstractParser { public class UserParser extends AbstractParser {
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) throws Exception {
init(inputStream); init(inputStream);
List<User> result = new ArrayList<User>(); List<User> result = new ArrayList<>();
List<MusicFolder> musicFolders = null; List<MusicFolder> musicFolders = null;
User user = null; User user = null;
int eventType; int eventType;
@ -54,8 +50,6 @@ public class UserParser extends AbstractParser {
if ("user".equals(tagName)) { if ("user".equals(tagName)) {
user = new User(); user = new User();
user.setUsername(get("username"));
user.setEmail(get("email"));
for (String role : User.ROLES) { for (String role : User.ROLES) {
parseSetting(user, role); parseSetting(user, role);
} }

View File

@ -21,20 +21,21 @@ package net.nullsum.audinaut.updates;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.util.Log; import android.util.Log;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.SilentBackgroundTask; import net.nullsum.audinaut.util.SilentBackgroundTask;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
/** /**
*
* @author Scott * @author Scott
*/ */
public class Updater { public class Updater {
protected String TAG = Updater.class.getSimpleName(); private final int version;
protected int version; String TAG = Updater.class.getSimpleName();
protected Context context; private 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
@ -46,7 +47,7 @@ public class Updater {
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<>();
updaters.add(new UpdaterSongPress()); updaters.add(new UpdaterSongPress());
SharedPreferences prefs = Util.getPreferences(context); SharedPreferences prefs = Util.getPreferences(context);
@ -55,8 +56,7 @@ public class Updater {
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();
@ -70,10 +70,18 @@ public class Updater {
} }
} }
public String getName() { private String getName() {
return this.TAG; return this.TAG;
} }
private boolean shouldUpdate(int version) {
return this.version > version;
}
void update(Context context) {
}
private class BackgroundUpdate extends SilentBackgroundTask<Void> { private class BackgroundUpdate extends SilentBackgroundTask<Void> {
private final Updater updater; private final Updater updater;
@ -92,11 +100,4 @@ public class Updater {
return null; return null;
} }
} }
public boolean shouldUpdate(int version) {
return this.version > version;
}
public void update(Context context) {
}
} }

View File

@ -21,7 +21,7 @@ import android.content.SharedPreferences;
import net.nullsum.audinaut.util.Constants; import net.nullsum.audinaut.util.Constants;
import net.nullsum.audinaut.util.Util; import net.nullsum.audinaut.util.Util;
public class UpdaterSongPress extends Updater { class UpdaterSongPress extends Updater {
public UpdaterSongPress() { public UpdaterSongPress() {
super(521); super(521);
TAG = this.getClass().getSimpleName(); TAG = this.getClass().getSimpleName();
@ -33,7 +33,7 @@ public class UpdaterSongPress extends Updater {
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) {
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

@ -18,42 +18,36 @@
*/ */
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import org.xmlpull.v1.XmlPullParserException;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.util.Log; import android.util.Log;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.view.ErrorDialog; import net.nullsum.audinaut.view.ErrorDialog;
import org.xmlpull.v1.XmlPullParserException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
*/ */
public abstract class BackgroundTask<T> implements ProgressListener { public abstract class BackgroundTask<T> implements ProgressListener {
static final BlockingQueue<BackgroundTask.Task> queue = new LinkedBlockingQueue<>(10);
private static final String TAG = BackgroundTask.class.getSimpleName(); private static final String TAG = BackgroundTask.class.getSimpleName();
private final Context context;
protected AtomicBoolean cancelled = new AtomicBoolean(false);
protected OnCancelListener cancelListener;
protected Runnable onCompletionListener = null;
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);
private static Handler handler = null; private static Handler handler = null;
static { static {
try { try {
handler = new Handler(Looper.getMainLooper()); handler = new Handler(Looper.getMainLooper());
@ -62,7 +56,12 @@ public abstract class BackgroundTask<T> implements ProgressListener {
} }
} }
public BackgroundTask(Context context) { final AtomicBoolean cancelled = new AtomicBoolean(false);
private final Context context;
private final Runnable onCompletionListener = null;
Task task;
BackgroundTask(Context context) {
this.context = context; this.context = context;
if (threads.size() < DEFAULT_CONCURRENCY) { if (threads.size() < DEFAULT_CONCURRENCY) {
@ -81,22 +80,11 @@ public abstract class BackgroundTask<T> implements ProgressListener {
} }
} }
public static void stopThreads() { private Activity getActivity() {
for(Thread thread: threads) {
thread.interrupt();
}
threads.clear();
queue.clear();
}
protected Activity getActivity() {
return (context instanceof Activity) ? ((Activity) context) : null; return (context instanceof Activity) ? ((Activity) context) : null;
} }
protected Context getContext() { Handler getHandler() {
return context;
}
protected Handler getHandler() {
return handler; return handler;
} }
@ -142,37 +130,25 @@ public abstract class BackgroundTask<T> implements ProgressListener {
public void cancel() { public void cancel() {
if (cancelled.compareAndSet(false, true)) { if (cancelled.compareAndSet(false, true)) {
if (isRunning()) { if (isRunning()) {
if(cancelListener != null) {
cancelListener.onCancel();
} 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) {
cancelListener = listener;
}
public boolean isRunning() { public boolean isRunning() {
if(task == null) { return task != null && task.isRunning();
return false;
} else {
return task.isRunning();
}
} }
@Override @Override
public abstract void updateProgress(final String message); public abstract void updateProgress(final String message);
@Override public void updateProgress() {
public void updateProgress(int messageId) { updateProgress(context.getResources().getString(R.string.settings_testing_connection));
updateProgress(context.getResources().getString(messageId));
} }
@Override @Override
@ -180,13 +156,9 @@ public abstract class BackgroundTask<T> implements ProgressListener {
} }
public void setOnCompletionListener(Runnable onCompletionListener) { class Task {
this.onCompletionListener = onCompletionListener; private final AtomicBoolean taskStart = new AtomicBoolean(false);
}
protected class Task {
private Thread thread; private Thread thread;
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
@ -205,9 +177,7 @@ public abstract class BackgroundTask<T> implements ProgressListener {
} }
if (handler != null) { if (handler != null) {
handler.post(new Runnable() { handler.post(() -> {
@Override
public void run() {
if (!isCancelled()) { if (!isCancelled()) {
try { try {
onDone(result); onDone(result);
@ -223,7 +193,6 @@ public abstract class BackgroundTask<T> implements ProgressListener {
} }
taskStart.set(false); taskStart.set(false);
}
}); });
} else { } else {
taskStart.set(false); taskStart.set(false);
@ -240,9 +209,7 @@ public abstract class BackgroundTask<T> implements ProgressListener {
} }
if (handler != null) { if (handler != null) {
handler.post(new Runnable() { handler.post(() -> {
@Override
public void run() {
if (!isCancelled()) { if (!isCancelled()) {
try { try {
onError(t); onError(t);
@ -252,7 +219,6 @@ public abstract class BackgroundTask<T> implements ProgressListener {
} }
taskStart.set(false); taskStart.set(false);
}
}); });
} else { } else {
taskStart.set(false); taskStart.set(false);
@ -269,15 +235,11 @@ public abstract class BackgroundTask<T> implements ProgressListener {
} }
} }
} }
public boolean isCancelled() { public boolean isCancelled() {
if(Thread.interrupted()) { return Thread.interrupted() || BackgroundTask.this.isCancelled();
return true;
} else if(BackgroundTask.this.isCancelled()) {
return true;
} else {
return false;
}
} }
public void onDone(T result) { public void onDone(T result) {
done(result); done(result);
@ -285,6 +247,7 @@ public abstract class BackgroundTask<T> implements ProgressListener {
onCompletionListener.run(); onCompletionListener.run();
} }
} }
public void onError(Throwable t) { public void onError(Throwable t) {
error(t); error(t);
} }
@ -318,8 +281,4 @@ public abstract class BackgroundTask<T> implements ProgressListener {
} }
} }
} }
public static interface OnCancelListener {
void onCancel();
}
} }

View File

@ -19,10 +19,16 @@ 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

@ -18,17 +18,8 @@ package net.nullsum.audinaut.util;
import java.io.File; import java.io.File;
import java.net.Socket; import java.net.Socket;
import android.content.Context;
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 BufferFile progress;
protected BufferFile progress;
public BufferProxy(Context context) {
super(context);
}
protected ProxyTask getTask(Socket client) { protected ProxyTask getTask(Socket client) {
return new BufferFileTask(client); return new BufferFileTask(client);
@ -56,6 +47,7 @@ public class BufferProxy extends FileProxy {
} }
return contentLength; return contentLength;
} }
@Override @Override
long getFileSize() { long getFileSize() {
return progress.getEstimatedSize(); return progress.getEstimatedSize();
@ -65,10 +57,12 @@ public class BufferProxy extends FileProxy {
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();

View File

@ -1,22 +1,21 @@
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import android.content.Context; import android.content.Context;
import android.util.Log;
import android.os.StatFs; import android.os.StatFs;
import android.util.Log;
import net.nullsum.audinaut.domain.Playlist; import net.nullsum.audinaut.domain.Playlist;
import net.nullsum.audinaut.service.DownloadFile; import net.nullsum.audinaut.service.DownloadFile;
import net.nullsum.audinaut.service.DownloadService; import net.nullsum.audinaut.service.DownloadService;
import net.nullsum.audinaut.service.MediaStoreService; import net.nullsum.audinaut.service.MediaStoreService;
import java.util.*; import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
@ -41,9 +40,11 @@ public class CacheCleaner {
public void clean() { public void clean() {
new BackgroundCleanup(context).execute(); new BackgroundCleanup(context).execute();
} }
public void cleanSpace() { public void cleanSpace() {
new BackgroundSpaceCleanup(context).execute(); new BackgroundSpaceCleanup(context).execute();
} }
public void cleanPlaylists(List<Playlist> playlists) { public void cleanPlaylists(List<Playlist> playlists) {
new BackgroundPlaylistsCleanup(context, playlists).execute(); new BackgroundPlaylistsCleanup(context, playlists).execute();
} }
@ -75,8 +76,8 @@ public class CacheCleaner {
// 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 = stat.getBlockCountLong() * stat.getBlockSizeLong();
long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize(); long bytesAvailableFs = stat.getAvailableBlocksLong() * stat.getBlockSizeLong();
long bytesUsedFs = bytesTotalFs - bytesAvailableFs; long bytesUsedFs = bytesTotalFs - bytesAvailableFs;
long minFsAvailability = bytesTotalFs - MIN_FREE_SPACE; long minFsAvailability = bytesTotalFs - MIN_FREE_SPACE;
@ -134,9 +135,7 @@ public class CacheCleaner {
} }
private void sortByAscendingModificationTime(List<File> files) { private void sortByAscendingModificationTime(List<File> files) {
Collections.sort(files, new Comparator<File>() { Collections.sort(files, (a, b) -> {
@Override
public int compare(File a, File b) {
if (a.lastModified() < b.lastModified()) { if (a.lastModified() < b.lastModified()) {
return -1; return -1;
} }
@ -144,12 +143,11 @@ public class CacheCleaner {
return 1; return 1;
} }
return 0; return 0;
}
}); });
} }
private Set<File> findUndeletableFiles() { private Set<File> findUndeletableFiles() {
Set<File> undeletable = new HashSet<File>(5); Set<File> undeletable = new HashSet<>(5);
for (DownloadFile downloadFile : downloadService.getDownloads()) { for (DownloadFile downloadFile : downloadService.getDownloads()) {
undeletable.add(downloadFile.getPartialFile()); undeletable.add(downloadFile.getPartialFile());
@ -163,7 +161,7 @@ public class CacheCleaner {
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<>();
long bytesUsed = 0L; long bytesUsed = 0L;
for (File file : dir.listFiles()) { for (File file : dir.listFiles()) {
if (file.isFile()) { if (file.isFile()) {
@ -208,9 +206,9 @@ public class CacheCleaner {
} }
try { try {
List<File> files = new ArrayList<File>(); List<File> files = new ArrayList<>();
List<File> pinned = new ArrayList<File>(); List<File> pinned = new ArrayList<>();
List<File> dirs = new ArrayList<File>(); List<File> dirs = new ArrayList<>();
findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, pinned, dirs); findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, pinned, dirs);
sortByAscendingModificationTime(files); sortByAscendingModificationTime(files);
@ -243,9 +241,9 @@ public class CacheCleaner {
} }
try { try {
List<File> files = new ArrayList<File>(); List<File> files = new ArrayList<>();
List<File> pinned = new ArrayList<File>(); List<File> pinned = new ArrayList<>();
List<File> dirs = new ArrayList<File>(); List<File> dirs = new ArrayList<>();
findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, pinned, dirs); findCandidatesForDeletion(FileUtil.getMusicDirectory(context), files, pinned, dirs);
long bytesToDelete = getMinimumDelete(files, pinned); long bytesToDelete = getMinimumDelete(files, pinned);

View File

@ -37,7 +37,6 @@ public final class Constants {
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_AUTOPLAY = "subsonic.playall"; public static final String INTENT_EXTRA_NAME_AUTOPLAY = "subsonic.playall";
public static final String INTENT_EXTRA_NAME_QUERY = "subsonic.query"; public static final String INTENT_EXTRA_NAME_QUERY = "subsonic.query";
public static final String INTENT_EXTRA_NAME_PLAYLIST_ID = "subsonic.playlist.id"; public static final String INTENT_EXTRA_NAME_PLAYLIST_ID = "subsonic.playlist.id";
@ -48,18 +47,14 @@ public final class Constants {
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_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_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_ENTRY = "passedEntry";
// Preferences keys. // Preferences keys.
public static final String PREFERENCES_KEY_SERVER_KEY = "server"; public static final String PREFERENCES_KEY_SERVER_KEY = "server";
@ -76,7 +71,6 @@ public final class Constants {
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_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";
@ -98,7 +92,6 @@ public final class Constants {
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_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";
@ -106,7 +99,6 @@ public final class Constants {
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_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";
@ -115,8 +107,6 @@ public final class Constants {
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_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";
@ -134,12 +124,6 @@ public final class Constants {
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 OFFLINE_STAR_COUNT = "starCount";
public static final String OFFLINE_STAR_ID = "starID";
public static final String OFFLINE_STAR_SEARCH = "starTitle";
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";
@ -152,21 +136,17 @@ public final class Constants {
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_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_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 TASKER_EXTRA_BUNDLE = "com.twofortyfouram.locale.intent.extra.BUNDLE"; public static final String TASKER_EXTRA_BUNDLE = "com.twofortyfouram.locale.intent.extra.BUNDLE";

View File

@ -2,10 +2,6 @@ package net.nullsum.audinaut.util;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper; import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.Log;
import java.util.ArrayDeque;
import java.util.Deque;
import net.nullsum.audinaut.adapter.SectionAdapter; import net.nullsum.audinaut.adapter.SectionAdapter;
import net.nullsum.audinaut.fragments.SubsonicFragment; import net.nullsum.audinaut.fragments.SubsonicFragment;
@ -14,14 +10,15 @@ import net.nullsum.audinaut.service.DownloadService;
import net.nullsum.audinaut.view.SongView; import net.nullsum.audinaut.view.SongView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import java.util.ArrayDeque;
import java.util.Deque;
public class DownloadFileItemHelperCallback extends ItemTouchHelper.SimpleCallback { public class DownloadFileItemHelperCallback extends ItemTouchHelper.SimpleCallback {
private static final String TAG = DownloadFileItemHelperCallback.class.getSimpleName();
private SubsonicFragment fragment;
private boolean mainList;
private final SubsonicFragment fragment;
private final boolean mainList;
private final Deque pendingOperations = new ArrayDeque();
private BackgroundTask pendingTask = null; private BackgroundTask pendingTask = null;
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);
@ -54,10 +51,11 @@ public class DownloadFileItemHelperCallback extends ItemTouchHelper.SimpleCallba
} }
} }
public DownloadService getDownloadService() { private DownloadService getDownloadService() {
return fragment.getDownloadService(); return fragment.getDownloadService();
} }
public SectionAdapter getSectionAdapter() {
private SectionAdapter getSectionAdapter() {
return fragment.getCurrentAdapter(); return fragment.getCurrentAdapter();
} }

View File

@ -21,45 +21,43 @@ import android.content.res.TypedArray;
import android.graphics.PorterDuff; import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.support.annotation.AttrRes; import android.support.annotation.AttrRes;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes; import android.support.annotation.DrawableRes;
import android.util.TypedValue; import android.util.TypedValue;
import net.nullsum.audinaut.R;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.WeakHashMap; import java.util.WeakHashMap;
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) {
return getTintedDrawable(context, drawableRes, R.attr.colorAccent); if (tintedDrawables.containsKey(R.drawable.ic_toggle_played)) {
} return tintedDrawables.get(R.drawable.ic_toggle_played);
public static Drawable getTintedDrawable(Context context, @DrawableRes int drawableRes, @AttrRes int colorAttr) {
if(tintedDrawables.containsKey(drawableRes)) {
return tintedDrawables.get(drawableRes);
} }
int color = getColorRes(context, colorAttr); int color = getColorRes(context, R.attr.colorAccent);
Drawable background = context.getResources().getDrawable(drawableRes); Drawable background = context.getResources().getDrawable(R.drawable.ic_toggle_played);
background.setColorFilter(color, PorterDuff.Mode.SRC_IN); background.setColorFilter(color, PorterDuff.Mode.SRC_IN);
tintedDrawables.put(drawableRes, background); tintedDrawables.put(R.drawable.ic_toggle_played, background);
return background; return background;
} }
public static Drawable getTintedDrawableFromColor(Context context, @DrawableRes int drawableRes, @ColorRes int colorRes) {
if(tintedDrawables.containsKey(drawableRes)) {
return tintedDrawables.get(drawableRes);
}
int color = context.getResources().getColor(colorRes); public static Drawable getTintedDrawableFromColor(Context context) {
Drawable background = context.getResources().getDrawable(drawableRes); if (tintedDrawables.containsKey(R.drawable.abc_spinner_mtrl_am_alpha)) {
return tintedDrawables.get(R.drawable.abc_spinner_mtrl_am_alpha);
}
int color = context.getResources().getColor(android.R.color.white);
Drawable background = context.getResources().getDrawable(R.drawable.abc_spinner_mtrl_am_alpha);
background.setColorFilter(color, PorterDuff.Mode.SRC_IN); background.setColorFilter(color, PorterDuff.Mode.SRC_IN);
tintedDrawables.put(drawableRes, background); tintedDrawables.put(R.drawable.abc_spinner_mtrl_am_alpha, 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)) {
@ -74,6 +72,7 @@ public class DrawableTint {
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);
@ -86,14 +85,6 @@ public class DrawableTint {
return drawableRes; return drawableRes;
} }
} }
public static Drawable getTintedAttrDrawable(Context context, @AttrRes int drawableAttr, @AttrRes int colorAttr) {
if(tintedDrawables.containsKey(drawableAttr)) {
return getTintedDrawable(context, attrMap.get(drawableAttr), colorAttr);
}
@DrawableRes int drawableRes = getDrawableRes(context, drawableAttr);
return getTintedDrawable(context, drawableRes, colorAttr);
}
public static void wipeTintCache() { public static void wipeTintCache() {
attrMap.clear(); attrMap.clear();

View File

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

View File

@ -15,6 +15,8 @@
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
import android.util.Log;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -23,18 +25,9 @@ import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException; import java.net.SocketException;
import android.content.Context;
import android.util.Log;
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) {
super(context);
}
protected ProxyTask getTask(Socket client) { protected ProxyTask getTask(Socket client) {
return new StreamFileTask(client); return new StreamFileTask(client);
} }
@ -60,11 +53,7 @@ public class FileProxy extends ServerProxy {
} }
// 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()) { return !(cbSkip != 0 && cbSkip >= file.length());
return false;
}
return true;
} }
File getFile(String path) { File getFile(String path) {
@ -74,6 +63,7 @@ public class FileProxy extends ServerProxy {
Long getContentLength() { Long getContentLength() {
return file.length(); return file.length();
} }
long getFileSize() { long getFileSize() {
return file.length(); return file.length();
} }
@ -178,14 +168,12 @@ public class FileProxy extends ServerProxy {
// 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());
} }
@ -196,8 +184,7 @@ public class FileProxy extends ServerProxy {
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());
} }
@ -206,12 +193,15 @@ public class FileProxy extends ServerProxy {
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();
} }

View File

@ -18,6 +18,26 @@
*/ */
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Environment;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import net.nullsum.audinaut.domain.Artist;
import net.nullsum.audinaut.domain.Genre;
import net.nullsum.audinaut.domain.Indexes;
import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.MusicFolder;
import net.nullsum.audinaut.domain.Playlist;
import net.nullsum.audinaut.service.MediaStoreService;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -28,34 +48,16 @@ import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.io.Serializable; import java.io.Serializable;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.zip.DeflaterOutputStream; import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream; import java.util.zip.InflaterInputStream;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Environment;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import net.nullsum.audinaut.domain.Artist;
import net.nullsum.audinaut.domain.Genre;
import net.nullsum.audinaut.domain.Indexes;
import net.nullsum.audinaut.domain.Playlist;
import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.MusicFolder;
import net.nullsum.audinaut.service.MediaStoreService;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
/** /**
* @author Sindre Mehus * @author Sindre Mehus
*/ */
@ -65,10 +67,10 @@ public class FileUtil {
private static final String[] FILE_SYSTEM_UNSAFE = {"/", "\\", "..", ":", "\"", "?", "*", "<", ">", "|"}; private static final String[] FILE_SYSTEM_UNSAFE = {"/", "\\", "..", ":", "\"", "?", "*", "<", ">", "|"};
private static final String[] FILE_SYSTEM_UNSAFE_DIR = {"\\", "..", ":", "\"", "?", "*", "<", ">", "|"}; private static final String[] FILE_SYSTEM_UNSAFE_DIR = {"\\", "..", ":", "\"", "?", "*", "<", ">", "|"};
private static final List<String> MUSIC_FILE_EXTENSIONS = Arrays.asList("mp3", "ogg", "aac", "flac", "m4a", "wav", "wma"); private static final List<String> MUSIC_FILE_EXTENSIONS = Arrays.asList("mp3", "ogg", "aac", "flac", "m4a", "wav", "wma");
private static final List<String> PLAYLIST_FILE_EXTENSIONS = Arrays.asList("m3u"); private static final List<String> PLAYLIST_FILE_EXTENSIONS = Collections.singletonList("m3u");
private static final int MAX_FILENAME_LENGTH = 254 - ".complete.mp3".length(); private static final int MAX_FILENAME_LENGTH = 254 - ".complete.mp3".length();
private static File DEFAULT_MUSIC_DIR;
private static final Kryo kryo = new Kryo(); private static final Kryo kryo = new Kryo();
private static File DEFAULT_MUSIC_DIR;
private static HashMap<String, MusicDirectory.Entry> entryLookup; private static HashMap<String, MusicDirectory.Entry> entryLookup;
static { static {
@ -80,25 +82,6 @@ public class FileUtil {
kryo.register(Genre.class); kryo.register(Genre.class);
} }
public static File getAnySong(Context context) {
File dir = getMusicDirectory(context);
return getAnySong(context, dir);
}
private static File getAnySong(Context context, File dir) {
for(File file: dir.listFiles()) {
if(file.isDirectory()) {
return getAnySong(context, file);
}
String extension = getExtension(file.getName());
if(MUSIC_FILE_EXTENSIONS.contains(extension)) {
return file;
}
}
return null;
}
public static File getEntryFile(Context context, MusicDirectory.Entry entry) { public static File getEntryFile(Context context, MusicDirectory.Entry entry) {
if (entry.isDirectory()) { if (entry.isDirectory()) {
return getAlbumDirectory(context, entry); return getAlbumDirectory(context, entry);
@ -138,6 +121,7 @@ public class FileUtil {
File playlistDir = getPlaylistDirectory(context, server); File playlistDir = getPlaylistDirectory(context, server);
return new File(playlistDir, fileSystemSafe(name) + ".m3u"); return new File(playlistDir, fileSystemSafe(name) + ".m3u");
} }
public static void writePlaylistFile(Context context, File file, MusicDirectory playlist) throws IOException { public static void writePlaylistFile(Context context, File file, MusicDirectory playlist) throws IOException {
FileWriter fw = new FileWriter(file); FileWriter fw = new FileWriter(file);
BufferedWriter bw = new BufferedWriter(fw); BufferedWriter bw = new BufferedWriter(fw);
@ -159,11 +143,13 @@ public class FileUtil {
fw.close(); fw.close();
} }
} }
public static File getPlaylistDirectory(Context context) { public static File getPlaylistDirectory(Context context) {
File playlistDir = new File(getSubsonicDirectory(context), "playlists"); File playlistDir = new File(getSubsonicDirectory(context), "playlists");
ensureDirectoryExistsAndIsReadWritable(playlistDir); ensureDirectoryExistsAndIsReadWritable(playlistDir);
return playlistDir; return playlistDir;
} }
public static File getPlaylistDirectory(Context context, String server) { public static File getPlaylistDirectory(Context context, String server) {
File playlistDir = new File(getPlaylistDirectory(context), server); File playlistDir = new File(getPlaylistDirectory(context), server);
ensureDirectoryExistsAndIsReadWritable(playlistDir); ensureDirectoryExistsAndIsReadWritable(playlistDir);
@ -171,7 +157,7 @@ public class FileUtil {
} }
public static File getAlbumArtFile(Context context, MusicDirectory.Entry entry) { public static File getAlbumArtFile(Context context, MusicDirectory.Entry entry) {
if(entry.getId().indexOf(ImageLoader.PLAYLIST_PREFIX) != -1) { if (entry.getId().contains(ImageLoader.PLAYLIST_PREFIX)) {
File dir = getAlbumArtDirectory(context); File dir = getAlbumArtDirectory(context);
return new File(dir, Util.md5Hex(ImageLoader.PLAYLIST_PREFIX + entry.getTitle()) + ".jpeg"); return new File(dir, Util.md5Hex(ImageLoader.PLAYLIST_PREFIX + entry.getTitle()) + ".jpeg");
} else { } else {
@ -191,10 +177,11 @@ public class FileUtil {
} }
} }
public static File getAlbumArtFile(File albumDir) { private static File getAlbumArtFile(File albumDir) {
return new File(albumDir, Constants.ALBUM_ART_FILE); return new File(albumDir, Constants.ALBUM_ART_FILE);
} }
public static File getHexAlbumArtFile(Context context, File albumDir) {
private static File getHexAlbumArtFile(Context context, File albumDir) {
return new File(getAlbumArtDirectory(context), Util.md5Hex(albumDir.getPath()) + ".jpeg"); return new File(getAlbumArtDirectory(context), Util.md5Hex(albumDir.getPath()) + ".jpeg");
} }
@ -214,25 +201,7 @@ public class FileUtil {
return null; return null;
} }
public static File getMiscDirectory(Context context) {
File dir = new File(getSubsonicDirectory(context), "misc");
ensureDirectoryExistsAndIsReadWritable(dir);
ensureDirectoryExistsAndIsReadWritable(new File(dir, ".nomedia"));
return dir;
}
public static File getMiscFile(Context context, String url) {
return new File(getMiscDirectory(context), Util.md5Hex(url) + ".jpeg");
}
public static Bitmap getMiscBitmap(Context context, String url, int size) {
return null;
}
public static Bitmap getSampledBitmap(byte[] bytes, int size) { public static Bitmap getSampledBitmap(byte[] bytes, int size) {
return getSampledBitmap(bytes, size, true);
}
public static Bitmap getSampledBitmap(byte[] bytes, int size, boolean allowUnscaled) {
final BitmapFactory.Options opt = new BitmapFactory.Options(); final BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inJustDecodeBounds = true; opt.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt); BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opt);
@ -243,16 +212,14 @@ public class FileUtil {
if (bitmap == null) { if (bitmap == null) {
return null; return null;
} else { } else {
return getScaledBitmap(bitmap, size, allowUnscaled); return getScaledBitmap(bitmap, size);
} }
} }
public static Bitmap getScaledBitmap(Bitmap bitmap, int size) {
return getScaledBitmap(bitmap, size, true); private static Bitmap getScaledBitmap(Bitmap bitmap, int size) {
}
public static Bitmap getScaledBitmap(Bitmap bitmap, int size, boolean allowUnscaled) {
// Don't waste time scaling if the difference is minor // Don't waste time scaling if the difference is minor
// Large album arts still need to be scaled since displayed as is on now playing! // Large album arts still need to be scaled since displayed as is on now playing!
if(allowUnscaled && size < 400 && bitmap.getWidth() < (size * 1.1)) { if (size < 400 && bitmap.getWidth() < (size * 1.1)) {
return bitmap; return bitmap;
} else { } else {
return Bitmap.createScaledBitmap(bitmap, size, Util.getScaledHeight(bitmap, size), true); return Bitmap.createScaledBitmap(bitmap, size, Util.getScaledHeight(bitmap, size), true);
@ -267,12 +234,11 @@ public class FileUtil {
} }
public static File getArtistDirectory(Context context, Artist artist) { public static File getArtistDirectory(Context context, Artist artist) {
File dir = new File(getMusicDirectory(context).getPath() + "/" + fileSystemSafe(artist.getName())); return new File(getMusicDirectory(context).getPath() + "/" + fileSystemSafe(artist.getName()));
return dir;
} }
public static File getArtistDirectory(Context context, MusicDirectory.Entry artist) { public static File getArtistDirectory(Context context, MusicDirectory.Entry artist) {
File dir = new File(getMusicDirectory(context).getPath() + "/" + fileSystemSafe(artist.getTitle())); return new File(getMusicDirectory(context).getPath() + "/" + fileSystemSafe(artist.getTitle()));
return dir;
} }
public static File getAlbumDirectory(Context context, MusicDirectory.Entry entry) { public static File getAlbumDirectory(Context context, MusicDirectory.Entry entry) {
@ -310,13 +276,13 @@ public class FileUtil {
public static MusicDirectory.Entry lookupChild(Context context, MusicDirectory.Entry entry, boolean allowDir) { public static MusicDirectory.Entry lookupChild(Context context, MusicDirectory.Entry entry, boolean allowDir) {
// Initialize lookupMap if first time called // Initialize lookupMap if first time called
String lookupName = Util.getCacheName(context, "entryLookup"); String lookupName = Util.getCacheName(context);
if (entryLookup == null) { if (entryLookup == null) {
entryLookup = deserialize(context, lookupName, HashMap.class); entryLookup = deserialize(context, lookupName, HashMap.class);
// Create it if // Create it if
if (entryLookup == null) { if (entryLookup == null) {
entryLookup = new HashMap<String, MusicDirectory.Entry>(); entryLookup = new HashMap<>();
} }
} }
@ -328,7 +294,7 @@ public class FileUtil {
// Do a special lookup since 4.7+ doesn't match artist/album to entry.getPath // Do a special lookup since 4.7+ doesn't match artist/album to entry.getPath
String s = Util.getRestUrl(context, null, false) + entry.getId(); String s = Util.getRestUrl(context, null, false) + entry.getId();
String cacheName = (Util.isTagBrowsing(context) ? "album-" : "directory-") + s.hashCode() + ".ser"; String cacheName = "album-" + s.hashCode() + ".ser";
MusicDirectory entryDir = FileUtil.deserialize(context, cacheName, MusicDirectory.class); MusicDirectory entryDir = FileUtil.deserialize(context, cacheName, MusicDirectory.class);
if (entryDir != null) { if (entryDir != null) {
@ -353,14 +319,6 @@ public class FileUtil {
} }
} }
private static File createDirectory(Context context, String name) {
File dir = new File(getSubsonicDirectory(context), name);
if (!dir.exists() && !dir.mkdirs()) {
Log.e(TAG, "Failed to create " + name);
}
return dir;
}
public static File getSubsonicDirectory(Context context) { public static File getSubsonicDirectory(Context context) {
return context.getExternalFilesDir(null); return context.getExternalFilesDir(null);
} }
@ -395,13 +353,14 @@ public class FileUtil {
return DEFAULT_MUSIC_DIR; return DEFAULT_MUSIC_DIR;
} }
private static File getBestDir(File[] dirs) { private static File getBestDir(File[] dirs) {
// Past 5.0 we can query directly for SD Card // Past 5.0 we can query directly for SD Card
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
for(int i = 0; i < dirs.length; i++) { for (File dir : dirs) {
try { try {
if (dirs[i] != null && Environment.isExternalStorageRemovable(dirs[i])) { if (dir != null && Environment.isExternalStorageRemovable(dir)) {
return dirs[i]; return dir;
} }
} catch (Exception e) { } catch (Exception e) {
Log.e(TAG, "Failed to check if is external", e); Log.e(TAG, "Failed to check if is external", e);
@ -425,25 +384,30 @@ public class FileUtil {
File dir = new File(path); File dir = new File(path);
return ensureDirectoryExistsAndIsReadWritable(dir) ? dir : getDefaultMusicDirectory(context); return ensureDirectoryExistsAndIsReadWritable(dir) ? dir : getDefaultMusicDirectory(context);
} }
public static boolean deleteMusicDirectory(Context context) {
public static void deleteMusicDirectory(Context context) {
File musicDirectory = FileUtil.getMusicDirectory(context); File musicDirectory = FileUtil.getMusicDirectory(context);
MediaStoreService mediaStore = new MediaStoreService(context); MediaStoreService mediaStore = new MediaStoreService(context);
return recursiveDelete(musicDirectory, mediaStore); recursiveDelete(musicDirectory, mediaStore);
} }
public static void deleteSerializedCache(Context context) { public static void deleteSerializedCache(Context context) {
for (File file : context.getCacheDir().listFiles()) { for (File file : context.getCacheDir().listFiles()) {
if(file.getName().indexOf(".ser") != -1) { if (file.getName().contains(".ser")) {
file.delete(); file.delete();
} }
} }
} }
public static boolean deleteArtworkCache(Context context) {
public static void deleteArtworkCache(Context context) {
File artDirectory = FileUtil.getAlbumArtDirectory(context); File artDirectory = FileUtil.getAlbumArtDirectory(context);
return recursiveDelete(artDirectory); recursiveDelete(artDirectory);
} }
public static boolean recursiveDelete(File dir) {
return recursiveDelete(dir, null); private static void recursiveDelete(File dir) {
recursiveDelete(dir, null);
} }
public static boolean recursiveDelete(File dir, MediaStoreService mediaStore) { public static boolean recursiveDelete(File dir, MediaStoreService mediaStore) {
if (dir != null && dir.exists()) { if (dir != null && dir.exists()) {
File[] list = dir.listFiles(); File[] list = dir.listFiles();
@ -489,28 +453,7 @@ public class FileUtil {
} }
} }
public static void unpinSong(Context context, File saveFile) { private static boolean ensureDirectoryExistsAndIsReadWritable(File dir) {
// Don't try to unpin a song which isn't actually pinned
if(saveFile.getName().contains(".complete")) {
return;
}
// Unpin file, rename to .complete
File completeFile = new File(saveFile.getParent(), FileUtil.getBaseName(saveFile.getName()) +
".complete." + FileUtil.getExtension(saveFile.getName()));
if(!saveFile.renameTo(completeFile)) {
Log.w(TAG, "Failed to upin " + saveFile + " to " + completeFile);
} else {
try {
new MediaStoreService(context).renameInMediaStore(completeFile, saveFile);
} catch(Exception e) {
Log.w(TAG, "Failed to write to media store");
}
}
}
public static boolean ensureDirectoryExistsAndIsReadWritable(File dir) {
if (dir == null) { if (dir == null) {
return false; return false;
} }
@ -540,6 +483,7 @@ public class FileUtil {
} }
return true; return true;
} }
public static boolean verifyCanWrite(File dir) { public static boolean verifyCanWrite(File dir) {
if (ensureDirectoryExistsAndIsReadWritable(dir)) { if (ensureDirectoryExistsAndIsReadWritable(dir)) {
try { try {
@ -618,10 +562,10 @@ public class FileUtil {
File[] files = dir.listFiles(); File[] files = dir.listFiles();
if (files == null) { if (files == null) {
Log.w(TAG, "Failed to list children for " + dir.getPath()); Log.w(TAG, "Failed to list children for " + dir.getPath());
return new TreeSet<File>(); return new TreeSet<>();
} }
return new TreeSet<File>(Arrays.asList(files)); return new TreeSet<>(Arrays.asList(files));
} }
public static SortedSet<File> listMediaFiles(File dir) { public static SortedSet<File> listMediaFiles(File dir) {
@ -641,11 +585,6 @@ public class FileUtil {
return MUSIC_FILE_EXTENSIONS.contains(extension); return MUSIC_FILE_EXTENSIONS.contains(extension);
} }
public static boolean isMusicFile(File file) {
String extension = getExtension(file.getName());
return MUSIC_FILE_EXTENSIONS.contains(extension);
}
public static boolean isPlaylistFile(File file) { public static boolean isPlaylistFile(File file) {
String extension = getExtension(file.getName()); String extension = getExtension(file.getName());
return PLAYLIST_FILE_EXTENSIONS.contains(extension); return PLAYLIST_FILE_EXTENSIONS.contains(extension);
@ -675,32 +614,7 @@ public class FileUtil {
return index == -1 ? name : name.substring(0, index); return index == -1 ? name : name.substring(0, index);
} }
public static Long[] getUsedSize(Context context, File file) { public static <T extends Serializable> void serialize(Context context, T obj, String fileName) {
long number = 0L;
long permanent = 0L;
long size = 0L;
if(file.isFile()) {
if(isMediaFile(file)) {
if(file.getAbsolutePath().indexOf(".complete") == -1) {
permanent++;
}
return new Long[] {1L, permanent, file.length()};
} else {
return new Long[] {0L, 0L, 0L};
}
} else {
for (File child : FileUtil.listFiles(file)) {
Long[] pair = getUsedSize(context, child);
number += pair[0];
permanent += pair[1];
size += pair[2];
}
return new Long[] {number, permanent, size};
}
}
public static <T extends Serializable> boolean serialize(Context context, T obj, String fileName) {
Output out = null; Output out = null;
try { try {
RandomAccessFile file = new RandomAccessFile(context.getCacheDir() + "/" + fileName, "rw"); RandomAccessFile file = new RandomAccessFile(context.getCacheDir() + "/" + fileName, "rw");
@ -708,20 +622,14 @@ public class FileUtil {
synchronized (kryo) { synchronized (kryo) {
kryo.writeObject(out, obj); kryo.writeObject(out, obj);
} }
return true;
} catch (Throwable x) { } catch (Throwable x) {
Log.w(TAG, "Failed to serialize object to " + fileName); Log.w(TAG, "Failed to serialize object to " + fileName);
return false;
} finally { } finally {
Util.close(out); Util.close(out);
} }
} }
public static <T extends Serializable> T deserialize(Context context, String fileName, Class<T> tClass) { public static <T extends Serializable> T deserialize(Context context, String fileName, Class<T> tClass) {
return deserialize(context, fileName, tClass, 0);
}
public static <T extends Serializable> T deserialize(Context context, String fileName, Class<T> tClass, int hoursOld) {
Input in = null; Input in = null;
try { try {
File file = new File(context.getCacheDir(), fileName); File file = new File(context.getCacheDir(), fileName);
@ -729,11 +637,11 @@ public class FileUtil {
return null; return null;
} }
if(hoursOld != 0) { if (0 != 0) {
Date fileDate = new Date(file.lastModified()); Date fileDate = new Date(file.lastModified());
// Convert into hours // Convert into hours
long age = (new Date().getTime() - fileDate.getTime()) / 1000 / 3600; long age = (new Date().getTime() - fileDate.getTime()) / 1000 / 3600;
if(age > hoursOld) { if (age > 0) {
return null; return null;
} }
} }
@ -742,8 +650,7 @@ public class FileUtil {
in = new Input(new FileInputStream(randomFile.getFD())); in = new Input(new FileInputStream(randomFile.getFD()));
synchronized (kryo) { synchronized (kryo) {
T result = kryo.readObject(in, tClass); return kryo.readObject(in, tClass);
return result;
} }
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
// Different error message // Different error message
@ -757,7 +664,7 @@ public class FileUtil {
} }
} }
public static <T extends Serializable> boolean serializeCompressed(Context context, T obj, String fileName) { public static <T extends Serializable> void serializeCompressed(Context context, T obj, String fileName) {
Output out = null; Output out = null;
try { try {
RandomAccessFile file = new RandomAccessFile(context.getCacheDir() + "/" + fileName, "rw"); RandomAccessFile file = new RandomAccessFile(context.getCacheDir() + "/" + fileName, "rw");
@ -765,10 +672,8 @@ public class FileUtil {
synchronized (kryo) { synchronized (kryo) {
kryo.writeObject(out, obj); kryo.writeObject(out, obj);
} }
return true;
} catch (Throwable x) { } catch (Throwable x) {
Log.w(TAG, "Failed to serialize compressed object to " + fileName); Log.w(TAG, "Failed to serialize compressed object to " + fileName);
return false;
} finally { } finally {
Util.close(out); Util.close(out);
} }
@ -781,8 +686,7 @@ public class FileUtil {
in = new Input(new InflaterInputStream(new FileInputStream(file.getFD()))); in = new Input(new InflaterInputStream(new FileInputStream(file.getFD())));
synchronized (kryo) { synchronized (kryo) {
T result = kryo.readObject(in, tClass); return kryo.readObject(in, tClass);
return result;
} }
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
// Different error message // Different error message

View File

@ -28,18 +28,15 @@ import android.graphics.Shader;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable; import android.graphics.drawable.TransitionDrawable;
import android.os.Build;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.support.v4.util.LruCache;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
import android.support.v4.util.LruCache;
import android.view.View; import android.view.View;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import java.lang.ref.WeakReference;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.domain.MusicDirectory; import net.nullsum.audinaut.domain.MusicDirectory;
import net.nullsum.audinaut.domain.Playlist; import net.nullsum.audinaut.domain.Playlist;
@ -54,20 +51,18 @@ 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();
public static final String PLAYLIST_PREFIX = "pl-"; public static final String PLAYLIST_PREFIX = "pl-";
private static final String TAG = ImageLoader.class.getSimpleName();
private Context context; private final static int[] COLORS = {0xFF33B5E5, 0xFFAA66CC, 0xFF99CC00, 0xFFFFBB33, 0xFFFF4444};
private LruCache<String, Bitmap> cache;
private Handler handler;
private Bitmap nowPlaying;
private Bitmap nowPlayingSmall;
private final int imageSizeDefault; private final int imageSizeDefault;
private final int imageSizeLarge; private final int imageSizeLarge;
private boolean clearingCache = false;
private final int cacheSize; private final int cacheSize;
private final Context context;
private final static int[] COLORS = {0xFF33B5E5, 0xFFAA66CC, 0xFF99CC00, 0xFFFFBB33, 0xFFFF4444}; private final Handler handler;
private LruCache<String, Bitmap> cache;
private Bitmap nowPlaying;
private Bitmap nowPlayingSmall;
private boolean clearingCache = false;
public ImageLoader(Context context) { public ImageLoader(Context context) {
this.context = context; this.context = context;
@ -112,10 +107,12 @@ public class ImageLoader {
} }
}.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");
@ -150,6 +147,7 @@ public class ImageLoader {
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) {
@ -159,6 +157,7 @@ public class ImageLoader {
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);
@ -212,10 +211,11 @@ public class ImageLoader {
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, 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)) {
@ -246,36 +246,12 @@ public class ImageLoader {
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, large, view, crossfade);
task.execute(); task.execute();
return task; return task;
} }
public SilentBackgroundTask<Void> loadImage(View view, String url, boolean large) { public SilentBackgroundTask loadImage(View view, Playlist playlist) {
Bitmap bitmap;
int size = large ? imageSizeLarge : imageSizeDefault;
if (url == null) {
String key = getKey(url + "unknown", size);
int color = COLORS[Math.abs(key.hashCode()) % COLORS.length];
bitmap = getUnknownImage(key, size, color, null, null);
setImage(view, Util.createDrawableFromBitmap(context, bitmap), true);
return null;
}
bitmap = cache.get(getKey(url, size));
if (bitmap != null && !bitmap.isRecycled()) {
final Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap);
setImage(view, drawable, true);
return null;
}
setImage(view, null, false);
SilentBackgroundTask<Void> task = new ViewUrlTask(view.getContext(), view, url, size);
task.execute();
return task;
}
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)) {
@ -290,7 +266,7 @@ public class ImageLoader {
// 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, false, true);
} }
private String getKey(String coverArtId, int size) { private String getKey(String coverArtId, int size) {
@ -326,14 +302,11 @@ public class ImageLoader {
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(() -> {
@Override
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);
@ -345,19 +318,17 @@ public class ImageLoader {
} }
public abstract class ImageTask extends SilentBackgroundTask<Void> { public abstract class ImageTask extends SilentBackgroundTask<Void> {
final MusicDirectory.Entry mEntry;
private final Context mContext; private final Context mContext;
protected final MusicDirectory.Entry mEntry;
private final int mSize; private final int mSize;
private final int mSaveSize;
private final boolean mIsNowPlaying; private final boolean mIsNowPlaying;
protected Drawable mDrawable; Drawable mDrawable;
public ImageTask(Context context, MusicDirectory.Entry entry, int size, int saveSize, boolean isNowPlaying) { public ImageTask(Context context, MusicDirectory.Entry entry, int size, boolean isNowPlaying) {
super(context); super(context);
mContext = context; mContext = context;
mEntry = entry; mEntry = entry;
mSize = size; mSize = size;
mSaveSize = saveSize;
mIsNowPlaying = isNowPlaying; mIsNowPlaying = isNowPlaying;
} }
@ -389,11 +360,11 @@ public class ImageLoader {
} }
private class ViewImageTask extends ImageTask { private class ViewImageTask extends ImageTask {
protected boolean mCrossfade; final boolean mCrossfade;
private View mView; private final 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, boolean isNowPlaying, View view, boolean crossfade) {
super(context, entry, size, saveSize, isNowPlaying); super(context, entry, size, isNowPlaying);
mView = view; mView = view;
mCrossfade = crossfade; mCrossfade = crossfade;
@ -409,20 +380,17 @@ public class ImageLoader {
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 boolean mIsNowPlaying; private final boolean mIsNowPlaying;
private final boolean mCrossfade;
private final View mView;
private Drawable mDrawable; private Drawable mDrawable;
private boolean mCrossfade;
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, boolean isNowPlaying, View view, boolean crossfade) {
super(context); super(context);
mContext = context; mContext = context;
mEntry = entry; mEntry = entry;
mSize = size; mSize = size;
mSaveSize = saveSize;
mIsNowPlaying = isNowPlaying; mIsNowPlaying = isNowPlaying;
mView = view; mView = view;
mCrossfade = crossfade; mCrossfade = crossfade;
@ -431,8 +399,6 @@ public class ImageLoader {
@Override @Override
protected Void doInBackground() throws Throwable { protected Void doInBackground() throws Throwable {
try { try {
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
@ -443,7 +409,7 @@ public class ImageLoader {
} }
if (mEntry != null && mEntry.getCoverArt() != null) { if (mEntry != null && mEntry.getCoverArt() != null) {
subTask = new ViewImageTask(mContext, mEntry, mSize, mSaveSize, mIsNowPlaying, mView, mCrossfade); subTask = new ViewImageTask(mContext, mEntry, mSize, mIsNowPlaying, mView, mCrossfade);
} else { } else {
// If entry is null as well, we need to just set as a blank image // If entry is null as well, we need to just set as a blank image
Bitmap bitmap = getUnknownImage(mEntry, mSize); Bitmap bitmap = getUnknownImage(mEntry, mSize);
@ -469,54 +435,4 @@ public class ImageLoader {
} }
} }
} }
private class ViewUrlTask extends SilentBackgroundTask<Void> {
private final Context mContext;
private final String mUrl;
private final ImageView mView;
private Drawable mDrawable;
private int mSize;
public ViewUrlTask(Context context, View view, String url, int size) {
super(context);
mContext = context;
mView = (ImageView) view;
mUrl = url;
mSize = size;
}
@Override
protected Void doInBackground() throws Throwable {
try {
MusicService musicService = MusicServiceFactory.getMusicService(mContext);
Bitmap bitmap = musicService.getBitmap(mUrl, mSize, mContext, null, this);
if(bitmap != null) {
String key = getKey(mUrl, mSize);
cache.put(key, bitmap);
// Make sure key is the most recently "used"
cache.get(key);
mDrawable = Util.createDrawableFromBitmap(mContext, bitmap);
}
} catch (Throwable x) {
Log.e(TAG, "Failed to download from url " + mUrl, x);
cancelled.set(true);
}
return null;
}
@Override
protected void done(Void result) {
if(mDrawable != null) {
mView.setImageDrawable(mDrawable);
} else {
failedToDownload();
}
}
protected void failedToDownload() {
}
}
} }

View File

@ -2,7 +2,6 @@ package net.nullsum.audinaut.util;
import android.app.Activity; import android.app.Activity;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.DialogInterface;
import net.nullsum.audinaut.activity.SubsonicActivity; import net.nullsum.audinaut.activity.SubsonicActivity;
@ -13,14 +12,15 @@ 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 final boolean cancellable; private final boolean cancellable;
private ProgressDialog loading;
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;
@ -29,11 +29,7 @@ public abstract class LoadingTask<T> extends BackgroundTask<T> {
@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, dialog -> cancel());
public void onCancel(DialogInterface dialog) {
cancel();
}
});
queue.offer(task = new Task() { queue.offer(task = new Task() {
@Override @Override
@ -62,12 +58,7 @@ public abstract class LoadingTask<T> extends BackgroundTask<T> {
@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(() -> loading.setMessage(message));
@Override
public void run() {
loading.setMessage(message);
}
});
} }
} }
} }

View File

@ -16,12 +16,9 @@
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log; import android.util.Log;
import android.view.Menu; import android.view.Menu;
import java.io.File;
import net.nullsum.audinaut.R; import net.nullsum.audinaut.R;
import net.nullsum.audinaut.service.DownloadFile; import net.nullsum.audinaut.service.DownloadFile;
import net.nullsum.audinaut.view.AlbumView; import net.nullsum.audinaut.view.AlbumView;
@ -30,6 +27,8 @@ import net.nullsum.audinaut.view.ArtistView;
import net.nullsum.audinaut.view.SongView; import net.nullsum.audinaut.view.SongView;
import net.nullsum.audinaut.view.UpdateView; import net.nullsum.audinaut.view.UpdateView;
import java.io.File;
public final class MenuUtil { public final class MenuUtil {
private final static String TAG = MenuUtil.class.getSimpleName(); private final static String TAG = MenuUtil.class.getSimpleName();

View File

@ -43,14 +43,11 @@ import net.nullsum.audinaut.service.DownloadService;
import static android.content.Context.NOTIFICATION_SERVICE; import static android.content.Context.NOTIFICATION_SERVICE;
public final class Notifications { public final class Notifications {
private static final int NOTIFICATION_ID_PLAYING = 100;
private static final int NOTIFICATION_ID_DOWNLOADING = 102;
private static final String CHANNEL_PLAYING_ID = "playback_controls";
private static final String CHANNEL_DOWNLOADING_ID = "media_download";
private static final String TAG = Notifications.class.getSimpleName(); private static final String TAG = Notifications.class.getSimpleName();
public static final int NOTIFICATION_ID_PLAYING = 100;
public static final int NOTIFICATION_ID_DOWNLOADING = 102;
public static final String CHANNEL_PLAYING_ID = "playback_controls";
public static final String CHANNEL_DOWNLOADING_ID = "media_download";
private static boolean playShowing = false; private static boolean playShowing = false;
private static boolean downloadShowing = false; private static boolean downloadShowing = false;
private static boolean downloadForeground = false; private static boolean downloadForeground = false;
@ -95,18 +92,13 @@ public final class Notifications {
playShowing = true; playShowing = true;
if (downloadForeground && downloadShowing) { if (downloadForeground && downloadShowing) {
downloadForeground = false; downloadForeground = false;
handler.post(new Runnable() { handler.post(() -> {
@Override
public void run() {
downloadService.stopForeground(true); downloadService.stopForeground(true);
showDownloadingNotification(context, downloadService, handler, downloadService.getCurrentDownloading(), downloadService.getBackgroundDownloads().size()); showDownloadingNotification(context, downloadService, handler, downloadService.getCurrentDownloading(), downloadService.getBackgroundDownloads().size());
downloadService.startForeground(NOTIFICATION_ID_PLAYING, notification); downloadService.startForeground(NOTIFICATION_ID_PLAYING, notification);
}
}); });
} else { } else {
handler.post(new Runnable() { handler.post(() -> {
@Override
public void run() {
if (playing) { if (playing) {
downloadService.startForeground(NOTIFICATION_ID_PLAYING, notification); downloadService.startForeground(NOTIFICATION_ID_PLAYING, notification);
} else { } else {
@ -116,7 +108,6 @@ public final class Notifications {
downloadService.stopForeground(false); downloadService.stopForeground(false);
notificationManager.notify(NOTIFICATION_ID_PLAYING, notification); notificationManager.notify(NOTIFICATION_ID_PLAYING, notification);
} }
}
}); });
} }
@ -174,7 +165,7 @@ public final class Notifications {
// Create actions for media buttons // Create actions for media buttons
PendingIntent pendingIntent; PendingIntent pendingIntent;
int previous = 0, pause = 0, next = 0, close = 0, rewind = 0, fastForward = 0; int previous = 0, pause, next, close = 0, rewind = 0, fastForward = 0;
if (persistent && !expanded) { if (persistent && !expanded) {
pause = R.id.control_previous; pause = R.id.control_previous;
next = R.id.control_pause; next = R.id.control_pause;
@ -246,9 +237,7 @@ public final class Notifications {
playShowing = false; playShowing = false;
// Remove notification and remove the service from the foreground // Remove notification and remove the service from the foreground
handler.post(new Runnable() { handler.post(() -> {
@Override
public void run() {
downloadService.stopForeground(true); downloadService.stopForeground(true);
if (persistentPlayingShowing) { if (persistentPlayingShowing) {
@ -256,7 +245,6 @@ public final class Notifications {
notificationManager.cancel(NOTIFICATION_ID_PLAYING); notificationManager.cancel(NOTIFICATION_ID_PLAYING);
persistentPlayingShowing = false; persistentPlayingShowing = false;
} }
}
}); });
// Get downloadNotification in foreground if playing // Get downloadNotification in foreground if playing
@ -316,15 +304,11 @@ public final class Notifications {
notificationManager.notify(NOTIFICATION_ID_DOWNLOADING, notification); notificationManager.notify(NOTIFICATION_ID_DOWNLOADING, notification);
} else { } else {
downloadForeground = true; downloadForeground = true;
handler.post(new Runnable() { handler.post(() -> downloadService.startForeground(NOTIFICATION_ID_DOWNLOADING, notification));
@Override
public void run() {
downloadService.startForeground(NOTIFICATION_ID_DOWNLOADING, notification);
}
});
} }
} }
public static void hideDownloadingNotification(final Context context, final DownloadService downloadService, Handler handler) { public static void hideDownloadingNotification(final Context context, final DownloadService downloadService, Handler handler) {
downloadShowing = false; downloadShowing = false;
if (playShowing) { if (playShowing) {
@ -332,12 +316,7 @@ public final class Notifications {
notificationManager.cancel(NOTIFICATION_ID_DOWNLOADING); notificationManager.cancel(NOTIFICATION_ID_DOWNLOADING);
} else { } else {
downloadForeground = false; downloadForeground = false;
handler.post(new Runnable() { handler.post(() -> downloadService.stopForeground(true));
@Override
public void run() {
downloadService.stopForeground(true);
}
});
} }
} }
} }

View File

@ -25,11 +25,8 @@ import java.io.Serializable;
*/ */
public class Pair<S, T> implements Serializable { public class Pair<S, T> implements Serializable {
private S first; private final S first;
private T second; private final T second;
public Pair() {
}
public Pair(S first, T second) { public Pair(S first, T second) {
this.first = first; this.first = first;
@ -40,15 +37,8 @@ public class Pair<S, T> implements Serializable {
return first; return first;
} }
public void setFirst(S first) {
this.first = first;
}
public T getSecond() { public T getSecond() {
return second; return second;
} }
public void setSecond(T second) {
this.second = second;
}
} }

View File

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

View File

@ -15,46 +15,36 @@
package net.nullsum.audinaut.util; package net.nullsum.audinaut.util;
import android.util.Log;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.nio.ByteOrder;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import android.content.Context;
import android.net.wifi.WifiManager;
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();
boolean isRunning;
private Thread thread; private Thread thread;
protected boolean isRunning;
private ServerSocket socket; private ServerSocket socket;
private int port; private int port;
private Context context;
public ServerProxy(Context context) { ServerProxy() {
// 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;
} 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);
@ -78,29 +68,12 @@ public abstract class ServerProxy implements Runnable {
} }
public String getPrivateAddress(String request) { public String getPrivateAddress(String request) {
return getAddress("127.0.0.1", request); return getAddress(request);
}
public String getPublicAddress(String request) {
WifiManager wifiManager = (WifiManager) context.getApplicationContext().getSystemService(Context.WIFI_SERVICE);
int ipAddress = wifiManager.getConnectionInfo().getIpAddress();
if (ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN)) {
ipAddress = Integer.reverseBytes(ipAddress);
} }
byte[] ipByteArray = BigInteger.valueOf(ipAddress).toByteArray(); private String getAddress(String request) {
String ipAddressString = null;
try { try {
ipAddressString = InetAddress.getByAddress(ipByteArray).getHostAddress(); return String.format("http://%s:%d/%s", "127.0.0.1", port, URLEncoder.encode(request, "UTF-8"));
} catch(UnknownHostException ex) {
Log.e(TAG, "Unable to get host address.");
}
return getAddress(ipAddressString, request);
}
private String getAddress(String host, String request) {
try {
return String.format("http://%s:%d/%s", host, port, URLEncoder.encode(request, "UTF-8"));
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
return null; return null;
} }
@ -134,16 +107,16 @@ public abstract class ServerProxy implements Runnable {
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; final Socket client;
protected String path; final Map<String, String> requestHeaders = new HashMap<>();
protected int cbSkip = 0; String path;
protected Map<String, String> requestHeaders = new HashMap<>(); int cbSkip = 0;
public ProxyTask(Socket client) { public ProxyTask(Socket client) {
this.client = client; this.client = client;
} }
protected boolean readRequest() { boolean readRequest() {
InputStream is; InputStream is;
String firstLine; String firstLine;
BufferedReader reader; BufferedReader reader;
@ -169,7 +142,6 @@ public abstract class ServerProxy implements Runnable {
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 uri = st.nextToken(); String uri = st.nextToken();
String realUri = uri.substring(1); String realUri = uri.substring(1);

View File

@ -23,11 +23,8 @@ import android.app.backup.BackupDataInput;
import android.app.backup.SharedPreferencesBackupHelper; import android.app.backup.SharedPreferencesBackupHelper;
import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor;
import java.io.IOError;
import java.io.IOException; import java.io.IOException;
import net.nullsum.audinaut.util.Constants;
public class SettingsBackupAgent extends BackupAgentHelper { public class SettingsBackupAgent extends BackupAgentHelper {
@Override @Override
public void onCreate() { public void onCreate() {

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