Compare commits
125 Commits
Author | SHA1 | Date |
---|---|---|
Andrew Rabert | 4c1bb5375d | |
Andrew Rabert | f1a9686eb4 | |
Andrew Rabert | 279adc166b | |
Andrew Rabert | c20a64ab15 | |
Andrew Rabert | aa4c877046 | |
Jordi Masip | 09c5d7ee51 | |
Andrew Rabert | 27b0dc742c | |
Andrew Rabert | 63df26cdfd | |
Andrew Rabert | 49f15f2a0d | |
Andrew Rabert | 2c3c9ede14 | |
Andrew Rabert | ef2e19ebf2 | |
Andrew Rabert | 4c5406c916 | |
Andrew Rabert | 072a6d7870 | |
Andrew Rabert | 5ae04b3643 | |
Andrew Rabert | 79ea6cb082 | |
Robert Robinson | 8cfae03550 | |
Andrew Rabert | 298a06ab5b | |
anasofiagribeiro | 41d17f960e | |
Andrew Rabert | a861e035ab | |
Morgan Lim | 4598f849ff | |
Morgan Lim | d37a72b2a0 | |
Andrew Rabert | e102dea3d3 | |
Andrew Rabert | a69b1385c0 | |
Morgan Lim | f506bfb14a | |
Morgan Lim | 0f525befca | |
Morgan Lim | d3d6186fb7 | |
Andrew Rabert | d10ea92edd | |
Andrew Rabert | d1f1331f35 | |
Andrew Rabert | 4fd53e74c5 | |
Andrew Rabert | 6704e05da2 | |
Andrew Rabert | e79aff9e98 | |
Andrew Rabert | ffa048177e | |
Andrew Rabert | f6d308c37c | |
Simão Mata | 3c17e91ca8 | |
Andrew Rabert | ec083cd79d | |
Simão Mata | cfae0d30b5 | |
Andrew Rabert | ecdae8c6e3 | |
Andrew Rabert | 76efc2c62c | |
Andrew Rabert | 26848852ac | |
Simão Mata | 377f21d732 | |
Simão Mata | 8af307da28 | |
Andrew Rabert | 3d7b173cb1 | |
Andrew Rabert | e7ea8d4dfc | |
dddddd-mmmmmm | e2280304e4 | |
emaiannone | 061c318e05 | |
Andrew Rabert | 8fc54ac68c | |
Andrew Rabert | 8f4d3be90b | |
Andrew Rabert | a6a784037e | |
dddddd-mmmmmm | 2ed89ab72f | |
Andrew Rabert | d5b56eecdd | |
dddddd-mmmmmm | 81086c4a3a | |
dddddd-mmmmmm | 02d94e1a6c | |
dddddd-mmmmmm | 5141eb6e81 | |
dddddd-mmmmmm | 4254c8ad9f | |
Andrew Rabert | bf9e9ad1e6 | |
Andrew Rabert | 02a8b1909a | |
Morgan Lim | ff4a1f3b13 | |
Morgan Lim | 153ccdd46a | |
Morgan Lim | 507c9008aa | |
Morgan Lim | 35a112509e | |
Andrew Rabert | af89b8ea76 | |
Morgan Lim | 0a84e9376a | |
Morgan Lim | 717cab5dd5 | |
Andrew Rabert | 13810a07a5 | |
Andrew Rabert | b147cc10dc | |
mlim15 | 357cbd2ba1 | |
Andrew Rabert | 435d770716 | |
Andrew Rabert | 4503ae4133 | |
Andrew Rabert | d43cfb1ce3 | |
mlim15 | cc0faa19ce | |
mlim15 | 8078eeff74 | |
mlim15 | d176ed4036 | |
mlim15 | cf4ab6bf05 | |
Andrew Rabert | 0239248b23 | |
Andrew Rabert | 8ee8858098 | |
Andrew Rabert | 23054ffab0 | |
Andrew Rabert | f623ad2b63 | |
Andrew Rabert | 4eac05e57f | |
Andrew Rabert | 1c269aac53 | |
Andrew Rabert | c5c4185e2f | |
Andrew Rabert | f56c976de7 | |
Andrew Rabert | 572024da52 | |
Andrew Rabert | 97507a25a1 | |
Andrew Rabert | e7628a97c7 | |
Andrew Rabert | f8a9d8ad34 | |
Andrew Rabert | 92c41fd463 | |
Andrew Rabert | 22c98d9606 | |
Andrew Rabert | bf3233d6b2 | |
Andrew Rabert | 93658f32d3 | |
Andrew Rabert | c0ee2d908e | |
Andrew Rabert | e4febf7260 | |
Andrew Rabert | 70f6e22be7 | |
Andrew Rabert | 54d6269a9e | |
Andrew Rabert | eaef36849a | |
Andrew Rabert | e28a70a6e6 | |
Andrew Rabert | 2ca504d7e9 | |
Andrew Rabert | 5e34f2d8e9 | |
Andrew Rabert | 9e57cf1433 | |
Andrew Rabert | 687f64c115 | |
Andrew Rabert | 3ebb48682b | |
Andrew Rabert | a334494186 | |
Andrew Rabert | d43cca9436 | |
Andrew Rabert | a6fa354622 | |
Andrew Rabert | 89ede8ff47 | |
Andrew Rabert | 3243f320b1 | |
Andrew Rabert | e12fbf68ad | |
Andrew Rabert | b943580fa8 | |
Andrew Rabert | a24faf6fae | |
Andrew Rabert | 5144f82051 | |
Andrew Rabert | 63fc23d9fb | |
Andrew Rabert | 11223bd44d | |
Andrew Rabert | 17091f8f86 | |
Andrew Rabert | 3648f64fa4 | |
Andrew Rabert | b0750949f0 | |
Andrew Rabert | 66db8db769 | |
Andrew Rabert | d62e010894 | |
Andrew Rabert | 39a7c39b94 | |
Andrew Rabert | 963aace2c5 | |
Andrew Rabert | 2e49bcadb2 | |
Andrew Rabert | f3b91bff2d | |
Andrew Rabert | 9d9ff7b728 | |
Andrew Rabert | ca15682a5e | |
Andrew Rabert | b213a99e7c | |
Andrew Rabert | cf579043f2 | |
Andrew Rabert | c6729e427b |
30
CHANGELOG.md
|
@ -1,6 +1,36 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
## Version 0.5.1
|
||||
_2020-04-30_
|
||||
* Add option to force server-side media scan
|
||||
* Change to local artist sorting (case-insensitive)
|
||||
* Fix crash while offline (#25)
|
||||
* Fix read timeout not being respected
|
||||
* Fix switching to playlist on app resume
|
||||
|
||||
## Version 0.5.0
|
||||
_2020-01-15_
|
||||
* Add 24kbps and 48kbps options
|
||||
* Add adaptive icon
|
||||
* Add support for p= authentication
|
||||
* Change to MediaStyle playback notification
|
||||
* Fix SSID selection
|
||||
* Fix keyboard being visible when switching to now playing
|
||||
* Fix now playing icon when using light theme
|
||||
|
||||
## Version 0.4.1
|
||||
_2019-12-28_
|
||||
* Revert attempt to fix infinite loop as it sometimes deleted valid files.
|
||||
|
||||
## Version 0.4.0
|
||||
_2019-12-22_
|
||||
* Add support for .opus files
|
||||
* Fix HTTP support
|
||||
* Fix infinite loop when playing contains only invalid files
|
||||
* Overhaul themes
|
||||
* Replace raster images with vector images
|
||||
|
||||
## Version 0.3.3
|
||||
_2019-03-17_
|
||||
* Fix [Funkwhale](https://funkwhale.audio/) (Subsonic API) support
|
||||
|
|
11
README.md
|
@ -1,7 +1,14 @@
|
|||
# Audinaut
|
||||
⚠ No longer maintained.
|
||||
|
||||
Although not a direct replacement, I've since moved onto syncing an Opus version
|
||||
of my entire library to my phone using [harmonize](https://github.com/nvllsvm/harmonize)
|
||||
and [Syncthing](https://syncthing.net/).
|
||||
|
||||
---
|
||||
<img src="audinaut.png" align="left" width="200" hspace="10" vspace="10">
|
||||
|
||||
An [Airsonic] client for Android.
|
||||
A Subsonic client for Android.
|
||||
|
||||
|
||||
<a href="https://f-droid.org/app/net.nullsum.audinaut">
|
||||
|
@ -12,5 +19,3 @@ An [Airsonic] client for Android.
|
|||
<img src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png"
|
||||
alt="Get it on Google Play" height="80" />
|
||||
</a>
|
||||
|
||||
[Airsonic]: https://airsonic.github.io
|
||||
|
|
|
@ -2,26 +2,16 @@ apply plugin: 'com.android.application'
|
|||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 28
|
||||
buildToolsVersion "28.0.3"
|
||||
compileSdkVersion 31
|
||||
buildToolsVersion "31.0.0"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "net.nullsum.audinaut"
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 28
|
||||
versionCode 198
|
||||
versionName '0.3.3'
|
||||
targetSdkVersion 30
|
||||
versionCode 202
|
||||
versionName '0.5.1'
|
||||
setProperty("archivesBaseName", "Audinaut $versionName")
|
||||
resConfigs "de", "es", "fr", "hu", "nl", "pt-rPT", "ru", "sv"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'META-INF/beans.xml'
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
|
@ -36,15 +26,16 @@ android {
|
|||
|
||||
dependencies {
|
||||
implementation 'com.esotericsoftware:kryo:4.0.2'
|
||||
implementation "com.android.support:design:$android_support_version"
|
||||
implementation 'com.sothree.slidinguppanel:library:3.3.1'
|
||||
implementation 'com.squareup.okhttp3:okhttp:3.14.0'
|
||||
implementation 'com.google.android.material:material:1.5.0'
|
||||
implementation 'com.github.hannesa2:AndroidSlidingUpPanel:4.4.1'
|
||||
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
implementation "androidx.media:media:1.5.0"
|
||||
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.3.21'
|
||||
ext.android_support_version = '27.1.1'
|
||||
ext.kotlin_version = '1.6.0'
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
<uses-permission android:name="android.permission.READ_SYNC_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.WRITE_SYNC_SETTINGS" />
|
||||
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<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.RECEIVE_BOOT_COMPLETED" />
|
||||
|
@ -45,6 +46,8 @@
|
|||
android:backupAgent="net.nullsum.audinaut.util.SettingsBackupAgent"
|
||||
android:icon="@drawable/launch"
|
||||
android:label="@string/common.appname"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:theme="@style/LaunchScreen">
|
||||
|
||||
<uses-library android:name="android.test.runner" />
|
||||
|
|
|
@ -15,11 +15,8 @@
|
|||
|
||||
package net.nullsum.audinaut.activity;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
@ -30,6 +27,10 @@ import android.widget.CheckBox;
|
|||
import android.widget.EditText;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.domain.Genre;
|
||||
import net.nullsum.audinaut.service.MusicService;
|
||||
|
@ -58,7 +59,7 @@ public class EditPlayActionActivity extends SubsonicActivity {
|
|||
super.onCreate(savedInstanceState);
|
||||
setTitle(R.string.tasker_start_playing_title);
|
||||
setContentView(R.layout.edit_play_action);
|
||||
final Activity context = this;
|
||||
final AppCompatActivity context = this;
|
||||
doNothing = context.getResources().getString(R.string.tasker_edit_do_nothing);
|
||||
|
||||
shuffleCheckbox = findViewById(R.id.edit_shuffle_checkbox);
|
||||
|
@ -218,12 +219,12 @@ public class EditPlayActionActivity extends SubsonicActivity {
|
|||
|
||||
intent.putExtra(Constants.TASKER_EXTRA_BUNDLE, data);
|
||||
|
||||
setResult(Activity.RESULT_OK, intent);
|
||||
setResult(AppCompatActivity.RESULT_OK, intent);
|
||||
finish();
|
||||
}
|
||||
|
||||
private void cancel() {
|
||||
setResult(Activity.RESULT_CANCELED);
|
||||
setResult(AppCompatActivity.RESULT_CANCELED);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,11 +19,12 @@
|
|||
|
||||
package net.nullsum.audinaut.activity;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.SearchManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import net.nullsum.audinaut.util.Constants;
|
||||
import net.nullsum.audinaut.util.Util;
|
||||
|
||||
|
@ -32,7 +33,7 @@ import net.nullsum.audinaut.util.Util;
|
|||
*
|
||||
* @author Sindre Mehus
|
||||
*/
|
||||
public class QueryReceiverActivity extends Activity {
|
||||
public class QueryReceiverActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -64,10 +65,10 @@ public class QueryReceiverActivity extends Activity {
|
|||
intent.putExtra(Constants.INTENT_EXTRA_VIEW_ALBUM, true);
|
||||
if (albumId.indexOf("ar-") == 0) {
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_ARTIST, true);
|
||||
albumId = albumId.replace("ar-", "");
|
||||
albumId = albumId.replaceFirst("ar-", "");
|
||||
} else if (albumId.indexOf("so-") == 0) {
|
||||
intent.putExtra(Constants.INTENT_EXTRA_SEARCH_SONG, name);
|
||||
albumId = albumId.replace("so-", "");
|
||||
albumId = albumId.replaceFirst("so-", "");
|
||||
}
|
||||
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, albumId);
|
||||
if (name != null) {
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
package net.nullsum.audinaut.activity;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.fragments.PreferenceCompatFragment;
|
||||
|
|
|
@ -21,22 +21,11 @@ package net.nullsum.audinaut.activity;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Handler;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.ActionBarDrawerToggle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.app.AppCompatDelegate;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
|
@ -53,6 +42,18 @@ import android.widget.ImageView;
|
|||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.ActionBarDrawerToggle;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.drawerlayout.widget.DrawerLayout;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.google.android.material.navigation.NavigationView;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.fragments.SubsonicFragment;
|
||||
import net.nullsum.audinaut.service.DownloadService;
|
||||
|
@ -66,8 +67,6 @@ 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.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -80,11 +79,16 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
|
|||
private static final int PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE = 1;
|
||||
private static String theme;
|
||||
private static boolean fullScreen;
|
||||
private static boolean actionbarColored;
|
||||
private static ImageLoader IMAGE_LOADER;
|
||||
|
||||
static {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO);
|
||||
// If Android Pie or older, set night mode by system clock
|
||||
if (Build.VERSION.SDK_INT<29) {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO);
|
||||
} else {
|
||||
// Else, for Android 10+, follow system dark mode setting
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
|
||||
}
|
||||
}
|
||||
|
||||
final List<SubsonicFragment> backStack = new ArrayList<>();
|
||||
|
@ -123,7 +127,6 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
|
|||
touchscreen = false;
|
||||
}
|
||||
|
||||
setUncaughtExceptionHandler();
|
||||
applyTheme();
|
||||
applyFullscreen();
|
||||
super.onCreate(bundle);
|
||||
|
@ -144,7 +147,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case PERMISSIONS_REQUEST_WRITE_EXTERNAL_STORAGE: {
|
||||
// If request is cancelled, the result arrays are empty.
|
||||
|
@ -175,7 +178,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
|
|||
|
||||
private void createCustomActionBarView() {
|
||||
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) && ThemeUtil.getThemeRes(this) != R.style.Theme_Audinaut_Light) {
|
||||
actionBarSpinner.setBackground(DrawableTint.getTintedDrawableFromColor(this));
|
||||
}
|
||||
spinnerAdapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item);
|
||||
|
@ -193,7 +196,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
|
|||
|
||||
// Make sure to update theme
|
||||
SharedPreferences prefs = Util.getPreferences(this);
|
||||
if (theme != null && !theme.equals(ThemeUtil.getTheme(this)) || fullScreen != prefs.getBoolean(Constants.PREFERENCES_KEY_FULL_SCREEN, false) || actionbarColored != prefs.getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true)) {
|
||||
if (theme != null && !theme.equals(ThemeUtil.getTheme(this)) || fullScreen != prefs.getBoolean(Constants.PREFERENCES_KEY_FULL_SCREEN, false)) {
|
||||
restart();
|
||||
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
|
||||
DrawableTint.wipeTintCache();
|
||||
|
@ -482,7 +485,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
|
|||
item.setChecked(true);
|
||||
}
|
||||
}
|
||||
drawerHeaderToggle.setImageResource(R.drawable.main_select_server_dark);
|
||||
drawerHeaderToggle.setImageResource(R.drawable.main_select_server);
|
||||
|
||||
showingTabs = true;
|
||||
}
|
||||
|
@ -499,7 +502,7 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
|
|||
}
|
||||
}
|
||||
drawerList.getMenu().setGroupCheckable(MENU_GROUP_SERVER, true, true);
|
||||
drawerHeaderToggle.setImageResource(R.drawable.main_select_tabs_dark);
|
||||
drawerHeaderToggle.setImageResource(R.drawable.main_select_tabs);
|
||||
|
||||
showingTabs = false;
|
||||
}
|
||||
|
@ -741,7 +744,6 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
|
|||
}
|
||||
|
||||
ThemeUtil.applyTheme(this, theme);
|
||||
actionbarColored = Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true);
|
||||
}
|
||||
|
||||
private void applyFullscreen() {
|
||||
|
@ -836,7 +838,6 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
|
|||
}
|
||||
Util.setActiveServer(this, instance);
|
||||
invalidate();
|
||||
UserUtil.refreshCurrentUser(this);
|
||||
updateDrawerHeader();
|
||||
}
|
||||
}
|
||||
|
@ -864,7 +865,6 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
|
|||
service.setOnline(isOffline);
|
||||
}
|
||||
|
||||
UserUtil.seedCurrentUser(this);
|
||||
this.updateDrawerHeader();
|
||||
drawer.closeDrawers();
|
||||
}
|
||||
|
@ -883,50 +883,4 @@ public class SubsonicActivity extends AppCompatActivity implements OnItemSelecte
|
|||
return R.id.drawer_library;
|
||||
}
|
||||
}
|
||||
|
||||
private void setUncaughtExceptionHandler() {
|
||||
Thread.UncaughtExceptionHandler handler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
if (!(handler instanceof SubsonicActivity.SubsonicUncaughtExceptionHandler)) {
|
||||
Thread.setDefaultUncaughtExceptionHandler(new SubsonicActivity.SubsonicUncaughtExceptionHandler(this));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs the stack trace of uncaught exceptions to a file on the SD card.
|
||||
*/
|
||||
private static class SubsonicUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
|
||||
|
||||
private final Thread.UncaughtExceptionHandler defaultHandler;
|
||||
private final Context context;
|
||||
|
||||
private SubsonicUncaughtExceptionHandler(Context context) {
|
||||
this.context = context;
|
||||
defaultHandler = Thread.getDefaultUncaughtExceptionHandler();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uncaughtException(Thread thread, Throwable throwable) {
|
||||
File file = null;
|
||||
PrintWriter printWriter = null;
|
||||
try {
|
||||
|
||||
PackageInfo packageInfo = context.getPackageManager().getPackageInfo("net.nullsum.audinaut", 0);
|
||||
file = new File(Environment.getExternalStorageDirectory(), "audinaut-stacktrace.txt");
|
||||
printWriter = new PrintWriter(file);
|
||||
printWriter.println("Subsonic version name: " + packageInfo.versionName);
|
||||
printWriter.println("Subsonic version code: " + packageInfo.versionCode);
|
||||
printWriter.println();
|
||||
throwable.printStackTrace(printWriter);
|
||||
Log.i(TAG, "Stack trace written to " + file);
|
||||
} catch (Throwable x) {
|
||||
Log.e(TAG, "Failed to write stack trace to " + file, x);
|
||||
} finally {
|
||||
Util.close(printWriter);
|
||||
if (defaultHandler != null) {
|
||||
defaultHandler.uncaughtException(thread, throwable);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,17 +27,19 @@ import android.content.SharedPreferences;
|
|||
import android.content.res.TypedArray;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
import com.sothree.slidinguppanel.PanelSlideListener;
|
||||
import com.sothree.slidinguppanel.PanelState;
|
||||
import com.sothree.slidinguppanel.SlidingUpPanelLayout;
|
||||
import com.sothree.slidinguppanel.SlidingUpPanelLayout.PanelState;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.domain.MusicDirectory;
|
||||
|
@ -55,7 +57,6 @@ import net.nullsum.audinaut.updates.Updater;
|
|||
import net.nullsum.audinaut.util.Constants;
|
||||
import net.nullsum.audinaut.util.FileUtil;
|
||||
import net.nullsum.audinaut.util.SilentBackgroundTask;
|
||||
import net.nullsum.audinaut.util.UserUtil;
|
||||
import net.nullsum.audinaut.util.Util;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -68,7 +69,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
|
|||
private static boolean infoDialogDisplayed;
|
||||
private static boolean sessionInitialized = false;
|
||||
private SlidingUpPanelLayout slideUpPanel;
|
||||
private SlidingUpPanelLayout.PanelSlideListener panelSlideListener;
|
||||
private PanelSlideListener panelSlideListener;
|
||||
private boolean isPanelClosing = false;
|
||||
private boolean resuming = false;
|
||||
private NowPlayingFragment nowPlayingFragment;
|
||||
|
@ -167,9 +168,10 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
|
|||
}
|
||||
|
||||
slideUpPanel = findViewById(R.id.slide_up_panel);
|
||||
panelSlideListener = new SlidingUpPanelLayout.PanelSlideListener() {
|
||||
panelSlideListener = new PanelSlideListener() {
|
||||
@Override
|
||||
public void onPanelSlide(View panel, float slideOffset) {
|
||||
Util.hideKeyboard(panel);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -365,7 +367,6 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
|
|||
getIntent().removeExtra(Constants.INTENT_EXTRA_VIEW_ALBUM);
|
||||
}
|
||||
|
||||
UserUtil.seedCurrentUser(this);
|
||||
createAccount();
|
||||
runWhenServiceAvailable(() -> getDownloadService().addOnSongChangedListener(SubsonicFragmentActivity.this));
|
||||
resuming = false;
|
||||
|
@ -414,7 +415,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
|
|||
drawerToggle.setDrawerIndicatorEnabled(false);
|
||||
}
|
||||
|
||||
if (savedInstanceState.getInt(Constants.MAIN_SLIDE_PANEL_STATE, -1) == SlidingUpPanelLayout.PanelState.EXPANDED.hashCode()) {
|
||||
if (savedInstanceState.getInt(Constants.MAIN_SLIDE_PANEL_STATE, -1) == PanelState.EXPANDED.hashCode()) {
|
||||
panelSlideListener.onPanelStateChanged(null, null, PanelState.EXPANDED);
|
||||
}
|
||||
}
|
||||
|
@ -533,12 +534,12 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
|
|||
|
||||
@Override
|
||||
public void openNowPlaying() {
|
||||
slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.EXPANDED);
|
||||
slideUpPanel.setPanelState(PanelState.EXPANDED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeNowPlaying() {
|
||||
slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED);
|
||||
slideUpPanel.setPanelState(PanelState.COLLAPSED);
|
||||
isPanelClosing = true;
|
||||
}
|
||||
|
||||
|
@ -703,7 +704,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity implements Downlo
|
|||
getImageLoader().loadImage(coverArtView, song, false, height, false);
|
||||
|
||||
// We need to update it immediately since it won't update if updater is not running for it
|
||||
if (nowPlayingFragment != null && slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.COLLAPSED) {
|
||||
if (nowPlayingFragment != null && slideUpPanel.getPanelState() == PanelState.COLLAPSED) {
|
||||
nowPlayingFragment.onMetadataUpdate(song, fieldChange);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,12 +19,13 @@
|
|||
|
||||
package net.nullsum.audinaut.activity;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.SearchManager;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.provider.MediaStore;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import net.nullsum.audinaut.util.Constants;
|
||||
import net.nullsum.audinaut.util.Util;
|
||||
|
||||
|
@ -35,7 +36,7 @@ import net.nullsum.audinaut.util.Util;
|
|||
*
|
||||
* @author Sindre Mehus
|
||||
*/
|
||||
public class VoiceQueryReceiverActivity extends Activity {
|
||||
public class VoiceQueryReceiverActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
|
|
@ -16,12 +16,13 @@
|
|||
package net.nullsum.audinaut.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.PopupMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.widget.PopupMenu;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.domain.Artist;
|
||||
import net.nullsum.audinaut.domain.MusicDirectory.Entry;
|
||||
|
|
|
@ -17,21 +17,17 @@ package net.nullsum.audinaut.adapter;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.support.v7.view.ActionMode;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.PopupMenu;
|
||||
|
||||
import androidx.appcompat.view.ActionMode;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.activity.SubsonicFragmentActivity;
|
||||
import net.nullsum.audinaut.util.Constants;
|
||||
|
@ -390,17 +386,6 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
|
|||
MenuUtil.hideMenuItems(context, menu, updateView);
|
||||
|
||||
mode.setTitle(context.getResources().getString(R.string.select_album_n_selected, selected.size()));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true)) {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
Resources.Theme theme = context.getTheme();
|
||||
theme.resolveAttribute(R.attr.colorPrimaryDark, typedValue, true);
|
||||
int colorPrimaryDark = typedValue.data;
|
||||
|
||||
Window window = ((SubsonicFragmentActivity) context).getWindow();
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
window.setStatusBarColor(colorPrimaryDark);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -427,11 +412,6 @@ public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewH
|
|||
updateView.setChecked(false);
|
||||
}
|
||||
selectedViews.clear();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true)) {
|
||||
Window window = ((SubsonicFragmentActivity) context).getWindow();
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ package net.nullsum.audinaut.fragments;
|
|||
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
|
@ -25,6 +24,8 @@ import android.view.MenuItem;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.adapter.DownloadFileAdapter;
|
||||
import net.nullsum.audinaut.adapter.SectionAdapter;
|
||||
|
|
|
@ -17,10 +17,6 @@ package net.nullsum.audinaut.fragments;
|
|||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.GestureDetector.OnGestureListener;
|
||||
|
@ -38,6 +34,10 @@ import android.widget.SeekBar;
|
|||
import android.widget.TextView;
|
||||
import android.widget.ViewFlipper;
|
||||
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.activity.SubsonicFragmentActivity;
|
||||
import net.nullsum.audinaut.adapter.DownloadFileAdapter;
|
||||
|
@ -56,17 +56,12 @@ import net.nullsum.audinaut.util.MenuUtil;
|
|||
import net.nullsum.audinaut.util.SilentBackgroundTask;
|
||||
import net.nullsum.audinaut.util.Util;
|
||||
import net.nullsum.audinaut.view.AutoRepeatButton;
|
||||
import net.nullsum.audinaut.view.FadeOutAnimation;
|
||||
import net.nullsum.audinaut.view.FastScroller;
|
||||
import net.nullsum.audinaut.view.UpdateView;
|
||||
|
||||
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.PlayerState.COMPLETED;
|
||||
|
@ -86,7 +81,9 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
|
|||
private TextView emptyTextView;
|
||||
private TextView songTitleTextView;
|
||||
private ImageView albumArtImageView;
|
||||
private ImageView albumArtBackgroundView;
|
||||
private View albumArtBackgroundView;
|
||||
private ImageView albumArtBackgroundImageView;
|
||||
private View nowPlayingView;
|
||||
private RecyclerView playlistView;
|
||||
private TextView positionTextView;
|
||||
private TextView durationTextView;
|
||||
|
@ -102,11 +99,9 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
|
|||
private ImageButton repeatButton;
|
||||
private View toggleListButton;
|
||||
|
||||
private ScheduledExecutorService executorService;
|
||||
private DownloadFile currentPlaying;
|
||||
private int swipeDistance;
|
||||
private int swipeVelocity;
|
||||
private ScheduledFuture<?> hideControlsFuture;
|
||||
private List<DownloadFile> songList;
|
||||
private DownloadFileAdapter songListAdapter;
|
||||
private boolean seekInProgress = false;
|
||||
|
@ -154,6 +149,8 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
|
|||
songTitleTextView = rootView.findViewById(R.id.download_song_title);
|
||||
albumArtImageView = rootView.findViewById(R.id.download_album_art_image);
|
||||
albumArtBackgroundView = rootView.findViewById(R.id.download_album_art_background);
|
||||
albumArtBackgroundImageView = rootView.findViewById(R.id.download_album_art_background_image);
|
||||
nowPlayingView = rootView.findViewById(R.id.now_playing_top);
|
||||
positionTextView = rootView.findViewById(R.id.download_position);
|
||||
durationTextView = rootView.findViewById(R.id.download_duration);
|
||||
statusTextView = rootView.findViewById(R.id.download_status);
|
||||
|
@ -196,7 +193,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
|
|||
return null;
|
||||
}
|
||||
}.execute();
|
||||
setControlsVisible(true);
|
||||
});
|
||||
previousButton.setOnRepeatListener(() -> changeProgress(true));
|
||||
|
||||
|
@ -209,7 +205,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
|
|||
return true;
|
||||
}
|
||||
}.execute();
|
||||
setControlsVisible(true);
|
||||
});
|
||||
nextButton.setOnRepeatListener(() -> changeProgress(false));
|
||||
|
||||
|
@ -264,12 +259,10 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
|
|||
break;
|
||||
}
|
||||
updateRepeatButton();
|
||||
setControlsVisible(true);
|
||||
});
|
||||
|
||||
toggleListButton.setOnClickListener(view -> {
|
||||
toggleFullscreenAlbumArt();
|
||||
setControlsVisible(true);
|
||||
});
|
||||
|
||||
View overlay = rootView.findViewById(R.id.download_overlay_buttons);
|
||||
|
@ -303,7 +296,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
|
|||
public void onProgressChanged(final SeekBar seekBar, final int position, final boolean fromUser) {
|
||||
if (fromUser) {
|
||||
positionTextView.setText(Util.formatDuration(position / 1000));
|
||||
setControlsVisible(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -468,7 +460,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
|
|||
if (controller != null) {
|
||||
SubsonicFragment fragment = new EqualizerFragment();
|
||||
replaceFragment(fragment);
|
||||
setControlsVisible(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -505,19 +496,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
|
|||
}
|
||||
|
||||
private void onResumeHandlers() {
|
||||
executorService = Executors.newSingleThreadScheduledExecutor();
|
||||
setControlsVisible(true);
|
||||
|
||||
final DownloadService downloadService = getDownloadService();
|
||||
if (downloadService == null || downloadService.getCurrentPlaying() == null || startFlipped) {
|
||||
playlistFlipper.setDisplayedChild(1);
|
||||
startFlipped = false;
|
||||
}
|
||||
|
||||
if (currentPlaying == null && downloadService != null && null == downloadService.getCurrentPlaying()) {
|
||||
setAlbumArt(null, false);
|
||||
}
|
||||
|
||||
context.runWhenServiceAvailable(() -> {
|
||||
if (primaryFragment) {
|
||||
DownloadService downloadService1 = getDownloadService();
|
||||
|
@ -535,11 +513,9 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
|
|||
}
|
||||
|
||||
private void onPauseHandlers() {
|
||||
if (executorService != null) {
|
||||
DownloadService downloadService = getDownloadService();
|
||||
if (downloadService != null) {
|
||||
downloadService.removeOnSongChangeListener(this);
|
||||
}
|
||||
DownloadService downloadService = getDownloadService();
|
||||
if (downloadService != null) {
|
||||
downloadService.removeOnSongChangeListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -576,29 +552,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
|
|||
return songListAdapter;
|
||||
}
|
||||
|
||||
private void scheduleHideControls() {
|
||||
if (hideControlsFuture != null) {
|
||||
hideControlsFuture.cancel(false);
|
||||
}
|
||||
|
||||
final Handler handler = new Handler();
|
||||
Runnable runnable = () -> handler.post(() -> setControlsVisible(false));
|
||||
hideControlsFuture = executorService.schedule(runnable, 3000L, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void setControlsVisible(boolean visible) {
|
||||
try {
|
||||
long duration = 1700L;
|
||||
FadeOutAnimation.createAndStart(rootView.findViewById(R.id.download_overlay_buttons), !visible, duration);
|
||||
|
||||
if (visible) {
|
||||
scheduleHideControls();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll to current playing/downloading.
|
||||
private void scrollToCurrent() {
|
||||
if (getDownloadService() == null || songListAdapter == null) {
|
||||
|
@ -688,7 +641,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
|
|||
|
||||
@Override
|
||||
public boolean onDown(MotionEvent me) {
|
||||
setControlsVisible(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -808,11 +760,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
|
|||
setAlbumArt(song, true);
|
||||
|
||||
DownloadService downloadService = getDownloadService();
|
||||
if (downloadService.isShufflePlayEnabled()) {
|
||||
setSubtitle(context.getResources().getString(R.string.download_playerstate_playing_shuffle));
|
||||
} else {
|
||||
setSubtitle(context.getResources().getString(R.string.download_playing_out_of, currentPlayingIndex + 1, currentPlayingSize));
|
||||
}
|
||||
} else {
|
||||
songTitleTextView.setText(null);
|
||||
setAlbumArt(null, false);
|
||||
|
@ -941,7 +888,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
|
|||
getImageLoader().loadImage(albumArtImageView, song, true, crossfade);
|
||||
if (Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_BLURRED_BACKGROUND, true)) {
|
||||
albumArtBackgroundView.setVisibility(ImageView.VISIBLE);
|
||||
getImageLoader().loadBlurImage(albumArtBackgroundView, song, true, crossfade);
|
||||
getImageLoader().loadBlurImage(albumArtBackgroundImageView, song, true, crossfade);
|
||||
} else {
|
||||
albumArtBackgroundView.setVisibility(ImageView.GONE);
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package net.nullsum.audinaut.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
|
@ -10,6 +8,10 @@ import android.view.MenuItem;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.adapter.ArtistAdapter;
|
||||
import net.nullsum.audinaut.adapter.EntryGridAdapter;
|
||||
|
@ -203,7 +205,7 @@ public class SearchFragment extends SubsonicFragment implements SectionAdapter.O
|
|||
task.execute();
|
||||
|
||||
if (searchItem != null) {
|
||||
searchItem.collapseActionView();
|
||||
MenuItemCompat.collapseActionView(searchItem);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -169,7 +169,7 @@ public class SelectArtistFragment extends SelectRecyclerFragment<Serializable> i
|
|||
String musicFolderId = Util.getSelectedMusicFolderId(context);
|
||||
|
||||
Indexes indexes = musicService.getIndexes(musicFolderId, refresh, context, listener);
|
||||
indexes.sortChildren(context);
|
||||
indexes.sortChildren();
|
||||
items = new ArrayList<>(indexes.getShortcuts().size() + indexes.getArtists().size());
|
||||
items.addAll(indexes.getShortcuts());
|
||||
items.addAll(indexes.getArtists());
|
||||
|
@ -184,8 +184,7 @@ public class SelectArtistFragment extends SelectRecyclerFragment<Serializable> i
|
|||
}
|
||||
|
||||
Indexes indexes = new Indexes();
|
||||
//indexes.setArtists = artists;
|
||||
indexes.sortChildren(context);
|
||||
indexes.sortChildren();
|
||||
items = new ArrayList<>(indexes.getArtists());
|
||||
|
||||
entries = dir.getChildren(false, true);
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
package net.nullsum.audinaut.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
|
@ -11,6 +8,10 @@ import android.view.MenuItem;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.adapter.AlphabeticalAlbumAdapter;
|
||||
import net.nullsum.audinaut.adapter.EntryGridAdapter;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package net.nullsum.audinaut.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
|
@ -9,6 +8,8 @@ import android.view.View;
|
|||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.adapter.PlaylistAdapter;
|
||||
import net.nullsum.audinaut.adapter.SectionAdapter;
|
||||
|
|
|
@ -16,8 +16,6 @@
|
|||
package net.nullsum.audinaut.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
|
@ -25,6 +23,9 @@ import android.view.MenuInflater;
|
|||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.adapter.SectionAdapter;
|
||||
import net.nullsum.audinaut.service.MusicService;
|
||||
|
|
|
@ -28,6 +28,7 @@ import android.preference.ListPreference;
|
|||
import android.preference.Preference;
|
||||
import android.preference.PreferenceCategory;
|
||||
import android.preference.PreferenceScreen;
|
||||
import android.preference.SwitchPreference;
|
||||
import android.text.InputType;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
@ -469,6 +470,12 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
|
|||
serverPasswordPreference.setSummary("***");
|
||||
serverPasswordPreference.setTitle(R.string.settings_server_password);
|
||||
|
||||
final SwitchPreference authMethodPreference = new SwitchPreference(context);
|
||||
authMethodPreference.setKey(Constants.PREFERENCES_KEY_AUTH_METHOD + instance);
|
||||
authMethodPreference.setSummary(R.string.settings_auth_summary);
|
||||
authMethodPreference.setDefaultValue(true); // use Token/Salt by default
|
||||
authMethodPreference.setTitle(R.string.settings_auth_method);
|
||||
|
||||
final Preference serverOpenBrowser = new Preference(context);
|
||||
serverOpenBrowser.setKey(Constants.PREFERENCES_KEY_OPEN_BROWSER);
|
||||
serverOpenBrowser.setPersistent(false);
|
||||
|
@ -523,13 +530,24 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
|
|||
return false;
|
||||
});
|
||||
|
||||
Preference serverStartScanPreference = new Preference(context);
|
||||
serverStartScanPreference.setKey(Constants.PREFERENCES_KEY_START_SCAN + instance);
|
||||
serverStartScanPreference.setPersistent(false);
|
||||
serverStartScanPreference.setTitle(R.string.settings_start_scan_title);
|
||||
serverStartScanPreference.setOnPreferenceClickListener(preference -> {
|
||||
startScan(instance);
|
||||
return false;
|
||||
});
|
||||
|
||||
screen.addPreference(serverNamePreference);
|
||||
screen.addPreference(serverUrlPreference);
|
||||
screen.addPreference(serverInternalUrlPreference);
|
||||
screen.addPreference(serverLocalNetworkSSIDPreference);
|
||||
screen.addPreference(serverUsernamePreference);
|
||||
screen.addPreference(serverPasswordPreference);
|
||||
screen.addPreference(authMethodPreference);
|
||||
screen.addPreference(serverTestConnectionPreference);
|
||||
screen.addPreference(serverStartScanPreference);
|
||||
screen.addPreference(serverOpenBrowser);
|
||||
screen.addPreference(serverRemoveServerPreference);
|
||||
|
||||
|
@ -599,6 +617,42 @@ public class SettingsFragment extends PreferenceCompatFragment implements Shared
|
|||
}
|
||||
}
|
||||
|
||||
private void startScan(final int instance) {
|
||||
LoadingTask<Boolean> task = new LoadingTask<Boolean>(context) {
|
||||
@Override
|
||||
protected Boolean doInBackground() throws Throwable {
|
||||
MusicService musicService = MusicServiceFactory.getOnlineService();
|
||||
|
||||
try {
|
||||
musicService.setInstance(instance);
|
||||
musicService.startScan(context);
|
||||
return true;
|
||||
} finally {
|
||||
musicService.setInstance(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done(Boolean licenseValid) {
|
||||
Log.d(TAG, "Finished media scan start");
|
||||
Util.toast(context, R.string.settings_media_scan_started);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel() {
|
||||
super.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void error(Throwable error) {
|
||||
Log.w(TAG, error.toString(), error);
|
||||
new ErrorDialog(context, getResources().getString(R.string.settings_media_scan_start_failed) +
|
||||
" " + getErrorMessage(error), false);
|
||||
}
|
||||
};
|
||||
task.execute();
|
||||
}
|
||||
|
||||
private void testConnection(final int instance) {
|
||||
LoadingTask<Boolean> task = new LoadingTask<Boolean>(context) {
|
||||
private int previousInstance;
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
*/
|
||||
package net.nullsum.audinaut.fragments;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.SearchManager;
|
||||
import android.app.SearchableInfo;
|
||||
import android.content.Context;
|
||||
|
@ -26,13 +25,6 @@ import android.content.SharedPreferences;
|
|||
import android.media.MediaMetadataRetriever;
|
||||
import android.os.Bundle;
|
||||
import android.os.StatFs;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.SearchView;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.Menu;
|
||||
|
@ -46,6 +38,16 @@ import android.widget.CheckBox;
|
|||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.widget.SearchView;
|
||||
import androidx.core.view.MenuItemCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.activity.SubsonicActivity;
|
||||
import net.nullsum.audinaut.adapter.SectionAdapter;
|
||||
|
@ -151,7 +153,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||
void onFinishSetupOptionsMenu(final Menu menu) {
|
||||
searchItem = menu.findItem(R.id.menu_global_search);
|
||||
if (searchItem != null) {
|
||||
searchView = (SearchView) searchItem.getActionView();
|
||||
searchView = (SearchView) MenuItemCompat.getActionView(searchItem);
|
||||
SearchManager searchManager = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
|
||||
SearchableInfo searchableInfo = searchManager.getSearchableInfo(context.getComponentName());
|
||||
if (searchableInfo == null) {
|
||||
|
@ -1444,7 +1446,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
|
|||
boolean playNowOverride = false;
|
||||
List<Entry> songs = new ArrayList<>();
|
||||
|
||||
public RecursiveLoader(Activity context) {
|
||||
public RecursiveLoader(AppCompatActivity context) {
|
||||
super(context);
|
||||
musicService = MusicServiceFactory.getMusicService(context);
|
||||
}
|
||||
|
|
|
@ -139,30 +139,6 @@ public class AudinautSearchProvider extends ContentProvider {
|
|||
cursor.addRow(new Object[]{artist.getId().hashCode(), artist.getName(), null, "ar-" + artist.getId(), artist.getName(), icon});
|
||||
} else {
|
||||
MusicDirectory.Entry entry = (MusicDirectory.Entry) obj;
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
String icon = RESOURCE_PREFIX + R.drawable.ic_action_album;
|
||||
cursor.addRow(new Object[]{entry.getId().hashCode(), entry.getTitle(), entry.getArtist(), entry.getId(), entry.getTitle(), icon});
|
||||
} else {
|
||||
String icon = RESOURCE_PREFIX + R.drawable.ic_action_song;
|
||||
String id;
|
||||
id = entry.getAlbumId();
|
||||
|
||||
String artistDisplay;
|
||||
if (entry.getArtist() == null) {
|
||||
if (entry.getAlbum() != null) {
|
||||
artistDisplay = entry.getAlbumDisplay();
|
||||
} else {
|
||||
artistDisplay = "";
|
||||
}
|
||||
} else if (entry.getAlbum() != null) {
|
||||
artistDisplay = entry.getArtist() + " - " + entry.getAlbumDisplay();
|
||||
} else {
|
||||
artistDisplay = entry.getArtist();
|
||||
}
|
||||
|
||||
cursor.addRow(new Object[]{entry.getId().hashCode(), entry.getTitle(), artistDisplay, "so-" + id, entry.getTitle(), icon});
|
||||
}
|
||||
}
|
||||
}
|
||||
return cursor;
|
||||
|
|
|
@ -34,6 +34,7 @@ import android.graphics.PorterDuff.Mode;
|
|||
import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
@ -239,11 +240,15 @@ public class AudinautWidgetProvider extends AppWidgetProvider {
|
|||
|
||||
// Set correct drawable for pause state
|
||||
if (playing) {
|
||||
views.setImageViewResource(R.id.control_play, R.drawable.media_pause_dark);
|
||||
views.setImageViewResource(R.id.control_play, R.drawable.widget_media_pause);
|
||||
} else {
|
||||
views.setImageViewResource(R.id.control_play, R.drawable.media_start_dark);
|
||||
views.setImageViewResource(R.id.control_play, R.drawable.widget_media_start);
|
||||
}
|
||||
|
||||
// Set next/back button images
|
||||
views.setImageViewResource(R.id.control_next, R.drawable.widget_media_forward);
|
||||
views.setImageViewResource(R.id.control_previous, R.drawable.widget_media_backward);
|
||||
|
||||
// Set the cover art
|
||||
try {
|
||||
boolean large = false;
|
||||
|
@ -286,19 +291,28 @@ public class AudinautWidgetProvider extends AppWidgetProvider {
|
|||
intent = new Intent("Audinaut.PLAY_PAUSE");
|
||||
intent.setComponent(new ComponentName(context, DownloadService.class));
|
||||
intent.setAction(DownloadService.CMD_TOGGLEPAUSE);
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
if (Build.VERSION.SDK_INT >= 26)
|
||||
pendingIntent = PendingIntent.getForegroundService(context, 0, intent, 0);
|
||||
else
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.control_play, pendingIntent);
|
||||
|
||||
intent = new Intent("Audinaut.NEXT"); // Use a unique action name to ensure a different PendingIntent to be created.
|
||||
intent.setComponent(new ComponentName(context, DownloadService.class));
|
||||
intent.setAction(DownloadService.CMD_NEXT);
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
if (Build.VERSION.SDK_INT >= 26)
|
||||
pendingIntent = PendingIntent.getForegroundService(context, 0, intent, 0);
|
||||
else
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.control_next, pendingIntent);
|
||||
|
||||
intent = new Intent("Audinaut.PREVIOUS"); // Use a unique action name to ensure a different PendingIntent to be created.
|
||||
intent.setComponent(new ComponentName(context, DownloadService.class));
|
||||
intent.setAction(DownloadService.CMD_PREVIOUS);
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
if (Build.VERSION.SDK_INT >= 26)
|
||||
pendingIntent = PendingIntent.getForegroundService(context, 0, intent, 0);
|
||||
else
|
||||
pendingIntent = PendingIntent.getService(context, 0, intent, 0);
|
||||
views.setOnClickPendingIntent(R.id.control_previous, pendingIntent);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,21 +24,30 @@ import net.nullsum.audinaut.service.DownloadService;
|
|||
import net.nullsum.audinaut.util.Constants;
|
||||
|
||||
public class PlayActionReceiver extends BroadcastReceiver {
|
||||
private Bundle lastdata = null;
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (lastdata.equals(intent.getBundleExtra(Constants.TASKER_EXTRA_BUNDLE))) {
|
||||
// nothing has changed; we can safely return
|
||||
return;
|
||||
}
|
||||
updateValues(intent);
|
||||
if (intent.hasExtra(Constants.TASKER_EXTRA_BUNDLE)) {
|
||||
Bundle data = intent.getBundleExtra(Constants.TASKER_EXTRA_BUNDLE);
|
||||
Boolean startShuffled = data.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE);
|
||||
Boolean startShuffled = lastdata.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE);
|
||||
|
||||
Intent start = new Intent(context, DownloadService.class);
|
||||
start.setAction(DownloadService.START_PLAY);
|
||||
start.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, startShuffled);
|
||||
start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, data.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR));
|
||||
start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, data.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR));
|
||||
start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, data.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE));
|
||||
start.putExtra(Constants.PREFERENCES_KEY_OFFLINE, data.getInt(Constants.PREFERENCES_KEY_OFFLINE));
|
||||
start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, lastdata.getString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR));
|
||||
start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, lastdata.getString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR));
|
||||
start.putExtra(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, lastdata.getString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE));
|
||||
start.putExtra(Constants.PREFERENCES_KEY_OFFLINE, lastdata.getInt(Constants.PREFERENCES_KEY_OFFLINE));
|
||||
context.startService(start);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateValues(Intent intent) {
|
||||
lastdata = intent.getBundleExtra(Constants.TASKER_EXTRA_BUNDLE);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,6 @@ 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.util.FileUtil;
|
||||
import net.nullsum.audinaut.util.ProgressListener;
|
||||
import net.nullsum.audinaut.util.SilentBackgroundTask;
|
||||
|
@ -617,21 +616,8 @@ public class CachedMusicService implements MusicService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) {
|
||||
User result = null;
|
||||
|
||||
try {
|
||||
result = musicService.getUser(refresh, username, context, progressListener);
|
||||
FileUtil.serialize(context, result, getCacheName(context, "user-" + username));
|
||||
} catch (Exception e) {
|
||||
// Don't care
|
||||
}
|
||||
|
||||
if (result == null && !refresh) {
|
||||
result = FileUtil.deserialize(context, getCacheName(context, "user-" + username), User.class);
|
||||
}
|
||||
|
||||
return result;
|
||||
public void startScan(Context c) throws Exception {
|
||||
musicService.startScan(c);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -32,9 +32,10 @@ import android.os.Handler;
|
|||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.PowerManager;
|
||||
import android.support.v4.util.LruCache;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.collection.LruCache;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.activity.SubsonicActivity;
|
||||
import net.nullsum.audinaut.audiofx.AudioEffectsController;
|
||||
|
@ -60,7 +61,6 @@ import java.util.Collections;
|
|||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import static net.nullsum.audinaut.domain.PlayerState.COMPLETED;
|
||||
import static net.nullsum.audinaut.domain.PlayerState.DOWNLOADING;
|
||||
import static net.nullsum.audinaut.domain.PlayerState.IDLE;
|
||||
import static net.nullsum.audinaut.domain.PlayerState.PAUSED;
|
||||
|
@ -949,8 +949,7 @@ public class DownloadService extends Service {
|
|||
|
||||
public synchronized void next(boolean forceStart) {
|
||||
// If only one song, just skip within song
|
||||
if (size() == 1 || (currentPlaying != null && !currentPlaying.isSong())) {
|
||||
fastForward();
|
||||
if (currentPlaying != null && !currentPlaying.isSong()) {
|
||||
return;
|
||||
} else if (playerState == PREPARING || playerState == PREPARED) {
|
||||
return;
|
||||
|
@ -958,8 +957,7 @@ public class DownloadService extends Service {
|
|||
|
||||
int index = getCurrentPlayingIndex();
|
||||
int nextPlayingIndex = getNextPlayingIndex();
|
||||
// Make sure to actually go to next when repeat song is on
|
||||
if (index == nextPlayingIndex) {
|
||||
if (index == nextPlayingIndex && size() > 1) {
|
||||
nextPlayingIndex++;
|
||||
}
|
||||
if (index != -1 && nextPlayingIndex < size()) {
|
||||
|
|
|
@ -28,7 +28,6 @@ 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.util.ProgressListener;
|
||||
import net.nullsum.audinaut.util.SilentBackgroundTask;
|
||||
|
||||
|
@ -87,7 +86,7 @@ public interface MusicService {
|
|||
|
||||
MusicDirectory getSongsByGenre(String genre, int count, int offset, Context context, ProgressListener progressListener) throws Exception;
|
||||
|
||||
User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception;
|
||||
void startScan(Context c) throws Exception;
|
||||
|
||||
void setInstance(Integer instance) throws Exception;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ 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.util.Constants;
|
||||
import net.nullsum.audinaut.util.FileUtil;
|
||||
import net.nullsum.audinaut.util.ProgressListener;
|
||||
|
@ -70,6 +69,7 @@ public class OfflineMusicService implements MusicService {
|
|||
public Indexes getIndexes(String musicFolderId, boolean refresh, Context context, ProgressListener progressListener) {
|
||||
List<Artist> artists = new ArrayList<>();
|
||||
List<Entry> entries = new ArrayList<>();
|
||||
|
||||
File root = FileUtil.getMusicDirectory(context);
|
||||
for (File file : FileUtil.listFiles(root)) {
|
||||
if (file.isDirectory()) {
|
||||
|
@ -499,7 +499,7 @@ public class OfflineMusicService implements MusicService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception {
|
||||
public void startScan(Context c) throws Exception {
|
||||
throw new OfflineException();
|
||||
}
|
||||
|
||||
|
|
|
@ -21,9 +21,11 @@ package net.nullsum.audinaut.service;
|
|||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.domain.Genre;
|
||||
import net.nullsum.audinaut.domain.Indexes;
|
||||
import net.nullsum.audinaut.domain.MusicDirectory;
|
||||
|
@ -31,7 +33,6 @@ 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.service.parser.EntryListParser;
|
||||
import net.nullsum.audinaut.service.parser.ErrorParser;
|
||||
|
@ -43,7 +44,6 @@ import net.nullsum.audinaut.service.parser.PlaylistParser;
|
|||
import net.nullsum.audinaut.service.parser.PlaylistsParser;
|
||||
import net.nullsum.audinaut.service.parser.RandomSongsParser;
|
||||
import net.nullsum.audinaut.service.parser.SearchResult2Parser;
|
||||
import net.nullsum.audinaut.service.parser.UserParser;
|
||||
import net.nullsum.audinaut.util.Constants;
|
||||
import net.nullsum.audinaut.util.FileUtil;
|
||||
import net.nullsum.audinaut.util.Pair;
|
||||
|
@ -60,11 +60,8 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import okhttp3.FormBody;
|
||||
import okhttp3.FormBody.Builder;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
/**
|
||||
|
@ -593,7 +590,7 @@ public class RESTMusicService implements MusicService {
|
|||
public Response getDownloadInputStream(Context context, MusicDirectory.Entry song, long offset, int maxBitrate, SilentBackgroundTask task) throws Exception {
|
||||
|
||||
OkHttpClient eagerClient = client.newBuilder()
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(Util.getNetworkTimeoutMs(context), TimeUnit.MILLISECONDS)
|
||||
.build();
|
||||
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
|
@ -658,24 +655,17 @@ public class RESTMusicService implements MusicService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public User getUser(boolean refresh, String username, Context context, ProgressListener progressListener) throws Exception {
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
public void startScan(Context context) throws Exception {
|
||||
String url = getRestUrl(context, "startScan", null);
|
||||
|
||||
parameters.put("username", username);
|
||||
|
||||
String url = getRestUrl(context, "getUser", parameters);
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(url)
|
||||
.build();
|
||||
Request request = new Request.Builder().url(url).build();
|
||||
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
List<User> users = new UserParser(context, getInstance(context)).parse(response.body().byteStream());
|
||||
if (users.size() > 0) {
|
||||
// Should only have returned one anyways
|
||||
return users.get(0);
|
||||
if (response.isSuccessful()) {
|
||||
Log.d(TAG, "Media scan started" + response.toString());
|
||||
} else {
|
||||
return null;
|
||||
Log.w(TAG, "media scan start failed" + response.toString());
|
||||
Util.toast(context, R.string.settings_media_scan_start_failed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,13 @@
|
|||
*/
|
||||
package net.nullsum.audinaut.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.view.ErrorDialog;
|
||||
|
||||
|
@ -79,8 +80,8 @@ public abstract class BackgroundTask<T> implements ProgressListener {
|
|||
}
|
||||
}
|
||||
|
||||
private Activity getActivity() {
|
||||
return (context instanceof Activity) ? ((Activity) context) : null;
|
||||
private AppCompatActivity getActivity() {
|
||||
return (context instanceof AppCompatActivity) ? ((AppCompatActivity) context) : null;
|
||||
}
|
||||
|
||||
Handler getHandler() {
|
||||
|
@ -95,7 +96,7 @@ public abstract class BackgroundTask<T> implements ProgressListener {
|
|||
|
||||
protected void error(Throwable error) {
|
||||
Log.w(TAG, "Got exception: " + error, error);
|
||||
Activity activity = getActivity();
|
||||
AppCompatActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
new ErrorDialog(activity, getErrorMessage(error), true);
|
||||
}
|
||||
|
|
|
@ -2,6 +2,10 @@ package net.nullsum.audinaut.util;
|
|||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorMatrix;
|
||||
import android.graphics.ColorMatrixColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.renderscript.Allocation;
|
||||
import android.renderscript.Element;
|
||||
import android.renderscript.RenderScript;
|
||||
|
@ -12,6 +16,15 @@ class BlurBuilder {
|
|||
private static final float BLUR_RADIUS = 25f;
|
||||
|
||||
public static Bitmap blur(Context context, Bitmap image) {
|
||||
Bitmap newImage = image;
|
||||
for(int i = 0; i<3; i++) {
|
||||
newImage = blur_real(context, newImage);
|
||||
}
|
||||
newImage = changeBitmapContrastBrightness(newImage, 0.5f, 48);
|
||||
return newImage;
|
||||
}
|
||||
|
||||
private static Bitmap blur_real(Context context, Bitmap image) {
|
||||
int width = Math.round(image.getWidth() * BITMAP_SCALE);
|
||||
int height = Math.round(image.getHeight() * BITMAP_SCALE);
|
||||
|
||||
|
@ -29,4 +42,25 @@ class BlurBuilder {
|
|||
|
||||
return outputBitmap;
|
||||
}
|
||||
|
||||
public static Bitmap changeBitmapContrastBrightness(Bitmap bmp, float contrast, float brightness)
|
||||
{
|
||||
ColorMatrix cm = new ColorMatrix(new float[]
|
||||
{
|
||||
contrast, 0, 0, 0, brightness,
|
||||
0, contrast, 0, 0, brightness,
|
||||
0, 0, contrast, 0, brightness,
|
||||
0, 0, 0, 1, 0
|
||||
});
|
||||
|
||||
Bitmap ret = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), bmp.getConfig());
|
||||
|
||||
Canvas canvas = new Canvas(ret);
|
||||
|
||||
Paint paint = new Paint();
|
||||
paint.setColorFilter(new ColorMatrixColorFilter(cm));
|
||||
canvas.drawBitmap(bmp, 0, 0, paint);
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,10 +67,12 @@ public final class Constants {
|
|||
public static final String PREFERENCES_KEY_SERVER_INTERNAL_URL = "serverInternalUrl";
|
||||
public static final String PREFERENCES_KEY_SERVER_LOCAL_NETWORK_SSID = "serverLocalNetworkSSID";
|
||||
public static final String PREFERENCES_KEY_TEST_CONNECTION = "serverTestConnection";
|
||||
public static final String PREFERENCES_KEY_START_SCAN = "serverStartScan";
|
||||
public static final String PREFERENCES_KEY_OPEN_BROWSER = "openBrowser";
|
||||
public static final String PREFERENCES_KEY_MUSIC_FOLDER_ID = "musicFolderId";
|
||||
public static final String PREFERENCES_KEY_USERNAME = "username";
|
||||
public static final String PREFERENCES_KEY_PASSWORD = "password";
|
||||
public static final String PREFERENCES_KEY_AUTH_METHOD = "authMethod";
|
||||
public static final String PREFERENCES_KEY_THEME = "theme";
|
||||
public static final String PREFERENCES_KEY_FULL_SCREEN = "fullScreen";
|
||||
public static final String PREFERENCES_KEY_DISPLAY_TRACK = "displayTrack";
|
||||
|
@ -121,7 +123,6 @@ public final class Constants {
|
|||
public static final String PREFERENCES_KEY_ALBUMS_PER_FOLDER = "albumsPerFolder";
|
||||
public static final String PREFERENCES_KEY_FIRST_LEVEL_ARTIST = "firstLevelArtist";
|
||||
public static final String PREFERENCES_KEY_START_ON_HEADPHONES = "startOnHeadphones";
|
||||
public static final String PREFERENCES_KEY_COLOR_ACTION_BAR = "colorActionBar";
|
||||
public static final String PREFERENCES_KEY_SHUFFLE_BY_ALBUM = "shuffleByAlbum";
|
||||
public static final String PREFERENCES_KEY_BATCH_MODE = "batchMode";
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package net.nullsum.audinaut.util;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import net.nullsum.audinaut.adapter.SectionAdapter;
|
||||
import net.nullsum.audinaut.fragments.SubsonicFragment;
|
||||
|
|
|
@ -20,11 +20,12 @@ import android.content.res.Resources;
|
|||
import android.content.res.TypedArray;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.annotation.AttrRes;
|
||||
import android.support.annotation.DrawableRes;
|
||||
import android.util.SparseArray;
|
||||
import android.util.TypedValue;
|
||||
|
||||
import androidx.annotation.AttrRes;
|
||||
import androidx.annotation.DrawableRes;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
|
||||
import java.util.WeakHashMap;
|
||||
|
|
|
@ -23,9 +23,10 @@ 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 androidx.core.content.ContextCompat;
|
||||
|
||||
import com.esotericsoftware.kryo.Kryo;
|
||||
import com.esotericsoftware.kryo.io.Input;
|
||||
import com.esotericsoftware.kryo.io.Output;
|
||||
|
@ -65,7 +66,7 @@ public class FileUtil {
|
|||
private static final String TAG = FileUtil.class.getSimpleName();
|
||||
private static final String[] FILE_SYSTEM_UNSAFE = {"/", "\\", "..", ":", "\"", "?", "*", "<", ">", "|"};
|
||||
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", "opus", "aac", "flac", "m4a", "wav", "wma");
|
||||
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 Kryo kryo = new Kryo();
|
||||
|
|
|
@ -30,13 +30,14 @@ import android.graphics.drawable.Drawable;
|
|||
import android.graphics.drawable.TransitionDrawable;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.support.v4.util.LruCache;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.collection.LruCache;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.domain.MusicDirectory;
|
||||
import net.nullsum.audinaut.domain.Playlist;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package net.nullsum.audinaut.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import net.nullsum.audinaut.activity.SubsonicActivity;
|
||||
|
||||
/**
|
||||
|
@ -11,17 +12,17 @@ import net.nullsum.audinaut.activity.SubsonicActivity;
|
|||
*/
|
||||
public abstract class LoadingTask<T> extends BackgroundTask<T> {
|
||||
|
||||
private final Activity tabActivity;
|
||||
private final AppCompatActivity tabActivity;
|
||||
private final boolean cancellable;
|
||||
private ProgressDialog loading;
|
||||
|
||||
public LoadingTask(Activity activity) {
|
||||
public LoadingTask(AppCompatActivity activity) {
|
||||
super(activity);
|
||||
tabActivity = activity;
|
||||
this.cancellable = true;
|
||||
}
|
||||
|
||||
public LoadingTask(Activity activity, final boolean cancellable) {
|
||||
public LoadingTask(AppCompatActivity activity, final boolean cancellable) {
|
||||
super(activity);
|
||||
tabActivity = activity;
|
||||
this.cancellable = cancellable;
|
||||
|
|
|
@ -23,13 +23,16 @@ import android.content.ComponentName;
|
|||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.support.v4.media.MediaMetadataCompat;
|
||||
import android.support.v4.media.session.MediaSessionCompat;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.media.app.NotificationCompat.MediaStyle;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.activity.SubsonicActivity;
|
||||
|
@ -66,28 +69,52 @@ public final class Notifications {
|
|||
}
|
||||
|
||||
final boolean playing = downloadService.getPlayerState() == PlayerState.STARTED;
|
||||
|
||||
RemoteViews expandedContentView = new RemoteViews(context.getPackageName(), R.layout.notification_expanded);
|
||||
setupViews(expandedContentView, context, song, true, playing);
|
||||
|
||||
RemoteViews smallContentView = new RemoteViews(context.getPackageName(), R.layout.notification);
|
||||
setupViews(smallContentView, context, song, false, playing);
|
||||
|
||||
Intent notificationIntent = new Intent(context, SubsonicFragmentActivity.class);
|
||||
notificationIntent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true);
|
||||
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
|
||||
final Notification notification = new NotificationCompat.Builder(context, CHANNEL_PLAYING_ID)
|
||||
Intent cancelIntent = new Intent("KEYCODE_MEDIA_STOP")
|
||||
.setComponent(new ComponentName(context, DownloadService.class))
|
||||
.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_STOP));
|
||||
int[] compactActions = new int[]{0, 1, 2};
|
||||
|
||||
MediaSessionCompat mediaSession = new MediaSessionCompat(context, "Audinaut");
|
||||
MediaSessionCompat.Token mediaToken = mediaSession.getSessionToken();
|
||||
MediaMetadataCompat.Builder metadataBuilder = new MediaMetadataCompat.Builder();
|
||||
|
||||
mediaSession.setMetadata(metadataBuilder
|
||||
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, -1)
|
||||
.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, getAlbumArt(context, song))
|
||||
//.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, R.drawable.notification_logo)
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, song.getTitle())
|
||||
.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, song.getArtist())
|
||||
.build() );
|
||||
|
||||
MediaStyle mediaStyle = new MediaStyle()
|
||||
.setShowActionsInCompactView(compactActions)
|
||||
.setShowCancelButton(true)
|
||||
.setCancelButtonIntent(PendingIntent.getService(context, 0, cancelIntent, 0))
|
||||
.setMediaSession(mediaToken);
|
||||
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_PLAYING_ID)
|
||||
.setChannelId(CHANNEL_PLAYING_ID)
|
||||
.setSmallIcon(R.drawable.stat_notify_playing)
|
||||
.setContentTitle(song.getTitle())
|
||||
.setContentText(song.getTitle())
|
||||
.setContentText(song.getArtist())
|
||||
.setSubText(song.getAlbum())
|
||||
.setTicker(song.getTitle())
|
||||
.setOngoing(playing)
|
||||
.setVisibility(Notification.VISIBILITY_PUBLIC)
|
||||
.setCustomContentView(smallContentView)
|
||||
.setCustomBigContentView(expandedContentView)
|
||||
.setContentIntent(PendingIntent.getActivity(context, 0, notificationIntent, 0))
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW).build();
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setShowWhen(false)
|
||||
.setLargeIcon(getAlbumArt(context, song))
|
||||
.setSmallIcon(R.drawable.notification_logo)
|
||||
.setStyle(mediaStyle)
|
||||
.setContentIntent(PendingIntent.getActivity(context, 0, notificationIntent, 0));
|
||||
addActions(context, builder, playing);
|
||||
final Notification notification = builder.build();
|
||||
|
||||
if(playing) {
|
||||
notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT;
|
||||
}
|
||||
|
||||
playShowing = true;
|
||||
if (downloadForeground && downloadShowing) {
|
||||
|
@ -115,13 +142,7 @@ public final class Notifications {
|
|||
AudinautWidgetProvider.notifyInstances(context, downloadService, playing);
|
||||
}
|
||||
|
||||
private static void setupViews(RemoteViews rv, Context context, MusicDirectory.Entry song, boolean expanded, boolean playing) {
|
||||
// Use the same text for the ticker and the expanded notification
|
||||
String title = song.getTitle();
|
||||
String arist = song.getArtist();
|
||||
String album = song.getAlbum();
|
||||
|
||||
// Set the album art.
|
||||
private static Bitmap getAlbumArt(Context context, MusicDirectory.Entry song) {
|
||||
try {
|
||||
ImageLoader imageLoader = SubsonicActivity.getStaticImageLoader(context);
|
||||
Bitmap bitmap = null;
|
||||
|
@ -130,89 +151,42 @@ public final class Notifications {
|
|||
}
|
||||
if (bitmap == null) {
|
||||
// set default album art
|
||||
rv.setImageViewResource(R.id.notification_image, R.drawable.unknown_album);
|
||||
return BitmapFactory.decodeResource(context.getResources(), R.drawable.unknown_album);
|
||||
} else {
|
||||
imageLoader.setNowPlayingSmall(bitmap);
|
||||
rv.setImageViewBitmap(R.id.notification_image, bitmap);
|
||||
return bitmap;
|
||||
}
|
||||
} catch (Exception x) {
|
||||
Log.w(TAG, "Failed to get notification cover art", x);
|
||||
rv.setImageViewResource(R.id.notification_image, R.drawable.unknown_album);
|
||||
return BitmapFactory.decodeResource(context.getResources(), R.drawable.unknown_album);
|
||||
}
|
||||
}
|
||||
|
||||
// set the text for the notifications
|
||||
rv.setTextViewText(R.id.notification_title, title);
|
||||
rv.setTextViewText(R.id.notification_artist, arist);
|
||||
rv.setTextViewText(R.id.notification_album, album);
|
||||
|
||||
boolean persistent = Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_PERSISTENT_NOTIFICATION, false);
|
||||
if (persistent) {
|
||||
if (expanded) {
|
||||
rv.setImageViewResource(R.id.control_pause, playing ? R.drawable.notification_pause : R.drawable.notification_start);
|
||||
|
||||
rv.setImageViewResource(R.id.control_previous, R.drawable.notification_backward);
|
||||
rv.setImageViewResource(R.id.control_next, R.drawable.notification_forward);
|
||||
} else {
|
||||
rv.setImageViewResource(R.id.control_previous, playing ? R.drawable.notification_pause : R.drawable.notification_start);
|
||||
rv.setImageViewResource(R.id.control_pause, R.drawable.notification_forward);
|
||||
rv.setImageViewResource(R.id.control_next, R.drawable.notification_close);
|
||||
}
|
||||
} else {
|
||||
// Necessary for switching back since it appears to re-use the same layout
|
||||
rv.setImageViewResource(R.id.control_previous, R.drawable.notification_backward);
|
||||
rv.setImageViewResource(R.id.control_next, R.drawable.notification_forward);
|
||||
}
|
||||
|
||||
// Create actions for media buttons
|
||||
private static void addActions(final Context context, final NotificationCompat.Builder builder, final boolean playing) {
|
||||
PendingIntent pendingIntent;
|
||||
int previous = 0, pause, next, close = 0;
|
||||
if (persistent && !expanded) {
|
||||
pause = R.id.control_previous;
|
||||
next = R.id.control_pause;
|
||||
close = R.id.control_next;
|
||||
} else {
|
||||
previous = R.id.control_previous;
|
||||
pause = R.id.control_pause;
|
||||
next = R.id.control_next;
|
||||
}
|
||||
|
||||
if (persistent && close == 0 && expanded) {
|
||||
close = R.id.notification_close;
|
||||
rv.setViewVisibility(close, View.VISIBLE);
|
||||
}
|
||||
|
||||
if (previous > 0) {
|
||||
Intent prevIntent = new Intent("KEYCODE_MEDIA_PREVIOUS");
|
||||
prevIntent.setComponent(new ComponentName(context, DownloadService.class));
|
||||
prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS));
|
||||
pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0);
|
||||
rv.setOnClickPendingIntent(previous, pendingIntent);
|
||||
}
|
||||
Intent prevIntent = new Intent("KEYCODE_MEDIA_PREVIOUS");
|
||||
prevIntent.setComponent(new ComponentName(context, DownloadService.class));
|
||||
prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS));
|
||||
pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0);
|
||||
builder.addAction(R.drawable.notification_media_backward, "Previous", pendingIntent);
|
||||
if (playing) {
|
||||
Intent pauseIntent = new Intent("KEYCODE_MEDIA_PLAY_PAUSE");
|
||||
pauseIntent.setComponent(new ComponentName(context, DownloadService.class));
|
||||
pauseIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
|
||||
pendingIntent = PendingIntent.getService(context, 0, pauseIntent, 0);
|
||||
rv.setOnClickPendingIntent(pause, pendingIntent);
|
||||
builder.addAction(R.drawable.notification_media_pause, "Pause", pendingIntent);
|
||||
} else {
|
||||
Intent prevIntent = new Intent("KEYCODE_MEDIA_START");
|
||||
prevIntent.setComponent(new ComponentName(context, DownloadService.class));
|
||||
prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY));
|
||||
pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0);
|
||||
rv.setOnClickPendingIntent(pause, pendingIntent);
|
||||
Intent playIntent = new Intent("KEYCODE_MEDIA_PLAY");
|
||||
playIntent.setComponent(new ComponentName(context, DownloadService.class));
|
||||
playIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY));
|
||||
pendingIntent = PendingIntent.getService(context, 0, playIntent, 0);
|
||||
builder.addAction(R.drawable.notification_media_start, "Play", pendingIntent);
|
||||
}
|
||||
Intent nextIntent = new Intent("KEYCODE_MEDIA_NEXT");
|
||||
nextIntent.setComponent(new ComponentName(context, DownloadService.class));
|
||||
nextIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT));
|
||||
pendingIntent = PendingIntent.getService(context, 0, nextIntent, 0);
|
||||
rv.setOnClickPendingIntent(next, pendingIntent);
|
||||
if (close > 0) {
|
||||
Intent prevIntent = new Intent("KEYCODE_MEDIA_STOP");
|
||||
prevIntent.setComponent(new ComponentName(context, DownloadService.class));
|
||||
prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_STOP));
|
||||
pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0);
|
||||
rv.setOnClickPendingIntent(close, pendingIntent);
|
||||
}
|
||||
builder.addAction(R.drawable.notification_media_forward, "Next", pendingIntent);
|
||||
}
|
||||
|
||||
public static void hidePlayingNotification(final Context context, final DownloadService downloadService, Handler handler) {
|
||||
|
|
|
@ -18,10 +18,9 @@ package net.nullsum.audinaut.util;
|
|||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.activity.SettingsActivity;
|
||||
import net.nullsum.audinaut.activity.SubsonicFragmentActivity;
|
||||
|
||||
public final class ThemeUtil {
|
||||
private static final String THEME_DARK = "dark";
|
||||
|
@ -32,7 +31,15 @@ public final class ThemeUtil {
|
|||
|
||||
public static String getTheme(Context context) {
|
||||
SharedPreferences prefs = Util.getPreferences(context);
|
||||
String theme = prefs.getString(Constants.PREFERENCES_KEY_THEME, null);
|
||||
String theme;
|
||||
|
||||
if (Build.VERSION.SDK_INT<29) {
|
||||
// If Android Pie or older, default to null (handled below as light)
|
||||
theme = prefs.getString(Constants.PREFERENCES_KEY_THEME, null);
|
||||
} else {
|
||||
// Else, for Android 10+, default to follow system dark mode setting
|
||||
theme = prefs.getString(Constants.PREFERENCES_KEY_THEME, THEME_DAY_NIGHT);
|
||||
}
|
||||
|
||||
if (THEME_DAY_NIGHT.equals(theme)) {
|
||||
int currentNightMode = context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
|
||||
|
@ -58,35 +65,16 @@ public final class ThemeUtil {
|
|||
}
|
||||
|
||||
private static int getThemeRes(Context context, String theme) {
|
||||
if (context instanceof SubsonicFragmentActivity || context instanceof SettingsActivity) {
|
||||
if (Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_COLOR_ACTION_BAR, true)) {
|
||||
switch (theme) {
|
||||
case THEME_DARK:
|
||||
return R.style.Theme_Audinaut_Dark_No_Actionbar;
|
||||
case THEME_BLACK:
|
||||
return R.style.Theme_Audinaut_Black_No_Actionbar;
|
||||
default:
|
||||
return R.style.Theme_Audinaut_Light_No_Actionbar;
|
||||
}
|
||||
} else {
|
||||
switch (theme) {
|
||||
case THEME_DARK:
|
||||
return R.style.Theme_Audinaut_Dark_No_Color;
|
||||
case THEME_BLACK:
|
||||
return R.style.Theme_Audinaut_Black_No_Color;
|
||||
default:
|
||||
return R.style.Theme_Audinaut_Light_No_Color;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (theme) {
|
||||
case THEME_DARK:
|
||||
return R.style.Theme_Audinaut_Dark;
|
||||
case THEME_BLACK:
|
||||
return R.style.Theme_Audinaut_Black;
|
||||
default:
|
||||
return R.style.Theme_Audinaut_Light;
|
||||
}
|
||||
if(theme == null)
|
||||
return R.style.Theme_Audinaut_Light;
|
||||
|
||||
switch (theme) {
|
||||
case THEME_DARK:
|
||||
return R.style.Theme_Audinaut_Dark;
|
||||
case THEME_BLACK:
|
||||
return R.style.Theme_Audinaut_Black;
|
||||
default:
|
||||
return R.style.Theme_Audinaut_Light;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,62 +17,8 @@ package net.nullsum.audinaut.util;
|
|||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.util.Log;
|
||||
|
||||
import net.nullsum.audinaut.domain.User;
|
||||
import net.nullsum.audinaut.service.MusicServiceFactory;
|
||||
|
||||
public final class UserUtil {
|
||||
private static final String TAG = UserUtil.class.getSimpleName();
|
||||
|
||||
private static int instance = -1;
|
||||
private static int instanceHash = -1;
|
||||
private static User currentUser;
|
||||
|
||||
public static void refreshCurrentUser(Context context) {
|
||||
currentUser = null;
|
||||
seedCurrentUser(context);
|
||||
}
|
||||
|
||||
public static void seedCurrentUser(Context context) {
|
||||
// Only try to seed if online
|
||||
if (Util.isOffline(context)) {
|
||||
currentUser = null;
|
||||
return;
|
||||
}
|
||||
|
||||
final int instance = Util.getActiveServer(context);
|
||||
final int instanceHash = (instance == 0) ? 0 : Util.getRestUrl(context).hashCode();
|
||||
if (UserUtil.instance == instance && UserUtil.instanceHash == instanceHash && currentUser != null) {
|
||||
return;
|
||||
} else {
|
||||
UserUtil.instance = instance;
|
||||
UserUtil.instanceHash = instanceHash;
|
||||
}
|
||||
|
||||
new SilentBackgroundTask<Void>(context) {
|
||||
@Override
|
||||
protected Void doInBackground() throws Throwable {
|
||||
currentUser = MusicServiceFactory.getMusicService(context).getUser(false, getCurrentUsername(context, instance), context, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void done(Void result) {
|
||||
if (context instanceof AppCompatActivity) {
|
||||
((AppCompatActivity) context).supportInvalidateOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void error(Throwable error) {
|
||||
// Don't do anything, supposed to be background pull
|
||||
Log.e(TAG, "Failed to seed user information");
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
private static String getCurrentUsername(Context context, int instance) {
|
||||
SharedPreferences prefs = Util.getPreferences(context);
|
||||
return prefs.getString(Constants.PREFERENCES_KEY_USERNAME + instance, null);
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
*/
|
||||
package net.nullsum.audinaut.util;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.ComponentName;
|
||||
|
@ -36,19 +35,23 @@ import android.net.NetworkInfo;
|
|||
import android.net.wifi.WifiManager;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.SpannableString;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.text.util.Linkify;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.adapter.DetailsAdapter;
|
||||
import net.nullsum.audinaut.domain.MusicDirectory;
|
||||
|
@ -118,6 +121,11 @@ public final class Util {
|
|||
editor.apply();
|
||||
}
|
||||
|
||||
public static int getNetworkTimeoutMs(Context context) {
|
||||
SharedPreferences prefs = getPreferences(context);
|
||||
return Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_NETWORK_TIMEOUT, "30000"));
|
||||
}
|
||||
|
||||
public static boolean isScreenLitOnDownload(Context context) {
|
||||
SharedPreferences prefs = getPreferences(context);
|
||||
return prefs.getBoolean(Constants.PREFERENCES_KEY_SCREEN_LIT_ON_DOWNLOAD, false);
|
||||
|
@ -297,6 +305,8 @@ public final class Util {
|
|||
private static String getRestUrl(Context context, String method, SharedPreferences prefs, int instance, boolean allowAltAddress, @Nullable Map<String, String> parameters) {
|
||||
String serverUrl = prefs.getString(Constants.PREFERENCES_KEY_SERVER_URL + instance, null);
|
||||
|
||||
if (serverUrl == null) return "OFFLINE";
|
||||
|
||||
HttpUrl.Builder builder;
|
||||
builder = HttpUrl.parse(serverUrl).newBuilder();
|
||||
|
||||
|
@ -322,18 +332,24 @@ public final class Util {
|
|||
builder.addPathSegment("rest");
|
||||
builder.addPathSegment(method + ".view");
|
||||
|
||||
int hash = (username + password).hashCode();
|
||||
Pair<String, String> values = tokens.get(hash);
|
||||
if (values == null) {
|
||||
String salt = new BigInteger(130, getRandom()).toString(32);
|
||||
String token = md5Hex(password + salt);
|
||||
values = new Pair<>(salt, token);
|
||||
tokens.put(hash, values);
|
||||
builder.addQueryParameter("u", username);
|
||||
|
||||
if (prefs.getBoolean(Constants.PREFERENCES_KEY_AUTH_METHOD + instance, true)) {
|
||||
int hash = (username + password).hashCode();
|
||||
Pair<String, String> values = tokens.get(hash);
|
||||
if (values == null) {
|
||||
String salt = new BigInteger(130, getRandom()).toString(32);
|
||||
String token = md5Hex(password + salt);
|
||||
values = new Pair<>(salt, token);
|
||||
tokens.put(hash, values);
|
||||
}
|
||||
|
||||
builder.addQueryParameter("s", values.getFirst());
|
||||
builder.addQueryParameter("t", values.getSecond());
|
||||
} else {
|
||||
builder.addQueryParameter("p", password);
|
||||
}
|
||||
|
||||
builder.addQueryParameter("u", username);
|
||||
builder.addQueryParameter("s", values.getFirst());
|
||||
builder.addQueryParameter("t", values.getSecond());
|
||||
builder.addQueryParameter("v", Constants.REST_PROTOCOL_VERSION_SUBSONIC);
|
||||
builder.addQueryParameter("c", Constants.REST_CLIENT_ID);
|
||||
|
||||
|
@ -792,9 +808,9 @@ public final class Util {
|
|||
m = t.length();
|
||||
}
|
||||
|
||||
int p[] = new int[n + 1];
|
||||
int d[] = new int[n + 1];
|
||||
int _d[];
|
||||
int[] p = new int[n + 1];
|
||||
int[] d = new int[n + 1];
|
||||
int[] _d;
|
||||
|
||||
int i;
|
||||
int j;
|
||||
|
@ -945,7 +961,7 @@ public final class Util {
|
|||
}
|
||||
}
|
||||
|
||||
public static void startActivityWithoutTransition(Activity currentActivity, Intent intent) {
|
||||
public static void startActivityWithoutTransition(AppCompatActivity currentActivity, Intent intent) {
|
||||
currentActivity.startActivity(intent);
|
||||
}
|
||||
|
||||
|
@ -1134,4 +1150,10 @@ public final class Util {
|
|||
|
||||
return random;
|
||||
}
|
||||
|
||||
public static void hideKeyboard(View view) {
|
||||
InputMethodManager imm = (InputMethodManager) view.getContext().getSystemService(AppCompatActivity.INPUT_METHOD_SERVICE);
|
||||
|
||||
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
package net.nullsum.audinaut.util.tags;
|
||||
|
||||
import android.support.v4.util.LruCache;
|
||||
import androidx.collection.LruCache;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Vector;
|
||||
|
|
|
@ -31,7 +31,7 @@ class FlacFile extends Common {
|
|||
public HashMap getTags(RandomAccessFile s) throws IOException {
|
||||
int xoff = 4; // skip file magic
|
||||
int retry = 64;
|
||||
int r[];
|
||||
int[] r;
|
||||
HashMap tags = new HashMap();
|
||||
|
||||
for (; retry > 0; retry--) {
|
||||
|
|
|
@ -106,7 +106,7 @@ class ID3v2File extends Common {
|
|||
rv[1] = getDecodedString(v);
|
||||
} else if (k.equals("TXXX")) {
|
||||
/* A freestyle field, ieks! */
|
||||
String txData[] = getDecodedString(v).split(Character.toString('\0'), 2);
|
||||
String[] txData = getDecodedString(v).split(Character.toString('\0'), 2);
|
||||
/* Check if we got replaygain info in key\0value style */
|
||||
if (txData.length == 2) {
|
||||
if (txData[0].matches("^(?i)REPLAYGAIN_(ALBUM|TRACK)_GAIN$")) {
|
||||
|
|
|
@ -37,7 +37,7 @@ class OggFile extends Common {
|
|||
HashMap tags = new HashMap();
|
||||
|
||||
for (; retry > 0; retry--) {
|
||||
long res[] = parse_ogg_page(s, offset);
|
||||
long[] res = parse_ogg_page(s, offset);
|
||||
if (res[2] == OGG_TYPE_COMMENT) {
|
||||
tags = parse_ogg_vorbis_comment(s, offset + res[0], res[1]);
|
||||
break;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package net.nullsum.audinaut.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.AppCompatImageButton;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import androidx.appcompat.widget.AppCompatImageButton;
|
||||
|
||||
public class AutoRepeatButton extends AppCompatImageButton {
|
||||
|
||||
private static final long initialRepeatDelay = 1000;
|
||||
|
|
|
@ -18,7 +18,6 @@ import android.content.Context;
|
|||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.preference.EditTextPreference;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
|
@ -28,6 +27,8 @@ import android.widget.Button;
|
|||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
|
||||
import java.io.File;
|
||||
|
|
|
@ -18,9 +18,10 @@
|
|||
*/
|
||||
package net.nullsum.audinaut.view;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.activity.SubsonicFragmentActivity;
|
||||
|
@ -31,11 +32,11 @@ import net.nullsum.audinaut.util.Util;
|
|||
*/
|
||||
public class ErrorDialog {
|
||||
|
||||
public ErrorDialog(Activity activity, int messageId) {
|
||||
public ErrorDialog(AppCompatActivity activity, int messageId) {
|
||||
this(activity, activity.getResources().getString(messageId), false);
|
||||
}
|
||||
|
||||
public ErrorDialog(final Activity activity, String message, final boolean finishActivityOnClose) {
|
||||
public ErrorDialog(final AppCompatActivity activity, String message, final boolean finishActivityOnClose) {
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setIcon(android.R.drawable.ic_dialog_alert);
|
||||
|
@ -60,7 +61,7 @@ public class ErrorDialog {
|
|||
}
|
||||
}
|
||||
|
||||
private void restart(Activity activity) {
|
||||
private void restart(AppCompatActivity activity) {
|
||||
Intent intent = new Intent(activity, SubsonicFragmentActivity.class);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
Util.startActivityWithoutTransition(activity, intent);
|
||||
|
|
|
@ -19,10 +19,6 @@ import android.animation.Animator;
|
|||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.RecyclerView.AdapterDataObserver;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
|
@ -32,9 +28,14 @@ import android.view.View;
|
|||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
|
||||
import static android.support.v7.widget.RecyclerView.OnScrollListener;
|
||||
import static androidx.recyclerview.widget.RecyclerView.OnScrollListener;
|
||||
|
||||
public class FastScroller extends LinearLayout {
|
||||
private static final String TAG = FastScroller.class.getSimpleName();
|
||||
|
|
|
@ -16,14 +16,15 @@
|
|||
package net.nullsum.audinaut.view;
|
||||
|
||||
import android.graphics.Rect;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class GridSpacingDecoration extends RecyclerView.ItemDecoration {
|
||||
public static final int SPACING = 10;
|
||||
|
||||
|
|
|
@ -20,9 +20,10 @@ import android.graphics.Canvas;
|
|||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.TransitionDrawable;
|
||||
import android.support.v7.widget.AppCompatImageView;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
|
||||
public class RecyclingImageView extends AppCompatImageView {
|
||||
private boolean invalidated = false;
|
||||
|
||||
|
@ -45,7 +46,7 @@ public class RecyclingImageView extends AppCompatImageView {
|
|||
if (drawable instanceof BitmapDrawable) {
|
||||
if (isBitmapRecycled(drawable)) {
|
||||
this.setImageDrawable(null);
|
||||
setInvalidated(true);
|
||||
this.invalidated = true;
|
||||
}
|
||||
} else if (drawable instanceof TransitionDrawable) {
|
||||
TransitionDrawable transitionDrawable = (TransitionDrawable) drawable;
|
||||
|
|
|
@ -177,9 +177,9 @@ public class SongView extends UpdateView2<MusicDirectory.Entry, Boolean> {
|
|||
moreButton.setImageResource(moreImage);
|
||||
this.moreImage = moreImage;
|
||||
}
|
||||
} else if (this.moreImage != R.drawable.download_none_light) {
|
||||
} else if (this.moreImage != R.drawable.download_none) {
|
||||
moreButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.download_none));
|
||||
this.moreImage = R.drawable.download_none_light;
|
||||
this.moreImage = R.drawable.download_none;
|
||||
}
|
||||
|
||||
if (downloadFile.isDownloading() && !downloadFile.isDownloadCancelled() && partialFileExists) {
|
||||
|
|
|
@ -22,7 +22,6 @@ import android.content.Context;
|
|||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
@ -30,6 +29,8 @@ import android.widget.AbsListView;
|
|||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import net.nullsum.audinaut.R;
|
||||
import net.nullsum.audinaut.domain.MusicDirectory;
|
||||
import net.nullsum.audinaut.util.DrawableTint;
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
package net.nullsum.audinaut.domain
|
||||
|
||||
import android.content.Context
|
||||
import java.io.Serializable
|
||||
import java.util.*
|
||||
|
||||
class Indexes(var shortcuts: MutableList<Artist> = mutableListOf(),
|
||||
var artists: MutableList<Artist> = mutableListOf(),
|
||||
var entries: MutableList<MusicDirectory.Entry> = mutableListOf()) : Serializable {
|
||||
fun sortChildren(context: Context) {
|
||||
|
||||
fun sortChildren() {
|
||||
shortcuts.sortBy { s -> s.id.toLowerCase(Locale.ROOT) }
|
||||
artists.sortBy { a -> a.name.toLowerCase(Locale.ROOT) }
|
||||
entries.sortBy { e -> e.artist.toLowerCase(Locale.ROOT) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
<adaptive-icon
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
Before Width: | Height: | Size: 400 B |
Before Width: | Height: | Size: 421 B |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 349 B After Width: | Height: | Size: 343 B |
Before Width: | Height: | Size: 905 B |
Before Width: | Height: | Size: 154 B |
Before Width: | Height: | Size: 167 B |
Before Width: | Height: | Size: 907 B |
Before Width: | Height: | Size: 263 B |
Before Width: | Height: | Size: 274 B |
Before Width: | Height: | Size: 138 B |
Before Width: | Height: | Size: 145 B |
Before Width: | Height: | Size: 407 B |
Before Width: | Height: | Size: 411 B |
Before Width: | Height: | Size: 241 B |
Before Width: | Height: | Size: 401 B |
Before Width: | Height: | Size: 425 B |
Before Width: | Height: | Size: 239 B |
Before Width: | Height: | Size: 255 B |
Before Width: | Height: | Size: 207 B |
Before Width: | Height: | Size: 222 B |
Before Width: | Height: | Size: 309 B |
Before Width: | Height: | Size: 323 B |
Before Width: | Height: | Size: 340 B |
Before Width: | Height: | Size: 370 B |
Before Width: | Height: | Size: 451 B |
Before Width: | Height: | Size: 494 B |
Before Width: | Height: | Size: 240 B |
Before Width: | Height: | Size: 256 B |
Before Width: | Height: | Size: 314 B |
Before Width: | Height: | Size: 335 B |
Before Width: | Height: | Size: 503 B |
Before Width: | Height: | Size: 555 B |
Before Width: | Height: | Size: 453 B |
Before Width: | Height: | Size: 489 B |
Before Width: | Height: | Size: 405 B |
Before Width: | Height: | Size: 423 B |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 387 B |
Before Width: | Height: | Size: 415 B |
Before Width: | Height: | Size: 238 B |
Before Width: | Height: | Size: 260 B |
Before Width: | Height: | Size: 230 B |
Before Width: | Height: | Size: 243 B |