diff options
author | Scott Jackson <daneren2005@gmail.com> | 2015-08-21 17:03:43 -0700 |
---|---|---|
committer | Scott Jackson <daneren2005@gmail.com> | 2015-08-21 17:03:43 -0700 |
commit | c777c62aea3a7b251e8f6c907a60ebf35ddbb8c8 (patch) | |
tree | 15df7a7ea0fdd94e89ba0113d8e1b186eef4d93d /app | |
parent | 9f597b5135b85b99755cd791e32796b89fbf81dd (diff) | |
parent | 5a175f3b94cb8b5bd078e373f4a25b7ab65c4cc8 (diff) | |
download | dsub-c777c62aea3a7b251e8f6c907a60ebf35ddbb8c8.tar.gz dsub-c777c62aea3a7b251e8f6c907a60ebf35ddbb8c8.tar.bz2 dsub-c777c62aea3a7b251e8f6c907a60ebf35ddbb8c8.zip |
Merge branch 'SlideUpPanel2'
Diffstat (limited to 'app')
706 files changed, 7287 insertions, 7092 deletions
diff --git a/app/.gitignore b/app/.gitignore index 796b96d1..e8fa30f8 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -1 +1,2 @@ /build +*.iml diff --git a/app/app.iml b/app/app.iml deleted file mode 100644 index 28b7ee49..00000000 --- a/app/app.iml +++ /dev/null @@ -1,121 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="DSub" external.system.module.version="unspecified" type="JAVA_MODULE" version="4"> - <component name="FacetManager"> - <facet type="android-gradle" name="Android-Gradle"> - <configuration> - <option name="GRADLE_PROJECT_PATH" value=":app" /> - </configuration> - </facet> - <facet type="android" name="Android"> - <configuration> - <option name="SELECTED_BUILD_VARIANT" value="debug" /> - <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" /> - <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" /> - <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" /> - <option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" /> - <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" /> - <option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" /> - <option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugAndroidTestSources" /> - <option name="ALLOW_USER_CONFIGURATION" value="false" /> - <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" /> - <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" /> - <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" /> - <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" /> - </configuration> - </facet> - </component> - <component name="NewModuleRootManager" inherit-compiler-output="false"> - <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" /> - <output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" /> - <exclude-output /> - <content url="file://$MODULE_DIR$"> - <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" /> - <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" /> - <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" /> - <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" /> - <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" /> - <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" /> - <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" /> - <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" /> - <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" /> - <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" /> - <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" /> - <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug" type="java-test-resource" /> - <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" /> - <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" /> - <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" /> - <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" /> - <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" /> - <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" /> - <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" /> - <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" /> - <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" /> - <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" /> - <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" /> - <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" /> - <sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" /> - <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/22.1.1/jars" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/mediarouter-v7/22.1.1/jars" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/22.1.1/jars" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-base/7.0.0/jars" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.google.android.gms/play-services-cast/7.0.0/jars" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" /> - <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" /> - <excludeFolder url="file://$MODULE_DIR$/build/outputs" /> - <excludeFolder url="file://$MODULE_DIR$/build/tmp" /> - </content> - <orderEntry type="jdk" jdkName="Android API 22 Platform" jdkType="Android SDK" /> - <orderEntry type="sourceFolder" forTests="false" /> - <orderEntry type="library" exported="" name="mediarouter-v7-22.1.1" level="project" /> - <orderEntry type="library" exported="" name="seamless-util-1.1.0" level="project" /> - <orderEntry type="library" exported="" name="cling-core-2.0.1" level="project" /> - <orderEntry type="library" exported="" name="jetty-continuation-8.1.16.v20140903" level="project" /> - <orderEntry type="library" exported="" name="javax.servlet-3.0.0.v201112011016" level="project" /> - <orderEntry type="library" exported="" name="jetty-server-8.1.16.v20140903" level="project" /> - <orderEntry type="library" exported="" name="support-annotations-22.1.1" level="project" /> - <orderEntry type="library" exported="" name="support-v4-22.1.1" level="project" /> - <orderEntry type="library" exported="" name="play-services-cast-7.0.0" level="project" /> - <orderEntry type="library" exported="" name="cling-support-2.0.1" level="project" /> - <orderEntry type="library" exported="" name="seamless-http-1.1.0" level="project" /> - <orderEntry type="library" exported="" name="jetty-util-8.1.16.v20140903" level="project" /> - <orderEntry type="library" exported="" name="appcompat-v7-22.1.1" level="project" /> - <orderEntry type="library" exported="" name="seamless-swing-1.1.0" level="project" /> - <orderEntry type="library" exported="" name="seamless-xml-1.1.0" level="project" /> - <orderEntry type="library" exported="" name="jetty-io-8.1.16.v20140903" level="project" /> - <orderEntry type="library" exported="" name="CWAC-EndlessAdapter" level="project" /> - <orderEntry type="library" exported="" name="jetty-security-8.1.16.v20140903" level="project" /> - <orderEntry type="library" exported="" name="kryo-2.21-all" level="project" /> - <orderEntry type="library" exported="" name="play-services-base-7.0.0" level="project" /> - <orderEntry type="library" exported="" name="jetty-servlet-8.1.16.v20140903" level="project" /> - <orderEntry type="library" exported="" name="CWAC-AdapterWrapper" level="project" /> - <orderEntry type="library" exported="" name="jetty-client-8.1.16.v20140903" level="project" /> - <orderEntry type="library" exported="" name="jetty-http-8.1.16.v20140903" level="project" /> - <orderEntry type="module" module-name="DragSort ListView" exported="" /> - <orderEntry type="module" module-name="Server Proxy" exported="" /> - </component> -</module>
\ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 0eeaec1d..98571c64 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,8 +6,8 @@ android { defaultConfig { applicationId "github.daneren2005.dsub" - minSdkVersion 9 - targetSdkVersion 19 + minSdkVersion 14 + targetSdkVersion 22 } buildTypes { release { @@ -32,13 +32,16 @@ android { } dependencies { - compile project(':DragSort ListView') compile project(':Server Proxy') compile fileTree(include: ['*.jar'], dir: 'libs') - compile 'com.android.support:support-v4:22.1.1' - compile 'com.android.support:appcompat-v7:22.1.1' - compile 'com.android.support:mediarouter-v7:22.1.1' + compile 'com.android.support:support-v4:22.2.+' + compile 'com.android.support:appcompat-v7:22.2.+' + compile 'com.android.support:mediarouter-v7:22.2.+' + compile 'com.android.support:recyclerview-v7:22.2.+' + compile 'com.android.support:design:22.2.+' compile 'com.google.android.gms:play-services-cast:7.0.0' + compile 'com.sothree.slidinguppanel:library:3.0.0' + compile 'de.hdodenhof:circleimageview:1.2.1' compile group: 'org.fourthline.cling', name: 'cling-core', version:'2.0.1' compile group: 'org.fourthline.cling', name: 'cling-support', version:'2.0.1' compile group: 'org.eclipse.jetty', name: 'jetty-server', version:'8.1.16.v20140903' diff --git a/app/src/androidTest/java/github/daneren2005/dsub/activity/DownloadActivityTest.java b/app/src/androidTest/java/github/daneren2005/dsub/activity/DownloadActivityTest.java deleted file mode 100644 index ce859181..00000000 --- a/app/src/androidTest/java/github/daneren2005/dsub/activity/DownloadActivityTest.java +++ /dev/null @@ -1,32 +0,0 @@ -package github.daneren2005.dsub.activity; - -import github.daneren2005.dsub.R; -import android.test.*; -import android.view.View; - -public class DownloadActivityTest extends - ActivityInstrumentationTestCase2<DownloadActivity> { - - private DownloadActivity activity; - - public DownloadActivityTest() { - super(DownloadActivity.class); - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - activity = getActivity(); - } - - /** - * Test the main layout. - */ - public void testLayout() { - View view = activity.findViewById(R.layout.download_activity); - assertNotNull(view); - assertNotNull(view.findViewById(R.layout.download_activity)); - assertNotNull(activity.findViewById(R.id.fragment_container)); - } - -} diff --git a/app/src/androidTest/java/github/daneren2005/dsub/domain/BookmarkTest.java b/app/src/androidTest/java/github/daneren2005/dsub/domain/BookmarkTest.java index 814f658a..30663543 100644 --- a/app/src/androidTest/java/github/daneren2005/dsub/domain/BookmarkTest.java +++ b/app/src/androidTest/java/github/daneren2005/dsub/domain/BookmarkTest.java @@ -15,7 +15,7 @@ public class BookmarkTest extends TestCase { */ public void testSetCreated() throws ParseException { Bookmark bookmark = new Bookmark(); - bookmark.setCreated(null); + bookmark.setCreated((String) null); assertEquals(null, bookmark.getCreated()); bookmark.setCreated(""); diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 38d80ae8..01adb232 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,8 +2,8 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="github.daneren2005.dsub" android:installLocation="internalOnly" - android:versionCode="152" - android:versionName="4.9.7"> + android:versionCode="154" + android:versionName="5.0 Beta 2"> <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="github.daneren2005.dsub" @@ -31,7 +31,7 @@ <uses-feature android:name="android.hardware.microphone" android:required="false" /> <uses-feature android:name="android.hardware.wifi" android:required="false" /> - <uses-sdk android:minSdkVersion="9" android:targetSdkVersion="19"/> + <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="22"/> <supports-screens android:anyDensity="true" android:xlargeScreens="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true"/> @@ -52,10 +52,6 @@ </intent-filter> </activity> - <activity android:name="github.daneren2005.dsub.activity.DownloadActivity" - android:configChanges="keyboardHidden" - android:launchMode="singleTask"/> - <activity android:name="github.daneren2005.dsub.activity.SettingsActivity" android:configChanges="orientation|keyboardHidden" android:launchMode="singleTask"/> diff --git a/app/src/main/java/github/daneren2005/dsub/activity/DownloadActivity.java b/app/src/main/java/github/daneren2005/dsub/activity/DownloadActivity.java deleted file mode 100644 index e13a8b8c..00000000 --- a/app/src/main/java/github/daneren2005/dsub/activity/DownloadActivity.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. - - Copyright 2009 (C) Sindre Mehus - */ -package github.daneren2005.dsub.activity; - -import github.daneren2005.dsub.R; -import android.os.Bundle; -import android.view.MotionEvent; -import github.daneren2005.dsub.fragments.NowPlayingFragment; - -import android.widget.EditText; - -import github.daneren2005.dsub.util.Constants; - -public class DownloadActivity extends SubsonicActivity { - private static final String TAG = DownloadActivity.class.getSimpleName(); - private EditText playlistNameView; - - /** - * Called when the activity is first created. - */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.download_activity); - - if (findViewById(R.id.fragment_container) != null && savedInstanceState == null) { - currentFragment = new NowPlayingFragment(); - if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW)) { - Bundle args = new Bundle(); - args.putBoolean(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW, true); - currentFragment.setArguments(args); - } - currentFragment.setPrimaryFragment(true); - getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, currentFragment, currentFragment.getSupportTag() + "").commit(); - } - } - - @Override - public boolean onTouchEvent(MotionEvent me) { - if(currentFragment != null && currentFragment.getGestureDetector() != null) { - return currentFragment.getGestureDetector().onTouchEvent(me); - } else { - return false; - } - } -} diff --git a/app/src/main/java/github/daneren2005/dsub/activity/EditPlayActionActivity.java b/app/src/main/java/github/daneren2005/dsub/activity/EditPlayActionActivity.java index e1f2cad3..0396f8a4 100644 --- a/app/src/main/java/github/daneren2005/dsub/activity/EditPlayActionActivity.java +++ b/app/src/main/java/github/daneren2005/dsub/activity/EditPlayActionActivity.java @@ -16,7 +16,7 @@ package github.daneren2005.dsub.activity; import android.app.Activity; -import android.app.AlertDialog; +import android.support.v7.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; diff --git a/app/src/main/java/github/daneren2005/dsub/activity/SettingsActivity.java b/app/src/main/java/github/daneren2005/dsub/activity/SettingsActivity.java index d5ac60d3..595529b7 100644 --- a/app/src/main/java/github/daneren2005/dsub/activity/SettingsActivity.java +++ b/app/src/main/java/github/daneren2005/dsub/activity/SettingsActivity.java @@ -19,61 +19,25 @@ package github.daneren2005.dsub.activity; import android.annotation.TargetApi; -import android.accounts.Account; -import android.content.ContentResolver; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.preference.CheckBoxPreference; -import android.preference.EditTextPreference; -import android.preference.ListPreference; -import android.preference.Preference; -import android.preference.PreferenceCategory; -import android.preference.PreferenceScreen; -import android.support.v7.app.ActionBarActivity; -import android.text.InputType; -import android.util.Log; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.EditText; -import android.widget.FrameLayout; +import android.support.v7.widget.Toolbar; import github.daneren2005.dsub.R; import github.daneren2005.dsub.fragments.PreferenceCompatFragment; import github.daneren2005.dsub.fragments.SettingsFragment; -import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.LoadingTask; -import github.daneren2005.dsub.util.SyncUtil; -import github.daneren2005.dsub.view.ErrorDialog; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.Util; - -import java.io.File; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.net.URL; -import java.text.DecimalFormat; -import java.util.LinkedHashMap; -import java.util.Map; public class SettingsActivity extends SubsonicActivity { - private static final String TAG = SettingsActivity.class.getSimpleName(); + private static final String TAG = SettingsActivity.class.getSimpleName(); private PreferenceCompatFragment fragment; @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.download_activity); + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + lastSelectedPosition = R.id.drawer_settings; + setContentView(R.layout.settings_activity); if (savedInstanceState == null) { fragment = new SettingsFragment(); @@ -87,5 +51,8 @@ public class SettingsActivity extends SubsonicActivity { currentFragment.setPrimaryFragment(true); getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, currentFragment, currentFragment.getSupportTag() + "").commit(); } - } + + Toolbar mainToolbar = (Toolbar) findViewById(R.id.main_toolbar); + setSupportActionBar(mainToolbar); + } } diff --git a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java index 4651eb0b..f336d178 100644 --- a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java +++ b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicActivity.java @@ -20,22 +20,26 @@ package github.daneren2005.dsub.activity; import android.app.UiModeManager; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Configuration; -import android.content.res.TypedArray; 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.v7.app.ActionBarDrawerToggle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.ActionBarActivity; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.KeyEvent; import android.view.LayoutInflater; @@ -51,14 +55,14 @@ import android.view.animation.AnimationUtils; import android.widget.AdapterView; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; -import android.widget.ListView; +import android.widget.CheckBox; +import android.widget.ImageView; import android.widget.Spinner; import android.widget.TextView; import java.io.File; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import github.daneren2005.dsub.R; @@ -66,22 +70,26 @@ import github.daneren2005.dsub.domain.ServerInfo; import github.daneren2005.dsub.fragments.SubsonicFragment; import github.daneren2005.dsub.service.DownloadService; import github.daneren2005.dsub.service.HeadphoneListenerService; +import github.daneren2005.dsub.service.MusicService; +import github.daneren2005.dsub.service.MusicServiceFactory; import github.daneren2005.dsub.util.Constants; +import github.daneren2005.dsub.util.DrawableTint; import github.daneren2005.dsub.util.ImageLoader; +import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.DrawerAdapter; import github.daneren2005.dsub.view.UpdateView; import github.daneren2005.dsub.util.UserUtil; -public class SubsonicActivity extends ActionBarActivity implements OnItemSelectedListener { +public class SubsonicActivity extends AppCompatActivity implements OnItemSelectedListener { private static final String TAG = SubsonicActivity.class.getSimpleName(); private static ImageLoader IMAGE_LOADER; protected static String theme; protected static boolean fullScreen; - private String[] drawerItemsDescriptions; - private String[] drawerItems; + private static final int MENU_GROUP_SERVER = 10; + private static final int MENU_ITEM_SERVER_BASE = 100; + + private final List<Runnable> afterServiceAvailable = new ArrayList<>(); private boolean drawerIdle = true; - private boolean[] enabledItems = {true, true, true, true, true}; private boolean destroyed = false; private boolean finished = false; protected List<SubsonicFragment> backStack = new ArrayList<SubsonicFragment>(); @@ -90,16 +98,22 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte protected View secondaryContainer; protected boolean tv = false; protected boolean touchscreen = true; + protected Handler handler = new Handler(); Spinner actionBarSpinner; ArrayAdapter<CharSequence> spinnerAdapter; ViewGroup rootView; DrawerLayout drawer; ActionBarDrawerToggle drawerToggle; - DrawerAdapter drawerAdapter; - ListView drawerList; - TextView lastSelectedView = null; + NavigationView drawerList; + View drawerHeader; + ImageView drawerUserAvatar; + ImageView drawerHeaderToggle; + TextView drawerServerName; + TextView drawerUserName; int lastSelectedPosition = 0; + boolean showingTabs = true; boolean drawerOpen = false; + SharedPreferences.OnSharedPreferenceChangeListener preferencesListener; @Override protected void onCreate(Bundle bundle) { @@ -118,26 +132,49 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte super.onCreate(bundle); startService(new Intent(this, DownloadService.class)); setVolumeControlStream(AudioManager.STREAM_MUSIC); - - View actionbar = getLayoutInflater().inflate(R.layout.actionbar_spinner, null); - actionBarSpinner = (Spinner)actionbar.findViewById(R.id.spinner); - spinnerAdapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item); - spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - actionBarSpinner.setOnItemSelectedListener(this); - actionBarSpinner.setAdapter(spinnerAdapter); - - getSupportActionBar().setCustomView(actionbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setHomeButtonEnabled(true); if(getIntent().hasExtra(Constants.FRAGMENT_POSITION)) { lastSelectedPosition = getIntent().getIntExtra(Constants.FRAGMENT_POSITION, 0); } + + if(preferencesListener == null) { + preferencesListener = new SharedPreferences.OnSharedPreferenceChangeListener() { + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + // When changing drawer settings change visibility + switch(key) { + case Constants.PREFERENCES_KEY_PODCASTS_ENABLED: + setDrawerItemVisible(R.id.drawer_podcasts, false); + break; + case Constants.PREFERENCES_KEY_BOOKMARKS_ENABLED: + setDrawerItemVisible(R.id.drawer_bookmarks, false); + break; + case Constants.PREFERENCES_KEY_SHARED_ENABLED: + setDrawerItemVisible(R.id.drawer_shares, false); + break; + case Constants.PREFERENCES_KEY_CHAT_ENABLED: + setDrawerItemVisible(R.id.drawer_chat, false); + break; + case Constants.PREFERENCES_KEY_ADMIN_ENABLED: + setDrawerItemVisible(R.id.drawer_admin, false); + break; + } + } + }; + Util.getPreferences(this).registerOnSharedPreferenceChangeListener(preferencesListener); + } } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); + + if(spinnerAdapter == null) { + createCustomActionBarView(); + } + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setHomeButtonEnabled(true); + // Sync the toggle state after onRestoreInstanceState has occurred. if(drawerToggle != null) { drawerToggle.syncState(); @@ -150,6 +187,17 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte } } + protected void createCustomActionBarView() { + View customActionbar = getLayoutInflater().inflate(R.layout.actionbar_spinner, null); + actionBarSpinner = (Spinner)customActionbar.findViewById(R.id.spinner); + spinnerAdapter = new ArrayAdapter(this, android.R.layout.simple_spinner_item); + spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + actionBarSpinner.setOnItemSelectedListener(this); + actionBarSpinner.setAdapter(spinnerAdapter); + + getSupportActionBar().setCustomView(customActionbar); + } + @Override protected void onResume() { super.onResume(); @@ -159,9 +207,10 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte if (theme != null && !theme.equals(Util.getTheme(this)) || fullScreen != Util.getPreferences(this).getBoolean(Constants.PREFERENCES_KEY_FULL_SCREEN, false)) { restart(); overridePendingTransition(R.anim.fade_in, R.anim.fade_out); + DrawableTint.wipeTintCache(); } - - populateDrawer(); + + populateTabs(); UpdateView.addActiveActivity(); } @@ -176,6 +225,7 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte protected void onDestroy() { super.onDestroy(); destroyed = true; + Util.getPreferences(this).unregisterOnSharedPreferenceChangeListener(preferencesListener); } @Override @@ -185,19 +235,6 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte } @Override - public void startActivity(Intent intent) { - if(intent.getComponent() != null) { - String name = intent.getComponent().getClassName(); - if(name != null && name.indexOf("DownloadActivity") != -1) { - intent.putExtra(Constants.FRAGMENT_POSITION, lastSelectedPosition); - } else if(name != null && name.indexOf("SettingsActivity") != -1) { - intent.putExtra(Constants.FRAGMENT_POSITION, drawerItems.length - 1); - } - } - super.startActivity(intent); - } - - @Override public void setContentView(int viewId) { if(isTv()) { super.setContentView(R.layout.static_drawer_activity); @@ -210,34 +247,104 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte LayoutInflater layoutInflater = getLayoutInflater(); layoutInflater.inflate(viewId, rootView); } - - drawerList = (ListView) findViewById(R.id.left_drawer); - drawerList.setOnItemClickListener(new ListView.OnItemClickListener() { + + drawerList = (NavigationView) findViewById(R.id.left_drawer); + drawerList.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override - public void onItemClick(AdapterView<?> parent, final View view, final int position, long id) { - final int actualPosition = drawerAdapter.getActualPosition(position); - if("Settings".equals(drawerItemsDescriptions[actualPosition])) { - startActivity(new Intent(SubsonicActivity.this, SettingsActivity.class)); - drawer.closeDrawers(); - } else if("Admin".equals(drawerItemsDescriptions[actualPosition]) && UserUtil.isCurrentAdmin()) { - UserUtil.confirmCredentials(SubsonicActivity.this, new Runnable() { - @Override - public void run() { - drawerItemSelected(actualPosition, view); - } - }); + public boolean onNavigationItemSelected(final MenuItem menuItem) { + if(showingTabs) { + // Settings are on a different selectable track + if (menuItem.getItemId() != R.id.drawer_settings && menuItem.getItemId() != R.id.drawer_admin && menuItem.getItemId() != R.id.drawer_offline) { + menuItem.setChecked(true); + lastSelectedPosition = menuItem.getItemId(); + } + + switch (menuItem.getItemId()) { + case R.id.drawer_home: + drawerItemSelected("Home"); + return true; + case R.id.drawer_library: + drawerItemSelected("Artist"); + return true; + case R.id.drawer_playlists: + drawerItemSelected("Playlist"); + return true; + case R.id.drawer_podcasts: + drawerItemSelected("Podcast"); + return true; + case R.id.drawer_bookmarks: + drawerItemSelected("Bookmark"); + return true; + case R.id.drawer_shares: + drawerItemSelected("Share"); + return true; + case R.id.drawer_chat: + drawerItemSelected("Chat"); + return true; + case R.id.drawer_admin: + if (UserUtil.isCurrentAdmin()) { + UserUtil.confirmCredentials(SubsonicActivity.this, new Runnable() { + @Override + public void run() { + drawerItemSelected("Admin"); + menuItem.setChecked(true); + lastSelectedPosition = menuItem.getItemId(); + } + }); + } else { + drawerItemSelected("Admin"); + menuItem.setChecked(true); + lastSelectedPosition = menuItem.getItemId(); + } + return true; + case R.id.drawer_downloading: + drawerItemSelected("Download"); + return true; + case R.id.drawer_offline: + toggleOffline(); + return true; + case R.id.drawer_settings: + startActivity(new Intent(SubsonicActivity.this, SettingsActivity.class)); + drawer.closeDrawers(); + return true; + } } else { - drawerItemSelected(actualPosition, view); + int activeServer = menuItem.getItemId() - MENU_ITEM_SERVER_BASE; + SubsonicActivity.this.setActiveServer(activeServer); + populateTabs(); + return true; } + + return false; } }); + drawerHeader = drawerList.inflateHeaderView(R.layout.drawer_header); + drawerHeader.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if(showingTabs) { + populateServers(); + } else { + populateTabs(); + } + } + }); + + drawerHeaderToggle = (ImageView) drawerHeader.findViewById(R.id.header_select_image); + drawerServerName = (TextView) drawerHeader.findViewById(R.id.header_server_name); + drawerUserName = (TextView) drawerHeader.findViewById(R.id.header_user_name); + + drawerUserAvatar = (ImageView) drawerHeader.findViewById(R.id.header_user_avatar); + updateDrawerHeader(); if(!isTv()) { drawer = (DrawerLayout) findViewById(R.id.drawer_layout); - drawerToggle = new ActionBarDrawerToggle(this, drawer, R.string.common_appname, R.string.common_appname) { + // Pass in toolbar if it exists + Toolbar toolbar = (Toolbar) findViewById(R.id.main_toolbar); + drawerToggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.common_appname, R.string.common_appname) { @Override public void onDrawerClosed(View view) { setTitle(currentFragment.getTitle()); @@ -246,23 +353,19 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte drawerOpen = false; supportInvalidateOptionsMenu(); + if(!showingTabs) { + populateTabs(); + } } @Override public void onDrawerOpened(View view) { DownloadService downloadService = getDownloadService(); - if (downloadService == null || downloadService.getBackgroundDownloads().isEmpty()) { - drawerAdapter.setDownloadVisible(false); - } else { - drawerAdapter.setDownloadVisible(true); - } - - if (lastSelectedView == null && drawerList.getCount() > lastSelectedPosition) { - lastSelectedView = (TextView) drawerList.getChildAt(lastSelectedPosition).findViewById(R.id.drawer_name); - if (lastSelectedView != null) { - lastSelectedView.setTextAppearance(SubsonicActivity.this, R.style.DSub_TextViewStyle_Bold); - } + boolean downloadingVisible = downloadService != null && !downloadService.getBackgroundDownloads().isEmpty(); + if(lastSelectedPosition == R.id.drawer_downloading) { + downloadingVisible = true; } + setDrawerItemVisible(R.id.drawer_downloading, downloadingVisible); getSupportActionBar().setTitle(R.string.common_appname); getSupportActionBar().setDisplayShowCustomEnabled(false); @@ -299,7 +402,7 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte primaryContainer = findViewById(R.id.fragment_container); } } - + @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); @@ -363,6 +466,12 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte } lastSelectedPosition = savedInstanceState.getInt(Constants.FRAGMENT_POSITION); + if(lastSelectedPosition != 0) { + MenuItem item = drawerList.getMenu().findItem(lastSelectedPosition); + if(item != null) { + item.setChecked(true); + } + } recreateSpinner(); } @@ -370,10 +479,11 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte public void onNewIntent(Intent intent) { super.onNewIntent(intent); } - + @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater menuInflater = getMenuInflater(); + SubsonicFragment currentFragment = getCurrentFragment(); if(drawerOpen) { menuInflater.inflate(R.menu.drawer_menu, menu); } else if(currentFragment != null) { @@ -399,7 +509,7 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte return true; } - return currentFragment.onOptionsItemSelected(item); + return getCurrentFragment().onOptionsItemSelected(item); } @Override @@ -415,7 +525,7 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte } return super.onKeyDown(keyCode, event); } - + @Override public void setTitle(CharSequence title) { if(title != null && !title.equals(getSupportActionBar().getTitle())) { @@ -426,7 +536,7 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte public void setSubtitle(CharSequence title) { getSupportActionBar().setSubtitle(title); } - + @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { int top = spinnerAdapter.getCount() - 1; @@ -439,97 +549,93 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte @Override public void onNothingSelected(AdapterView<?> parent) { - + } - - private void populateDrawer() { + + private void populateTabs() { + drawerList.getMenu().clear(); + drawerList.inflateMenu(R.menu.drawer_navigation); + SharedPreferences prefs = Util.getPreferences(this); boolean podcastsEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_PODCASTS_ENABLED, true); boolean bookmarksEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_BOOKMARKS_ENABLED, true) && !Util.isOffline(this) && ServerInfo.canBookmark(this); boolean sharedEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_SHARED_ENABLED, true) && !Util.isOffline(this); boolean chatEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_CHAT_ENABLED, true) && !Util.isOffline(this); boolean adminEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_ADMIN_ENABLED, true) && !Util.isOffline(this); - - if(drawerItems == null || !enabledItems[0] == podcastsEnabled || !enabledItems[1] == bookmarksEnabled || !enabledItems[2] == sharedEnabled || !enabledItems[3] == chatEnabled || !enabledItems[4] == adminEnabled) { - drawerItems = getResources().getStringArray(R.array.drawerItems); - drawerItemsDescriptions = getResources().getStringArray(R.array.drawerItemsDescriptions); - - List<String> drawerItemsList = new ArrayList<String>(Arrays.asList(drawerItems)); - List<Integer> drawerItemsIconsList = new ArrayList<Integer>(); - List<Boolean> drawerItemsVisibleList = new ArrayList<Boolean>(); - - int[] arrayAttr = {R.attr.drawerItemsIcons}; - TypedArray arrayType = obtainStyledAttributes(arrayAttr); - int arrayId = arrayType.getResourceId(0, 0); - TypedArray iconType = getResources().obtainTypedArray(arrayId); - for(int i = 0; i < drawerItemsList.size(); i++) { - drawerItemsIconsList.add(iconType.getResourceId(i, 0)); - drawerItemsVisibleList.add(true); - } - iconType.recycle(); - arrayType.recycle(); - // Hide listings user doesn't want to see - if(!podcastsEnabled) { - drawerItemsVisibleList.set(3, false); - } - if(!bookmarksEnabled) { - drawerItemsVisibleList.set(4, false); - } - if(!sharedEnabled) { - drawerItemsVisibleList.set(5, false); - } - if(!chatEnabled) { - drawerItemsVisibleList.set(6, false); - } - if(!adminEnabled) { - drawerItemsVisibleList.set(7, false); - } - if(!getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW)) { - drawerItemsVisibleList.set(8, false); - } - - drawerList.setAdapter(drawerAdapter = new DrawerAdapter(this, drawerItemsList, drawerItemsIconsList, drawerItemsVisibleList)); - enabledItems[0] = podcastsEnabled; - enabledItems[1] = bookmarksEnabled; - enabledItems[2] = sharedEnabled; - enabledItems[3] = chatEnabled; - enabledItems[4] = adminEnabled; - - String fragmentType = getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE); - if(fragmentType != null && lastSelectedPosition == 0) { - for(int i = 0; i < drawerItemsDescriptions.length; i++) { - if(fragmentType.equals(drawerItemsDescriptions[i])) { - lastSelectedPosition = drawerAdapter.getAdapterPosition(i); - break; - } + MenuItem offlineMenuItem = drawerList.getMenu().findItem(R.id.drawer_offline); + if(Util.isOffline(this)) { + setDrawerItemVisible(R.id.drawer_home, false); + + if(lastSelectedPosition == 0 || lastSelectedPosition == R.id.drawer_home) { + String newFragment = Util.openToTab(this); + if(newFragment == null || "Home".equals(newFragment)) { + newFragment = "Artist"; } + + lastSelectedPosition = getDrawerItemId(newFragment); + drawerItemSelected(newFragment); } - if(drawerList.getChildAt(lastSelectedPosition) == null) { - lastSelectedView = null; - drawerAdapter.setSelectedPosition(lastSelectedPosition); - } else { - lastSelectedView = (TextView) drawerList.getChildAt(lastSelectedPosition).findViewById(R.id.drawer_name); - if(lastSelectedView != null) { - lastSelectedView.setTextAppearance(SubsonicActivity.this, R.style.DSub_TextViewStyle_Bold); - } + offlineMenuItem.setTitle(R.string.main_online); + } else { + offlineMenuItem.setTitle(R.string.main_offline); + } + + if(!podcastsEnabled) { + setDrawerItemVisible(R.id.drawer_podcasts, false); + } + if(!bookmarksEnabled) { + setDrawerItemVisible(R.id.drawer_bookmarks, false); + } + if(!sharedEnabled) { + setDrawerItemVisible(R.id.drawer_shares, false); + } + if(!chatEnabled) { + setDrawerItemVisible(R.id.drawer_chat, false); + } + if(!adminEnabled) { + setDrawerItemVisible(R.id.drawer_admin, false); + } + + if(lastSelectedPosition != 0) { + MenuItem item = drawerList.getMenu().findItem(lastSelectedPosition); + if(item != null) { + item.setChecked(true); } } + drawerHeaderToggle.setImageResource(R.drawable.main_select_server_dark); + + showingTabs = true; } - - private void drawerItemSelected(int position, View view) { - startFragmentActivity(drawerItemsDescriptions[position]); - - if(lastSelectedView != view) { - if(lastSelectedView != null) { - lastSelectedView.setTextAppearance(this, R.style.DSub_TextViewStyle); + private void populateServers() { + drawerList.getMenu().clear(); + + int serverCount = Util.getServerCount(this); + int activeServer = Util.getActiveServer(this); + for(int i = 1; i <= serverCount; i++) { + MenuItem item = drawerList.getMenu().add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_BASE + i, MENU_ITEM_SERVER_BASE + i, Util.getServerName(this, i)); + if(activeServer == i) { + item.setChecked(true); } - - lastSelectedView = (TextView) view.findViewById(R.id.drawer_name); - lastSelectedView.setTextAppearance(this, R.style.DSub_TextViewStyle_Bold); - lastSelectedPosition = position; } + drawerList.getMenu().setGroupCheckable(MENU_GROUP_SERVER, true, true); + drawerHeaderToggle.setImageResource(R.drawable.main_select_tabs_dark); + + showingTabs = false; + } + private void setDrawerItemVisible(int id, boolean visible) { + MenuItem item = drawerList.getMenu().findItem(id); + if(item != null) { + item.setVisible(visible); + } + } + + protected void drawerItemSelected(String fragmentType) { + if(currentFragment != null) { + currentFragment.stopActionMode(); + } + startFragmentActivity(fragmentType); } public void startFragmentActivity(String fragmentType) { @@ -539,6 +645,9 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte if(!"".equals(fragmentType)) { intent.putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, fragmentType); } + if(lastSelectedPosition != 0) { + intent.putExtra(Constants.FRAGMENT_POSITION, lastSelectedPosition); + } startActivity(intent); finish(); } @@ -575,6 +684,10 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte } } + protected SubsonicFragment getCurrentFragment() { + return this.currentFragment; + } + public void replaceFragment(SubsonicFragment fragment, int tag) { replaceFragment(fragment, tag, false); } @@ -628,11 +741,11 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte backStack.remove(backStack.size() - 1); } } - + // Add fragment to the right container trans.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right); trans.add(R.id.fragment_second_container, fragment, tag + ""); - + // Commit it all trans.commit(); } @@ -656,7 +769,7 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte trans.commit(); } else { FragmentTransaction trans = getSupportFragmentManager().beginTransaction(); - + // Remove old right fragment trans.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left); trans.remove(oldFrag); @@ -682,7 +795,7 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte secondaryContainer.startAnimation(AnimationUtils.loadAnimation(this, R.anim.exit_to_right)); secondaryContainer.setVisibility(View.GONE); } - + trans.commit(); } recreateSpinner(); @@ -695,16 +808,19 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte } currentFragment.invalidate(); - populateDrawer(); + populateTabs(); } - + supportInvalidateOptionsMenu(); } - + protected void recreateSpinner() { if(currentFragment == null || currentFragment.getTitle() == null) { return; } + if(spinnerAdapter == null) { + createCustomActionBarView(); + } if(backStack.size() > 0) { spinnerAdapter.clear(); @@ -727,6 +843,7 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte getSupportActionBar().setDisplayShowCustomEnabled(true); } } else if(!isTv()) { + getSupportActionBar().setTitle(currentFragment.getTitle()); getSupportActionBar().setDisplayShowCustomEnabled(false); } } @@ -735,6 +852,7 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte Intent intent = new Intent(this, ((Object) this).getClass()); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.putExtras(getIntent()); + intent.putExtra(Constants.FRAGMENT_POSITION, lastSelectedPosition); Util.startActivityWithoutTransition(this, intent); } @@ -745,7 +863,7 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte theme = theme.substring(0, theme.indexOf("_fullscreen")); Util.setTheme(this, theme); } - + Util.applyTheme(this, theme); } private void applyFullscreen() { @@ -754,8 +872,8 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte // Hide additional elements on higher Android versions if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { int flags = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_FULLSCREEN | - View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; + View.SYSTEM_UI_FLAG_FULLSCREEN | + View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY; getWindow().getDecorView().setSystemUiVisibility(flags); } else if(Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { @@ -786,20 +904,35 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte if(finished) { return null; } - + // If service is not available, request it to start and wait for it. for (int i = 0; i < 5; i++) { DownloadService downloadService = DownloadService.getInstance(); if (downloadService != null) { - return downloadService; + break; } Log.w(TAG, "DownloadService not running. Attempting to start it."); startService(new Intent(this, DownloadService.class)); Util.sleepQuietly(50L); } - return DownloadService.getInstance(); + + final DownloadService downloadService = DownloadService.getInstance(); + if(downloadService != null && afterServiceAvailable.size() > 0) { + for(Runnable runnable: afterServiceAvailable) { + handler.post(runnable); + } + afterServiceAvailable.clear(); + } + return downloadService; } - + public void runWhenServiceAvailable(Runnable runnable) { + if(getDownloadService() != null) { + runnable.run(); + } else { + afterServiceAvailable.add(runnable); + } + } + public static String getThemeName() { return theme; } @@ -811,6 +944,170 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte return touchscreen; } + public void openNowPlaying() { + + } + public void closeNowPlaying() { + + } + + public void setActiveServer(int instance) { + if (Util.getActiveServer(this) != instance) { + final DownloadService service = getDownloadService(); + if (service != null) { + new SilentBackgroundTask<Void>(this) { + @Override + protected Void doInBackground() throws Throwable { + service.clearIncomplete(); + return null; + } + }.execute(); + + } + Util.setActiveServer(this, instance); + invalidate(); + UserUtil.refreshCurrentUser(this, false, true); + updateDrawerHeader(); + } + } + public void updateDrawerHeader() { + if(Util.isOffline(this)) { + drawerServerName.setText(R.string.select_album_offline); + drawerUserName.setText(""); + drawerUserAvatar.setVisibility(View.GONE); + drawerHeader.setClickable(false); + drawerHeaderToggle.setVisibility(View.GONE); + } else { + drawerServerName.setText(Util.getServerName(this)); + drawerUserName.setText(UserUtil.getCurrentUsername(this)); + drawerUserAvatar.setVisibility(View.VISIBLE); + getImageLoader().loadAvatar(this, drawerUserAvatar, UserUtil.getCurrentUsername(this)); + drawerHeader.setClickable(true); + drawerHeaderToggle.setVisibility(View.VISIBLE); + } + } + + public void toggleOffline() { + boolean isOffline = Util.isOffline(this); + Util.setOffline(this, !isOffline); + invalidate(); + DownloadService service = getDownloadService(); + if (service != null) { + service.setOnline(isOffline); + } + + // Coming back online + if(isOffline) { + int scrobblesCount = Util.offlineScrobblesCount(this); + int starsCount = Util.offlineStarsCount(this); + if(scrobblesCount > 0 || starsCount > 0){ + showOfflineSyncDialog(scrobblesCount, starsCount); + } + } + + UserUtil.seedCurrentUser(this); + this.updateDrawerHeader(); + } + + private void showOfflineSyncDialog(final int scrobbleCount, final int starsCount) { + String syncDefault = Util.getSyncDefault(this); + if(syncDefault != null) { + if("sync".equals(syncDefault)) { + syncOffline(scrobbleCount, starsCount); + return; + } else if("delete".equals(syncDefault)) { + deleteOffline(); + return; + } + } + + View checkBoxView = this.getLayoutInflater().inflate(R.layout.sync_dialog, null); + final CheckBox checkBox = (CheckBox)checkBoxView.findViewById(R.id.sync_default); + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setIcon(android.R.drawable.ic_dialog_info) + .setTitle(R.string.offline_sync_dialog_title) + .setMessage(this.getResources().getString(R.string.offline_sync_dialog_message, scrobbleCount, starsCount)) + .setView(checkBoxView) + .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if(checkBox.isChecked()) { + Util.setSyncDefault(SubsonicActivity.this, "sync"); + } + syncOffline(scrobbleCount, starsCount); + } + }).setNeutralButton(R.string.common_cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + dialogInterface.dismiss(); + } + }).setNegativeButton(R.string.common_delete, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + if (checkBox.isChecked()) { + Util.setSyncDefault(SubsonicActivity.this, "delete"); + } + deleteOffline(); + } + }); + + builder.create().show(); + } + + private void syncOffline(final int scrobbleCount, final int starsCount) { + new SilentBackgroundTask<Integer>(this) { + @Override + protected Integer doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(SubsonicActivity.this); + return musicService.processOfflineSyncs(SubsonicActivity.this, null); + } + + @Override + protected void done(Integer result) { + if(result == scrobbleCount) { + Util.toast(SubsonicActivity.this, getResources().getString(R.string.offline_sync_success, result)); + } else { + Util.toast(SubsonicActivity.this, getResources().getString(R.string.offline_sync_partial, result, scrobbleCount + starsCount)); + } + } + + @Override + protected void error(Throwable error) { + Log.w(TAG, "Failed to sync offline stats", error); + String msg = getResources().getString(R.string.offline_sync_error) + " " + getErrorMessage(error); + Util.toast(SubsonicActivity.this, msg); + } + }.execute(); + } + private void deleteOffline() { + SharedPreferences.Editor offline = Util.getOfflineSync(this).edit(); + offline.putInt(Constants.OFFLINE_SCROBBLE_COUNT, 0); + offline.putInt(Constants.OFFLINE_STAR_COUNT, 0); + offline.commit(); + } + + public int getDrawerItemId(String fragmentType) { + switch(fragmentType) { + case "Home": + return R.id.drawer_home; + case "Artist": + return R.id.drawer_library; + case "Playlist": + return R.id.drawer_playlists; + case "Podcast": + return R.id.drawer_podcasts; + case "Bookmark": + return R.id.drawer_bookmarks; + case "Share": + return R.id.drawer_shares; + case "Chat": + return R.id.drawer_chat; + default: + return R.id.drawer_home; + } + } + private void setUncaughtExceptionHandler() { Thread.UncaughtExceptionHandler handler = Thread.getDefaultUncaughtExceptionHandler(); if (!(handler instanceof SubsonicActivity.SubsonicUncaughtExceptionHandler)) { diff --git a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java index 6614e09d..56b14ca9 100644 --- a/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java +++ b/app/src/main/java/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java @@ -30,16 +30,22 @@ import android.content.res.TypedArray; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; +import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; +import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.widget.ImageButton; +import android.widget.ImageView; import android.widget.TextView; +import com.sothree.slidinguppanel.SlidingUpPanelLayout; + import java.io.File; -import java.text.SimpleDateFormat; import java.util.Date; +import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -53,6 +59,7 @@ import github.daneren2005.dsub.fragments.AdminFragment; import github.daneren2005.dsub.fragments.ChatFragment; import github.daneren2005.dsub.fragments.DownloadFragment; import github.daneren2005.dsub.fragments.MainFragment; +import github.daneren2005.dsub.fragments.NowPlayingFragment; import github.daneren2005.dsub.fragments.SearchFragment; import github.daneren2005.dsub.fragments.SelectArtistFragment; import github.daneren2005.dsub.fragments.SelectBookmarkFragment; @@ -66,7 +73,6 @@ import github.daneren2005.dsub.service.DownloadService; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.MusicServiceFactory; import github.daneren2005.dsub.updates.Updater; -import github.daneren2005.dsub.util.BackgroundTask; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.FileUtil; import github.daneren2005.dsub.util.SilentBackgroundTask; @@ -77,15 +83,21 @@ import github.daneren2005.dsub.view.ChangeLog; /** * Created by Scott on 10/14/13. */ -public class SubsonicFragmentActivity extends SubsonicActivity { +public class SubsonicFragmentActivity extends SubsonicActivity implements DownloadService.OnSongChangedListener { private static String TAG = SubsonicFragmentActivity.class.getSimpleName(); private static boolean infoDialogDisplayed; private static boolean sessionInitialized = false; private static long ALLOWED_SKEW = 30000L; - private ScheduledExecutorService executorService; + private SlidingUpPanelLayout slideUpPanel; + private SlidingUpPanelLayout.PanelSlideListener panelSlideListener; + private NowPlayingFragment nowPlayingFragment; + private SubsonicFragment secondaryFragment; + private Toolbar mainToolbar; + private Toolbar nowPlayingToolbar; + private View bottomBar; - private View coverArtView; + private ImageView coverArtView; private TextView trackView; private TextView artistView; private ImageButton startButton; @@ -95,6 +107,24 @@ public class SubsonicFragmentActivity extends SubsonicActivity { @Override public void onCreate(Bundle savedInstanceState) { + if(savedInstanceState == null) { + String fragmentType = getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE); + boolean firstRun = false; + if (fragmentType == null) { + fragmentType = Util.openToTab(this); + if (fragmentType != null) { + firstRun = true; + } + } + + if ("".equals(fragmentType) || fragmentType == null || firstRun) { + // Initial startup stuff + if (!sessionInitialized) { + loadSession(); + } + } + } + super.onCreate(savedInstanceState); if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) { stopService(new Intent(this, DownloadService.class)); @@ -102,75 +132,130 @@ public class SubsonicFragmentActivity extends SubsonicActivity { getImageLoader().clearCache(); } else if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW)) { getIntent().putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, "Download"); - if(drawerAdapter != null) { - drawerAdapter.setDownloadVisible(true); - } - } else if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD)) { - DownloadService service = getDownloadService(); - if((service != null && service.getCurrentPlaying() != null)) { - getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD); - Intent intent = new Intent(); - intent.setClass(this, DownloadActivity.class); - startActivity(intent); - } + lastSelectedPosition = R.id.drawer_downloading; } setContentView(R.layout.abstract_fragment_activity); UserUtil.seedCurrentUser(this); if (findViewById(R.id.fragment_container) != null && savedInstanceState == null) { String fragmentType = getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE); - boolean firstRun = false; if(fragmentType == null) { fragmentType = Util.openToTab(this); if(fragmentType != null) { getIntent().putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, fragmentType); - firstRun = true; + lastSelectedPosition = getDrawerItemId(fragmentType); + } else { + lastSelectedPosition = R.id.drawer_home; } - } - currentFragment = getNewFragment(fragmentType); - - if("".equals(fragmentType) || fragmentType == null || firstRun) { - // Initial startup stuff - if(!sessionInitialized) { - loadSession(); + + MenuItem item = drawerList.getMenu().findItem(lastSelectedPosition); + if(item != null) { + item.setChecked(true); } } - + currentFragment = getNewFragment(fragmentType); currentFragment.setPrimaryFragment(true); getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, currentFragment, currentFragment.getSupportTag() + "").commit(); - + if(getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY) != null) { SearchFragment fragment = new SearchFragment(); replaceFragment(fragment, fragment.getSupportTag()); } - + // If a album type is set, switch to that album type view String albumType = getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE); if(albumType != null) { SubsonicFragment fragment = new SelectDirectoryFragment(); - + Bundle args = new Bundle(); args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, albumType); args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20); args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0); - + fragment.setArguments(args); replaceFragment(fragment, fragment.getSupportTag()); } } - bottomBar = findViewById(R.id.bottom_bar); - bottomBar.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - Intent intent = new Intent(); - intent.setClass(v.getContext(), DownloadActivity.class); - startActivity(intent); + slideUpPanel = (SlidingUpPanelLayout) findViewById(R.id.slide_up_panel); + panelSlideListener = new SlidingUpPanelLayout.PanelSlideListener() { + @Override + public void onPanelSlide(View panel, float slideOffset) { + } - }); - coverArtView = bottomBar.findViewById(R.id.album_art); + + @Override + public void onPanelCollapsed(View panel) { + bottomBar.setVisibility(View.VISIBLE); + nowPlayingToolbar.setVisibility(View.GONE); + nowPlayingFragment.setPrimaryFragment(false); + setSupportActionBar(mainToolbar); + + if(getSupportActionBar().getCustomView() == null) { + createCustomActionBarView(); + } + recreateSpinner(); + if(drawerToggle != null && backStack.size() > 0) { + drawerToggle.setDrawerIndicatorEnabled(false); + } else { + drawerToggle.setDrawerIndicatorEnabled(true); + } + } + + @Override + public void onPanelExpanded(View panel) { + currentFragment.stopActionMode(); + + // Disable custom view before switching + getSupportActionBar().setDisplayShowCustomEnabled(false); + + bottomBar.setVisibility(View.GONE); + nowPlayingToolbar.setVisibility(View.VISIBLE); + setSupportActionBar(nowPlayingToolbar); + nowPlayingFragment.setPrimaryFragment(true); + + drawerToggle.setDrawerIndicatorEnabled(false); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + } + + @Override + public void onPanelAnchored(View panel) { + + } + + @Override + public void onPanelHidden(View panel) { + + } + }; + slideUpPanel.setPanelSlideListener(panelSlideListener); + + if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD)) { + // Post this later so it actually runs + handler.postDelayed(new Runnable() { + @Override + public void run() { + openNowPlaying(); + } + }, 200); + } + + bottomBar = findViewById(R.id.bottom_bar); + mainToolbar = (Toolbar) findViewById(R.id.main_toolbar); + nowPlayingToolbar = (Toolbar) findViewById(R.id.now_playing_toolbar); + coverArtView = (ImageView) bottomBar.findViewById(R.id.album_art); trackView = (TextView) bottomBar.findViewById(R.id.track_name); artistView = (TextView) bottomBar.findViewById(R.id.artist_name); + setSupportActionBar(mainToolbar); + + if (findViewById(R.id.fragment_container) != null && savedInstanceState == null) { + nowPlayingFragment = new NowPlayingFragment(); + FragmentTransaction trans = getSupportFragmentManager().beginTransaction(); + trans.add(R.id.now_playing_fragment_container, nowPlayingFragment, nowPlayingFragment.getTag() + ""); + trans.commit(); + } + ImageButton previousButton = (ImageButton) findViewById(R.id.download_previous); previousButton.setOnClickListener(new View.OnClickListener() { @Override @@ -185,11 +270,6 @@ public class SubsonicFragmentActivity extends SubsonicActivity { getDownloadService().previous(); return null; } - - @Override - protected void done(Void result) { - update(); - } }.execute(); } }); @@ -210,11 +290,6 @@ public class SubsonicFragmentActivity extends SubsonicActivity { return null; } - - @Override - protected void done(Void result) { - update(); - } }.execute(); } }); @@ -233,11 +308,6 @@ public class SubsonicFragmentActivity extends SubsonicActivity { getDownloadService().next(); return null; } - - @Override - protected void done(Void result) { - update(); - } }.execute(); } }); @@ -262,7 +332,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity { } } } - + @Override public void onNewIntent(Intent intent) { super.onNewIntent(intent); @@ -276,7 +346,6 @@ public class SubsonicFragmentActivity extends SubsonicActivity { if (query != null) { ((SearchFragment)currentFragment).search(query, autoplay); } else { - ((SearchFragment)currentFragment).populateList(); if (requestsearch) { onSearchRequested(); } @@ -300,19 +369,6 @@ public class SubsonicFragmentActivity extends SubsonicActivity { public void onResume() { super.onResume(); - final Handler handler = new Handler(); - Runnable runnable = new Runnable() { - @Override - public void run() { - handler.post(new Runnable() { - @Override - public void run() { - update(); - } - }); - } - }; - if(getIntent().hasExtra(Constants.INTENT_EXTRA_VIEW_ALBUM)) { SubsonicFragment fragment = new SelectDirectoryFragment(); Bundle args = new Bundle(); @@ -329,29 +385,46 @@ public class SubsonicFragmentActivity extends SubsonicActivity { replaceFragment(fragment, fragment.getSupportTag()); getIntent().removeExtra(Constants.INTENT_EXTRA_VIEW_ALBUM); - if("Artist".equals(getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE))) { - lastSelectedPosition = 1; - } } createAccount(); - - executorService = Executors.newSingleThreadScheduledExecutor(); - executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS); + runWhenServiceAvailable(new Runnable() { + @Override + public void run() { + getDownloadService().addOnSongChangedListener(SubsonicFragmentActivity.this, true); + } + }); } @Override public void onPause() { super.onPause(); - executorService.shutdown(); + DownloadService downloadService = getDownloadService(); + if(downloadService != null) { + downloadService.removeOnSongChangeListener(this); + } } @Override + public void onSaveInstanceState(Bundle savedInstanceState) { + super.onSaveInstanceState(savedInstanceState); + savedInstanceState.putString(Constants.MAIN_NOW_PLAYING, nowPlayingFragment.getTag()); + savedInstanceState.putInt(Constants.MAIN_SLIDE_PANEL_STATE, slideUpPanel.getPanelState().hashCode()); + } + @Override public void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); + + String id = savedInstanceState.getString(Constants.MAIN_NOW_PLAYING); + FragmentManager fm = getSupportFragmentManager(); + nowPlayingFragment = (NowPlayingFragment) fm.findFragmentByTag(id); if(drawerToggle != null && backStack.size() > 0) { drawerToggle.setDrawerIndicatorEnabled(false); } + + if(savedInstanceState.getInt(Constants.MAIN_SLIDE_PANEL_STATE, -1) == SlidingUpPanelLayout.PanelState.EXPANDED.hashCode()) { + panelSlideListener.onPanelExpanded(null); + } } @Override @@ -369,7 +442,9 @@ public class SubsonicFragmentActivity extends SubsonicActivity { @Override public void onBackPressed() { - if(onBackPressedSupport()) { + if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED && secondaryFragment == null) { + slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); + } else if(onBackPressedSupport()) { if(!Util.disableExitPrompt(this) && lastBackPressTime < (System.currentTimeMillis() - 4000)) { lastBackPressTime = System.currentTimeMillis(); Util.toast(this, R.string.main_back_confirm); @@ -380,37 +455,99 @@ public class SubsonicFragmentActivity extends SubsonicActivity { } @Override + public boolean onBackPressedSupport() { + if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) { + removeCurrent(); + return false; + } else { + return super.onBackPressedSupport(); + } + } + + @Override + protected SubsonicFragment getCurrentFragment() { + if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) { + return nowPlayingFragment; + } else { + return super.getCurrentFragment(); + } + } + + @Override public void replaceFragment(SubsonicFragment fragment, int tag, boolean replaceCurrent) { - super.replaceFragment(fragment, tag, replaceCurrent); - if(drawerToggle != null) { - drawerToggle.setDrawerIndicatorEnabled(false); + if(slideUpPanel != null && slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) { + secondaryFragment = fragment; + nowPlayingFragment.setPrimaryFragment(false); + secondaryFragment.setPrimaryFragment(true); + supportInvalidateOptionsMenu(); + + FragmentTransaction trans = getSupportFragmentManager().beginTransaction(); + trans.setCustomAnimations(R.anim.enter_from_right, R.anim.exit_to_left, R.anim.enter_from_left, R.anim.exit_to_right); + trans.hide(nowPlayingFragment); + trans.add(R.id.now_playing_fragment_container, secondaryFragment, tag + ""); + trans.commit(); + } else { + super.replaceFragment(fragment, tag, replaceCurrent); + if (drawerToggle != null) { + drawerToggle.setDrawerIndicatorEnabled(false); + } } } @Override public void removeCurrent() { - super.removeCurrent(); - if(drawerToggle != null && backStack.isEmpty()) { - drawerToggle.setDrawerIndicatorEnabled(true); + if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED && secondaryFragment != null) { + FragmentTransaction trans = getSupportFragmentManager().beginTransaction(); + trans.setCustomAnimations(R.anim.enter_from_left, R.anim.exit_to_right, R.anim.enter_from_right, R.anim.exit_to_left); + trans.remove(secondaryFragment); + trans.show(nowPlayingFragment); + trans.commit(); + + secondaryFragment = null; + nowPlayingFragment.setPrimaryFragment(true); + supportInvalidateOptionsMenu(); + } else { + super.removeCurrent(); + if (drawerToggle != null && backStack.isEmpty()) { + drawerToggle.setDrawerIndicatorEnabled(true); + } } } - + + @Override + public void setTitle(CharSequence title) { + if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) { + getSupportActionBar().setTitle(title); + } else { + super.setTitle(title); + } + } + + @Override + protected void drawerItemSelected(String fragmentType) { + super.drawerItemSelected(fragmentType); + + if(slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED) { + slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); + } + } + @Override public void startFragmentActivity(String fragmentType) { // Create a transaction that does all of this FragmentTransaction trans = getSupportFragmentManager().beginTransaction(); - + // Clear existing stack for(int i = backStack.size() - 1; i >= 0; i--) { trans.remove(backStack.get(i)); } trans.remove(currentFragment); backStack.clear(); - + // Create new stack currentFragment = getNewFragment(fragmentType); currentFragment.setPrimaryFragment(true); trans.add(R.id.fragment_container, currentFragment, currentFragment.getSupportTag() + ""); - + // Done, cleanup trans.commit(); supportInvalidateOptionsMenu(); @@ -426,7 +563,16 @@ public class SubsonicFragmentActivity extends SubsonicActivity { drawerToggle.setDrawerIndicatorEnabled(true); } } - + + @Override + public void openNowPlaying() { + slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.EXPANDED); + } + @Override + public void closeNowPlaying() { + slideUpPanel.setPanelState(SlidingUpPanelLayout.PanelState.COLLAPSED); + } + private SubsonicFragment getNewFragment(String fragmentType) { if("Artist".equals(fragmentType)) { return new SelectArtistFragment(); @@ -447,38 +593,6 @@ public class SubsonicFragmentActivity extends SubsonicActivity { } else { return new MainFragment(); } - } - - private void update() { - DownloadService downloadService = getDownloadService(); - if (downloadService == null) { - return; - } - - DownloadFile current = downloadService.getCurrentPlaying(); - PlayerState state = downloadService.getPlayerState(); - if(current == currentPlaying && state == currentState) { - return; - } else { - currentPlaying = current; - currentState = state; - } - - MusicDirectory.Entry song = null; - if(current != null) { - song = current.getSong(); - trackView.setText(song.getTitle()); - artistView.setText(song.getArtist()); - } else { - trackView.setText("Title"); - artistView.setText("Artist"); - } - - getImageLoader().loadImage(coverArtView, song, false, false); - int[] attrs = new int[] {(state == PlayerState.STARTED) ? R.attr.media_button_pause : R.attr.media_button_start}; - TypedArray typedArray = this.obtainStyledAttributes(attrs); - startButton.setImageResource(typedArray.getResourceId(0, 0)); - typedArray.recycle(); } public void checkUpdates() { @@ -502,7 +616,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity { if(ServerInfo.canSavePlayQueue(this) && !Util.isOffline(this)) { loadRemotePlayQueue(); } - + sessionInitialized = true; } private void loadSettings() { @@ -551,7 +665,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity { return true; } } - + private void loadBookmarks() { final Context context = this; new SilentBackgroundTask<Void>(context) { @@ -562,7 +676,7 @@ public class SubsonicFragmentActivity extends SubsonicActivity { return null; } - + @Override public void error(Throwable error) { Log.e(TAG, "Failed to get bookmarks", error); @@ -683,4 +797,54 @@ public class SubsonicFragmentActivity extends SubsonicActivity { } } } + + public Toolbar getActiveToolbar() { + return slideUpPanel.getPanelState() == SlidingUpPanelLayout.PanelState.EXPANDED ? nowPlayingToolbar : mainToolbar; + } + + @Override + public void onSongChanged(DownloadFile currentPlaying, int currentPlayingIndex) { + this.currentPlaying = currentPlaying; + + MusicDirectory.Entry song = null; + if (currentPlaying != null) { + song = currentPlaying.getSong(); + trackView.setText(song.getTitle()); + artistView.setText(song.getArtist()); + } else { + trackView.setText(R.string.main_title); + artistView.setText(R.string.main_artist); + } + + if (coverArtView != null) { + int height = coverArtView.getHeight(); + if (height <= 0) { + int[] attrs = new int[]{R.attr.actionBarSize}; + TypedArray typedArray = this.obtainStyledAttributes(attrs); + height = typedArray.getDimensionPixelSize(0, 0); + typedArray.recycle(); + } + getImageLoader().loadImage(coverArtView, song, false, height, false); + } + } + + @Override + public void onSongsChanged(List<DownloadFile> songs, DownloadFile currentPlaying, int currentPlayingIndex) { + if(this.currentPlaying != currentPlaying || currentPlaying == null) { + onSongChanged(currentPlaying, currentPlayingIndex); + } + } + + @Override + public void onSongProgress(DownloadFile currentPlaying, int millisPlayed, Integer duration, boolean isSeekable) { + + } + + @Override + public void onStateUpdate(DownloadFile downloadFile, PlayerState playerState) { + int[] attrs = new int[]{(playerState == PlayerState.STARTED) ? R.attr.actionbar_pause : R.attr.actionbar_start}; + TypedArray typedArray = this.obtainStyledAttributes(attrs); + startButton.setImageResource(typedArray.getResourceId(0, 0)); + typedArray.recycle(); + } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/AlbumGridAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/AlbumGridAdapter.java deleted file mode 100644 index eb187569..00000000 --- a/app/src/main/java/github/daneren2005/dsub/adapter/AlbumGridAdapter.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.adapter; - -import android.content.Context; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; - -import java.util.List; - -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.view.AlbumCell; - -public class AlbumGridAdapter extends ArrayAdapter<MusicDirectory.Entry> { - private final static String TAG = AlbumGridAdapter.class.getSimpleName(); - private final Context activity; - private final ImageLoader imageLoader; - private List<MusicDirectory.Entry> entries; - private boolean showArtist; - - public AlbumGridAdapter(Context activity, ImageLoader imageLoader, List<MusicDirectory.Entry> entries, boolean showArtist) { - super(activity, android.R.layout.simple_list_item_1, entries); - this.entries = entries; - this.activity = activity; - this.imageLoader = imageLoader; - - // Always show artist if they aren't all the same - if(!showArtist) { - String artist = null; - for(MusicDirectory.Entry entry: entries) { - if(artist == null) { - artist = entry.getArtist(); - } - - if(artist != null && !artist.equals(entry.getArtist())) { - showArtist = true; - } - } - } - this.showArtist = showArtist; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - MusicDirectory.Entry entry = getItem(position); - - AlbumCell view; - if(convertView instanceof AlbumCell) { - view = (AlbumCell) convertView; - } else { - view = new AlbumCell(activity); - } - - view.setShowArtist(showArtist); - view.setObject(entry, imageLoader); - return view; - } -} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/AlbumListAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/AlbumListAdapter.java deleted file mode 100644 index 7151362c..00000000 --- a/app/src/main/java/github/daneren2005/dsub/adapter/AlbumListAdapter.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.adapter; - -import android.content.Context; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.SectionIndexer; - -import com.commonsware.cwac.endless.EndlessAdapter; -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.ServerInfo; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; - -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Set; - -public class AlbumListAdapter extends EndlessAdapter implements SectionIndexer { - private static final String TAG = AlbumListAdapter.class.getSimpleName(); - Context context; - ArrayAdapter<MusicDirectory.Entry> adapter; - String type; - String extra; - int size; - int offset; - List<MusicDirectory.Entry> entries; - - private boolean shouldIndex = false; - private Object[] sections; - private Integer[] positions; - - public AlbumListAdapter(Context context, ArrayAdapter<MusicDirectory.Entry> adapter, String type, String extra, int size) { - super(adapter); - this.context = context; - this.adapter = adapter; - this.type = type; - this.extra = extra; - this.size = size; - this.offset = size; - - if("alphabeticalByName".equals(this.type)) { - shouldIndex = true; - recreateIndexes(); - } - } - - @Override - protected boolean cacheInBackground() throws Exception { - MusicService service = MusicServiceFactory.getMusicService(context); - MusicDirectory result; - if(("genres".equals(type) && ServerInfo.checkServerVersion(context, "1.10.0")) || "years".equals(type)) { - result = service.getAlbumList(type, extra, size, offset, context, null); - } else if("genres".equals(type) || "genres-songs".equals(type)) { - result = service.getSongsByGenre(extra, size, offset, context, null); - } else { - result = service.getAlbumList(type, size, offset, context, null); - } - entries = result.getChildren(); - return entries.size() > 0; - } - - @Override - protected void appendCachedData() { - for(MusicDirectory.Entry entry: entries) { - adapter.add(entry); - } - offset += entries.size(); - recreateIndexes(); - } - - @Override - protected View getPendingView(ViewGroup parent) { - View progress = LayoutInflater.from(context).inflate(R.layout.tab_progress, null); - progress.setVisibility(View.VISIBLE); - return progress; - } - - private void recreateIndexes() { - try { - if (!shouldIndex) { - return; - } - - Set<String> sectionSet = new LinkedHashSet<String>(30); - List<Integer> positionList = new ArrayList<Integer>(30); - for (int i = 0; i < adapter.getCount(); i++) { - MusicDirectory.Entry entry = adapter.getItem(i); - String index; - if (entry.getAlbum() != null) { - index = entry.getAlbum().substring(0, 1); - if (!Character.isLetter(index.charAt(0))) { - index = "#"; - } - } else { - index = "*"; - } - - if (!sectionSet.contains(index)) { - sectionSet.add(index); - positionList.add(i); - } - } - sections = sectionSet.toArray(new Object[sectionSet.size()]); - positions = positionList.toArray(new Integer[positionList.size()]); - } catch(Exception e) { - Log.e(TAG, "Error while recreating indexes"); - } - } - - @Override - public Object[] getSections() { - if(sections != null) { - return sections; - } else { - return new Object[0]; - } - } - - @Override - public int getPositionForSection(int section) { - if(sections != null) { - section = Math.min(section, positions.length - 1); - return positions[section]; - } else { - return 0; - } - } - - @Override - public int getSectionForPosition(int pos) { - if(sections != null) { - for (int i = 0; i < sections.length - 1; i++) { - if (pos < positions[i + 1]) { - return i; - } - } - return sections.length - 1; - } else { - return 0; - } - } -} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/AlphabeticalAlbumAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/AlphabeticalAlbumAdapter.java new file mode 100644 index 00000000..ccb3df4e --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/adapter/AlphabeticalAlbumAdapter.java @@ -0,0 +1,44 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.adapter; + +import android.content.Context; + +import java.util.List; + +import github.daneren2005.dsub.domain.MusicDirectory; +import github.daneren2005.dsub.util.ImageLoader; +import github.daneren2005.dsub.view.FastScroller; + +public class AlphabeticalAlbumAdapter extends EntryInfiniteGridAdapter implements FastScroller.BubbleTextGetter { + public AlphabeticalAlbumAdapter(Context context, List<MusicDirectory.Entry> entries, ImageLoader imageLoader, boolean largeCell) { + super(context, entries, imageLoader, largeCell); + } + + @Override + public String getTextToShowInBubble(int position) { + // Make sure that we are not trying to get an item for the loading placeholder + if(position >= sections.get(0).size()) { + if(sections.get(0).size() > 0) { + return getTextToShowInBubble(position - 1); + } else { + return "*"; + } + } else { + return getNameIndex(getItemForPosition(position).getAlbum()); + } + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/ArtistAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/ArtistAdapter.java index 4d469faf..2eea0e74 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/ArtistAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/ArtistAdapter.java @@ -1,97 +1,134 @@ /* - This file is part of Subsonic. + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. - - Copyright 2010 (C) Sindre Mehus - */ package github.daneren2005.dsub.adapter; import android.content.Context; -import github.daneren2005.dsub.R; -import java.util.List; +import android.support.v7.widget.PopupMenu; +import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.SectionIndexer; +import android.widget.TextView; + +import java.util.List; + +import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.Artist; +import github.daneren2005.dsub.domain.MusicFolder; +import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.ArtistView; +import github.daneren2005.dsub.view.FastScroller; +import github.daneren2005.dsub.view.UpdateView; + +public class ArtistAdapter extends SectionAdapter<Artist> implements FastScroller.BubbleTextGetter { + public static int VIEW_TYPE_ARTIST = 4; + + private List<MusicFolder> musicFolders; + private OnMusicFolderChanged onMusicFolderChanged; + + public ArtistAdapter(Context context, List<Artist> artists, OnItemClickedListener listener) { + this(context, artists, null, listener, null); + } + + public ArtistAdapter(Context context, List<Artist> artists, List<MusicFolder> musicFolders, OnItemClickedListener onItemClickedListener, OnMusicFolderChanged onMusicFolderChanged) { + super(context, artists); + this.musicFolders = musicFolders; + this.onItemClickedListener = onItemClickedListener; + this.onMusicFolderChanged = onMusicFolderChanged; + + if(musicFolders != null) { + this.singleSectionHeader = true; + } + } -import java.util.ArrayList; -import java.util.LinkedHashSet; -import java.util.Set; - -/** - * @author Sindre Mehus - */ -public class ArtistAdapter extends ArrayAdapter<Artist> implements SectionIndexer { - - private final Context activity; - - // Both arrays are indexed by section ID. - private final Object[] sections; - private final Integer[] positions; - - public ArtistAdapter(Context activity, List<Artist> artists) { - super(activity, R.layout.basic_list_item, artists); - this.activity = activity; - - Set<String> sectionSet = new LinkedHashSet<String>(30); - List<Integer> positionList = new ArrayList<Integer>(30); - for (int i = 0; i < artists.size(); i++) { - Artist artist = artists.get(i); - String index = artist.getIndex(); - if (!sectionSet.contains(index)) { - sectionSet.add(index); - positionList.add(i); - } - } - sections = sectionSet.toArray(new Object[sectionSet.size()]); - positions = positionList.toArray(new Integer[positionList.size()]); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Artist entry = getItem(position); - ArtistView view; - if (convertView != null && convertView instanceof ArtistView) { - view = (ArtistView) convertView; + @Override + public UpdateView.UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) { + final View header = LayoutInflater.from(context).inflate(R.layout.select_artist_header, parent, false); + header.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + PopupMenu popup = new PopupMenu(context, header.findViewById(R.id.select_artist_folder_2)); + + popup.getMenu().add(R.string.select_artist_all_folders); + for (MusicFolder musicFolder : musicFolders) { + popup.getMenu().add(musicFolder.getName()); + } + + popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + for (MusicFolder musicFolder : musicFolders) { + if(item.getTitle().equals(musicFolder.getName())) { + if(onMusicFolderChanged != null) { + onMusicFolderChanged.onMusicFolderChanged(musicFolder); + } + return true; + } + } + + if(onMusicFolderChanged != null) { + onMusicFolderChanged.onMusicFolderChanged(null); + } + return true; + } + }); + popup.show(); + } + }); + + return new UpdateView.UpdateViewHolder(header, false); + } + @Override + public void onBindHeaderHolder(UpdateView.UpdateViewHolder holder, String header) { + TextView folderName = (TextView) holder.getView().findViewById(R.id.select_artist_folder_2); + + String musicFolderId = Util.getSelectedMusicFolderId(context); + if(musicFolderId != null) { + for (MusicFolder musicFolder : musicFolders) { + if (musicFolder.getId().equals(musicFolderId)) { + folderName.setText(musicFolder.getName()); + break; + } + } } else { - view = new ArtistView(activity); + folderName.setText(R.string.select_artist_all_folders); } - view.setObject(entry); - return view; - } - + } + @Override - public Object[] getSections() { - return sections; - } - - @Override - public int getPositionForSection(int section) { - section = Math.min(section, positions.length - 1); - return positions[section]; - } - - @Override - public int getSectionForPosition(int pos) { - for (int i = 0; i < sections.length - 1; i++) { - if (pos < positions[i + 1]) { - return i; - } - } - return sections.length - 1; - } + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new ArtistView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Artist item, int viewType) { + holder.getUpdateView().setObject(item); + } + + @Override + public int getItemViewType(Artist item) { + return VIEW_TYPE_ARTIST; + } + + @Override + public String getTextToShowInBubble(int position) { + return getNameIndex(getItemForPosition(position).getName(), true); + } + + public interface OnMusicFolderChanged { + void onMusicFolderChanged(MusicFolder musicFolder); + } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/BasicListAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/BasicListAdapter.java new file mode 100644 index 00000000..dfea91bf --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/adapter/BasicListAdapter.java @@ -0,0 +1,48 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.adapter; + +import android.content.Context; +import android.view.ViewGroup; + +import java.util.List; + +import github.daneren2005.dsub.view.BasicListView; +import github.daneren2005.dsub.view.UpdateView; + +public class BasicListAdapter extends SectionAdapter<String> { + public static int VIEW_TYPE_LINE = 1; + + public BasicListAdapter(Context context, List<String> strings, OnItemClickedListener listener) { + super(context, strings); + this.onItemClickedListener = listener; + } + + @Override + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new BasicListView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, String item, int viewType) { + holder.getUpdateView().setObject(item); + } + + @Override + public int getItemViewType(String item) { + return VIEW_TYPE_LINE; + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/BookmarkAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/BookmarkAdapter.java index 26d3e16a..8e960de4 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/BookmarkAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/BookmarkAdapter.java @@ -1,20 +1,16 @@ /* - This file is part of Subsonic. - + This file is part of Subsonic. Subsonic is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Subsonic is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License along with Subsonic. If not, see <http://www.gnu.org/licenses/>. - - Copyright 2010 (C) Sindre Mehus + Copyright 2015 (C) Scott Jackson */ package github.daneren2005.dsub.adapter; @@ -22,9 +18,10 @@ package github.daneren2005.dsub.adapter; import android.content.Context; import java.util.List; -import android.view.View; + +import android.view.Menu; +import android.view.MenuInflater; import android.view.ViewGroup; -import android.widget.ArrayAdapter; import android.widget.TextView; import github.daneren2005.dsub.R; @@ -32,33 +29,48 @@ import github.daneren2005.dsub.domain.Bookmark; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.view.SongView; +import github.daneren2005.dsub.view.UpdateView; -public class BookmarkAdapter extends ArrayAdapter<MusicDirectory.Entry> { +public class BookmarkAdapter extends SectionAdapter<MusicDirectory.Entry> { private final static String TAG = BookmarkAdapter.class.getSimpleName(); - private Context activity; - public BookmarkAdapter(Context activity, List<MusicDirectory.Entry> bookmarks) { - super(activity, android.R.layout.simple_list_item_1, bookmarks); - this.activity = activity; + public BookmarkAdapter(Context activity, List<MusicDirectory.Entry> bookmarks, OnItemClickedListener listener) { + super(activity, bookmarks); + this.onItemClickedListener = listener; + checkable = true; } - - public View getView(int position, View convertView, ViewGroup parent) { - MusicDirectory.Entry entry = getItem(position); - Bookmark bookmark = entry.getBookmark(); - SongView view; - if (convertView != null) { - view = (SongView) convertView; - } else { - view = new SongView(activity); - } - view.setObject(entry, false); - + @Override + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new SongView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, MusicDirectory.Entry item, int viewType) { + SongView songView = (SongView) holder.getUpdateView(); + Bookmark bookmark = item.getBookmark(); + + songView.setObject(item, true); + // Add current position to duration - TextView durationTextView = (TextView) view.findViewById(R.id.song_duration); + TextView durationTextView = (TextView) songView.findViewById(R.id.song_duration); String duration = durationTextView.getText().toString(); durationTextView.setText(Util.formatDuration(bookmark.getPosition() / 1000) + " / " + duration); - - return view; + } + + @Override + public int getItemViewType(MusicDirectory.Entry item) { + return EntryGridAdapter.VIEW_TYPE_SONG; + } + + @Override + public void onCreateActionModeMenu(Menu menu, MenuInflater menuInflater) { + if(Util.isOffline(context)) { + menuInflater.inflate(R.menu.multiselect_media_offline, menu); + } else { + menuInflater.inflate(R.menu.multiselect_media, menu); + } + + menu.removeItem(R.id.menu_remove_playlist); } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/DetailsAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/DetailsAdapter.java new file mode 100644 index 00000000..927b63ae --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/adapter/DetailsAdapter.java @@ -0,0 +1,62 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.adapter; + +import android.content.Context; +import android.text.SpannableString; +import android.text.method.LinkMovementMethod; +import android.text.util.Linkify; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +import java.util.List; + +import github.daneren2005.dsub.R; + +public class DetailsAdapter extends ArrayAdapter<String> { + private List<String> headers; + private List<String> details; + + public DetailsAdapter(Context context, int layout, List<String> headers, List<String> details) { + super(context, layout, headers); + + this.headers = headers; + this.details = details; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent){ + View view; + if(convertView == null) { + view = LayoutInflater.from(getContext()).inflate(R.layout.details_item, null); + } else { + view = convertView; + } + + TextView nameView = (TextView) view.findViewById(R.id.detail_name); + TextView detailsView = (TextView) view.findViewById(R.id.detail_value); + + nameView.setText(headers.get(position)); + + detailsView.setText(details.get(position)); + Linkify.addLinks(detailsView, Linkify.WEB_URLS | Linkify.EMAIL_ADDRESSES); + + return view; + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/DownloadFileAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/DownloadFileAdapter.java index be9b4cb9..37a4ab93 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/DownloadFileAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/DownloadFileAdapter.java @@ -24,26 +24,30 @@ import java.util.List; import github.daneren2005.dsub.service.DownloadFile; import github.daneren2005.dsub.view.SongView; +import github.daneren2005.dsub.view.UpdateView; -public class DownloadFileAdapter extends ArrayAdapter<DownloadFile> { - Context context; +public class DownloadFileAdapter extends SectionAdapter<DownloadFile> { + public static int VIEW_TYPE_DOWNLOAD_FILE = 1; - public DownloadFileAdapter(Context context, List<DownloadFile> entries) { - super(context, android.R.layout.simple_list_item_1, entries); - this.context = context; + public DownloadFileAdapter(Context context, List<DownloadFile> entries, OnItemClickedListener onItemClickedListener) { + super(context, entries); + this.onItemClickedListener = onItemClickedListener; } @Override - public View getView(int position, View convertView, ViewGroup parent) { - SongView view; - if (convertView != null && convertView instanceof SongView) { - view = (SongView) convertView; - } else { - view = new SongView(context); - } - DownloadFile downloadFile = getItem(position); - view.setObject(downloadFile.getSong(), false); - view.setDownloadFile(downloadFile); - return view; + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new SongView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, DownloadFile item, int viewType) { + SongView songView = (SongView) holder.getUpdateView(); + songView.setObject(item.getSong(), false); + songView.setDownloadFile(item); + } + + @Override + public int getItemViewType(DownloadFile item) { + return VIEW_TYPE_DOWNLOAD_FILE; } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/DrawerAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/DrawerAdapter.java deleted file mode 100644 index b0a4a33d..00000000 --- a/app/src/main/java/github/daneren2005/dsub/adapter/DrawerAdapter.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. - - Copyright 2009 (C) Sindre Mehus -*/ -package github.daneren2005.dsub.adapter; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.ImageView; -import android.widget.TextView; - -import java.util.List; - -import github.daneren2005.dsub.R; - -/** - * Created by Scott on 11/8/13. - */ -public class DrawerAdapter extends ArrayAdapter<String> { - private static String TAG = DrawerAdapter.class.getSimpleName(); - private Context context; - private List<String> items; - private List<Integer> icons; - private List<Boolean> visible; - private int selectedPosition = -1; - - public DrawerAdapter(Context context, List<String> items, List<Integer> icons, List<Boolean> visible) { - super(context, R.layout.drawer_list_item, items); - - this.context = context; - this.items = items; - this.icons = icons; - this.visible = visible; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - position = getActualPosition(position); - String item = items.get(position); - Integer icon = icons.get(position); - - if(convertView == null) { - convertView = LayoutInflater.from(context).inflate(R.layout.drawer_list_item, null); - } - - TextView textView = (TextView) convertView.findViewById(R.id.drawer_name); - textView.setText(item); - - if(selectedPosition == position) { - textView.setTextAppearance(context, R.style.DSub_TextViewStyle_Bold); - selectedPosition = -1; - } - - ImageView iconView = (ImageView) convertView.findViewById(R.id.drawer_icon); - iconView.setImageResource(icon); - - return convertView; - } - - @Override - public int getCount() { - int count = 0; - for(int i = 0; i < visible.size(); i++) { - if(visible.get(i)) { - count++; - } - } - - return count; - } - - public int getActualPosition(int position) { - for(int i = 0; i <= position; i++) { - if(!visible.get(i)) { - position++; - } - } - - return position; - } - public int getAdapterPosition(int position) { - if(!visible.get(position)) { - visible.set(position, true); - notifyDataSetChanged(); - } - - for(int i = position; i >= 0; i--) { - if(!visible.get(i)) { - position--; - } - } - - return position; - } - - public void setItemVisible(int position, boolean visible) { - if(this.visible.get(position) != visible) { - this.visible.set(position, visible); - notifyDataSetInvalidated(); - } - } - public void setDownloadVisible(boolean visible) { - setItemVisible(items.size() - 2, visible); - } - - public void setSelectedPosition(int position) { - selectedPosition = position; - } -} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/EntryAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/EntryAdapter.java deleted file mode 100644 index 9e506e5a..00000000 --- a/app/src/main/java/github/daneren2005/dsub/adapter/EntryAdapter.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.adapter; - -import android.content.Context; - -import java.util.List; - -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.view.AlbumView; -import github.daneren2005.dsub.view.ArtistEntryView; -import github.daneren2005.dsub.view.SongView; - -/** - * @author Sindre Mehus - */ -public class EntryAdapter extends ArrayAdapter<MusicDirectory.Entry> { - private final static String TAG = EntryAdapter.class.getSimpleName(); - private final Context activity; - private final ImageLoader imageLoader; - private final boolean checkable; - private List<MusicDirectory.Entry> entries; - - public EntryAdapter(Context activity, ImageLoader imageLoader, List<MusicDirectory.Entry> entries, boolean checkable) { - super(activity, android.R.layout.simple_list_item_1, entries); - this.entries = entries; - this.activity = activity; - this.imageLoader = imageLoader; - this.checkable = checkable; - } - - public void removeAt(int position) { - entries.remove(position); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - MusicDirectory.Entry entry = getItem(position); - - if (entry.isDirectory()) { - if(entry.isAlbum()) { - AlbumView view; - view = new AlbumView(activity); - view.setObject(entry, imageLoader); - return view; - } else { - ArtistEntryView view = new ArtistEntryView(activity); - view.setObject(entry); - return view; - } - } else { - SongView view; - if (convertView != null && convertView instanceof SongView) { - view = (SongView) convertView; - } else { - view = new SongView(activity); - } - view.setObject(entry, checkable); - return view; - } - } -} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java new file mode 100644 index 00000000..78ef13ed --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/adapter/EntryGridAdapter.java @@ -0,0 +1,145 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.adapter; + +import android.content.Context; +import android.util.Log; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; +import java.util.List; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.MusicDirectory; +import github.daneren2005.dsub.domain.MusicDirectory.Entry; +import github.daneren2005.dsub.util.ImageLoader; +import github.daneren2005.dsub.util.Util; +import github.daneren2005.dsub.view.AlbumView; +import github.daneren2005.dsub.view.SongView; +import github.daneren2005.dsub.view.UpdateView; +import github.daneren2005.dsub.view.UpdateView.UpdateViewHolder; + +public class EntryGridAdapter extends SectionAdapter<Entry> { + private static String TAG = EntryGridAdapter.class.getSimpleName(); + + public static int VIEW_TYPE_ALBUM_CELL = 1; + public static int VIEW_TYPE_ALBUM_LINE = 2; + public static int VIEW_TYPE_SONG = 3; + + private ImageLoader imageLoader; + private boolean largeAlbums; + private boolean showArtist = false; + private boolean removeFromPlaylist = false; + private View header; + + public EntryGridAdapter(Context context, List<Entry> entries, ImageLoader imageLoader, boolean largeCell) { + super(context, entries); + this.imageLoader = imageLoader; + this.largeAlbums = largeCell; + + // Always show artist if they aren't all the same + String artist = null; + for(MusicDirectory.Entry entry: entries) { + if(artist == null) { + artist = entry.getArtist(); + } + + if(artist != null && !artist.equals(entry.getArtist())) { + showArtist = true; + } + } + checkable = true; + } + + @Override + public UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + UpdateView updateView = null; + if(viewType == VIEW_TYPE_ALBUM_LINE || viewType == VIEW_TYPE_ALBUM_CELL) { + updateView = new AlbumView(context, viewType == VIEW_TYPE_ALBUM_CELL); + } else if(viewType == VIEW_TYPE_SONG) { + updateView = new SongView(context); + } + + return new UpdateViewHolder(updateView); + } + + @Override + public void onBindViewHolder(UpdateViewHolder holder, Entry entry, int viewType) { + UpdateView view = holder.getUpdateView(); + if(viewType == VIEW_TYPE_ALBUM_CELL || viewType == VIEW_TYPE_ALBUM_LINE) { + AlbumView albumView = (AlbumView) view; + albumView.setShowArtist(showArtist); + albumView.setObject(entry, imageLoader); + } else if(viewType == VIEW_TYPE_SONG) { + SongView songView = (SongView) view; + songView.setObject(entry, checkable && !entry.isVideo()); + } + } + + public UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) { + return new UpdateViewHolder(header, false); + } + public void onBindHeaderHolder(UpdateViewHolder holder, String header) { + + } + + @Override + public int getItemViewType(Entry entry) { + if(entry.isDirectory()) { + if (largeAlbums) { + return VIEW_TYPE_ALBUM_CELL; + } else { + return VIEW_TYPE_ALBUM_LINE; + } + } else { + return VIEW_TYPE_SONG; + } + } + + public void setHeader(View header) { + this.header = header; + this.singleSectionHeader = true; + } + + public void setShowArtist(boolean showArtist) { + this.showArtist = showArtist; + } + + public void removeAt(int index) { + sections.get(0).remove(index); + notifyItemRemoved(index); + } + + public void setRemoveFromPlaylist(boolean removeFromPlaylist) { + this.removeFromPlaylist = removeFromPlaylist; + } + + @Override + public void onCreateActionModeMenu(Menu menu, MenuInflater menuInflater) { + if(Util.isOffline(context)) { + menuInflater.inflate(R.menu.multiselect_media_offline, menu); + } else { + menuInflater.inflate(R.menu.multiselect_media, menu); + } + + if(!removeFromPlaylist) { + menu.removeItem(R.id.menu_remove_playlist); + } + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/EntryInfiniteGridAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/EntryInfiniteGridAdapter.java new file mode 100644 index 00000000..2c4f75dc --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/adapter/EntryInfiniteGridAdapter.java @@ -0,0 +1,146 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.adapter; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import java.util.List; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.MusicDirectory; +import github.daneren2005.dsub.domain.MusicDirectory.Entry; +import github.daneren2005.dsub.domain.ServerInfo; +import github.daneren2005.dsub.service.MusicService; +import github.daneren2005.dsub.service.MusicServiceFactory; +import github.daneren2005.dsub.util.ImageLoader; +import github.daneren2005.dsub.util.SilentBackgroundTask; +import github.daneren2005.dsub.view.UpdateView; + +public class EntryInfiniteGridAdapter extends EntryGridAdapter { + public static int VIEW_TYPE_LOADING = 4; + + private String type; + private String extra; + private int size; + + private boolean loading = false; + private boolean allLoaded = false; + + public EntryInfiniteGridAdapter(Context context, List<Entry> entries, ImageLoader imageLoader, boolean largeCell) { + super(context, entries, imageLoader, largeCell); + } + + @Override + public UpdateView.UpdateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if(viewType == VIEW_TYPE_LOADING) { + View progress = LayoutInflater.from(context).inflate(R.layout.tab_progress, null); + progress.setVisibility(View.VISIBLE); + return new UpdateView.UpdateViewHolder(progress, false); + } + + return super.onCreateViewHolder(parent, viewType); + } + + @Override + public int getItemViewType(int position) { + if(isLoadingView(position)) { + return VIEW_TYPE_LOADING; + } + + return super.getItemViewType(position); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, int position) { + if(!isLoadingView(position)) { + super.onBindViewHolder(holder, position); + } + } + + @Override + public int getItemCount() { + int size = super.getItemCount(); + + if(!allLoaded) { + size++; + } + + return size; + } + + public void setData(String type, String extra, int size) { + this.type = type; + this.extra = extra; + this.size = size; + } + + public void loadMore() { + if(loading || allLoaded) { + return; + } + loading = true; + + new SilentBackgroundTask<Void>(context) { + private List<Entry> newData; + + @Override + protected Void doInBackground() throws Throwable { + newData = cacheInBackground(); + return null; + } + + @Override + protected void done(Void result) { + appendCachedData(newData); + loading = false; + + if(newData.isEmpty()) { + allLoaded = true; + notifyDataSetChanged(); + } + } + }.execute(); + } + + protected List<Entry> cacheInBackground() throws Exception { + MusicService service = MusicServiceFactory.getMusicService(context); + MusicDirectory result; + int offset = sections.get(0).size(); + if(("genres".equals(type) && ServerInfo.checkServerVersion(context, "1.10.0")) || "years".equals(type)) { + result = service.getAlbumList(type, extra, size, offset, false, context, null); + } else if("genres".equals(type) || "genres-songs".equals(type)) { + result = service.getSongsByGenre(extra, size, offset, context, null); + } else { + result = service.getAlbumList(type, size, offset, false, context, null); + } + return result.getChildren(); + } + + protected void appendCachedData(List<Entry> newData) { + if(newData.size() > 0) { + int start = sections.get(0).size(); + sections.get(0).addAll(newData); + this.notifyItemRangeInserted(start, newData.size()); + } + } + + protected boolean isLoadingView(int position) { + return !allLoaded && position >= sections.get(0).size(); + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/GenreAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/GenreAdapter.java index abb208c9..70aa5fe3 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/GenreAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/GenreAdapter.java @@ -1,60 +1,54 @@ /* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ - Copyright 2010 (C) Sindre Mehus - */ package github.daneren2005.dsub.adapter; -import android.widget.ArrayAdapter; -import android.widget.SectionIndexer; import android.content.Context; -import android.view.View; import android.view.ViewGroup; -import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.Genre; +import github.daneren2005.dsub.view.FastScroller; import github.daneren2005.dsub.view.GenreView; +import github.daneren2005.dsub.view.UpdateView; import java.util.List; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.ArrayList; -/** - * @author Sindre Mehus -*/ -public class GenreAdapter extends ArrayAdapter<Genre>{ - private Context activity; - private List<Genre> genres; - - public GenreAdapter(Context context, List<Genre> genres) { - super(context, android.R.layout.simple_list_item_1, genres); - this.activity = context; - this.genres = genres; +public class GenreAdapter extends SectionAdapter<Genre> implements FastScroller.BubbleTextGetter{ + public static int VIEW_TYPE_GENRE = 1; + + public GenreAdapter(Context context, List<Genre> genres, OnItemClickedListener listener) { + super(context, genres); + this.onItemClickedListener = listener; } - + @Override - public View getView(int position, View convertView, ViewGroup parent) { - Genre genre = genres.get(position); - GenreView view; - if (convertView != null && convertView instanceof GenreView) { - view = (GenreView) convertView; - } else { - view = new GenreView(activity); - } - view.setObject(genre); - return view; - } + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new GenreView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Genre item, int viewType) { + holder.getUpdateView().setObject(item); + } + + @Override + public int getItemViewType(Genre item) { + return VIEW_TYPE_GENRE; + } + + @Override + public String getTextToShowInBubble(int position) { + return getNameIndex(getItemForPosition(position).getName()); + } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/MainAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/MainAdapter.java new file mode 100644 index 00000000..8f1f1c38 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/adapter/MainAdapter.java @@ -0,0 +1,112 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.adapter; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.CompoundButton; + +import java.util.List; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.ServerInfo; +import github.daneren2005.dsub.util.Util; +import github.daneren2005.dsub.view.AlbumListCountView; +import github.daneren2005.dsub.view.BasicHeaderView; +import github.daneren2005.dsub.view.BasicListView; +import github.daneren2005.dsub.view.UpdateView; + +public class MainAdapter extends SectionAdapter<Integer> { + public static final int VIEW_TYPE_ALBUM_LIST = 1; + public static final int VIEW_TYPE_ALBUM_COUNT_LIST = 2; + + public MainAdapter(Context context, List<String> headers, List<List<Integer>> sections, OnItemClickedListener onItemClickedListener) { + super(context, headers, sections); + this.onItemClickedListener = onItemClickedListener; + } + + @Override + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + UpdateView updateView; + if(viewType == VIEW_TYPE_ALBUM_LIST) { + updateView = new BasicListView(context); + } else { + updateView = new AlbumListCountView(context); + } + + return new UpdateView.UpdateViewHolder(updateView); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Integer item, int viewType) { + UpdateView updateView = holder.getUpdateView(); + + if(viewType == VIEW_TYPE_ALBUM_LIST) { + updateView.setObject(context.getResources().getString(item)); + } else { + updateView.setObject(item); + } + } + + @Override + public int getItemViewType(Integer item) { + if(item == R.string.main_albums_newest) { + return VIEW_TYPE_ALBUM_COUNT_LIST; + } else { + return VIEW_TYPE_ALBUM_LIST; + } + } + + @Override + public UpdateView.UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) { + return new UpdateView.UpdateViewHolder(new BasicHeaderView(context, R.layout.album_list_header)); + } + @Override + public void onBindHeaderHolder(UpdateView.UpdateViewHolder holder, String header) { + UpdateView view = holder.getUpdateView(); + CheckBox checkBox = (CheckBox) view.findViewById(R.id.item_checkbox); + + String display; + if ("albums".equals(header)) { + display = context.getResources().getString(R.string.main_albums_title); + + if(!Util.isOffline(context) && ServerInfo.canAlbumListPerFolder(context)) { + checkBox.setVisibility(View.VISIBLE); + checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + Util.setAlbumListsPerFolder(context, isChecked); + } + }); + checkBox.setChecked(Util.getAlbumListsPerFolder(context)); + } else { + checkBox.setVisibility(View.GONE); + } + } else if("videos".equals(header)) { + display = context.getResources().getString(R.string.main_videos); + checkBox.setVisibility(View.GONE); + } else { + display = header; + checkBox.setVisibility(View.GONE); + } + + if(view != null) { + view.setObject(display); + } + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/MergeAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/MergeAdapter.java deleted file mode 100644 index a2db4cf0..00000000 --- a/app/src/main/java/github/daneren2005/dsub/adapter/MergeAdapter.java +++ /dev/null @@ -1,290 +0,0 @@ -/*** - Copyright (c) 2008-2009 CommonsWare, LLC - Portions (c) 2009 Google, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); you may - not use this file except in compliance with the License. You may obtain - a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -package github.daneren2005.dsub.adapter; - -import android.database.DataSetObserver; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.ListAdapter; - -import java.util.ArrayList; -import java.util.List; -import java.util.Arrays; - -/** - * Adapter that merges multiple child adapters and views - * into a single contiguous whole. - * <p/> - * Adapters used as pieces within MergeAdapter must - * have view type IDs monotonically increasing from 0. Ideally, - * adapters also have distinct ranges for their row ids, as - * returned by getItemId(). - */ -public class MergeAdapter extends BaseAdapter { - - private final CascadeDataSetObserver observer = new CascadeDataSetObserver(); - private final ArrayList<ListAdapter> pieces = new ArrayList<ListAdapter>(); - - /** - * Stock constructor, simply chaining to the superclass. - */ - public MergeAdapter() { - super(); - } - - /** - * Adds a new adapter to the roster of things to appear - * in the aggregate list. - * - * @param adapter Source for row views for this section - */ - public void addAdapter(ListAdapter adapter) { - pieces.add(adapter); - adapter.registerDataSetObserver(observer); - } - - public void removeAdapter(ListAdapter adapter) { - adapter.unregisterDataSetObserver(observer); - pieces.remove(adapter); - } - - /** - * Adds a new View to the roster of things to appear - * in the aggregate list. - * - * @param view Single view to add - */ - public ListAdapter addView(View view) { - return addView(view, false); - } - - /** - * Adds a new View to the roster of things to appear - * in the aggregate list. - * - * @param view Single view to add - * @param enabled false if views are disabled, true if enabled - */ - public ListAdapter addView(View view, boolean enabled) { - return addViews(Arrays.asList(view), enabled); - } - - /** - * Adds a list of views to the roster of things to appear - * in the aggregate list. - * - * @param views List of views to add - */ - public ListAdapter addViews(List<View> views) { - return addViews(views, false); - } - - /** - * Adds a list of views to the roster of things to appear - * in the aggregate list. - * - * @param views List of views to add - * @param enabled false if views are disabled, true if enabled - */ - public ListAdapter addViews(List<View> views, boolean enabled) { - ListAdapter adapter = enabled ? new EnabledSackAdapter(views) : new SackOfViewsAdapter(views); - addAdapter(adapter); - return adapter; - } - - /** - * Get the data item associated with the specified - * position in the data set. - * - * @param position Position of the item whose data we want - */ - @Override - public Object getItem(int position) { - for (ListAdapter piece : pieces) { - int size = piece.getCount(); - - if (position < size) { - return (piece.getItem(position)); - } - - position -= size; - } - - return (null); - } - - /** - * How many items are in the data set represented by this - * Adapter. - */ - @Override - public int getCount() { - int total = 0; - - for (ListAdapter piece : pieces) { - total += piece.getCount(); - } - - return (total); - } - - /** - * Returns the number of types of Views that will be - * created by getView(). - */ - @Override - public int getViewTypeCount() { - int total = 0; - - for (ListAdapter piece : pieces) { - total += piece.getViewTypeCount(); - } - - return (Math.max(total, 1)); // needed for setListAdapter() before content add' - } - - /** - * Get the type of View that will be created by getView() - * for the specified item. - * - * @param position Position of the item whose data we want - */ - @Override - public int getItemViewType(int position) { - int typeOffset = 0; - int result = -1; - - for (ListAdapter piece : pieces) { - int size = piece.getCount(); - - if (position < size) { - result = typeOffset + piece.getItemViewType(position); - break; - } - - position -= size; - typeOffset += piece.getViewTypeCount(); - } - - return (result); - } - - /** - * Are all items in this ListAdapter enabled? If yes it - * means all items are selectable and clickable. - */ - @Override - public boolean areAllItemsEnabled() { - return (false); - } - - /** - * Returns true if the item at the specified position is - * not a separator. - * - * @param position Position of the item whose data we want - */ - @Override - public boolean isEnabled(int position) { - for (ListAdapter piece : pieces) { - int size = piece.getCount(); - - if (position < size) { - return (piece.isEnabled(position)); - } - - position -= size; - } - - return (false); - } - - /** - * Get a View that displays the data at the specified - * position in the data set. - * - * @param position Position of the item whose data we want - * @param convertView View to recycle, if not null - * @param parent ViewGroup containing the returned View - */ - @Override - public View getView(int position, View convertView, - ViewGroup parent) { - for (ListAdapter piece : pieces) { - int size = piece.getCount(); - - if (position < size) { - - return (piece.getView(position, convertView, parent)); - } - - position -= size; - } - - return (null); - } - - /** - * Get the row id associated with the specified position - * in the list. - * - * @param position Position of the item whose data we want - */ - @Override - public long getItemId(int position) { - for (ListAdapter piece : pieces) { - int size = piece.getCount(); - - if (position < size) { - return (piece.getItemId(position)); - } - - position -= size; - } - - return (-1); - } - - private static class EnabledSackAdapter extends SackOfViewsAdapter { - public EnabledSackAdapter(List<View> views) { - super(views); - } - - @Override - public boolean areAllItemsEnabled() { - return (true); - } - - @Override - public boolean isEnabled(int position) { - return (true); - } - } - - private class CascadeDataSetObserver extends DataSetObserver { - @Override - public void onChanged() { - notifyDataSetChanged(); - } - - @Override - public void onInvalidated() { - notifyDataSetInvalidated(); - } - } -} - diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/PlaylistAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/PlaylistAdapter.java index d56a6b97..7f7aacff 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/PlaylistAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/PlaylistAdapter.java @@ -1,70 +1,67 @@ /* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. - - Copyright 2010 (C) Sindre Mehus - */ + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ package github.daneren2005.dsub.adapter; import android.content.Context; -import github.daneren2005.dsub.R; + import java.util.List; -import android.view.View; + import android.view.ViewGroup; -import android.widget.ArrayAdapter; import github.daneren2005.dsub.domain.Playlist; +import github.daneren2005.dsub.util.ImageLoader; +import github.daneren2005.dsub.view.FastScroller; import github.daneren2005.dsub.view.PlaylistView; +import github.daneren2005.dsub.view.UpdateView; -import java.util.Collections; -import java.util.Comparator; - -/** - * @author Sindre Mehus - */ -public class PlaylistAdapter extends ArrayAdapter<Playlist> { +public class PlaylistAdapter extends SectionAdapter<Playlist> implements FastScroller.BubbleTextGetter { + public static int VIEW_TYPE_PLAYLIST = 1; - private final Context activity; + private ImageLoader imageLoader; + private boolean largeCell; - public PlaylistAdapter(Context activity, List<Playlist> Playlists) { - super(activity, R.layout.basic_list_item, Playlists); - this.activity = activity; + public PlaylistAdapter(Context context, List<Playlist> playlists, ImageLoader imageLoader, boolean largeCell, OnItemClickedListener listener) { + super(context, playlists); + this.imageLoader = imageLoader; + this.largeCell = largeCell; + this.onItemClickedListener = listener; + } + public PlaylistAdapter(Context context, List<String> headers, List<List<Playlist>> sections, ImageLoader imageLoader, boolean largeCell, OnItemClickedListener listener) { + super(context, headers, sections); + this.imageLoader = imageLoader; + this.largeCell = largeCell; + this.onItemClickedListener = listener; } @Override - public View getView(int position, View convertView, ViewGroup parent) { - Playlist entry = getItem(position); - PlaylistView view; - if (convertView != null && convertView instanceof PlaylistView) { - view = (PlaylistView) convertView; - } else { - view = new PlaylistView(activity); - } - view.setObject(entry); - return view; + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new PlaylistView(context, imageLoader, largeCell)); } - public static class PlaylistComparator implements Comparator<Playlist> { - @Override - public int compare(Playlist playlist1, Playlist playlist2) { - return playlist1.getName().compareToIgnoreCase(playlist2.getName()); - } + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Playlist playlist, int viewType) { + holder.getUpdateView().setObject(playlist); + holder.setItem(playlist); + } - public static List<Playlist> sort(List<Playlist> playlists) { - Collections.sort(playlists, new PlaylistComparator()); - return playlists; - } + @Override + public int getItemViewType(Playlist playlist) { + return VIEW_TYPE_PLAYLIST; + } + @Override + public String getTextToShowInBubble(int position) { + return getNameIndex(getItemForPosition(position).getName()); } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/PodcastChannelAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/PodcastChannelAdapter.java index 8ee39a10..e1ca4814 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/PodcastChannelAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/PodcastChannelAdapter.java @@ -1,60 +1,53 @@ /* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. - - Copyright 2010 (C) Sindre Mehus - */ + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ package github.daneren2005.dsub.adapter; -import android.widget.ArrayAdapter; -import android.widget.SectionIndexer; import android.content.Context; -import android.view.View; import android.view.ViewGroup; -import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.PodcastChannel; +import github.daneren2005.dsub.view.FastScroller; import github.daneren2005.dsub.view.PodcastChannelView; +import github.daneren2005.dsub.view.UpdateView; import java.util.List; -import java.util.Set; -import java.util.LinkedHashSet; -import java.util.ArrayList; -/** - * @author Sindre Mehus -*/ -public class PodcastChannelAdapter extends ArrayAdapter<PodcastChannel>{ - private Context activity; - private List<PodcastChannel> podcasts; - - public PodcastChannelAdapter(Context context, List<PodcastChannel> podcasts) { - super(context, android.R.layout.simple_list_item_1, podcasts); - this.activity = context; - this.podcasts = podcasts; +public class PodcastChannelAdapter extends SectionAdapter<PodcastChannel> implements FastScroller.BubbleTextGetter { + public static int VIEW_TYPE_PODCAST = 1; + + public PodcastChannelAdapter(Context context, List<PodcastChannel> podcasts, OnItemClickedListener listener) { + super(context, podcasts); + this.onItemClickedListener = listener; } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - PodcastChannel podcast = podcasts.get(position); - PodcastChannelView view; - if (convertView != null && convertView instanceof PodcastChannelView) { - view = (PodcastChannelView) convertView; - } else { - view = new PodcastChannelView(activity); - } - view.setObject(podcast); - return view; + + @Override + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new PodcastChannelView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, PodcastChannel item, int viewType) { + holder.getUpdateView().setObject(item); + } + + @Override + public int getItemViewType(PodcastChannel item) { + return VIEW_TYPE_PODCAST; + } + + @Override + public String getTextToShowInBubble(int position) { + return getNameIndex(getItemForPosition(position).getName(), true); } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/SackOfViewsAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/SackOfViewsAdapter.java deleted file mode 100644 index e4744cc5..00000000 --- a/app/src/main/java/github/daneren2005/dsub/adapter/SackOfViewsAdapter.java +++ /dev/null @@ -1,181 +0,0 @@ -/*** - Copyright (c) 2008-2009 CommonsWare, LLC - Portions (c) 2009 Google, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); you may - not use this file except in compliance with the License. You may obtain - a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ -package github.daneren2005.dsub.adapter; - -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.ListView; - -import java.util.ArrayList; -import java.util.List; - -/** - * Adapter that simply returns row views from a list. - * <p/> - * If you supply a size, you must implement newView(), to - * create a required view. The adapter will then cache these - * views. - * <p/> - * If you supply a list of views in the constructor, that - * list will be used directly. If any elements in the list - * are null, then newView() will be called just for those - * slots. - * <p/> - * Subclasses may also wish to override areAllItemsEnabled() - * (default: false) and isEnabled() (default: false), if some - * of their rows should be selectable. - * <p/> - * It is assumed each view is unique, and therefore will not - * get recycled. - * <p/> - * Note that this adapter is not designed for long lists. It - * is more for screens that should behave like a list. This - * is particularly useful if you combine this with other - * adapters (e.g., SectionedAdapter) that might have an - * arbitrary number of rows, so it all appears seamless. - */ -public class SackOfViewsAdapter extends BaseAdapter { - private List<View> views = null; - - /** - * Constructor creating an empty list of views, but with - * a specified count. Subclasses must override newView(). - */ - public SackOfViewsAdapter(int count) { - super(); - - views = new ArrayList<View>(count); - - for (int i = 0; i < count; i++) { - views.add(null); - } - } - - /** - * Constructor wrapping a supplied list of views. - * Subclasses must override newView() if any of the elements - * in the list are null. - */ - public SackOfViewsAdapter(List<View> views) { - for (View view : views) { - view.setLayoutParams(new ListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - } - this.views = views; - } - - /** - * Get the data item associated with the specified - * position in the data set. - * - * @param position Position of the item whose data we want - */ - @Override - public Object getItem(int position) { - return (views.get(position)); - } - - /** - * How many items are in the data set represented by this - * Adapter. - */ - @Override - public int getCount() { - return (views.size()); - } - - /** - * Returns the number of types of Views that will be - * created by getView(). - */ - @Override - public int getViewTypeCount() { - return (getCount()); - } - - /** - * Get the type of View that will be created by getView() - * for the specified item. - * - * @param position Position of the item whose data we want - */ - @Override - public int getItemViewType(int position) { - return (position); - } - - /** - * Are all items in this ListAdapter enabled? If yes it - * means all items are selectable and clickable. - */ - @Override - public boolean areAllItemsEnabled() { - return (false); - } - - /** - * Returns true if the item at the specified position is - * not a separator. - * - * @param position Position of the item whose data we want - */ - @Override - public boolean isEnabled(int position) { - return (false); - } - - /** - * Get a View that displays the data at the specified - * position in the data set. - * - * @param position Position of the item whose data we want - * @param convertView View to recycle, if not null - * @param parent ViewGroup containing the returned View - */ - @Override - public View getView(int position, View convertView, - ViewGroup parent) { - View result = views.get(position); - - if (result == null) { - result = newView(position, parent); - views.set(position, result); - } - - return (result); - } - - /** - * Get the row id associated with the specified position - * in the list. - * - * @param position Position of the item whose data we want - */ - @Override - public long getItemId(int position) { - return (position); - } - - /** - * Create a new View to go into the list at the specified - * position. - * - * @param position Position of the item whose data we want - * @param parent ViewGroup containing the returned View - */ - protected View newView(int position, ViewGroup parent) { - throw new RuntimeException("You must override newView()!"); - } -} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/SearchAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/SearchAdapter.java new file mode 100644 index 00000000..66f2db21 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/adapter/SearchAdapter.java @@ -0,0 +1,129 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.adapter; + +import android.content.Context; +import android.content.res.Resources; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.ViewGroup; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.MusicDirectory.Entry; +import github.daneren2005.dsub.domain.SearchResult; +import github.daneren2005.dsub.util.ImageLoader; +import github.daneren2005.dsub.util.Util; +import github.daneren2005.dsub.view.AlbumView; +import github.daneren2005.dsub.view.ArtistView; +import github.daneren2005.dsub.view.SongView; +import github.daneren2005.dsub.view.UpdateView; + +import static github.daneren2005.dsub.adapter.ArtistAdapter.VIEW_TYPE_ARTIST; +import static github.daneren2005.dsub.adapter.EntryGridAdapter.VIEW_TYPE_ALBUM_CELL; +import static github.daneren2005.dsub.adapter.EntryGridAdapter.VIEW_TYPE_ALBUM_LINE; +import static github.daneren2005.dsub.adapter.EntryGridAdapter.VIEW_TYPE_SONG; + +public class SearchAdapter extends SectionAdapter<Serializable> { + private SearchResult searchResult; + private ImageLoader imageLoader; + private boolean largeAlbums; + + public SearchAdapter(Context context, SearchResult searchResult, ImageLoader imageLoader, boolean largeAlbums, OnItemClickedListener listener) { + this.context = context; + this.searchResult = searchResult; + this.imageLoader = imageLoader; + this.largeAlbums = largeAlbums; + + this.sections = new ArrayList<>(); + this.headers = new ArrayList<>(); + Resources res = context.getResources(); + if(!searchResult.getArtists().isEmpty()) { + this.sections.add((List<Serializable>) (List<?>) searchResult.getArtists()); + this.headers.add(res.getString(R.string.search_artists)); + } + if(!searchResult.getAlbums().isEmpty()) { + this.sections.add((List<Serializable>) (List<?>) searchResult.getAlbums()); + this.headers.add(res.getString(R.string.search_albums)); + } + if(!searchResult.getSongs().isEmpty()) { + this.sections.add((List<Serializable>) (List<?>) searchResult.getSongs()); + this.headers.add(res.getString(R.string.search_songs)); + } + this.onItemClickedListener = listener; + checkable = true; + } + + @Override + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + UpdateView updateView = null; + if(viewType == VIEW_TYPE_ALBUM_CELL || viewType == VIEW_TYPE_ALBUM_LINE) { + updateView = new AlbumView(context, viewType == VIEW_TYPE_ALBUM_CELL); + } else if(viewType == VIEW_TYPE_SONG) { + updateView = new SongView(context); + } else if(viewType == VIEW_TYPE_ARTIST) { + updateView = new ArtistView(context); + } + + return new UpdateView.UpdateViewHolder(updateView); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Serializable item, int viewType) { + UpdateView view = holder.getUpdateView(); + if(viewType == VIEW_TYPE_ALBUM_CELL || viewType == VIEW_TYPE_ALBUM_LINE) { + AlbumView albumView = (AlbumView) view; + albumView.setObject((Entry) item, imageLoader); + } else if(viewType == VIEW_TYPE_SONG) { + SongView songView = (SongView) view; + songView.setObject((Entry) item, true); + } else if(viewType == VIEW_TYPE_ARTIST) { + view.setObject(item); + } + } + + @Override + public int getItemViewType(Serializable item) { + if(item instanceof Entry) { + Entry entry = (Entry) item; + if (entry.isDirectory()) { + if (largeAlbums) { + return VIEW_TYPE_ALBUM_CELL; + } else { + return VIEW_TYPE_ALBUM_LINE; + } + } else { + return VIEW_TYPE_SONG; + } + } else { + return VIEW_TYPE_ARTIST; + } + } + + @Override + public void onCreateActionModeMenu(Menu menu, MenuInflater menuInflater) { + if(Util.isOffline(context)) { + menuInflater.inflate(R.menu.multiselect_media_offline, menu); + } else { + menuInflater.inflate(R.menu.multiselect_media, menu); + } + + menu.removeItem(R.id.menu_remove_playlist); + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java new file mode 100644 index 00000000..53cc5e99 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/adapter/SectionAdapter.java @@ -0,0 +1,505 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.adapter; + +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.os.Build; +import android.support.v7.widget.PopupMenu; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.util.TypedValue; +import android.view.ActionMode; +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 java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.activity.SubsonicFragmentActivity; +import github.daneren2005.dsub.util.Constants; +import github.daneren2005.dsub.util.MenuUtil; +import github.daneren2005.dsub.util.Util; +import github.daneren2005.dsub.view.BasicHeaderView; +import github.daneren2005.dsub.view.UpdateView; +import github.daneren2005.dsub.view.UpdateView.UpdateViewHolder; + +public abstract class SectionAdapter<T> extends RecyclerView.Adapter<UpdateViewHolder<T>> { + private static String TAG = SectionAdapter.class.getSimpleName(); + public static int VIEW_TYPE_HEADER = 0; + public static String[] ignoredArticles; + + protected Context context; + protected List<String> headers; + protected List<List<T>> sections; + protected boolean singleSectionHeader; + protected OnItemClickedListener<T> onItemClickedListener; + protected List<T> selected = new ArrayList<>(); + protected List<UpdateView> selectedViews = new ArrayList<>(); + protected ActionMode currentActionMode; + protected boolean checkable = false; + + protected SectionAdapter() {} + public SectionAdapter(Context context, List<T> section) { + this(context, section, false); + } + public SectionAdapter(Context context, List<T> section, boolean singleSectionHeader) { + this.context = context; + this.headers = Arrays.asList("Section"); + this.sections = new ArrayList<>(); + this.sections.add(section); + this.singleSectionHeader = singleSectionHeader; + } + public SectionAdapter(Context context, List<String> headers, List<List<T>> sections) { + this(context, headers, sections, true); + } + public SectionAdapter(Context context, List<String> headers, List<List<T>> sections, boolean singleSectionHeader){ + this.context = context; + this.headers = headers; + this.sections = sections; + this.singleSectionHeader = singleSectionHeader; + } + + public void replaceExistingData(List<T> section) { + this.sections = new ArrayList<>(); + this.sections.add(section); + notifyDataSetChanged(); + } + public void replaceExistingData(List<String> headers, List<List<T>> sections) { + this.headers = headers; + this.sections = sections; + notifyDataSetChanged(); + } + + @Override + public UpdateViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + if(viewType == VIEW_TYPE_HEADER) { + return onCreateHeaderHolder(parent); + } else { + final UpdateViewHolder<T> holder = onCreateSectionViewHolder(parent, viewType); + final UpdateView updateView = holder.getUpdateView(); + + if(updateView != null) { + updateView.getChildAt(0).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + T item = holder.getItem(); + updateView.onClick(); + if (currentActionMode != null) { + if(updateView.isCheckable()) { + if (selected.contains(item)) { + selected.remove(item); + selectedViews.remove(updateView); + setChecked(updateView, false); + } else { + selected.add(item); + selectedViews.add(updateView); + setChecked(updateView, true); + } + + if (selected.isEmpty()) { + currentActionMode.finish(); + } else { + currentActionMode.setTitle(context.getResources().getString(R.string.select_album_n_selected, selected.size())); + } + } + } else if (onItemClickedListener != null) { + onItemClickedListener.onItemClicked(item); + } + } + }); + + View moreButton = updateView.findViewById(R.id.more_button); + if(moreButton == null) { + moreButton = updateView.findViewById(R.id.item_more); + } + if (moreButton != null) { + moreButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + final T item = holder.getItem(); + if(onItemClickedListener != null) { + PopupMenu popup = new PopupMenu(context, v); + onItemClickedListener.onCreateContextMenu(popup.getMenu(), popup.getMenuInflater(), updateView, item); + + popup.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem menuItem) { + return onItemClickedListener.onContextItemSelected(menuItem, updateView, item); + } + }); + popup.show(); + } + } + }); + + if(checkable) { + updateView.getChildAt(0).setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + if(currentActionMode == null) { + startActionMode(holder); + } else { + updateView.getChildAt(0).performClick(); + } + return true; + } + }); + } + } + } + + return holder; + } + } + + @Override + public void onBindViewHolder(UpdateViewHolder holder, int position) { + UpdateView updateView = holder.getUpdateView(); + + if(sections.size() == 1 && !singleSectionHeader) { + T item = sections.get(0).get(position); + onBindViewHolder(holder, item, getItemViewType(position)); + postBindView(updateView, item); + holder.setItem(item); + return; + } + + int subPosition = 0; + int subHeader = 0; + for(List<T> section: sections) { + boolean validHeader = headers.get(subHeader) != null; + if(position == subPosition && validHeader) { + onBindHeaderHolder(holder, headers.get(subHeader)); + return; + } + + int headerOffset = validHeader ? 1 : 0; + if(position < (subPosition + section.size() + headerOffset)) { + T item = section.get(position - subPosition - headerOffset); + onBindViewHolder(holder, item, getItemViewType(item)); + + postBindView(updateView, item); + holder.setItem(item); + return; + } + + subPosition += section.size(); + if(validHeader) { + subPosition += 1; + } + subHeader++; + } + } + + private void postBindView(UpdateView updateView, T item) { + if(updateView.isCheckable()) { + setChecked(updateView, selected.contains(item)); + } + + View moreButton = updateView.findViewById(R.id.more_button); + if(moreButton == null) { + moreButton = updateView.findViewById(R.id.item_more); + } + if(moreButton != null) { + if(onItemClickedListener != null) { + PopupMenu popup = new PopupMenu(context, moreButton); + Menu menu = popup.getMenu(); + onItemClickedListener.onCreateContextMenu(popup.getMenu(), popup.getMenuInflater(), updateView, item); + if (menu.size() == 0) { + moreButton.setVisibility(View.GONE); + } else { + moreButton.setVisibility(View.VISIBLE); + } + } else { + moreButton.setVisibility(View.VISIBLE); + } + } + } + + @Override + public int getItemCount() { + if(sections.size() == 1 && !singleSectionHeader) { + return sections.get(0).size(); + } + + int count = 0; + for(String header: headers) { + if(header != null) { + count++; + } + } + for(List<T> section: sections) { + count += section.size(); + } + + return count; + } + + @Override + public int getItemViewType(int position) { + if(sections.size() == 1 && !singleSectionHeader) { + return getItemViewType(sections.get(0).get(position)); + } + + int subPosition = 0; + int subHeader = 0; + for(List<T> section: sections) { + boolean validHeader = headers.get(subHeader) != null; + if(position == subPosition && validHeader) { + return VIEW_TYPE_HEADER; + } + + int headerOffset = validHeader ? 1 : 0; + if(position < (subPosition + section.size() + headerOffset)) { + return getItemViewType(section.get(position - subPosition - headerOffset)); + } + + subPosition += section.size(); + if(validHeader) { + subPosition += 1; + } + subHeader++; + } + + return -1; + } + + public UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) { + return new UpdateViewHolder(new BasicHeaderView(context)); + } + public void onBindHeaderHolder(UpdateViewHolder holder, String header) { + UpdateView view = holder.getUpdateView(); + if(view != null) { + view.setObject(header); + } + } + + public T getItemForPosition(int position) { + if(sections.size() == 1 && !singleSectionHeader) { + return sections.get(0).get(position); + } + + int subPosition = 0; + for(List<T> section: sections) { + if(position == subPosition) { + return null; + } + + if(position <= (subPosition + section.size())) { + return section.get(position - subPosition - 1); + } + + subPosition += section.size() + 1; + } + + return null; + } + public int getItemPosition(T item) { + if(sections.size() == 1 && !singleSectionHeader) { + return sections.get(0).indexOf(item); + } + + int subPosition = 0; + for(List<T> section: sections) { + subPosition += section.size() + 1; + + int position = section.indexOf(item); + if(position != -1) { + return position + subPosition; + } + } + + return -1; + } + + public void setOnItemClickedListener(OnItemClickedListener<T> onItemClickedListener) { + this.onItemClickedListener = onItemClickedListener; + } + + public void addSelected(T item) { + selected.add(item); + } + public List<T> getSelected() { + List<T> selected = new ArrayList<>(); + selected.addAll(this.selected); + return selected; + } + + public void clearSelected() { + // TODO: This needs to work with multiple sections + for(T item: selected) { + int index = sections.get(0).indexOf(item); + + if(singleSectionHeader) { + index++; + } + } + selected.clear(); + + for(UpdateView updateView: selectedViews) { + updateView.setChecked(false); + } + } + + public void removeItem(T item) { + int subPosition = 0; + for(List<T> section: sections) { + if(sections.size() > 1 || singleSectionHeader) { + subPosition++; + } + + int index = section.indexOf(item); + if (index != -1) { + section.remove(item); + notifyItemRemoved(subPosition + index); + break; + } + + subPosition += section.size(); + } + } + + public abstract UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType); + public abstract void onBindViewHolder(UpdateViewHolder holder, T item, int viewType); + public abstract int getItemViewType(T item); + public void setCheckable(boolean checkable) { + this.checkable = checkable; + } + public void setChecked(UpdateView updateView, boolean checked) { + updateView.setChecked(checked); + } + public void onCreateActionModeMenu(Menu menu, MenuInflater menuInflater) {} + + private void startActionMode(final UpdateView.UpdateViewHolder<T> holder) { + final UpdateView<T> updateView = holder.getUpdateView(); + if (context instanceof SubsonicFragmentActivity && currentActionMode == null) { + final SubsonicFragmentActivity fragmentActivity = (SubsonicFragmentActivity) context; + Toolbar toolbar = fragmentActivity.getActiveToolbar(); + + toolbar.startActionMode(new ActionMode.Callback() { + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + currentActionMode = mode; + onCreateActionModeMenu(menu, mode.getMenuInflater()); + MenuUtil.hideMenuItems(context, menu); + + T item = holder.getItem(); + selected.add(item); + selectedViews.add(updateView); + setChecked(updateView, true); + + mode.setTitle(context.getResources().getString(R.string.select_album_n_selected, selected.size())); + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + 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; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return false; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + if (fragmentActivity.onOptionsItemSelected(item)) { + currentActionMode.finish(); + return true; + } else { + return false; + } + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + currentActionMode = null; + selected.clear(); + for(UpdateView<T> updateView: selectedViews) { + updateView.setChecked(false); + } + selectedViews.clear(); + + if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + Window window = ((SubsonicFragmentActivity) context).getWindow(); + window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); + } + } + }); + } + } + public void stopActionMode() { + if(currentActionMode != null) { + currentActionMode.finish(); + } + } + + public String getNameIndex(String name) { + return getNameIndex(name, false); + } + public String getNameIndex(String name, boolean removeIgnoredArticles) { + if(name == null) { + return "*"; + } + + if(removeIgnoredArticles) { + if (ignoredArticles == null) { + SharedPreferences prefs = Util.getPreferences(context); + String ignoredArticlesString = prefs.getString(Constants.CACHE_KEY_IGNORE, "The El La Los Las Le Les"); + ignoredArticles = ignoredArticlesString.split(" "); + } + + name = name.toLowerCase(); + for (String article : ignoredArticles) { + int index = name.indexOf(article.toLowerCase() + " "); + if (index == 0) { + name = name.substring(article.length() + 1); + } + } + } + + String index = name.substring(0, 1).toUpperCase(); + if (!Character.isLetter(index.charAt(0))) { + index = "#"; + } + + return index; + } + + public interface OnItemClickedListener<T> { + void onItemClicked(T item); + void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<T> updateView, T item); + boolean onContextItemSelected(MenuItem menuItem, UpdateView<T> updateView, T item); + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/SettingsAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/SettingsAdapter.java index 45c3ead1..d99b294b 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/SettingsAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/SettingsAdapter.java @@ -16,44 +16,83 @@ package github.daneren2005.dsub.adapter; import android.content.Context; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; import java.util.List; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.User; +import github.daneren2005.dsub.util.ImageLoader; import github.daneren2005.dsub.view.SettingView; +import github.daneren2005.dsub.view.UpdateView; import static github.daneren2005.dsub.domain.User.Setting; -public class SettingsAdapter extends ArrayAdapter<Setting> { - private final Context context; +public class SettingsAdapter extends SectionAdapter<Setting> { + public final int VIEW_TYPE_SETTING = 1; + + private final User user; private final boolean editable; + private final ImageLoader imageLoader; - public SettingsAdapter(Context context, User user, boolean editable) { - super(context, R.layout.basic_list_item, user.getSettings()); - this.context = context; + public SettingsAdapter(Context context, User user, ImageLoader imageLoader, boolean editable) { + super(context, user.getSettings(), imageLoader != null); + this.user = user; + this.imageLoader = imageLoader; this.editable = editable; + + List<Setting> settings = sections.get(0); + for(Setting setting: settings) { + if(setting.getValue()) { + addSelected(setting); + } + } } - public SettingsAdapter(Context context, List<Setting> settings, boolean editable) { - super(context, R.layout.basic_list_item, settings); - this.context = context; - this.editable = editable; + public UpdateView.UpdateViewHolder onCreateHeaderHolder(ViewGroup parent) { + View header = LayoutInflater.from(context).inflate(R.layout.user_header, parent, false); + return new UpdateView.UpdateViewHolder(header, false); } + public void onBindHeaderHolder(UpdateView.UpdateViewHolder holder, String description) { + View header = holder.getView(); - @Override - public View getView(int position, View convertView, ViewGroup parent) { - Setting entry = getItem(position); - SettingView view; - if (convertView != null && convertView instanceof SettingView) { - view = (SettingView) convertView; + ImageView coverArtView = (ImageView) header.findViewById(R.id.user_avatar); + imageLoader.loadAvatar(context, coverArtView, user.getUsername()); + + TextView usernameView = (TextView) header.findViewById(R.id.user_username); + usernameView.setText(user.getUsername()); + + final TextView emailView = (TextView) header.findViewById(R.id.user_email); + if(user.getEmail() != null) { + emailView.setText(user.getEmail()); } else { - view = new SettingView(context); + emailView.setVisibility(View.GONE); + } + } + + @Override + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new SettingView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Setting item, int viewType) { + holder.getUpdateView().setObject(item, editable); + } + + @Override + public int getItemViewType(Setting item) { + return VIEW_TYPE_SETTING; + } + + @Override + public void setChecked(UpdateView updateView, boolean checked) { + if(updateView instanceof SettingView) { + ((SettingView) updateView).setChecked(checked); } - view.setObject(entry, editable); - return view; } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/ShareAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/ShareAdapter.java index 4121a85a..6db3d927 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/ShareAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/ShareAdapter.java @@ -1,56 +1,49 @@ /* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ - Copyright 2010 (C) Sindre Mehus - */ package github.daneren2005.dsub.adapter; import android.content.Context; -import android.view.View; import android.view.ViewGroup; -import android.widget.ArrayAdapter; import java.util.List; import github.daneren2005.dsub.domain.Share; import github.daneren2005.dsub.view.ShareView; +import github.daneren2005.dsub.view.UpdateView; -/** - * @author Sindre Mehus -*/ -public class ShareAdapter extends ArrayAdapter<Share>{ - private Context activity; - private List<Share> shares; - - public ShareAdapter(Context context, List<Share> shares) { - super(context, android.R.layout.simple_list_item_1, shares); - this.activity = context; - this.shares = shares; +public class ShareAdapter extends SectionAdapter<Share>{ + public static int VIEW_TYPE_SHARE = 1; + + public ShareAdapter(Context context, List<Share> shares, OnItemClickedListener listener) { + super(context, shares); + this.onItemClickedListener = listener; } - + @Override - public View getView(int position, View convertView, ViewGroup parent) { - Share share = shares.get(position); - ShareView view; - if (convertView != null && convertView instanceof ShareView) { - view = (ShareView) convertView; - } else { - view = new ShareView(activity); - } - view.setObject(share); - return view; - } + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new ShareView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, Share item, int viewType) { + holder.getUpdateView().setObject(item); + } + + @Override + public int getItemViewType(Share item) { + return VIEW_TYPE_SHARE; + } } diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/TopRatedAlbumAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/TopRatedAlbumAdapter.java new file mode 100644 index 00000000..876e5907 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/adapter/TopRatedAlbumAdapter.java @@ -0,0 +1,44 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.adapter; + +import android.content.Context; + +import java.util.List; + +import github.daneren2005.dsub.domain.MusicDirectory; +import github.daneren2005.dsub.util.ImageLoader; +import github.daneren2005.dsub.view.FastScroller; + +public class TopRatedAlbumAdapter extends EntryInfiniteGridAdapter implements FastScroller.BubbleTextGetter { + public TopRatedAlbumAdapter(Context context, List<MusicDirectory.Entry> entries, ImageLoader imageLoader, boolean largeCell) { + super(context, entries, imageLoader, largeCell); + } + + @Override + public String getTextToShowInBubble(int position) { + // Make sure that we are not trying to get an item for the loading placeholder + if(position >= sections.get(0).size()) { + if(sections.get(0).size() > 0) { + return getTextToShowInBubble(position - 1); + } else { + return "*"; + } + } else { + return Integer.toString(getItemForPosition(position).getRating()); + } + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/adapter/UserAdapter.java b/app/src/main/java/github/daneren2005/dsub/adapter/UserAdapter.java index f0f78d97..95809e48 100644 --- a/app/src/main/java/github/daneren2005/dsub/adapter/UserAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/adapter/UserAdapter.java @@ -25,28 +25,32 @@ import java.util.List; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.User; import github.daneren2005.dsub.util.ImageLoader; +import github.daneren2005.dsub.view.UpdateView; import github.daneren2005.dsub.view.UserView; -public class UserAdapter extends ArrayAdapter<User> { - private final Context activity; +public class UserAdapter extends SectionAdapter<User> { + public static int VIEW_TYPE_USER = 1; + private final ImageLoader imageLoader; - public UserAdapter(Context activity, List<User> users, ImageLoader imageLoader) { - super(activity, R.layout.basic_list_item, users); - this.activity = activity; + public UserAdapter(Context context, List<User> users, ImageLoader imageLoader, OnItemClickedListener listener) { + super(context, users); this.imageLoader = imageLoader; + this.onItemClickedListener = listener; + } + + @Override + public UpdateView.UpdateViewHolder onCreateSectionViewHolder(ViewGroup parent, int viewType) { + return new UpdateView.UpdateViewHolder(new UserView(context)); + } + + @Override + public void onBindViewHolder(UpdateView.UpdateViewHolder holder, User item, int viewType) { + holder.getUpdateView().setObject(item, imageLoader); } @Override - public View getView(int position, View convertView, ViewGroup parent) { - User entry = getItem(position); - UserView view; - if (convertView != null && convertView instanceof UserView) { - view = (UserView) convertView; - } else { - view = new UserView(activity); - } - view.setObject(entry, imageLoader); - return view; + public int getItemViewType(User item) { + return VIEW_TYPE_USER; } }
\ No newline at end of file diff --git a/app/src/main/java/github/daneren2005/dsub/domain/Playlist.java b/app/src/main/java/github/daneren2005/dsub/domain/Playlist.java index 7cd820c0..99b85ce9 100644 --- a/app/src/main/java/github/daneren2005/dsub/domain/Playlist.java +++ b/app/src/main/java/github/daneren2005/dsub/domain/Playlist.java @@ -19,6 +19,9 @@ package github.daneren2005.dsub.domain; import java.io.Serializable; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; /** * @author Sindre Mehus @@ -125,4 +128,16 @@ public class Playlist implements Serializable { Playlist playlist = (Playlist) o; return playlist.id.equals(this.id); } + + public static class PlaylistComparator implements Comparator<Playlist> { + @Override + public int compare(Playlist playlist1, Playlist playlist2) { + return playlist1.getName().compareToIgnoreCase(playlist2.getName()); + } + + public static List<Playlist> sort(List<Playlist> playlists) { + Collections.sort(playlists, new PlaylistComparator()); + return playlists; + } + } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/AdminFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/AdminFragment.java index 66ce5f15..69164036 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/AdminFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/AdminFragment.java @@ -17,6 +17,7 @@ package github.daneren2005.dsub.fragments; import android.os.Bundle; import android.view.ContextMenu; +import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; @@ -28,6 +29,7 @@ import java.util.ArrayList; import java.util.List; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.User; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.parser.SubsonicRESTException; @@ -36,8 +38,9 @@ import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.UserUtil; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.adapter.UserAdapter; +import github.daneren2005.dsub.view.UpdateView; -public class AdminFragment extends SelectListFragment<User> { +public class AdminFragment extends SelectRecyclerFragment<User> { private static String TAG = AdminFragment.class.getSimpleName(); @Override @@ -56,22 +59,16 @@ public class AdminFragment extends SelectListFragment<User> { } @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - MenuInflater inflater = context.getMenuInflater(); + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<User> updateView, User item) { if(UserUtil.isCurrentAdmin()) { - inflater.inflate(R.menu.admin_context, menu); + menuInflater.inflate(R.menu.admin_context, menu); } else if(UserUtil.isCurrentRole(User.SETTINGS)) { - inflater.inflate(R.menu.admin_context_user, menu); + menuInflater.inflate(R.menu.admin_context_user, menu); } } @Override - public boolean onContextItemSelected(MenuItem menuItem) { - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - User user = objects.get(info.position); - + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<User> updateView, User user) { switch(menuItem.getItemId()) { case R.id.admin_change_email: UserUtil.changeEmail(context, user); @@ -97,8 +94,8 @@ public class AdminFragment extends SelectListFragment<User> { } @Override - public ArrayAdapter getAdapter(List<User> objs) { - return new UserAdapter(context, objs, getImageLoader()); + public SectionAdapter getAdapter(List<User> objs) { + return new UserAdapter(context, objs, getImageLoader(), this); } @Override @@ -134,9 +131,7 @@ public class AdminFragment extends SelectListFragment<User> { } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - User user = (User) parent.getItemAtPosition(position); - + public void onItemClicked(User user) { SubsonicFragment fragment = new UserFragment(); Bundle args = new Bundle(); args.putSerializable(Constants.INTENT_EXTRA_NAME_ID, user); diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/DownloadFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/DownloadFragment.java index 59229c3f..b4e4be93 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/DownloadFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/DownloadFragment.java @@ -16,10 +16,17 @@ package github.daneren2005.dsub.fragments; import android.content.DialogInterface; +import android.os.Bundle; import android.os.Handler; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; import android.view.ContextMenu; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; @@ -30,6 +37,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.service.DownloadFile; import github.daneren2005.dsub.service.DownloadService; @@ -38,13 +46,60 @@ import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.adapter.DownloadFileAdapter; +import github.daneren2005.dsub.view.SongView; +import github.daneren2005.dsub.view.UpdateView; -public class DownloadFragment extends SelectListFragment<DownloadFile> { +public class DownloadFragment extends SelectRecyclerFragment<DownloadFile> implements SectionAdapter.OnItemClickedListener<DownloadFile> { private long currentRevision; private ScheduledExecutorService executorService; public DownloadFragment() { serialize = false; + pullToRefresh = false; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { + super.onCreateView(inflater, container, bundle); + + ItemTouchHelper touchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { + @Override + public boolean onMove(RecyclerView recyclerView, final RecyclerView.ViewHolder fromHolder, final RecyclerView.ViewHolder toHolder) { + new SilentBackgroundTask<Void>(context) { + private int from; + private int to; + + @Override + protected Void doInBackground() throws Throwable { + from = fromHolder.getAdapterPosition(); + to = toHolder.getAdapterPosition(); + getDownloadService().swap(false, from, to); + return null; + } + + @Override + protected void done(Void result) { + adapter.notifyItemMoved(from, to); + } + }.execute(); + + return true; + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { + SongView songView = (SongView) ((UpdateView.UpdateViewHolder) viewHolder).getUpdateView(); + DownloadFile downloadFile = songView.getDownloadFile(); + + DownloadService downloadService = getDownloadService(); + downloadService.removeBackground(downloadFile); + adapter.removeItem(downloadFile); + currentRevision = downloadService.getDownloadListUpdateRevision(); + } + }); + touchHelper.attachToRecyclerView(recyclerView); + + return rootView; } @Override @@ -80,8 +135,8 @@ public class DownloadFragment extends SelectListFragment<DownloadFile> { } @Override - public ArrayAdapter getAdapter(List<DownloadFile> objs) { - return new DownloadFileAdapter(context, objs); + public SectionAdapter getAdapter(List<DownloadFile> objs) { + return new DownloadFileAdapter(context, objs, this); } @Override @@ -91,9 +146,6 @@ public class DownloadFragment extends SelectListFragment<DownloadFile> { return new ArrayList<DownloadFile>(); } - listView.setOnScrollListener(null); - refreshLayout.setEnabled(false); - List<DownloadFile> songList = new ArrayList<DownloadFile>(); songList.addAll(downloadService.getBackgroundDownloads()); currentRevision = downloadService.getDownloadListUpdateRevision(); @@ -106,8 +158,25 @@ public class DownloadFragment extends SelectListFragment<DownloadFile> { } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + public void onItemClicked(DownloadFile item) { + + } + + @Override + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<DownloadFile> updateView, DownloadFile downloadFile) { + MusicDirectory.Entry selectedItem = downloadFile.getSong(); + onCreateContextMenuSupport(menu, menuInflater, updateView, selectedItem); + if(!selectedItem.isVideo() && !Util.isOffline(context)) { + menu.removeItem(R.id.song_menu_remove_playlist); + } + + recreateContextMenu(menu); + } + @Override + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<DownloadFile> updateView, DownloadFile downloadFile) { + MusicDirectory.Entry selectedItem = downloadFile.getSong(); + return onContextItemSelected(menuItem, selectedItem); } @Override @@ -141,36 +210,6 @@ public class DownloadFragment extends SelectListFragment<DownloadFile> { return false; } - @Override - public void onCreateContextMenu(android.view.ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Object selectedItem = ((DownloadFile) listView.getItemAtPosition(info.position)).getSong(); - onCreateContextMenu(menu, view, menuInfo, selectedItem); - if(selectedItem instanceof MusicDirectory.Entry && !((MusicDirectory.Entry) selectedItem).isVideo() && !Util.isOffline(context)) { - menu.removeItem(R.id.song_menu_remove_playlist); - } - - recreateContextMenu(menu); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Object selectedItem = ((DownloadFile) listView.getItemAtPosition(info.position)).getSong(); - - if(onContextItemSelected(menuItem, selectedItem)) { - return true; - } - - return true; - } - private void update() { DownloadService downloadService = getDownloadService(); if (downloadService == null || objects == null || adapter == null) { diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/EqualizerFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/EqualizerFragment.java index ea61f2c7..e2535e04 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/EqualizerFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/EqualizerFragment.java @@ -104,6 +104,7 @@ public class EqualizerFragment extends SubsonicFragment { }); setTitle(R.string.equalizer_label); + setSubtitle(null); return rootView; } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/LyricsFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/LyricsFragment.java index 826029f5..402bd257 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/LyricsFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/LyricsFragment.java @@ -62,6 +62,7 @@ public final class LyricsFragment extends SubsonicFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { setTitle(R.string.download_menu_lyrics); + setSubtitle(null); rootView = inflater.inflate(R.layout.lyrics, container, false); artistView = (TextView) rootView.findViewById(R.id.lyrics_artist); titleView = (TextView) rootView.findViewById(R.id.lyrics_title); diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java index ae38534a..1f3cb11d 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/MainFragment.java @@ -1,6 +1,7 @@ package github.daneren2005.dsub.fragments; -import android.app.AlertDialog; +import android.content.res.Resources; +import android.support.v7.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; @@ -9,69 +10,43 @@ import android.os.Build; import android.os.Bundle; import android.os.StatFs; import android.util.Log; -import android.view.ContextMenu; -import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; import android.widget.CheckBox; -import android.widget.CompoundButton; -import android.widget.ListView; -import android.widget.TextView; + import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; +import github.daneren2005.dsub.adapter.MainAdapter; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.ServerInfo; import github.daneren2005.dsub.service.DownloadService; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.FileUtil; import github.daneren2005.dsub.util.LoadingTask; import github.daneren2005.dsub.util.Pair; +import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.UserUtil; -import github.daneren2005.dsub.adapter.MergeAdapter; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.MusicServiceFactory; import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.view.ChangeLog; +import github.daneren2005.dsub.view.UpdateView; + import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -public class MainFragment extends SubsonicFragment { +public class MainFragment extends SelectRecyclerFragment<Integer> { private static final String TAG = MainFragment.class.getSimpleName(); - private LayoutInflater inflater; - private TextView countView; - - private static final int MENU_GROUP_SERVER = 10; - private static final int MENU_ITEM_SERVER_BASE = 100; - - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - this.inflater = inflater; - rootView = inflater.inflate(R.layout.home, container, false); - - createLayout(); - - return rootView; - } - - @Override - public void onResume() { - super.onResume(); - } - @Override - public void onDestroy() { - super.onDestroy(); + public MainFragment() { + super(); + pullToRefresh = false; + serialize = false; + backgroundUpdate = false; } @Override @@ -116,180 +91,52 @@ public class MainFragment extends SubsonicFragment { } @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - int serverCount = Util.getServerCount(context); - int activeServer = Util.getActiveServer(context); - for(int i = 1; i <= serverCount; i++) { - android.view.MenuItem menuItem = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_BASE + i, MENU_ITEM_SERVER_BASE + i, Util.getServerName(context, i)); - if(i == activeServer) { - menuItem.setChecked(true); - } - } - menu.setGroupCheckable(MENU_GROUP_SERVER, true, true); - menu.setHeaderTitle(R.string.main_select_server); - - recreateContextMenu(menu); + public int getOptionsMenu() { + return 0; } @Override - public boolean onContextItemSelected(android.view.MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; + public SectionAdapter getAdapter(List objs) { + List<List<Integer>> sections = new ArrayList<>(); + List<String> headers = new ArrayList<>(); + + headers.add(null); + List<Integer> stars = Arrays.asList(R.string.main_albums_starred); + sections.add(stars); + + List<Integer> albums = new ArrayList<>(); + albums.add(R.string.main_albums_newest); + albums.add(R.string.main_albums_random); + if(ServerInfo.checkServerVersion(context, "1.8")) { + albums.add(R.string.main_albums_alphabetical); } - - int activeServer = menuItem.getItemId() - MENU_ITEM_SERVER_BASE; - setActiveServer(activeServer); - return true; - } - - @Override - protected void refresh(boolean refresh) { - createLayout(); - } - - private void createLayout() { - View buttons = inflater.inflate(R.layout.main_buttons, null); - - final View serverButton = buttons.findViewById(R.id.main_select_server); - final TextView serverTextView = (TextView) serverButton.findViewById(R.id.main_select_server_2); - final TextView offlineButton = (TextView) buttons.findViewById(R.id.main_offline); - offlineButton.setText(Util.isOffline(context) ? R.string.main_online : R.string.main_offline); - - final View albumsTitle = buttons.findViewById(R.id.main_albums); - final View videoTitle = buttons.findViewById(R.id.main_video_section); - final View albumsNewestButton = buttons.findViewById(R.id.main_albums_newest); - countView = (TextView) buttons.findViewById(R.id.main_albums_recent_count); - final View albumsRandomButton = buttons.findViewById(R.id.main_albums_random); - final View albumsHighestButton = buttons.findViewById(R.id.main_albums_highest); - final View albumsRecentButton = buttons.findViewById(R.id.main_albums_recent); - final View albumsFrequentButton = buttons.findViewById(R.id.main_albums_frequent); - final View albumsStarredButton = buttons.findViewById(R.id.main_albums_starred); - final View albumsGenresButton = buttons.findViewById(R.id.main_albums_genres); - final View albumsYearButton = buttons.findViewById(R.id.main_albums_year); - final View albumsAlphabeticalButton = buttons.findViewById(R.id.main_albums_alphabetical); - final View videosButton = buttons.findViewById(R.id.main_videos); - - final View dummyView = rootView.findViewById(R.id.main_dummy); - - final CheckBox albumsPerFolderCheckbox = (CheckBox) buttons.findViewById(R.id.main_albums_per_folder); - if(!Util.isOffline(context) && ServerInfo.canAlbumListPerFolder(context)) { - albumsPerFolderCheckbox.setChecked(Util.getAlbumListsPerFolder(context)); - albumsPerFolderCheckbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - Util.setAlbumListsPerFolder(context, isChecked); - } - }); - } else { - albumsPerFolderCheckbox.setVisibility(View.GONE); + if(!Util.isTagBrowsing(context)) { + albums.add(R.string.main_albums_highest); } + albums.add(R.string.main_albums_genres); + albums.add(R.string.main_albums_year); + albums.add(R.string.main_albums_recent); - int instance = Util.getActiveServer(context); - String name = Util.getServerName(context, instance); - serverTextView.setText(name); - - ListView list = (ListView) rootView.findViewById(R.id.main_list); + sections.add(albums); + headers.add("albums"); - MergeAdapter adapter = new MergeAdapter(); - if (!Util.isOffline(context)) { - adapter.addViews(Arrays.asList(serverButton), true); + if(ServerInfo.checkServerVersion(context, "1.8") && !Util.isTagBrowsing(context)) { + List<Integer> videos = Arrays.asList(R.string.main_videos); + sections.add(videos); + headers.add("videos"); } - adapter.addView(offlineButton, true); - if (!Util.isOffline(context)) { - adapter.addView(albumsTitle, false); - adapter.addViews(Arrays.asList(albumsNewestButton, albumsRandomButton), true); - if(ServerInfo.checkServerVersion(context, "1.8")) { - adapter.addView(albumsAlphabeticalButton, true); - } - if(!Util.isTagBrowsing(context)) { - adapter.addView(albumsHighestButton, true); - } - adapter.addViews(Arrays.asList(albumsStarredButton, albumsGenresButton, albumsYearButton, albumsRecentButton, albumsFrequentButton), true); - if(ServerInfo.checkServerVersion(context, "1.8") && !Util.isTagBrowsing(context)) { - adapter.addView(videoTitle, false); - adapter.addView(videosButton, true); - } - } - list.setAdapter(adapter); - registerForContextMenu(dummyView); - - list.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - if (view == serverButton) { - dummyView.showContextMenu(); - } else if (view == offlineButton) { - toggleOffline(); - } else if (view == albumsNewestButton) { - showAlbumList("newest"); - } else if (view == albumsRandomButton) { - showAlbumList("random"); - } else if (view == albumsHighestButton) { - showAlbumList("highest"); - } else if (view == albumsRecentButton) { - showAlbumList("recent"); - } else if (view == albumsFrequentButton) { - showAlbumList("frequent"); - } else if (view == albumsStarredButton) { - showAlbumList("starred"); - } else if(view == albumsGenresButton) { - showAlbumList("genres"); - } else if(view == albumsYearButton) { - showAlbumList("years"); - } else if(view == albumsAlphabeticalButton) { - showAlbumList("alphabeticalByName"); - } else if(view == videosButton) { - showVideos(); - } - } - }); - setTitle(R.string.common_appname); - if(!Util.isOffline(context)) { - getMostRecentCount(); - } + return new MainAdapter(context, headers, sections, this); } - private void setActiveServer(int instance) { - if (Util.getActiveServer(context) != instance) { - final DownloadService service = getDownloadService(); - if (service != null) { - new SilentBackgroundTask<Void>(context) { - @Override - protected Void doInBackground() throws Throwable { - service.clearIncomplete(); - return null; - } - }.execute(); - - } - Util.setActiveServer(context, instance); - context.invalidate(); - UserUtil.refreshCurrentUser(context, false, true); - } + @Override + public List<Integer> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { + return Arrays.asList(0); } - private void toggleOffline() { - boolean isOffline = Util.isOffline(context); - Util.setOffline(context, !isOffline); - context.invalidate(); - DownloadService service = getDownloadService(); - if (service != null) { - service.setOnline(isOffline); - } - - // Coming back online - if(isOffline) { - int scrobblesCount = Util.offlineScrobblesCount(context); - int starsCount = Util.offlineStarsCount(context); - if(scrobblesCount > 0 || starsCount > 0){ - showOfflineSyncDialog(scrobblesCount, starsCount); - } - } - - UserUtil.seedCurrentUser(context); + @Override + public int getTitleResource() { + return R.string.common_appname; } private void showAlbumList(String type) { @@ -305,9 +152,6 @@ public class MainFragment extends SubsonicFragment { SharedPreferences.Editor editor = Util.getPreferences(context).edit(); editor.putInt(Constants.PREFERENCES_KEY_RECENT_COUNT + Util.getActiveServer(context), 0); editor.commit(); - - // Clear immediately so doesn't still show when pressing back - setMostRecentCount(0); } SubsonicFragment fragment = new SelectDirectoryFragment(); @@ -324,112 +168,56 @@ public class MainFragment extends SubsonicFragment { SubsonicFragment fragment = new SelectVideoFragment(); replaceFragment(fragment); } - - private void showOfflineSyncDialog(final int scrobbleCount, final int starsCount) { - String syncDefault = Util.getSyncDefault(context); - if(syncDefault != null) { - if("sync".equals(syncDefault)) { - syncOffline(scrobbleCount, starsCount); - return; - } else if("delete".equals(syncDefault)) { - deleteOffline(); - return; - } - } - - View checkBoxView = context.getLayoutInflater().inflate(R.layout.sync_dialog, null); - final CheckBox checkBox = (CheckBox)checkBoxView.findViewById(R.id.sync_default); - - AlertDialog.Builder builder = new AlertDialog.Builder(context); - builder.setIcon(android.R.drawable.ic_dialog_info) - .setTitle(R.string.offline_sync_dialog_title) - .setMessage(context.getResources().getString(R.string.offline_sync_dialog_message, scrobbleCount, starsCount)) - .setView(checkBoxView) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if(checkBox.isChecked()) { - Util.setSyncDefault(context, "sync"); - } - syncOffline(scrobbleCount, starsCount); - } - }).setNeutralButton(R.string.common_cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dialogInterface.dismiss(); - } - }).setNegativeButton(R.string.common_delete, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if(checkBox.isChecked()) { - Util.setSyncDefault(context, "delete"); - } - deleteOffline(); - } - }); - - builder.create().show(); - } - - private void syncOffline(final int scrobbleCount, final int starsCount) { - new SilentBackgroundTask<Integer>(context) { - @Override - protected Integer doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - return musicService.processOfflineSyncs(context, null); - } - - @Override - protected void done(Integer result) { - if(result == scrobbleCount) { - Util.toast(context, context.getResources().getString(R.string.offline_sync_success, result)); - } else { - Util.toast(context, context.getResources().getString(R.string.offline_sync_partial, result, scrobbleCount + starsCount)); - } - } - - @Override - protected void error(Throwable error) { - Log.w(TAG, "Failed to sync offline stats", error); - String msg = context.getResources().getString(R.string.offline_sync_error) + " " + getErrorMessage(error); - Util.toast(context, msg); - } - }.execute(); - } - private void deleteOffline() { - SharedPreferences.Editor offline = Util.getOfflineSync(context).edit(); - offline.putInt(Constants.OFFLINE_SCROBBLE_COUNT, 0); - offline.putInt(Constants.OFFLINE_STAR_COUNT, 0); - offline.commit(); - } private void showAboutDialog() { - new LoadingTask<String>(context) { + new LoadingTask<Void>(context) { + Long[] used; + long bytesTotalFs; + long bytesAvailableFs; + @Override - protected String doInBackground() throws Throwable { + protected Void doInBackground() throws Throwable { File rootFolder = FileUtil.getMusicDirectory(context); StatFs stat = new StatFs(rootFolder.getPath()); - long bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize(); - long bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize(); - - Pair<Long, Long> used = FileUtil.getUsedSize(context, rootFolder); - - return getResources().getString(R.string.main_about_text, - context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName, - used.getFirst(), - Util.formatLocalizedBytes(used.getSecond(), context), - Util.formatLocalizedBytes(Util.getCacheSizeMB(context) * 1024L * 1024L, context), - Util.formatLocalizedBytes(bytesAvailableFs, context), - Util.formatLocalizedBytes(bytesTotalFs, context)); + bytesTotalFs = (long) stat.getBlockCount() * (long) stat.getBlockSize(); + bytesAvailableFs = (long) stat.getAvailableBlocks() * (long) stat.getBlockSize(); + + used = FileUtil.getUsedSize(context, rootFolder); + return null; } @Override - protected void done(String msg) { + protected void done(Void result) { + List<Integer> headers = new ArrayList<>(); + List<String> details = new ArrayList<>(); + + headers.add(R.string.details_author); + details.add("Scott Jackson"); + + headers.add(R.string.details_email); + details.add("dsub.android@gmail.com"); + try { - Util.info(context, R.string.main_about_title, msg); + headers.add(R.string.details_version); + details.add(context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName); } catch(Exception e) { - Util.toast(context, "Failed to open dialog"); + details.add(""); } + + Resources res = context.getResources(); + headers.add(R.string.details_files_cached); + details.add(Long.toString(used[0])); + + headers.add(R.string.details_files_permanent); + details.add(Long.toString(used[1])); + + headers.add(R.string.details_used_space); + details.add(res.getString(R.string.details_of, Util.formatLocalizedBytes(used[2], context), Util.formatLocalizedBytes(Util.getCacheSizeMB(context) * 1024L * 1024L, context))); + + headers.add(R.string.details_available_space); + details.add(res.getString(R.string.details_of, Util.formatLocalizedBytes(bytesAvailableFs, context), Util.formatLocalizedBytes(bytesTotalFs, context))); + + Util.showDetailsDialog(context, R.string.main_about_title, headers, details); } }.execute(); } @@ -506,81 +294,37 @@ public class MainFragment extends SubsonicFragment { }.execute(); } catch(Exception e) {} } - - private void getMostRecentCount() { - // Use stashed value until after refresh occurs - SharedPreferences prefs = Util.getPreferences(context); - final int startCount = prefs.getInt(Constants.PREFERENCES_KEY_RECENT_COUNT + Util.getActiveServer(context), 0); - setMostRecentCount(startCount); - - new SilentBackgroundTask<Integer>(context) { - @Override - public Integer doInBackground() throws Exception { - String recentAddedFile = Util.getCacheName(context, "recent_count"); - ArrayList<String> recents = FileUtil.deserialize(context, recentAddedFile, ArrayList.class); - if(recents == null) { - recents = new ArrayList<String>(); - } - - MusicService musicService = MusicServiceFactory.getMusicService(context); - MusicDirectory recentlyAdded = musicService.getAlbumList("newest", 20, 0, context, null); - - // If first run, just put everything in it and return 0 - boolean firstRun = recents.isEmpty(); - - // Count how many new albums are in the list - int count = 0; - for(MusicDirectory.Entry album: recentlyAdded.getChildren()) { - if(!recents.contains(album.getId())) { - recents.add(album.getId()); - count++; - } - } - - // Keep recents list from growing infinitely - while(recents.size() > 40) { - recents.remove(0); - } - FileUtil.serialize(context, recents, recentAddedFile); - - if(firstRun) { - return 0; - } else { - // Add the old count which will get cleared out after viewing recents - count += startCount; - SharedPreferences.Editor editor = Util.getPreferences(context).edit(); - editor.putInt(Constants.PREFERENCES_KEY_RECENT_COUNT + Util.getActiveServer(context), count); - editor.commit(); - - return count; - } - } - - @Override - public void done(Integer result) { - setMostRecentCount(result); - } - - @Override - public void error(Throwable x) { - Log.w(TAG, "Failed to refresh most recent count", x); - } - }.execute(); - } - - private void setMostRecentCount(int count) { - if(count <= 0) { - countView.setVisibility(View.GONE); - } else { - String displayValue; - if(count < 10) { - displayValue = "0" + count; - } else { - displayValue = "" + count; - } - - countView.setText(displayValue); - countView.setVisibility(View.VISIBLE); + + @Override + public void onItemClicked(Integer item) { + if (item == R.string.main_albums_newest) { + showAlbumList("newest"); + } else if (item == R.string.main_albums_random) { + showAlbumList("random"); + } else if (item == R.string.main_albums_highest) { + showAlbumList("highest"); + } else if (item == R.string.main_albums_recent) { + showAlbumList("recent"); + } else if (item == R.string.main_albums_frequent) { + showAlbumList("frequent"); + } else if (item == R.string.main_albums_starred) { + showAlbumList("starred"); + } else if(item == R.string.main_albums_genres) { + showAlbumList("genres"); + } else if(item == R.string.main_albums_year) { + showAlbumList("years"); + } else if(item == R.string.main_albums_alphabetical) { + showAlbumList("alphabeticalByName"); + } else if(item == R.string.main_videos) { + showVideos(); } } + + @Override + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Integer> updateView, Integer item) {} + + @Override + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Integer> updateView, Integer item) { + return false; + } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java index 3e30af50..5e09e69c 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/NowPlayingFragment.java @@ -20,7 +20,8 @@ import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; -import android.app.AlertDialog; +import android.annotation.TargetApi; +import android.support.v7.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; @@ -30,6 +31,9 @@ import android.os.Bundle; import android.os.Handler; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.MediaRouteButton; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; import android.util.Log; import android.view.ContextMenu; import android.view.Display; @@ -54,6 +58,7 @@ import android.widget.TextView; import android.widget.ViewFlipper; import github.daneren2005.dsub.R; import github.daneren2005.dsub.activity.SubsonicFragmentActivity; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.audiofx.EqualizerController; import github.daneren2005.dsub.domain.Bookmark; import github.daneren2005.dsub.domain.PlayerState; @@ -61,6 +66,7 @@ import github.daneren2005.dsub.domain.RepeatMode; import github.daneren2005.dsub.domain.ServerInfo; import github.daneren2005.dsub.service.DownloadFile; import github.daneren2005.dsub.service.DownloadService; +import github.daneren2005.dsub.service.DownloadService.OnSongChangedListener; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.MusicServiceFactory; import github.daneren2005.dsub.service.OfflineException; @@ -69,6 +75,7 @@ import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.adapter.DownloadFileAdapter; import github.daneren2005.dsub.view.FadeOutAnimation; +import github.daneren2005.dsub.view.SongView; import github.daneren2005.dsub.view.UpdateView; import github.daneren2005.dsub.util.Util; @@ -78,14 +85,12 @@ import github.daneren2005.dsub.util.*; import github.daneren2005.dsub.view.AutoRepeatButton; import java.util.ArrayList; import java.util.concurrent.ScheduledFuture; -import com.mobeta.android.dslv.*; import github.daneren2005.dsub.activity.SubsonicActivity; -public class NowPlayingFragment extends SubsonicFragment implements OnGestureListener { +public class NowPlayingFragment extends SubsonicFragment implements OnGestureListener, SectionAdapter.OnItemClickedListener<DownloadFile>, OnSongChangedListener { private static final String TAG = NowPlayingFragment.class.getSimpleName(); private static final int PERCENTAGE_OF_SCREEN_FOR_SWIPE = 10; private static final int INCREMENT_TIME = 5000; - private static final int SERVICE_BACKOFF = 200; private static final int ACTION_PREVIOUS = 1; private static final int ACTION_NEXT = 2; @@ -96,7 +101,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis private TextView emptyTextView; private TextView songTitleTextView; private ImageView albumArtImageView; - private DragSortListView playlistView; + private RecyclerView playlistView; private TextView positionTextView; private TextView durationTextView; private TextView statusTextView; @@ -112,22 +117,20 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis private ImageButton bookmarkButton; private ImageButton rateBadButton; private ImageButton rateGoodButton; - private View mainLayout; + private ScheduledExecutorService executorService; private DownloadFile currentPlaying; - private long currentRevision; private int swipeDistance; private int swipeVelocity; private ScheduledFuture<?> hideControlsFuture; private List<DownloadFile> songList; private DownloadFileAdapter songListAdapter; - private SilentBackgroundTask<Void> onProgressChangedTask; - private SilentBackgroundTask<Void> onCurrentChangedTask; - private SilentBackgroundTask<Void> onDownloadListChangedTask; private boolean seekInProgress = false; private boolean startFlipped = false; private boolean scrollWhenLoaded = false; private int lastY = 0; + private int currentPlayingSize = 0; + private MenuItem timerMenu; /** * Called when the activity is first created. @@ -141,6 +144,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis startFlipped = true; } } + primaryFragment = false; } @Override @@ -153,11 +157,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { rootView = inflater.inflate(R.layout.download, container, false); setTitle(R.string.button_bar_now_playing); - - mainLayout = rootView.findViewById(R.id.download_layout); - if(!primaryFragment) { - mainLayout.setVisibility(View.GONE); - } WindowManager w = context.getWindowManager(); Display d = w.getDefaultDisplay(); @@ -173,7 +172,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis durationTextView = (TextView)rootView.findViewById(R.id.download_duration); statusTextView = (TextView)rootView.findViewById(R.id.download_status); progressBar = (SeekBar)rootView.findViewById(R.id.download_progress_bar); - playlistView = (DragSortListView)rootView.findViewById(R.id.download_list); previousButton = (AutoRepeatButton)rootView.findViewById(R.id.download_previous); nextButton = (AutoRepeatButton)rootView.findViewById(R.id.download_next); pauseButton =rootView.findViewById(R.id.download_pause); @@ -185,6 +183,44 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis rateGoodButton = (ImageButton) rootView.findViewById(R.id.download_rating_good); toggleListButton =rootView.findViewById(R.id.download_toggle_list); + playlistView = (RecyclerView)rootView.findViewById(R.id.download_list); + setupLayoutManager(playlistView, false); + ItemTouchHelper touchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) { + @Override + public boolean onMove(RecyclerView recyclerView, final RecyclerView.ViewHolder fromHolder, final RecyclerView.ViewHolder toHolder) { + new SilentBackgroundTask<Void>(context) { + private int from; + private int to; + + @Override + protected Void doInBackground() throws Throwable { + from = fromHolder.getAdapterPosition(); + to = toHolder.getAdapterPosition(); + getDownloadService().swap(true, from, to); + return null; + } + + @Override + protected void done(Void result) { + songListAdapter.notifyItemMoved(from, to); + } + }.execute(); + + return true; + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { + SongView songView = (SongView) ((UpdateView.UpdateViewHolder) viewHolder).getUpdateView(); + DownloadFile downloadFile = songView.getDownloadFile(); + + DownloadService downloadService = getDownloadService(); + downloadService.remove(downloadFile); + songListAdapter.removeItem(downloadFile); + } + }); + touchHelper.attachToRecyclerView(playlistView); + starButton = (ImageButton)rootView.findViewById(R.id.download_star); if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_MENU_STAR, true)) { starButton.setOnClickListener(new OnClickListener() { @@ -196,7 +232,15 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis toggleStarred(currentSong, new OnStarChange() { @Override void starChange(boolean starred) { - starButton.setImageResource(currentSong.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off); + if(currentSong.isStarred()) { + starButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_toggle_star)); + } else { + if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + starButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.star_outline)); + } else { + starButton.setImageResource(R.drawable.ic_toggle_star_outline_dark); + } + } } }); } @@ -239,12 +283,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis getDownloadService().previous(); return null; } - - @Override - protected void done(Void result) { - onCurrentChanged(); - onProgressChanged(); - } }.execute(); setControlsVisible(true); } @@ -265,14 +303,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis getDownloadService().next(); return true; } - - @Override - protected void done(Boolean result) { - if (result) { - onCurrentChanged(); - onProgressChanged(); - } - } }.execute(); setControlsVisible(true); } @@ -292,12 +322,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis getDownloadService().pause(); return null; } - - @Override - protected void done(Void result) { - onCurrentChanged(); - onProgressChanged(); - } }.execute(); } }); @@ -311,12 +335,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis getDownloadService().reset(); return null; } - - @Override - protected void done(Void result) { - onCurrentChanged(); - onProgressChanged(); - } }.execute(); } }); @@ -331,12 +349,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis start(); return null; } - - @Override - protected void done(Void result) { - onCurrentChanged(); - onProgressChanged(); - } }.execute(); } }); @@ -346,7 +358,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis public void onClick(View view) { RepeatMode repeatMode = getDownloadService().getRepeatMode().next(); getDownloadService().setRepeatMode(repeatMode); - onDownloadListChanged(); switch (repeatMode) { case OFF: Util.toast(context, R.string.download_repeat_off); @@ -360,6 +371,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis default: break; } + updateRepeatButton(); setControlsVisible(true); } }); @@ -392,21 +404,21 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { rateBadButton.setImageResource(R.drawable.ic_action_rating_bad_dark); } else { - rateBadButton.setImageResource(Util.getAttribute(context, R.attr.rating_bad)); + rateBadButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.rating_bad)); } } else { // Immediately skip to the next song downloadService.next(true); - + // Otherwise set rating to 1 setRating(entry, 1); - rateBadButton.setImageResource(R.drawable.ic_action_rating_bad_selected); + rateBadButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_action_rating_bad_selected)); // Make sure good rating is blank if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { rateGoodButton.setImageResource(R.drawable.ic_action_rating_good_dark); } else { - rateGoodButton.setImageResource(Util.getAttribute(context, R.attr.rating_good)); + rateGoodButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.rating_good)); } } } @@ -432,18 +444,18 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { rateGoodButton.setImageResource(R.drawable.ic_action_rating_good_dark); } else { - rateGoodButton.setImageResource(Util.getAttribute(context, R.attr.rating_good)); + rateGoodButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.rating_good)); } } else { // Otherwise set rating to maximum setRating(entry, 5); - rateGoodButton.setImageResource(R.drawable.ic_action_rating_good_selected); + rateGoodButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_action_rating_good_selected)); // Make sure bad rating is blank if (context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { rateBadButton.setImageResource(R.drawable.ic_action_rating_bad_dark); } else { - rateBadButton.setImageResource(Util.getAttribute(context, R.attr.rating_bad)); + rateBadButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.rating_bad)); } } } @@ -482,7 +494,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis @Override protected void done(Void result) { seekInProgress = false; - NowPlayingFragment.this.onProgressChanged(); } }.execute(); } @@ -500,55 +511,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis } } }); - playlistView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> parent, View view, final int position, long id) { - warnIfStorageUnavailable(); - new SilentBackgroundTask<Void>(context) { - @Override - protected Void doInBackground() throws Throwable { - getDownloadService().play(position); - return null; - } - - @Override - protected void done(Void result) { - onCurrentChanged(); - onProgressChanged(); - } - }.execute(); - } - }); - playlistView.setDropListener(new DragSortListView.DropListener() { - @Override - public void drop(final int from, final int to) { - new SilentBackgroundTask<Void>(context) { - @Override - protected Void doInBackground() throws Throwable { - getDownloadService().swap(true, from, to); - onDownloadListChanged(); - - return null; - } - }.execute(); - } - }); - playlistView.setRemoveListener(new DragSortListView.RemoveListener() { - @Override - public void remove(int which) { - getDownloadService().remove(which); - onDownloadListChanged(); - } - }); - - registerForContextMenu(playlistView); - - DownloadService downloadService = getDownloadService(); - if (downloadService != null && context.getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, false)) { - context.getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE); - warnIfStorageUnavailable(); - downloadService.setShufflePlayEnabled(true); - } if(Build.MODEL.equals("Nexus 4") || Build.MODEL.equals("GT-I9100")) { View slider = rootView.findViewById(R.id.download_slider); @@ -565,10 +527,11 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis menuInflater.inflate(R.menu.nowplaying_offline, menu); } else { menuInflater.inflate(R.menu.nowplaying, menu); - - if(downloadService != null && downloadService.getSleepTimer()) { - menu.findItem(R.id.menu_toggle_timer).setTitle(R.string.download_stop_timer); - } + } + if(downloadService != null && downloadService.getSleepTimer()) { + int timeRemaining = downloadService.getSleepTimeRemaining(); + timerMenu = menu.findItem(R.id.menu_toggle_timer); + timerMenu.setTitle(context.getResources().getString(R.string.download_stop_time_remaining, Util.formatDuration(timeRemaining))); } if(downloadService != null && downloadService.getKeepScreenOn()) { menu.findItem(R.id.menu_screen_on_off).setChecked(true); @@ -604,47 +567,30 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis if(menuItemSelected(menuItem.getItemId(), null)) { return true; } - + return super.onOptionsItemSelected(menuItem); } @Override - public void onCreateContextMenu(android.view.ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - if(!primaryFragment) { - return; + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<DownloadFile> updateView, DownloadFile downloadFile) { + if(Util.isOffline(context)) { + menuInflater.inflate(R.menu.nowplaying_context_offline, menu); + } else { + menuInflater.inflate(R.menu.nowplaying_context, menu); + menu.findItem(R.id.menu_star).setTitle(downloadFile.getSong().isStarred() ? R.string.common_unstar : R.string.common_star); } - if (view == playlistView) { - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - DownloadFile downloadFile = (DownloadFile) playlistView.getItemAtPosition(info.position); - - android.view.MenuInflater inflater = context.getMenuInflater(); - if(Util.isOffline(context)) { - inflater.inflate(R.menu.nowplaying_context_offline, menu); - } else { - inflater.inflate(R.menu.nowplaying_context, menu); - menu.findItem(R.id.menu_star).setTitle(downloadFile.getSong().isStarred() ? R.string.common_unstar : R.string.common_star); - } - - if (downloadFile.getSong().getParent() == null) { - menu.findItem(R.id.menu_show_album).setVisible(false); - menu.findItem(R.id.menu_show_artist).setVisible(false); - } - - hideMenuItems(menu, (AdapterView.AdapterContextMenuInfo) menuInfo); + if (downloadFile.getSong().getParent() == null) { + menu.findItem(R.id.menu_show_album).setVisible(false); + menu.findItem(R.id.menu_show_artist).setVisible(false); } + + MenuUtil.hideMenuItems(context, menu); } @Override - public boolean onContextItemSelected(android.view.MenuItem menuItem) { - if(!primaryFragment) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - DownloadFile downloadFile = (DownloadFile) playlistView.getItemAtPosition(info.position); - return menuItemSelected(menuItem.getItemId(), downloadFile) || super.onContextItemSelected(menuItem); + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<DownloadFile> updateView, DownloadFile downloadFile) { + return menuItemSelected(menuItem.getItemId(), downloadFile); } private boolean menuItemSelected(int menuItemId, final DownloadFile song) { @@ -712,20 +658,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis replaceFragment(fragment); return true; - } case R.id.menu_remove: - new SilentBackgroundTask<Void>(context) { - @Override - protected Void doInBackground() throws Throwable { - getDownloadService().remove(song); - return null; - } - - @Override - protected void done(Void result) { - onDownloadListChanged(); - } - }.execute(); - return true; + } case R.id.menu_delete: List<Entry> songs = new ArrayList<Entry>(1); songs.add(song.getSong()); @@ -745,7 +678,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis @Override protected void done(Void result) { - onDownloadListChanged(); + context.closeNowPlaying(); } }.execute(); } @@ -841,26 +774,18 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis @Override public void onResume() { super.onResume(); - + if(this.primaryFragment) { + onResumeHandlers(); + } else { + update(); + } + } + private void onResumeHandlers() { final Handler handler = new Handler(); - Runnable runnable = new Runnable() { - @Override - public void run() { - handler.post(new Runnable() { - @Override - public void run() { - update(); - } - }); - } - }; - executorService = Executors.newSingleThreadScheduledExecutor(); - executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS); - setControlsVisible(true); - DownloadService downloadService = getDownloadService(); + final DownloadService downloadService = getDownloadService(); if (downloadService == null || downloadService.getCurrentPlaying() == null || startFlipped) { playlistFlipper.setDisplayedChild(1); } @@ -875,48 +800,63 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis if(currentPlaying == null && downloadService != null && currentPlaying == downloadService.getCurrentPlaying()) { getImageLoader().loadImage(albumArtImageView, (Entry) null, true, false); } - if(downloadService != null) { - downloadService.startRemoteScan(); - } else { - // Make sure to call remote scan once the service is ready - final Runnable waitForService = new Runnable() { - @Override - public void run() { - DownloadService service = getDownloadService(); - if(service != null) { - service.startRemoteScan(); - } else { - handler.postDelayed(this, SERVICE_BACKOFF); - } - } - }; - handler.postDelayed(waitForService, SERVICE_BACKOFF); - } + context.runWhenServiceAvailable(new Runnable() { + @Override + public void run() { + if(primaryFragment) { + DownloadService downloadService = getDownloadService(); + downloadService.startRemoteScan(); + downloadService.addOnSongChangedListener(NowPlayingFragment.this, true); + } + updateRepeatButton(); + } + }); } @Override public void onPause() { super.onPause(); - executorService.shutdown(); - if(getDownloadService() != null) { - getDownloadService().stopRemoteScan(); + onPauseHandlers(); + } + private void onPauseHandlers() { + if(executorService != null) { + DownloadService downloadService = getDownloadService(); + if (downloadService != null) { + downloadService.stopRemoteScan(); + downloadService.removeOnSongChangeListener(this); + } + playlistFlipper.setDisplayedChild(0); } } - + @Override public void setPrimaryFragment(boolean primary) { super.setPrimaryFragment(primary); if(rootView != null) { if(primary) { - mainLayout.setVisibility(View.VISIBLE); - updateButtons(); + onResumeHandlers(); } else { - mainLayout.setVisibility(View.GONE); + onPauseHandlers(); } } } + @Override + public void setTitle(int title) { + this.title = context.getResources().getString(title); + if(this.primaryFragment) { + context.setTitle(this.title); + } + } + @Override + public void setSubtitle(CharSequence title) { + this.subtitle = title; + if(this.primaryFragment) { + context.setSubtitle(title); + } + } + private void scheduleHideControls() { if (hideControlsFuture != null) { hideControlsFuture.cancel(false); @@ -954,7 +894,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis if(context == null) { return; } - + if(Util.isOffline(context)) { bookmarkButton.setVisibility(View.GONE); rateBadButton.setVisibility(View.GONE); @@ -971,46 +911,33 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis } // Scroll to current playing/downloading. + @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void scrollToCurrent() { if (getDownloadService() == null || songListAdapter == null) { scrollWhenLoaded = true; return; } - for (int i = 0; i < songListAdapter.getCount(); i++) { - if (currentPlaying == playlistView.getItemAtPosition(i)) { - playlistView.setSelectionFromTop(i, 40); - return; - } + // Try to get position of current playing/downloading + int position = songListAdapter.getItemPosition(currentPlaying); + if(position == -1) { + DownloadFile currentDownloading = getDownloadService().getCurrentDownloading(); + position = songListAdapter.getItemPosition(currentDownloading); } - DownloadFile currentDownloading = getDownloadService().getCurrentDownloading(); - for (int i = 0; i < songListAdapter.getCount(); i++) { - if (currentDownloading == playlistView.getItemAtPosition(i)) { - playlistView.setSelectionFromTop(i, 40); - return; - } + + // If found, scroll to it + if(position != -1) { + // RecyclerView.scrollToPosition just puts it on the screen (ie: bottom if scrolled below it) + LinearLayoutManager layoutManager = (LinearLayoutManager) playlistView.getLayoutManager(); + layoutManager.scrollToPositionWithOffset(position, 0); } } private void update() { - if (getDownloadService() == null) { - return; - } - - if (currentRevision != getDownloadService().getDownloadListUpdateRevision()) { - onDownloadListChanged(); - } - - if (currentPlaying != getDownloadService().getCurrentPlaying()) { - onCurrentChanged(); - } - if(startFlipped) { startFlipped = false; scrollToCurrent(); } - - onProgressChanged(); } protected void startTimer() { @@ -1043,26 +970,26 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis public void onStopTrackingTouch(SeekBar seekBar) { } }); - lengthBar.setProgress(length - 1); + lengthBar.setProgress(length - 1); AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.menu_set_timer) - .setView(dialogView) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - int length = getMinutes(lengthBar.getProgress()); + .setView(dialogView) + .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + int length = getMinutes(lengthBar.getProgress()); - SharedPreferences.Editor editor = prefs.edit(); - editor.putString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, Integer.toString(length)); - editor.commit(); + SharedPreferences.Editor editor = prefs.edit(); + editor.putString(Constants.PREFERENCES_KEY_SLEEP_TIMER_DURATION, Integer.toString(length)); + editor.commit(); - getDownloadService().setSleepTimerDuration(length); - getDownloadService().startSleepTimer(); - context.supportInvalidateOptionsMenu(); - } - }) - .setNegativeButton(R.string.common_cancel, null); + getDownloadService().setSleepTimerDuration(length); + getDownloadService().startSleepTimer(); + context.supportInvalidateOptionsMenu(); + } + }) + .setNegativeButton(R.string.common_cancel, null); AlertDialog dialog = builder.create(); dialog.show(); } @@ -1087,7 +1014,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis playlistFlipper.setInAnimation(AnimationUtils.loadAnimation(context, R.anim.push_up_in)); playlistFlipper.setOutAnimation(AnimationUtils.loadAnimation(context, R.anim.push_up_out)); playlistFlipper.setDisplayedChild(1); - + UpdateView.triggerUpdate(); } } @@ -1108,258 +1035,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis } } } - private void onDownloadListChanged() { - onDownloadListChanged(false); - } - private void onDownloadListChanged(final boolean refresh) { - final DownloadService downloadService = getDownloadService(); - if (downloadService == null || onDownloadListChangedTask != null) { - return; - } - - onDownloadListChangedTask = new SilentBackgroundTask<Void>(context) { - int currentPlayingIndex; - int size; - - @Override - protected Void doInBackground() throws Throwable { - currentPlayingIndex = downloadService.getCurrentPlayingIndex() + 1; - size = downloadService.size(); - - return null; - } - - @Override - protected void done(Void result) { - List<DownloadFile> list; - list = downloadService.getSongs(); - - if(downloadService.isShufflePlayEnabled()) { - emptyTextView.setText(R.string.download_shuffle_loading); - } - else { - emptyTextView.setText(R.string.download_empty); - } - - if(songListAdapter == null || refresh) { - songList = new ArrayList<DownloadFile>(); - songList.addAll(list); - playlistView.setAdapter(songListAdapter = new DownloadFileAdapter(context, songList)); - } else { - songList.clear(); - songList.addAll(list); - songListAdapter.notifyDataSetChanged(); - } - - emptyTextView.setVisibility(list.isEmpty() ? View.VISIBLE : View.GONE); - currentRevision = downloadService.getDownloadListUpdateRevision(); - - switch (downloadService.getRepeatMode()) { - case OFF: - if("light".equals(SubsonicActivity.getThemeName()) | "light_fullscreen".equals(SubsonicActivity.getThemeName())) { - repeatButton.setImageResource(R.drawable.media_repeat_off_light); - } else { - repeatButton.setImageResource(R.drawable.media_repeat_off); - } - break; - case ALL: - repeatButton.setImageResource(R.drawable.media_repeat_all); - break; - case SINGLE: - repeatButton.setImageResource(R.drawable.media_repeat_single); - break; - default: - break; - } - - if(scrollWhenLoaded) { - scrollToCurrent(); - scrollWhenLoaded = false; - } - - setSubtitle(context.getResources().getString(R.string.download_playing_out_of, currentPlayingIndex, size)); - onDownloadListChangedTask = null; - if(onCurrentChangedTask != null) { - onCurrentChangedTask.execute(); - } else if(onProgressChangedTask != null) { - onProgressChangedTask.execute(); - } - } - }; - onDownloadListChangedTask.execute(); - } - - private void onCurrentChanged() { - final DownloadService downloadService = getDownloadService(); - if (downloadService == null || onCurrentChangedTask != null) { - return; - } - - onCurrentChangedTask = new SilentBackgroundTask<Void>(context) { - int currentPlayingIndex; - int currentPlayingSize; - - @Override - protected Void doInBackground() throws Throwable { - currentPlaying = downloadService.getCurrentPlaying(); - currentPlayingIndex = downloadService.getCurrentPlayingIndex() + 1; - currentPlayingSize = downloadService.size(); - return null; - } - - @Override - protected void done(Void result) { - if (currentPlaying != null) { - Entry song = currentPlaying.getSong(); - songTitleTextView.setText(song.getTitle()); - getImageLoader().loadImage(albumArtImageView, song, true, true); - starButton.setImageResource(song.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off); - setSubtitle(context.getResources().getString(R.string.download_playing_out_of, currentPlayingIndex, currentPlayingSize)); - - int badRating, goodRating, bookmark; - if(song.getRating() == 1) { - badRating = R.drawable.ic_action_rating_bad_selected; - } else if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - badRating = R.drawable.ic_action_rating_bad_dark; - } else { - badRating = Util.getAttribute(context, R.attr.rating_bad); - } - rateBadButton.setImageResource(badRating); - - if(song.getRating() == 5) { - goodRating = R.drawable.ic_action_rating_good_selected; - } else if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - goodRating = R.drawable.ic_action_rating_good_dark; - } else { - goodRating = Util.getAttribute(context, R.attr.rating_good); - } - rateGoodButton.setImageResource(goodRating); - - if(song.getBookmark() != null) { - bookmark = R.drawable.ic_menu_bookmark_selected; - } else if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { - bookmark = R.drawable.ic_menu_bookmark_dark; - } else { - bookmark = Util.getAttribute(context, R.attr.bookmark); - } - bookmarkButton.setImageResource(bookmark); - } else { - songTitleTextView.setText(null); - getImageLoader().loadImage(albumArtImageView, (Entry) null, true, false); - starButton.setImageResource(android.R.drawable.btn_star_big_off); - setSubtitle(null); - } - onCurrentChangedTask = null; - if(onProgressChangedTask != null) { - onProgressChangedTask.execute(); - } - } - }; - - if(onDownloadListChangedTask == null) { - onCurrentChangedTask.execute(); - } - } - - private void onProgressChanged() { - // Make sure to only be trying to run one of these at a time - if (getDownloadService() == null || onProgressChangedTask != null) { - return; - } - - onProgressChangedTask = new SilentBackgroundTask<Void>(context) { - DownloadService downloadService; - int millisPlayed; - Integer duration; - PlayerState playerState; - boolean isSeekable; - - @Override - protected Void doInBackground() throws Throwable { - downloadService = getDownloadService(); - millisPlayed = Math.max(0, downloadService.getPlayerPosition()); - duration = downloadService.getPlayerDuration(); - playerState = getDownloadService().getPlayerState(); - isSeekable = downloadService.isSeekable(); - return null; - } - - @Override - protected void done(Void result) { - if (currentPlaying != null) { - int millisTotal = duration == null ? 0 : duration; - - positionTextView.setText(Util.formatDuration(millisPlayed / 1000)); - if(millisTotal > 0) { - durationTextView.setText(Util.formatDuration(millisTotal / 1000)); - } else { - durationTextView.setText("-:--"); - } - progressBar.setMax(millisTotal == 0 ? 100 : millisTotal); // Work-around for apparent bug. - if(!seekInProgress) { - progressBar.setProgress(millisPlayed); - } - progressBar.setEnabled(isSeekable); - } else { - positionTextView.setText("0:00"); - durationTextView.setText("-:--"); - progressBar.setProgress(0); - progressBar.setEnabled(false); - } - - switch (playerState) { - case DOWNLOADING: - if(currentPlaying != null) { - if(Util.isWifiRequiredForDownload(context)) { - statusTextView.setText(context.getResources().getString(R.string.download_playerstate_mobile_disabled)); - } else { - long bytes = currentPlaying.getPartialFile().length(); - statusTextView.setText(context.getResources().getString(R.string.download_playerstate_downloading, Util.formatLocalizedBytes(bytes, context))); - } - } - break; - case PREPARING: - statusTextView.setText(R.string.download_playerstate_buffering); - break; - default: - if(currentPlaying != null) { - String artist = ""; - if(currentPlaying.getSong().getArtist() != null) { - artist = currentPlaying.getSong().getArtist() + " - "; - } - statusTextView.setText(artist + currentPlaying.getSong().getAlbum()); - } else { - statusTextView.setText(null); - } - break; - } - - switch (playerState) { - case STARTED: - pauseButton.setVisibility(View.VISIBLE); - stopButton.setVisibility(View.INVISIBLE); - startButton.setVisibility(View.INVISIBLE); - break; - case DOWNLOADING: - case PREPARING: - pauseButton.setVisibility(View.INVISIBLE); - stopButton.setVisibility(View.VISIBLE); - startButton.setVisibility(View.INVISIBLE); - break; - default: - pauseButton.setVisibility(View.INVISIBLE); - stopButton.setVisibility(View.INVISIBLE); - startButton.setVisibility(View.VISIBLE); - break; - } - - onProgressChangedTask = null; - } - }; - if(onDownloadListChangedTask == null && onCurrentChangedTask == null) { - onProgressChangedTask.execute(); - } - } private void changeProgress(final int ms) { final DownloadService downloadService = getDownloadService(); @@ -1395,33 +1070,33 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis } }.execute(); } - + private void createBookmark() { DownloadService downloadService = getDownloadService(); if(downloadService == null) { return; } - + final DownloadFile currentDownload = downloadService.getCurrentPlaying(); if(currentDownload == null) { return; } - + View dialogView = context.getLayoutInflater().inflate(R.layout.create_bookmark, null); final EditText commentBox = (EditText)dialogView.findViewById(R.id.comment_text); AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.download_save_bookmark_title) - .setView(dialogView) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - String comment = commentBox.getText().toString(); + .setView(dialogView) + .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + String comment = commentBox.getText().toString(); - createBookmark(currentDownload, comment); - } - }) - .setNegativeButton(R.string.common_cancel, null); + createBookmark(currentDownload, comment); + } + }) + .setNegativeButton(R.string.common_cancel, null); AlertDialog dialog = builder.create(); dialog.show(); } @@ -1430,13 +1105,13 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis if(downloadService == null) { return; } - + final Entry currentSong = currentDownload.getSong(); final int position = downloadService.getPlayerPosition(); final Bookmark oldBookmark = currentSong.getBookmark(); currentSong.setBookmark(new Bookmark(position)); - bookmarkButton.setImageResource(R.drawable.ic_menu_bookmark_selected); - + bookmarkButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_menu_bookmark_selected)); + new SilentBackgroundTask<Void>(context) { @Override protected Void doInBackground() throws Throwable { @@ -1458,30 +1133,30 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis Util.toast(context, R.string.download_save_bookmark); setControlsVisible(true); } - + @Override protected void error(Throwable error) { Log.w(TAG, "Failed to create bookmark", error); currentSong.setBookmark(oldBookmark); - + // If no bookmark at start, then return to no bookmark if(oldBookmark == null) { int bookmark; if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { bookmark = R.drawable.ic_menu_bookmark_dark; } else { - bookmark = Util.getAttribute(context, R.attr.bookmark); + bookmark = DrawableTint.getDrawableRes(context, R.attr.bookmark); } bookmarkButton.setImageResource(bookmark); } - + String msg; if(error instanceof OfflineException || error instanceof ServerTooOldException) { msg = getErrorMessage(error); } else { msg = context.getResources().getString(R.string.download_save_bookmark_failed) + getErrorMessage(error); } - + Util.toast(context, msg, false); } }.execute(); @@ -1538,11 +1213,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis downloadService.seekTo(downloadService.getPlayerPosition() - DownloadService.REWIND); break; } - - onProgressChanged(); - if(performAction == ACTION_NEXT || performAction == ACTION_PREVIOUS) { - onCurrentChanged(); - } return null; } }.execute(); @@ -1570,4 +1240,206 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis public boolean onSingleTapUp(MotionEvent e) { return false; } + + @Override + public void onItemClicked(final DownloadFile item) { + warnIfStorageUnavailable(); + new SilentBackgroundTask<Void>(context) { + @Override + protected Void doInBackground() throws Throwable { + getDownloadService().play(item); + return null; + } + }.execute(); + } + + @Override + public void onSongChanged(DownloadFile currentPlaying, int currentPlayingIndex) { + this.currentPlaying = currentPlaying; + if (currentPlaying != null) { + Entry song = currentPlaying.getSong(); + songTitleTextView.setText(song.getTitle()); + getImageLoader().loadImage(albumArtImageView, song, true, true); + if(song.isStarred()) { + starButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_toggle_star)); + } else { + if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) { + starButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.star_outline)); + } else { + starButton.setImageResource(R.drawable.ic_toggle_star_outline_dark); + } + } + setSubtitle(context.getResources().getString(R.string.download_playing_out_of, currentPlayingIndex + 1, currentPlayingSize)); + + int badRating, goodRating, bookmark; + if(song.getRating() == 1) { + rateBadButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_action_rating_bad_selected)); + } else { + if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { + badRating = R.drawable.ic_action_rating_bad_dark; + } else { + badRating = DrawableTint.getDrawableRes(context, R.attr.rating_bad); + } + rateBadButton.setImageResource(badRating); + } + + if(song.getRating() == 5) { + rateGoodButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_action_rating_good_selected)); + } else { + if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { + goodRating = R.drawable.ic_action_rating_good_dark; + } else { + goodRating = DrawableTint.getDrawableRes(context, R.attr.rating_good); + } + rateGoodButton.setImageResource(goodRating); + } + + if(song.getBookmark() != null) { + bookmarkButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_menu_bookmark_selected)); + } else { + if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) { + bookmark = R.drawable.ic_menu_bookmark_dark; + } else { + bookmark = DrawableTint.getDrawableRes(context, R.attr.bookmark); + } + bookmarkButton.setImageResource(bookmark); + } + } else { + songTitleTextView.setText(null); + getImageLoader().loadImage(albumArtImageView, (Entry) null, true, false); + starButton.setImageResource(R.drawable.ic_toggle_star_outline_dark); + setSubtitle(null); + } + } + + @Override + public void onSongsChanged(List<DownloadFile> songs, DownloadFile currentPlaying, int currentPlayingIndex) { + currentPlayingSize = songs.size(); + + DownloadService downloadService = getDownloadService(); + if(downloadService.isShufflePlayEnabled()) { + emptyTextView.setText(R.string.download_shuffle_loading); + } + else { + emptyTextView.setText(R.string.download_empty); + } + + if(songListAdapter == null) { + songList = new ArrayList<>(); + songList.addAll(songs); + playlistView.setAdapter(songListAdapter = new DownloadFileAdapter(context, songList, NowPlayingFragment.this)); + } else { + songList.clear(); + songList.addAll(songs); + songListAdapter.notifyDataSetChanged(); + } + + emptyTextView.setVisibility(songs.isEmpty() ? View.VISIBLE : View.GONE); + + if(scrollWhenLoaded) { + scrollToCurrent(); + scrollWhenLoaded = false; + } + + setSubtitle(context.getResources().getString(R.string.download_playing_out_of, currentPlayingIndex + 1, currentPlayingSize)); + if(this.currentPlaying != currentPlaying) { + onSongChanged(currentPlaying, currentPlayingIndex); + } + } + + @Override + public void onSongProgress(DownloadFile currentPlaying, int millisPlayed, Integer duration, boolean isSeekable) { + if (currentPlaying != null) { + int millisTotal = duration == null ? 0 : duration; + + positionTextView.setText(Util.formatDuration(millisPlayed / 1000)); + if(millisTotal > 0) { + durationTextView.setText(Util.formatDuration(millisTotal / 1000)); + } else { + durationTextView.setText("-:--"); + } + progressBar.setMax(millisTotal == 0 ? 100 : millisTotal); // Work-around for apparent bug. + if(!seekInProgress) { + progressBar.setProgress(millisPlayed); + } + progressBar.setEnabled(isSeekable); + } else { + positionTextView.setText("0:00"); + durationTextView.setText("-:--"); + progressBar.setProgress(0); + progressBar.setEnabled(false); + } + + DownloadService downloadService = getDownloadService(); + if(downloadService.getSleepTimer() && timerMenu != null) { + int timeRemaining = downloadService.getSleepTimeRemaining(); + timerMenu.setTitle(context.getResources().getString(R.string.download_stop_time_remaining, Util.formatDuration(timeRemaining))); + } + } + + @Override + public void onStateUpdate(DownloadFile downloadFile, PlayerState playerState) { + switch (playerState) { + case DOWNLOADING: + if(currentPlaying != null) { + if(Util.isWifiRequiredForDownload(context)) { + statusTextView.setText(context.getResources().getString(R.string.download_playerstate_mobile_disabled)); + } else { + long bytes = currentPlaying.getPartialFile().length(); + statusTextView.setText(context.getResources().getString(R.string.download_playerstate_downloading, Util.formatLocalizedBytes(bytes, context))); + } + } + break; + case PREPARING: + statusTextView.setText(R.string.download_playerstate_buffering); + break; + default: + if(currentPlaying != null) { + String artist = ""; + if(currentPlaying.getSong().getArtist() != null) { + artist = currentPlaying.getSong().getArtist() + " - "; + } + statusTextView.setText(artist + currentPlaying.getSong().getAlbum()); + } else { + statusTextView.setText(null); + } + break; + } + + switch (playerState) { + case STARTED: + pauseButton.setVisibility(View.VISIBLE); + stopButton.setVisibility(View.INVISIBLE); + startButton.setVisibility(View.INVISIBLE); + break; + case DOWNLOADING: + case PREPARING: + pauseButton.setVisibility(View.INVISIBLE); + stopButton.setVisibility(View.VISIBLE); + startButton.setVisibility(View.INVISIBLE); + break; + default: + pauseButton.setVisibility(View.INVISIBLE); + stopButton.setVisibility(View.INVISIBLE); + startButton.setVisibility(View.VISIBLE); + break; + } + } + + public void updateRepeatButton() { + DownloadService downloadService = getDownloadService(); + switch (downloadService.getRepeatMode()) { + case OFF: + repeatButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.media_button_repeat_off)); + break; + case ALL: + repeatButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.media_button_repeat_all)); + break; + case SINGLE: + repeatButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.media_button_repeat_single)); + break; + default: + break; + } + } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SearchFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SearchFragment.java index 0f1598dd..cd294161 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SearchFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SearchFragment.java @@ -1,12 +1,16 @@ package github.daneren2005.dsub.fragments; +import java.io.Serializable; import java.util.ArrayList; -import java.util.List; import java.util.Arrays; +import java.util.List; import android.content.Intent; import android.os.Bundle; import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.util.Log; import android.view.ContextMenu; import android.view.LayoutInflater; import android.view.Menu; @@ -14,11 +18,13 @@ import android.view.MenuInflater; import android.view.View; import android.view.MenuItem; import android.widget.AdapterView; -import android.widget.ListAdapter; -import android.widget.ListView; import android.net.Uri; import android.view.ViewGroup; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.ArtistAdapter; +import github.daneren2005.dsub.adapter.EntryGridAdapter; +import github.daneren2005.dsub.adapter.SearchAdapter; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.Artist; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.SearchCritera; @@ -26,40 +32,24 @@ import github.daneren2005.dsub.domain.SearchResult; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.MusicServiceFactory; import github.daneren2005.dsub.service.DownloadService; -import github.daneren2005.dsub.adapter.ArtistAdapter; import github.daneren2005.dsub.util.BackgroundTask; import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.adapter.EntryAdapter; -import github.daneren2005.dsub.adapter.MergeAdapter; import github.daneren2005.dsub.util.TabBackgroundTask; import github.daneren2005.dsub.util.Util; +import github.daneren2005.dsub.view.UpdateView; -public class SearchFragment extends SubsonicFragment { +public class SearchFragment extends SubsonicFragment implements SectionAdapter.OnItemClickedListener<Serializable> { private static final String TAG = SearchFragment.class.getSimpleName(); - private static final int DEFAULT_ARTISTS = 3; - private static final int DEFAULT_ALBUMS = 5; - private static final int DEFAULT_SONGS = 10; - private static final int MAX_ARTISTS = 10; - private static final int MAX_ALBUMS = 20; + private static final int MAX_ALBUMS = 10; private static final int MAX_SONGS = 25; - private ListView list; - - private View artistsHeading; - private View albumsHeading; - private View songsHeading; - private View moreArtistsButton; - private View moreAlbumsButton; - private View moreSongsButton; + + protected RecyclerView recyclerView; + protected SearchAdapter adapter; + protected boolean largeAlbums = false; + private SearchResult searchResult; - private MergeAdapter mergeAdapter; - private ArtistAdapter artistAdapter; - private ListAdapter moreArtistsAdapter; - private EntryAdapter albumAdapter; - private ListAdapter moreAlbumsAdapter; - private ListAdapter moreSongsAdapter; - private EntryAdapter songAdapter; private boolean skipSearch = false; private String currentQuery; @@ -70,6 +60,7 @@ public class SearchFragment extends SubsonicFragment { if(savedInstanceState != null) { searchResult = (SearchResult) savedInstanceState.getSerializable(Constants.FRAGMENT_LIST); } + largeAlbums = Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_LARGE_ALBUM_ART, true); } @Override @@ -80,63 +71,42 @@ public class SearchFragment extends SubsonicFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false); + rootView = inflater.inflate(R.layout.abstract_recycler_fragment, container, false); setTitle(R.string.search_title); - View buttons = inflater.inflate(R.layout.search_buttons, null); - - artistsHeading = buttons.findViewById(R.id.search_artists); - albumsHeading = buttons.findViewById(R.id.search_albums); - songsHeading = buttons.findViewById(R.id.search_songs); - - moreArtistsButton = buttons.findViewById(R.id.search_more_artists); - moreAlbumsButton = buttons.findViewById(R.id.search_more_albums); - moreSongsButton = buttons.findViewById(R.id.search_more_songs); - refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); refreshLayout.setEnabled(false); - list = (ListView) rootView.findViewById(R.id.fragment_list); + recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_recycler); + setupLayoutManager(recyclerView, largeAlbums); - list.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - if (view == moreArtistsButton) { - expandArtists(); - } else if (view == moreAlbumsButton) { - expandAlbums(); - } else if (view == moreSongsButton) { - expandSongs(); - } else { - Object item = parent.getItemAtPosition(position); - if (item instanceof Artist) { - onArtistSelected((Artist) item, false); - } else if (item instanceof MusicDirectory.Entry) { - MusicDirectory.Entry entry = (MusicDirectory.Entry) item; - if (entry.isDirectory()) { - onAlbumSelected(entry, false); - } else if (entry.isVideo()) { - onVideoSelected(entry); - } else { - onSongSelected(entry, false, true, true, false); - } - - } - } - } - }); - registerForContextMenu(list); + registerForContextMenu(recyclerView); context.onNewIntent(context.getIntent()); if(searchResult != null) { skipSearch = true; - populateList(); + recyclerView.setAdapter(adapter = new SearchAdapter(context, searchResult, getImageLoader(), largeAlbums, this)); } return rootView; } @Override + public GridLayoutManager.SpanSizeLookup getSpanSizeLookup(final int columns) { + return new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + int viewType = adapter.getItemViewType(position); + if(viewType == EntryGridAdapter.VIEW_TYPE_SONG || viewType == EntryGridAdapter.VIEW_TYPE_HEADER || viewType == ArtistAdapter.VIEW_TYPE_ARTIST) { + return columns; + } else { + return 1; + } + } + }; + } + + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { menuInflater.inflate(R.menu.search, menu); } @@ -154,43 +124,52 @@ public class SearchFragment extends SubsonicFragment { } @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Object selectedItem = list.getItemAtPosition(info.position); - onCreateContextMenu(menu, view, menuInfo, selectedItem); - if(selectedItem instanceof MusicDirectory.Entry && !((MusicDirectory.Entry) selectedItem).isVideo() && !Util.isOffline(context)) { + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Serializable> updateView, Serializable item) { + onCreateContextMenuSupport(menu, menuInflater, updateView, item); + if(item instanceof MusicDirectory.Entry && !((MusicDirectory.Entry) item).isVideo() && !Util.isOffline(context)) { menu.removeItem(R.id.song_menu_remove_playlist); } - recreateContextMenu(menu); } @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Object selectedItem = list.getItemAtPosition(info.position); - - if(onContextItemSelected(menuItem, selectedItem)) { - return true; - } + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Serializable> updateView, Serializable item) { + return onContextItemSelected(menuItem, item); + } - return true; + @Override + public void refresh(boolean refresh) { + context.onNewIntent(context.getIntent()); } - + @Override - public void setPrimaryFragment(boolean primary) { - super.setPrimaryFragment(primary); + public void onItemClicked(Serializable item) { + Log.d(TAG, item.getClass().getSimpleName()); + if (item instanceof Artist) { + onArtistSelected((Artist) item, false); + } else if (item instanceof MusicDirectory.Entry) { + MusicDirectory.Entry entry = (MusicDirectory.Entry) item; + if (entry.isDirectory()) { + onAlbumSelected(entry, false); + } else if (entry.isVideo()) { + onVideoSelected(entry); + } else { + onSongSelected(entry, false, true, true, false); + } + } } @Override - public void refresh(boolean refresh) { - context.onNewIntent(context.getIntent()); + protected List<MusicDirectory.Entry> getSelectedEntries() { + List<Serializable> selected = adapter.getSelected(); + List<MusicDirectory.Entry> selectedMedia = new ArrayList<>(); + for(Serializable ser: selected) { + if(ser instanceof MusicDirectory.Entry) { + selectedMedia.add((MusicDirectory.Entry) ser); + } + } + + return selectedMedia; } public void search(final String query, final boolean autoplay) { @@ -200,9 +179,6 @@ public class SearchFragment extends SubsonicFragment { } currentQuery = query; - mergeAdapter = new MergeAdapter(); - list.setAdapter(mergeAdapter); - BackgroundTask<SearchResult> task = new TabBackgroundTask<SearchResult>(this) { @Override protected SearchResult doInBackground() throws Throwable { @@ -214,7 +190,7 @@ public class SearchFragment extends SubsonicFragment { @Override protected void done(SearchResult result) { searchResult = result; - populateList(); + recyclerView.setAdapter(adapter = new SearchAdapter(context, searchResult, getImageLoader(), largeAlbums, SearchFragment.this)); if (autoplay) { autoplay(query); } @@ -224,82 +200,6 @@ public class SearchFragment extends SubsonicFragment { task.execute(); } - public void populateList() { - mergeAdapter = new MergeAdapter(); - - if (searchResult != null) { - List<Artist> artists = searchResult.getArtists(); - if (!artists.isEmpty()) { - mergeAdapter.addView(artistsHeading); - List<Artist> displayedArtists = new ArrayList<Artist>(artists.subList(0, Math.min(DEFAULT_ARTISTS, artists.size()))); - artistAdapter = new ArtistAdapter(context, displayedArtists); - mergeAdapter.addAdapter(artistAdapter); - if (artists.size() > DEFAULT_ARTISTS) { - moreArtistsAdapter = mergeAdapter.addView(moreArtistsButton, true); - } - } - - List<MusicDirectory.Entry> albums = searchResult.getAlbums(); - if (!albums.isEmpty()) { - mergeAdapter.addView(albumsHeading); - List<MusicDirectory.Entry> displayedAlbums = new ArrayList<MusicDirectory.Entry>(albums.subList(0, Math.min(DEFAULT_ALBUMS, albums.size()))); - albumAdapter = new EntryAdapter(context, getImageLoader(), displayedAlbums, false); - mergeAdapter.addAdapter(albumAdapter); - if (albums.size() > DEFAULT_ALBUMS) { - moreAlbumsAdapter = mergeAdapter.addView(moreAlbumsButton, true); - } - } - - List<MusicDirectory.Entry> songs = searchResult.getSongs(); - if (!songs.isEmpty()) { - mergeAdapter.addView(songsHeading); - List<MusicDirectory.Entry> displayedSongs = new ArrayList<MusicDirectory.Entry>(songs.subList(0, Math.min(DEFAULT_SONGS, songs.size()))); - songAdapter = new EntryAdapter(context, getImageLoader(), displayedSongs, false); - mergeAdapter.addAdapter(songAdapter); - if (songs.size() > DEFAULT_SONGS) { - moreSongsAdapter = mergeAdapter.addView(moreSongsButton, true); - } - } - - boolean empty = searchResult.getArtists().isEmpty() && searchResult.getAlbums().isEmpty() && searchResult.getSongs().isEmpty(); - if(empty) { - setEmpty(true); - } - } - - list.setAdapter(mergeAdapter); - } - - private void expandArtists() { - artistAdapter.clear(); - for (Artist artist : searchResult.getArtists()) { - artistAdapter.add(artist); - } - artistAdapter.notifyDataSetChanged(); - mergeAdapter.removeAdapter(moreArtistsAdapter); - mergeAdapter.notifyDataSetChanged(); - } - - private void expandAlbums() { - albumAdapter.clear(); - for (MusicDirectory.Entry album : searchResult.getAlbums()) { - albumAdapter.add(album); - } - albumAdapter.notifyDataSetChanged(); - mergeAdapter.removeAdapter(moreAlbumsAdapter); - mergeAdapter.notifyDataSetChanged(); - } - - private void expandSongs() { - songAdapter.clear(); - for (MusicDirectory.Entry song : searchResult.getSongs()) { - songAdapter.add(song); - } - songAdapter.notifyDataSetChanged(); - mergeAdapter.removeAdapter(moreSongsAdapter); - mergeAdapter.notifyDataSetChanged(); - } - private void onArtistSelected(Artist artist, boolean autoplay) { SubsonicFragment fragment = new SelectDirectoryFragment(); Bundle args = new Bundle(); diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectArtistFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectArtistFragment.java index 5488c95b..a9d5afd6 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectArtistFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectArtistFragment.java @@ -11,10 +11,11 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.LinearLayout; -import android.widget.TextView; + import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.ArtistAdapter; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.Artist; import github.daneren2005.dsub.domain.Indexes; import github.daneren2005.dsub.domain.MusicDirectory; @@ -23,19 +24,16 @@ import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.ArtistAdapter; +import github.daneren2005.dsub.view.UpdateView; import java.io.Serializable; import java.util.ArrayList; import java.util.List; -public class SelectArtistFragment extends SelectListFragment<Artist> { +public class SelectArtistFragment extends SelectRecyclerFragment<Artist> implements ArtistAdapter.OnMusicFolderChanged { private static final String TAG = SelectArtistFragment.class.getSimpleName(); private static final int MENU_GROUP_MUSIC_FOLDER = 10; - private View folderButtonParent; - private View folderButton; - private TextView folderName; private List<MusicFolder> musicFolders = null; private List<MusicDirectory.Entry> entries; private String groupId; @@ -75,110 +73,44 @@ public class SelectArtistFragment extends SelectListFragment<Artist> { } } - folderButton = null; super.onCreateView(inflater, container, bundle); - - if("4.4.2".equals(Build.VERSION.RELEASE)) { - listView.setFastScrollAlwaysVisible(true); - } - - if(objects != null && currentTask == null) { - if (Util.isOffline(context) || Util.isTagBrowsing(context) || groupId != null) { - folderButton.setVisibility(View.GONE); - } - setMusicFolders(); - } return rootView; } @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Object entry = listView.getItemAtPosition(info.position); - - if (entry instanceof Artist) { - onCreateContextMenu(menu, view, menuInfo, entry); - } else if (info.position == 0) { - String musicFolderId = Util.getSelectedMusicFolderId(context); - MenuItem menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, -1, 0, R.string.select_artist_all_folders); - if (musicFolderId == null) { - menuItem.setChecked(true); - } - if (musicFolders != null) { - for (int i = 0; i < musicFolders.size(); i++) { - MusicFolder musicFolder = musicFolders.get(i); - menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, i, i + 1, musicFolder.getName()); - if (musicFolder.getId().equals(musicFolderId)) { - menuItem.setChecked(true); - } - } - } - menu.setGroupCheckable(MENU_GROUP_MUSIC_FOLDER, true, true); - } - + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Artist> updateView, Artist item) { + onCreateContextMenuSupport(menu, menuInflater, updateView, item); recreateContextMenu(menu); } @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Artist artist = (Artist) listView.getItemAtPosition(info.position); - - if (artist != null) { - return onContextItemSelected(menuItem, artist); - } else if (info.position == 0) { - MusicFolder selectedFolder = menuItem.getItemId() == -1 ? null : musicFolders.get(menuItem.getItemId()); - String musicFolderId = selectedFolder == null ? null : selectedFolder.getId(); - String musicFolderName = selectedFolder == null ? context.getString(R.string.select_artist_all_folders) - : selectedFolder.getName(); - Util.setSelectedMusicFolderId(context, musicFolderId); - folderName.setText(musicFolderName); - context.invalidate(); - } - - return true; + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Artist> updateView, Artist item) { + return onContextItemSelected(menuItem, item); } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - if (view == folderButtonParent) { - selectFolder(); - } else { - Artist artist = (Artist) parent.getItemAtPosition(position); - - SubsonicFragment fragment; - if((Util.isFirstLevelArtist(context) || Util.isOffline(context) || Util.isTagBrowsing(context)) || "root".equals(artist.getId()) || groupId != null) { - fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); - if ("root".equals(artist.getId())) { - args.putSerializable(Constants.FRAGMENT_LIST, (Serializable) entries); - } - args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); - fragment.setArguments(args); - } else { - fragment = new SelectArtistFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); - fragment.setArguments(args); + public void onItemClicked(Artist artist) { + SubsonicFragment fragment; + if((Util.isFirstLevelArtist(context) || Util.isOffline(context) || Util.isTagBrowsing(context)) || "root".equals(artist.getId()) || groupId != null) { + fragment = new SelectDirectoryFragment(); + Bundle args = new Bundle(); + args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); + args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); + if ("root".equals(artist.getId())) { + args.putSerializable(Constants.FRAGMENT_LIST, (Serializable) entries); } - - replaceFragment(fragment); + args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); + fragment.setArguments(args); + } else { + fragment = new SelectArtistFragment(); + Bundle args = new Bundle(); + args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); + args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); + fragment.setArguments(args); } - } - @Override - public void onFinishRefresh() { - setMusicFolders(); + replaceFragment(fragment); } @Override @@ -215,9 +147,8 @@ public class SelectArtistFragment extends SelectListFragment<Artist> { } @Override - public ArrayAdapter getAdapter(List<Artist> objects) { - createMusicFolderButton(); - return new ArtistAdapter(context, objects); + public SectionAdapter getAdapter(List<Artist> objects) { + return new ArtistAdapter(context, objects, musicFolders, this, this); } @Override @@ -236,12 +167,12 @@ public class SelectArtistFragment extends SelectListFragment<Artist> { String musicFolderId = Util.getSelectedMusicFolderId(context); Indexes indexes = musicService.getIndexes(musicFolderId, refresh, context, listener); - artists = new ArrayList<Artist>(indexes.getShortcuts().size() + indexes.getArtists().size()); + artists = new ArrayList<>(indexes.getShortcuts().size() + indexes.getArtists().size()); artists.addAll(indexes.getShortcuts()); artists.addAll(indexes.getArtists()); entries = indexes.getEntries(); } else { - artists = new ArrayList<Artist>(); + artists = new ArrayList<>(); MusicDirectory dir = musicService.getMusicDirectory(groupId, groupName, refresh, context, listener); for(MusicDirectory.Entry entry: dir.getChildren(true, false)) { Artist artist = new Artist(); @@ -251,7 +182,7 @@ public class SelectArtistFragment extends SelectListFragment<Artist> { artists.add(artist); } - entries = new ArrayList<MusicDirectory.Entry>(); + entries = new ArrayList<>(); entries.addAll(dir.getChildren(false, true)); if(!entries.isEmpty()) { Artist root = new Artist(); @@ -270,32 +201,14 @@ public class SelectArtistFragment extends SelectListFragment<Artist> { return groupId == null ? R.string.button_bar_browse : 0; } - private void createMusicFolderButton() { - if(folderButton == null) { - folderButtonParent = context.getLayoutInflater().inflate(R.layout.select_artist_header, listView, false); - folderName = (TextView) folderButtonParent.findViewById(R.id.select_artist_folder_2); - listView.addHeaderView(folderButtonParent); - folderButton = folderButtonParent.findViewById(R.id.select_artist_folder); - } - - if (Util.isOffline(context) || Util.isTagBrowsing(context) || musicFolders == null) { - folderButton.setVisibility(View.GONE); - } else { - folderButton.setVisibility(View.VISIBLE); - } - } - @Override public void setEmpty(boolean empty) { super.setEmpty(empty); if(empty && !Util.isOffline(context)) { - createMusicFolderButton(); - setMusicFolders(); - objects.clear(); - listView.setAdapter(new ArtistAdapter(context, objects)); - listView.setVisibility(View.VISIBLE); + recyclerView.setAdapter(new ArtistAdapter(context, objects, musicFolders, this, this)); + recyclerView.setVisibility(View.VISIBLE); View view = rootView.findViewById(R.id.tab_progress); LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) view.getLayoutParams(); @@ -305,29 +218,19 @@ public class SelectArtistFragment extends SelectListFragment<Artist> { } } - private void setMusicFolders() { - // Display selected music folder - if (musicFolders != null) { - String musicFolderId = Util.getSelectedMusicFolderId(context); - if (musicFolderId == null) { - folderName.setText(R.string.select_artist_all_folders); - } else { - for (MusicFolder musicFolder : musicFolders) { - if (musicFolder.getId().equals(musicFolderId)) { - folderName.setText(musicFolder.getName()); - break; - } - } - } - } - } - - private void selectFolder() { - folderButton.showContextMenu(); - } - private void toggleFirstLevelArtist() { Util.toggleFirstLevelArtist(context); context.invalidateOptionsMenu(); } + + @Override + public void onMusicFolderChanged(MusicFolder selectedFolder) { + String startMusicFolderId = Util.getSelectedMusicFolderId(context); + String musicFolderId = selectedFolder == null ? null : selectedFolder.getId(); + + if(!Util.equals(startMusicFolderId, musicFolderId)) { + Util.setSelectedMusicFolderId(context, musicFolderId); + context.invalidate(); + } + } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java index c71d99f6..d992319b 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java @@ -19,43 +19,40 @@ package github.daneren2005.dsub.fragments; import android.view.ContextMenu; +import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.DownloadActivity; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.Bookmark; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.service.DownloadService; import github.daneren2005.dsub.service.MusicService; +import github.daneren2005.dsub.util.MenuUtil; import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.adapter.BookmarkAdapter; +import github.daneren2005.dsub.view.UpdateView; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; -public class SelectBookmarkFragment extends SelectListFragment<MusicDirectory.Entry> { +public class SelectBookmarkFragment extends SelectRecyclerFragment<MusicDirectory.Entry> { private static final String TAG = SelectBookmarkFragment.class.getSimpleName(); @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - MenuInflater inflater = context.getMenuInflater(); - inflater.inflate(R.menu.select_bookmark_context, menu); - - hideMenuItems(menu, (AdapterView.AdapterContextMenuInfo) menuInfo); + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<MusicDirectory.Entry> updateView, MusicDirectory.Entry item) { + menuInflater.inflate(R.menu.select_bookmark_context, menu); + MenuUtil.hideMenuItems(context, menu); } @Override - public boolean onContextItemSelected(MenuItem menuItem) { - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - MusicDirectory.Entry bookmark = objects.get(info.position); - + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<MusicDirectory.Entry> updateView, MusicDirectory.Entry bookmark) { switch(menuItem.getItemId()) { case R.id.bookmark_menu_info: displayBookmarkInfo(bookmark); @@ -64,12 +61,8 @@ public class SelectBookmarkFragment extends SelectListFragment<MusicDirectory.En deleteBookmark(bookmark, adapter); return true; } - - if(onContextItemSelected(menuItem, bookmark)) { - return true; - } - return true; + return onContextItemSelected(menuItem, bookmark); } @Override @@ -78,8 +71,8 @@ public class SelectBookmarkFragment extends SelectListFragment<MusicDirectory.En } @Override - public ArrayAdapter getAdapter(List<MusicDirectory.Entry> bookmarks) { - return new BookmarkAdapter(context, bookmarks); + public SectionAdapter getAdapter(List<MusicDirectory.Entry> bookmarks) { + return new BookmarkAdapter(context, bookmarks, this); } @Override @@ -93,13 +86,12 @@ public class SelectBookmarkFragment extends SelectListFragment<MusicDirectory.En } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + public void onItemClicked(final MusicDirectory.Entry bookmark) { final DownloadService downloadService = getDownloadService(); if(downloadService == null) { return; } - final MusicDirectory.Entry bookmark = (MusicDirectory.Entry) parent.getItemAtPosition(position); new SilentBackgroundTask<Void>(context) { @Override protected Void doInBackground() throws Throwable { @@ -110,22 +102,42 @@ public class SelectBookmarkFragment extends SelectListFragment<MusicDirectory.En @Override protected void done(Void result) { - Util.startActivityWithoutTransition(context, DownloadActivity.class); + context.openNowPlaying(); } }.execute(); } - + private void displayBookmarkInfo(final MusicDirectory.Entry entry) { Bookmark bookmark = entry.getBookmark(); - String comment = bookmark.getComment(); - if(comment == null) { - comment = ""; + List<Integer> headers = new ArrayList<>(); + List<String> details = new ArrayList<>(); + + headers.add(R.string.details_song); + details.add(entry.getTitle()); + + if(entry.getArtist() != null) { + headers.add(R.string.details_artist); + details.add(entry.getArtist()); + } + if(entry.getAlbum() != null) { + headers.add(R.string.details_album); + details.add(entry.getAlbum()); + } + + headers.add(R.string.details_position); + details.add(Util.formatDuration(bookmark.getPosition() / 1000)); + + headers.add(R.string.details_created); + details.add(Util.formatDate(bookmark.getCreated())); + + headers.add(R.string.details_updated); + details.add(Util.formatDate(bookmark.getChanged())); + + if(bookmark.getComment() != null) { + headers.add(R.string.details_comments); + details.add(bookmark.getComment()); } - String msg = context.getResources().getString(R.string.bookmark_details, - entry.getTitle(), Util.formatDuration(bookmark.getPosition() / 1000), - Util.formatDate(bookmark.getCreated()), Util.formatDate(bookmark.getChanged()), comment); - - Util.info(context, R.string.bookmark_details_title, msg, false); + Util.showDetailsDialog(context, R.string.bookmark_details_title, headers, details); } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java index 841a6369..6fbf49bc 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java @@ -1,7 +1,7 @@ package github.daneren2005.dsub.fragments; import android.annotation.TargetApi; -import android.app.AlertDialog; +import android.support.v7.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; @@ -9,12 +9,14 @@ import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.text.Html; import android.text.SpannableString; import android.text.Spanned; import android.text.method.LinkMovementMethod; import android.util.Log; -import android.view.ContextMenu; import android.view.Display; import android.view.LayoutInflater; import android.view.Menu; @@ -22,31 +24,29 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.BaseAdapter; -import android.widget.GridView; import android.widget.ImageButton; import android.widget.ImageView; -import android.widget.ListAdapter; -import android.widget.ListView; import android.widget.RatingBar; import android.widget.RelativeLayout; import android.widget.TextView; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.AlphabeticalAlbumAdapter; +import github.daneren2005.dsub.adapter.EntryInfiniteGridAdapter; +import github.daneren2005.dsub.adapter.EntryGridAdapter; +import github.daneren2005.dsub.adapter.SectionAdapter; +import github.daneren2005.dsub.adapter.TopRatedAlbumAdapter; import github.daneren2005.dsub.domain.ArtistInfo; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.ServerInfo; import github.daneren2005.dsub.domain.Share; import github.daneren2005.dsub.service.DownloadService; +import github.daneren2005.dsub.util.DrawableTint; import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.adapter.AlbumGridAdapter; -import github.daneren2005.dsub.adapter.EntryAdapter; import java.io.Serializable; import java.util.Iterator; import java.util.List; -import github.daneren2005.dsub.activity.DownloadActivity; import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.MusicServiceFactory; @@ -59,9 +59,10 @@ import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.TabBackgroundTask; import github.daneren2005.dsub.util.UserUtil; import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.AlbumListAdapter; -import github.daneren2005.dsub.view.HeaderGridView; +import github.daneren2005.dsub.view.FastScroller; +import github.daneren2005.dsub.view.GridSpacingDecoration; import github.daneren2005.dsub.view.MyLeadingMarginSpan2; +import github.daneren2005.dsub.view.UpdateView; import java.util.ArrayList; import java.util.Arrays; @@ -70,17 +71,15 @@ import java.util.Set; import static github.daneren2005.dsub.domain.MusicDirectory.Entry; -public class SelectDirectoryFragment extends SubsonicFragment implements AdapterView.OnItemClickListener { +public class SelectDirectoryFragment extends SubsonicFragment implements SectionAdapter.OnItemClickedListener<Entry> { private static final String TAG = SelectDirectoryFragment.class.getSimpleName(); - private GridView albumList; - private ListView entryList; + private RecyclerView recyclerView; + private FastScroller fastScroller; + private EntryGridAdapter entryGridAdapter; private Boolean licenseValid; - private EntryAdapter entryAdapter; private List<Entry> albums; private List<Entry> entries; - private boolean albumContext = false; - private boolean addAlbumHeader = false; private LoadTask currentTask; private ArtistInfo artistInfo; private String artistInfoDelayed; @@ -114,12 +113,11 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter super.onCreate(bundle); if(bundle != null) { entries = (List<Entry>) bundle.getSerializable(Constants.FRAGMENT_LIST); - albums = (List<Entry>) bundle.getSerializable(Constants.FRAGMENT_LIST2); artistInfo = (ArtistInfo) bundle.getSerializable(Constants.FRAGMENT_EXTRA); restoredInstance = true; } } - + @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); @@ -167,33 +165,41 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter } } - rootView = inflater.inflate(R.layout.select_album, container, false); + rootView = inflater.inflate(R.layout.abstract_recycler_fragment, container, false); refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); refreshLayout.setOnRefreshListener(this); - entryList = (ListView) rootView.findViewById(R.id.select_album_entries); - entryList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); - entryList.setOnItemClickListener(this); - setupScrollList(entryList); - if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_LARGE_ALBUM_ART, true)) { largeAlbums = true; } - if(albumListType == null || "starred".equals(albumListType) || !largeAlbums) { - albumList = (GridView) inflater.inflate(R.layout.unscrollable_grid_view, entryList, false); - addAlbumHeader = true; - } else { - ViewGroup rootGroup = (ViewGroup) rootView.findViewById(R.id.select_album_layout); - albumList = (GridView) inflater.inflate(R.layout.grid_view, rootGroup, false); - rootGroup.removeView(entryList); - rootGroup.addView(albumList); + recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_recycler); + recyclerView.setHasFixedSize(true); + fastScroller = (FastScroller) rootView.findViewById(R.id.fragment_fast_scroller); + setupScrollList(recyclerView); - setupScrollList(albumList); + if(largeAlbums) { + final int columns = context.getResources().getInteger(R.integer.Grid_Columns); + GridLayoutManager gridLayoutManager = new GridLayoutManager(context, columns); + gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + int viewType = entryGridAdapter.getItemViewType(position); + if(viewType == EntryGridAdapter.VIEW_TYPE_SONG || viewType == EntryGridAdapter.VIEW_TYPE_HEADER || viewType == EntryInfiniteGridAdapter.VIEW_TYPE_LOADING) { + return columns; + } else { + return 1; + } + } + }); + recyclerView.addItemDecoration(new GridSpacingDecoration()); + recyclerView.setLayoutManager(gridLayoutManager); + } else { + LinearLayoutManager layoutManager = new LinearLayoutManager(context); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + recyclerView.setLayoutManager(layoutManager); } - registerForContextMenu(entryList); - setupAlbumList(); if(entries == null) { if(primaryFragment || secondaryFragment) { @@ -257,7 +263,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter } else { menuInflater.inflate(R.menu.select_podcast_episode, menu); - + if(!UserUtil.canPodcast()) { menu.removeItem(R.id.menu_download_all); } @@ -273,36 +279,6 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.menu_play_now: - playNow(false, false); - return true; - case R.id.menu_play_last: - playNow(false, true); - return true; - case R.id.menu_play_next: - playNow(false, true, true); - return true; - case R.id.menu_shuffle: - playNow(true, false); - return true; - case R.id.menu_download: - downloadBackground(false); - selectAll(false, false); - return true; - case R.id.menu_cache: - downloadBackground(true); - selectAll(false, false); - return true; - case R.id.menu_delete: - delete(); - selectAll(false, false); - return true; - case R.id.menu_add_playlist: - if(getSelectedSongs().isEmpty()) { - selectAll(true, false); - } - addToPlaylist(getSelectedSongs()); - return true; case R.id.menu_remove_playlist: removeFromPlaylist(playlistId, playlistName, getSelectedIndexes()); return true; @@ -331,32 +307,8 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter } @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - - Entry entry; - if(view.getId() == R.id.select_album_entries) { - if(info.position == 0) { - return; - } - entry = (Entry) entryList.getItemAtPosition(info.position); - // When List has Grid embedded in header, this is called against the header as well - if(entry != null) { - albumContext = false; - } - } else { - entry = (Entry) albumList.getItemAtPosition(info.position); - albumContext = true; - } - - // Don't try to display a context menu if error here - if(entry == null) { - return; - } - - onCreateContextMenu(menu, view, menuInfo, entry); + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView updateView, Entry entry) { + onCreateContextMenuSupport(menu, menuInflater, updateView, entry); if(!entry.isVideo() && !Util.isOffline(context) && (playlistId == null || !playlistOwner) && (podcastId == null || Util.isOffline(context) && podcastId != null)) { menu.removeItem(R.id.song_menu_remove_playlist); } @@ -378,88 +330,70 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter recreateContextMenu(menu); } - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Object selectedItem; - int headers = entryList.getHeaderViewsCount(); - if(albumContext) { - selectedItem = albumList.getItemAtPosition(info.position); - } else { - if(info.position == 0) { - return false; - } - selectedItem = entries.get(info.position - headers); - } - - if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_PLAY_NOW_AFTER, false) && menuItem.getItemId() == R.id.song_menu_play_now) { - List<Entry> songs = new ArrayList<Entry>(); - Iterator it = entries.listIterator(info.position - headers); - while(it.hasNext()) { - songs.add((Entry) it.next()); - } - - playNow(songs); - return true; - } - - if(onContextItemSelected(menuItem, selectedItem)) { + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Entry> updateView, Entry entry) { + if(onContextItemSelected(menuItem, entry)) { return true; } switch (menuItem.getItemId()) { case R.id.song_menu_remove_playlist: - removeFromPlaylist(playlistId, playlistName, Arrays.<Integer>asList(info.position - headers)); + removeFromPlaylist(playlistId, playlistName, Arrays.<Integer>asList(entries.indexOf(entry))); break; case R.id.song_menu_server_download: - downloadPodcastEpisode((PodcastEpisode)selectedItem); + downloadPodcastEpisode((PodcastEpisode) entry); break; case R.id.song_menu_server_delete: - deletePodcastEpisode((PodcastEpisode)selectedItem); + deletePodcastEpisode((PodcastEpisode) entry); break; } - + return true; } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - if (position >= 0) { - Entry entry = (Entry) parent.getItemAtPosition(position); - if (entry.isDirectory()) { - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getTitle()); - args.putSerializable(Constants.INTENT_EXTRA_NAME_DIRECTORY, entry); - if ("newest".equals(albumListType)) { - args.putBoolean(Constants.INTENT_EXTRA_REFRESH_LISTINGS, true); - } - if(entry.getArtist() == null && entry.getParent() == null) { - args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); - } - fragment.setArguments(args); + public void onItemClicked(Entry entry) { + if (entry.isDirectory()) { + SubsonicFragment fragment = new SelectDirectoryFragment(); + Bundle args = new Bundle(); + args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getId()); + args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getTitle()); + args.putSerializable(Constants.INTENT_EXTRA_NAME_DIRECTORY, entry); + if ("newest".equals(albumListType)) { + args.putBoolean(Constants.INTENT_EXTRA_REFRESH_LISTINGS, true); + } + if(!entry.isAlbum()) { + args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); + } + fragment.setArguments(args); + + replaceFragment(fragment, true); + } else if (entry.isVideo()) { + playVideo(entry); + } else if(entry instanceof PodcastEpisode) { + String status = ((PodcastEpisode)entry).getStatus(); + if("error".equals(status)) { + Util.toast(context, R.string.select_podcasts_error); + return; + } else if(!"completed".equals(status)) { + Util.toast(context, R.string.select_podcasts_skipped); + return; + } - replaceFragment(fragment, true); - } else if (entry.isVideo()) { - playVideo(entry); - } else if(entry instanceof PodcastEpisode) { - String status = ((PodcastEpisode)entry).getStatus(); - if("error".equals(status)) { - Util.toast(context, R.string.select_podcasts_error); - return; - } else if(!"completed".equals(status)) { - Util.toast(context, R.string.select_podcasts_skipped); - return; + playNow(Arrays.asList(entry)); + } else { + List<Entry> songs = new ArrayList<Entry>(); + + if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_PLAY_NOW_AFTER, true)) { + Iterator it = entries.listIterator(entries.indexOf(entry)); + while(it.hasNext()) { + songs.add((Entry) it.next()); } - - playNow(Arrays.asList(entry)); + } else { + songs.add(entry); } + + playNow(songs); } } @@ -474,12 +408,12 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter if(refreshListing) { refresh = true; } - + if(currentTask != null) { currentTask.cancel(); } - - entryList.setVisibility(View.INVISIBLE); + + recyclerView.setVisibility(View.INVISIBLE); if (playlistId != null) { getPlaylist(playlistId, playlistName, refresh); } else if(podcastId != null) { @@ -491,7 +425,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter getShare(share, refresh); } } else if (albumListType != null) { - getAlbumList(albumListType, albumListSize); + getAlbumList(albumListType, albumListSize, refresh); } else { if(showAll) { getRecursiveMusicDirectory(id, name, refresh); @@ -530,7 +464,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter return dir; } - + @Override protected void done(Pair<MusicDirectory, Boolean> result) { SelectDirectoryFragment.this.name = result.getFirst().getName(); @@ -539,7 +473,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter } }.execute(); } - + private void getRecursiveMusicDirectory(final String id, final String name, final boolean refresh) { setTitle(name); @@ -557,7 +491,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter root.replaceChildren(songs); return root; } - + private void getSongsRecursively(MusicDirectory parent, List<Entry> songs) throws Exception { songs.addAll(parent.getChildren(false, true)); for (Entry dir : parent.getChildren(true, false)) { @@ -572,7 +506,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter getSongsRecursively(musicDirectory, songs); } } - + @Override protected void done(Pair<MusicDirectory, Boolean> result) { SelectDirectoryFragment.this.name = result.getFirst().getName(); @@ -592,7 +526,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter } }.execute(); } - + private void getPodcast(final String podcastId, final String podcastName, final boolean refresh) { setTitle(podcastName); @@ -626,7 +560,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter }.execute(); } - private void getAlbumList(final String albumListType, final int size) { + private void getAlbumList(final String albumListType, final int size, final boolean refresh) { if ("newest".equals(albumListType)) { setTitle(R.string.main_albums_newest); } else if ("random".equals(albumListType)) { @@ -652,7 +586,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter if ("starred".equals(albumListType)) { result = service.getStarredList(context, this); } else if(("genres".equals(albumListType) && ServerInfo.checkServerVersion(context, "1.10.0")) || "years".equals(albumListType)) { - result = service.getAlbumList(albumListType, albumListExtra, size, 0, context, this); + result = service.getAlbumList(albumListType, albumListExtra, size, 0, refresh, context, this); if(result.getChildrenSize() == 0 && "genres".equals(albumListType)) { SelectDirectoryFragment.this.albumListType = "genres-songs"; result = service.getSongsByGenre(albumListExtra, size, 0, context, this); @@ -660,7 +594,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter } else if("genres".equals(albumListType) || "genres-songs".equals(albumListType)) { result = service.getSongsByGenre(albumListExtra, size, 0, context, this); } else { - result = service.getAlbumList(albumListType, size, 0, context, this); + result = service.getAlbumList(albumListType, size, 0, refresh, context, this); } return result; } @@ -673,7 +607,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter public LoadTask(boolean refresh) { super(SelectDirectoryFragment.this); this.refresh = refresh; - + currentTask = this; } @@ -684,13 +618,9 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter MusicService musicService = MusicServiceFactory.getMusicService(context); MusicDirectory dir = load(musicService); licenseValid = musicService.isLicenseValid(context, this); - + albums = dir.getChildren(true, false); - if(largeAlbums) { - entries = dir.getChildren(false, true); - } else { - entries = dir.getChildren(); - } + entries = dir.getChildren(); // This isn't really an artist if no albums on it! if(albums.size() == 0) { @@ -716,7 +646,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter Log.w(TAG, "Failed to get Artist Info even though it should be supported"); } } - + return new Pair<MusicDirectory, Boolean>(dir, licenseValid); } @@ -727,121 +657,132 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter } } + @Override + protected SectionAdapter<Entry> getCurrentAdapter() { + return entryGridAdapter; + } + private void finishLoading() { - // Show header if not album list type and not root and not artist - // For Subsonic 5.1+ display a header for artists with getArtistInfo data if it exists - View header = null; - if(albumListType == null && !"root".equals(id) && (!artist || artistInfo != null || artistInfoDelayed != null)) { - header = createHeader(); + boolean validData = !entries.isEmpty() || !albums.isEmpty(); + if(!validData) { + setEmpty(true); + } - if(header != null && artistInfoDelayed != null) { - final View finalHeader = header.findViewById(R.id.select_album_header); - final View headerProgress = header.findViewById(R.id.header_progress); + if(validData) { + recyclerView.setVisibility(View.VISIBLE); + } - finalHeader.setVisibility(View.INVISIBLE); - headerProgress.setVisibility(View.VISIBLE); + if(albumListType == null || "starred".equals(albumListType)) { + entryGridAdapter = new EntryGridAdapter(context, entries, getImageLoader(), largeAlbums); + entryGridAdapter.setRemoveFromPlaylist(playlistId != null); + } else { + if("alphabeticalByName".equals(albumListType)) { + entryGridAdapter = new AlphabeticalAlbumAdapter(context, entries, getImageLoader(), largeAlbums); + } else if("highest".equals(albumListType)) { + entryGridAdapter = new TopRatedAlbumAdapter(context, entries, getImageLoader(), largeAlbums); + } else { + entryGridAdapter = new EntryInfiniteGridAdapter(context, entries, getImageLoader(), largeAlbums); + } - new SilentBackgroundTask<Void>(context) { - @Override - protected Void doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - artistInfo = musicService.getArtistInfo(artistInfoDelayed, false, true, context, this); + // Setup infinite loading based on scrolling + final EntryInfiniteGridAdapter infiniteGridAdapter = (EntryInfiniteGridAdapter) entryGridAdapter; + infiniteGridAdapter.setData(albumListType, albumListExtra, albumListSize); - return null; - } + recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + } - @Override - protected void done(Void result) { - /*if(albumList instanceof HeaderGridView) { - HeaderGridView headerGridView = (HeaderGridView) albumList; - headerGridView.invalidateRowHeight(); - ((BaseAdapter) headerGridView.getAdapter()).notifyDataSetChanged(); - }*/ - - setupCoverArt(finalHeader); - setupTextDisplay(finalHeader); - setupButtonEvents(finalHeader); - - finalHeader.setVisibility(View.VISIBLE); - headerProgress.setVisibility(View.GONE); + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + super.onScrolled(recyclerView, dx, dy); + + RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager(); + int totalItemCount = layoutManager.getItemCount(); + int lastVisibleItem; + if(layoutManager instanceof GridLayoutManager) { + lastVisibleItem = ((GridLayoutManager) layoutManager).findLastVisibleItemPosition(); + } else if(layoutManager instanceof LinearLayoutManager) { + lastVisibleItem = ((LinearLayoutManager) layoutManager).findLastVisibleItemPosition(); + } else { + return; } - }.execute(); - } - // Only add header to entry list if we aren't going recreate album grid as root anyways - if(header != null && entryList != null && (!addAlbumHeader || entries.size() > 0)) { - entryList.addHeaderView(header, null, false); - header = null; - } - } - - // Needs to be added here, GB crashes if you to try to remove the header view before adapter is set - if(addAlbumHeader) { - if(entries.size() > 0 || playlistId != null || podcastId != null) { - entryList.addHeaderView(albumList); - } else { - ViewGroup rootGroup = (ViewGroup) rootView.findViewById(R.id.select_album_layout); - albumList = (GridView) context.getLayoutInflater().inflate(R.layout.grid_view, rootGroup, false); - rootGroup.removeView(entryList); - rootGroup.addView(albumList); - - setupScrollList(albumList); - setupAlbumList(); - - // This should only not be null for a artist with only albums - if(header != null) { - HeaderGridView headerGridView = (HeaderGridView) albumList; - headerGridView.addHeaderView(header); + if(totalItemCount > 0 && lastVisibleItem >= totalItemCount - 2) { + infiniteGridAdapter.loadMore(); + } } - } - addAlbumHeader = false; + }); } - - boolean validData = !entries.isEmpty() || !albums.isEmpty(); - if(!validData) { - setEmpty(true); + entryGridAdapter.setOnItemClickedListener(this); + // Always show artist if this is not a artist we are viewing + if(!artist) { + entryGridAdapter.setShowArtist(true); } - // Always going to have entries in entryAdapter - entryAdapter = new EntryAdapter(context, getImageLoader(), entries, (podcastId == null)); - ListAdapter listAdapter = entryAdapter; - // Song-only genre needs to always be entry list + infinite adapter - if("genres-songs".equals(albumListType)) { - ViewGroup rootGroup = (ViewGroup) rootView.findViewById(R.id.select_album_layout); - if(rootGroup.findViewById(R.id.gridview) != null && largeAlbums) { - rootGroup.removeView(albumList); - rootGroup.addView(entryList); - } - listAdapter = new AlbumListAdapter(context, entryAdapter, albumListType, albumListExtra, albumListSize); - } else if(albumListType == null || "starred".equals(albumListType)) { - // Only set standard album adapter if not album list and largeAlbums is true - if(largeAlbums) { - albumList.setAdapter(new AlbumGridAdapter(context, getImageLoader(), albums, !artist)); - } - } else { - // If album list, use infinite adapters for either depending on whether or not largeAlbums is true - if(largeAlbums) { - albumList.setAdapter(new AlbumListAdapter(context, new AlbumGridAdapter(context, getImageLoader(), albums, true), albumListType, albumListExtra, albumListSize)); - } else { - listAdapter = new AlbumListAdapter(context, entryAdapter, albumListType, albumListExtra, albumListSize); + // Show header if not album list type and not root and not artist + // For Subsonic 5.1+ display a header for artists with getArtistInfo data if it exists + boolean addedHeader = false; + if(albumListType == null && !"root".equals(id) && (!artist || artistInfo != null || artistInfoDelayed != null) && (share == null || entries.size() != albums.size())) { + View header = createHeader(); + + if(header != null) { + if (artistInfoDelayed != null) { + final View finalHeader = header.findViewById(R.id.select_album_header); + final View headerProgress = header.findViewById(R.id.header_progress); + + finalHeader.setVisibility(View.INVISIBLE); + headerProgress.setVisibility(View.VISIBLE); + + new SilentBackgroundTask<Void>(context) { + @Override + protected Void doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(context); + artistInfo = musicService.getArtistInfo(artistInfoDelayed, false, true, context, this); + + return null; + } + + @Override + protected void done(Void result) { + setupCoverArt(finalHeader); + setupTextDisplay(finalHeader); + setupButtonEvents(finalHeader); + + finalHeader.setVisibility(View.VISIBLE); + headerProgress.setVisibility(View.GONE); + } + }.execute(); + } + + entryGridAdapter.setHeader(header); + addedHeader = true; } } - entryList.setAdapter(listAdapter); - if(validData) { - entryList.setVisibility(View.VISIBLE); - } - context.supportInvalidateOptionsMenu(); + int scrollToPosition = -1; if(lookupEntry != null) { for(int i = 0; i < entries.size(); i++) { if(lookupEntry.equals(entries.get(i).getTitle())) { - entryList.setSelection(i + entryList.getHeaderViewsCount()); + scrollToPosition = i; + entryGridAdapter.addSelected(entries.get(i)); lookupEntry = null; break; } } } + recyclerView.setAdapter(entryGridAdapter); + if(entryGridAdapter instanceof FastScroller.BubbleTextGetter) { + fastScroller.attachRecyclerView(recyclerView); + } + context.supportInvalidateOptionsMenu(); + + if(scrollToPosition != -1) { + recyclerView.scrollToPosition(scrollToPosition + (addedHeader ? 1 : 0)); + } + Bundle args = getArguments(); boolean playAll = args.getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false); if (playAll && !restoredInstance) { @@ -849,169 +790,52 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter } } - private void setupAlbumList() { - albumList.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - Entry entry = (Entry) parent.getItemAtPosition(position); - SubsonicFragment fragment = new SelectDirectoryFragment(); - Bundle args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getTitle()); - args.putSerializable(Constants.INTENT_EXTRA_NAME_DIRECTORY, entry); - if ("newest".equals(albumListType)) { - args.putBoolean(Constants.INTENT_EXTRA_REFRESH_LISTINGS, true); - } - if(entry.getArtist() == null && entry.getParent() == null) { - args.putBoolean(Constants.INTENT_EXTRA_NAME_ARTIST, true); - } - fragment.setArguments(args); - - replaceFragment(fragment, true); - } - }); - - registerForContextMenu(entryList); - registerForContextMenu(albumList); - } - - private void playNow(final boolean shuffle, final boolean append) { - playNow(shuffle, append, false); - } - private void playNow(final boolean shuffle, final boolean append, final boolean playNext) { - if(getSelectedSongs().size() > 0) { - download(append, false, !append, playNext, shuffle); - selectAll(false, false); + @Override + protected void playNow(final boolean shuffle, final boolean append, final boolean playNext) { + List<Entry> songs = getSelectedEntries(); + if(!songs.isEmpty()) { + download(songs, append, false, !append, playNext, shuffle); + entryGridAdapter.clearSelected(); } else { playAll(shuffle, append); } } private void playAll(final boolean shuffle, final boolean append) { - boolean hasSubFolders = false; - for (int i = 0; i < entryList.getCount(); i++) { - Entry entry = (Entry) entryList.getItemAtPosition(i); - if (entry != null && entry.isDirectory()) { - hasSubFolders = true; - break; - } - } - if(albums.size() > 0) { - hasSubFolders = true; - } + boolean hasSubFolders = !albums.isEmpty(); if (hasSubFolders && (id != null || share != null || "starred".equals(albumListType))) { downloadRecursively(id, false, append, !append, shuffle, false); } else if(hasSubFolders && albumListType != null) { downloadRecursively(albums, shuffle, append); } else { - selectAll(true, false); - download(append, false, !append, false, shuffle); - selectAll(false, false); + download(entries, append, false, !append, false, shuffle); } } - private void selectAll(boolean selected, boolean toast) { - int count = entryList.getCount(); - int selectedCount = 0; - for (int i = 0; i < count; i++) { - Entry entry = (Entry) entryList.getItemAtPosition(i); - if (entry != null && !entry.isDirectory() && !entry.isVideo()) { - entryList.setItemChecked(i, selected); - selectedCount++; - } - } - - // Display toast: N tracks selected / N tracks unselected - if (toast) { - int toastResId = selected ? R.string.select_album_n_selected - : R.string.select_album_n_unselected; - Util.toast(context, context.getString(toastResId, selectedCount)); - } - } - - private List<Entry> getSelectedSongs() { - List<Entry> songs = new ArrayList<Entry>(10); - int count = entryList.getCount(); - for (int i = 0; i < count; i++) { - if (entryList.isItemChecked(i)) { - Entry entry = (Entry) entryList.getItemAtPosition(i); - // Don't try to add directories or 1-starred songs - if(!entry.isDirectory() && entry.getRating() != 1) { - songs.add(entry); - } - } - } - return songs; - } - private List<Integer> getSelectedIndexes() { + List<Entry> selected = entryGridAdapter.getSelected(); List<Integer> indexes = new ArrayList<Integer>(); - int count = entryList.getCount(); - int headers = entryList.getHeaderViewsCount(); - for (int i = 0; i < count; i++) { - if (entryList.isItemChecked(i)) { - indexes.add(i - headers); - } + for(Entry entry: selected) { + indexes.add(entries.indexOf(entry)); } return indexes; } - private void download(final boolean append, final boolean save, final boolean autoplay, final boolean playNext, final boolean shuffle) { - if (getDownloadService() == null) { - return; - } - - final List<Entry> songs = getSelectedSongs(); - warnIfStorageUnavailable(); - - // Conditions for using play now button - if(!append && !save && autoplay && !playNext && !shuffle) { - // Call playNow which goes through and tries to use bookmark information - playNow(songs, playlistName, playlistId); - return; - } - - LoadingTask<Void> onValid = new LoadingTask<Void>(context) { - @Override - protected Void doInBackground() throws Throwable { - if (!append) { - getDownloadService().clear(); - } - - getDownloadService().download(songs, save, autoplay, playNext, shuffle); - if (playlistName != null) { - getDownloadService().setSuggestedPlaylistName(playlistName, playlistId); - } else { - getDownloadService().setSuggestedPlaylistName(null, null); - } - return null; - } - - @Override - protected void done(Void result) { - if (autoplay) { - Util.startActivityWithoutTransition(context, DownloadActivity.class); - } else if (save) { - Util.toast(context, - context.getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size())); - } else if (append) { - Util.toast(context, - context.getResources().getQuantityString(R.plurals.select_album_n_songs_added, songs.size(), songs.size())); - } - } - }; - + @Override + protected void executeOnValid(RecursiveLoader onValid) { checkLicenseAndTrialPeriod(onValid); } - private void downloadBackground(final boolean save) { + + @Override + protected void downloadBackground(final boolean save) { + List<Entry> songs = getSelectedEntries(); if(playlistId != null) { - selectAll(true, false); + songs = entries; } - List<Entry> songs = getSelectedSongs(); if(songs.isEmpty()) { // Get both songs and albums downloadRecursively(id, save, false, false, false, true); @@ -1019,21 +843,23 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter downloadBackground(save, songs); } } - private void downloadBackground(final boolean save, final List<Entry> songs) { + @Override + protected void downloadBackground(final boolean save, final List<Entry> entries) { if (getDownloadService() == null) { return; } warnIfStorageUnavailable(); - LoadingTask<Void> onValid = new LoadingTask<Void>(context) { + RecursiveLoader onValid = new RecursiveLoader(context) { @Override - protected Void doInBackground() throws Throwable { + protected Boolean doInBackground() throws Throwable { + getSongsRecursively(entries, songs); getDownloadService().downloadBackground(songs, save); return null; } @Override - protected void done(Void result) { + protected void done(Boolean result) { Util.toast(context, context.getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size())); } }; @@ -1041,15 +867,21 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter checkLicenseAndTrialPeriod(onValid); } - private void delete() { - List<Entry> songs = getSelectedSongs(); - if(songs.isEmpty()) { - selectAll(true, false); - songs = getSelectedSongs(); + @Override + protected void download(List<Entry> entries, boolean append, boolean save, boolean autoplay, boolean playNext, boolean shuffle) { + download(entries, append, save, autoplay, playNext, shuffle, playlistName, playlistId); + } - // Also delete all directories - for(Entry album: albums) { - deleteRecursively(album); + @Override + protected void delete() { + List<Entry> songs = getSelectedEntries(); + if(songs.isEmpty()) { + for(Entry entry: entries) { + if(entry.isDirectory()) { + deleteRecursively(entry); + } else { + songs.add(entry); + } } } if (getDownloadService() != null) { @@ -1068,11 +900,9 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter @Override protected void done(Void result) { - for(int i = indexes.size() - 1; i >= 0; i--) { - entryList.setItemChecked(indexes.get(i) + 1, false); - entryAdapter.removeAt(indexes.get(i)); + for(Integer index: indexes) { + entryGridAdapter.removeAt(index); } - entryAdapter.notifyDataSetChanged(); Util.toast(context, context.getResources().getString(R.string.removed_playlist, indexes.size(), name)); } @@ -1144,7 +974,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter public void onClick(DialogInterface dialog, int which) { new LoadingTask<Void>(context, true) { @Override - protected Void doInBackground() throws Throwable { + protected Void doInBackground() throws Throwable { MusicService musicService = MusicServiceFactory.getMusicService(context); musicService.deletePodcastEpisode(episode.getEpisodeId(), episode.getParent(), null, context); if (getDownloadService() != null) { @@ -1157,8 +987,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter @Override protected void done(Void result) { - entries.remove(episode); - entryAdapter.notifyDataSetChanged(); + entryGridAdapter.removeItem(episode); } @Override @@ -1172,7 +1001,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter } public void unstarSelected() { - List<Entry> selected = getSelectedSongs(); + List<Entry> selected = getSelectedEntries(); if(selected.size() == 0) { selected = entries; } @@ -1219,10 +1048,8 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter Util.toast(context, context.getResources().getString(R.string.starring_content_unstarred, Integer.toString(unstar.size()))); for(Entry entry: unstar) { - entries.remove(entry); + entryGridAdapter.removeItem(entry); } - entryAdapter.notifyDataSetChanged(); - selectAll(false, false); } @Override @@ -1335,31 +1162,19 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter @Override protected void done(Void result) { - Util.startActivityWithoutTransition(context, DownloadActivity.class); + context.openNowPlaying(); } }.execute(); } private View createHeader() { - View header = entryList.findViewById(R.id.select_album_header_wrapper); - boolean add = false; - if(header == null) { - header = LayoutInflater.from(context).inflate(R.layout.select_album_header, entryList, false); - add = true; - } + View header = LayoutInflater.from(context).inflate(R.layout.select_album_header, null, false); setupCoverArt(header); setupTextDisplay(header); + setupButtonEvents(header); - if(add) { - setupButtonEvents(header); - } - - if(add) { - return header; - } else { - return null; - } + return header; } private void setupCoverArt(View header) { @@ -1508,11 +1323,6 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter } else { artistView.setMaxLines(minLines); } - - if(albumList instanceof HeaderGridView) { - HeaderGridView headerGridView = (HeaderGridView) albumList; - ((BaseAdapter) headerGridView.getAdapter()).notifyDataSetChanged(); - } } }); artistView.setMovementMethod(LinkMovementMethod.getInstance()); @@ -1559,14 +1369,23 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter final ImageButton starButton = (ImageButton) header.findViewById(R.id.select_album_star); if(directory != null && Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_MENU_STAR, true) && artistInfo == null) { - starButton.setImageResource(directory.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off); + if(directory.isStarred()) { + starButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_toggle_star)); + } else { + starButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.star_outline)); + } starButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { toggleStarred(directory, new OnStarChange() { @Override void starChange(boolean starred) { - starButton.setImageResource(directory.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off); + if(directory.isStarred()) { + starButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.star_outline)); + starButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_toggle_star)); + } else { + starButton.setImageResource(DrawableTint.getDrawableRes(context, R.attr.star_outline)); + } } }); } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectGenreFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectGenreFragment.java index 2d310172..cb57c280 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectGenreFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectGenreFragment.java @@ -1,37 +1,39 @@ /* - This file is part of Subsonic. + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. - - Copyright 2010 (C) Sindre Mehus - */ package github.daneren2005.dsub.fragments; import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.Genre; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.adapter.GenreAdapter; +import github.daneren2005.dsub.view.UpdateView; import java.util.List; -public class SelectGenreFragment extends SelectListFragment<Genre> { +public class SelectGenreFragment extends SelectRecyclerFragment<Genre> { private static final String TAG = SelectGenreFragment.class.getSimpleName(); @Override @@ -40,8 +42,8 @@ public class SelectGenreFragment extends SelectListFragment<Genre> { } @Override - public ArrayAdapter getAdapter(List<Genre> objs) { - return new GenreAdapter(context, objs); + public SectionAdapter getAdapter(List<Genre> objs) { + return new GenreAdapter(context, objs, this); } @Override @@ -55,9 +57,7 @@ public class SelectGenreFragment extends SelectListFragment<Genre> { } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - Genre genre = (Genre) parent.getItemAtPosition(position); - + public void onItemClicked(Genre genre) { SubsonicFragment fragment = new SelectDirectoryFragment(); Bundle args = new Bundle(); args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, "genres"); @@ -68,4 +68,12 @@ public class SelectGenreFragment extends SelectListFragment<Genre> { replaceFragment(fragment); } + + @Override + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Genre> updateView, Genre item) {} + + @Override + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Genre> updateView, Genre item) { + return false; + } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectListFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectListFragment.java deleted file mode 100644 index 6f73f6e8..00000000 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectListFragment.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. - - Copyright 2010 (C) Sindre Mehus - */ -package github.daneren2005.dsub.fragments; - -import android.os.Bundle; -import android.support.v4.widget.SwipeRefreshLayout; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.ListView; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.service.MusicService; -import github.daneren2005.dsub.service.MusicServiceFactory; -import github.daneren2005.dsub.util.BackgroundTask; -import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.util.TabBackgroundTask; - -public abstract class SelectListFragment<T> extends SubsonicFragment implements AdapterView.OnItemClickListener { - private static final String TAG = SelectListFragment.class.getSimpleName(); - protected ListView listView; - protected ArrayAdapter adapter; - protected BackgroundTask<List<T>> currentTask; - protected List<T> objects; - protected boolean serialize = true; - - @Override - public void onCreate(Bundle bundle) { - super.onCreate(bundle); - - if(bundle != null && serialize) { - objects = (List<T>) bundle.getSerializable(Constants.FRAGMENT_LIST); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - if(serialize) { - outState.putSerializable(Constants.FRAGMENT_LIST, (Serializable) objects); - } - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false); - - refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); - refreshLayout.setOnRefreshListener(this); - - listView = (ListView)rootView.findViewById(R.id.fragment_list); - listView.setOnItemClickListener(this); - setupScrollList(listView); - registerForContextMenu(listView); - - if(objects == null) { - refresh(false); - } else { - listView.setAdapter(adapter = getAdapter(objects)); - } - - return rootView; - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { - if(!primaryFragment) { - return; - } - - menuInflater.inflate(getOptionsMenu(), menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - return super.onOptionsItemSelected(item); - } - - @Override - protected void refresh(final boolean refresh) { - int titleRes = getTitleResource(); - if(titleRes != 0) { - setTitle(getTitleResource()); - } - listView.setVisibility(View.GONE); - - // Cancel current running task before starting another one - if(currentTask != null) { - currentTask.cancel(); - } - - currentTask = new TabBackgroundTask<List<T>>(this) { - @Override - protected List<T> doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(context); - - objects = new ArrayList<T>(); - - try { - objects = getObjects(musicService, refresh, this); - } catch (Exception x) { - Log.e(TAG, "Failed to load", x); - } - - return objects; - } - - @Override - protected void done(List<T> result) { - if (result != null && !result.isEmpty()) { - // Toggle fast scroll to get around issue when length of list changes - listView.setFastScrollEnabled(false); - listView.setAdapter(adapter = getAdapter(result)); - listView.setFastScrollEnabled(true); - - onFinishRefresh(); - listView.setVisibility(View.VISIBLE); - } else { - setEmpty(true); - } - - currentTask = null; - } - }; - currentTask.execute(); - } - - public abstract int getOptionsMenu(); - public abstract ArrayAdapter getAdapter(List<T> objs); - public abstract List<T> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception; - public abstract int getTitleResource(); - - public void onFinishRefresh() { - - } -} diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java index 3d7e664f..a2f1aabd 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java @@ -1,19 +1,21 @@ package github.daneren2005.dsub.fragments; -import android.app.AlertDialog; +import android.support.v7.app.AlertDialog; import android.content.DialogInterface; +import android.content.res.Resources; import android.os.Bundle; import android.support.v4.app.FragmentTransaction; +import android.support.v7.widget.RecyclerView; import android.view.ContextMenu; +import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.EditText; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.Playlist; import github.daneren2005.dsub.domain.ServerInfo; @@ -30,31 +32,37 @@ import github.daneren2005.dsub.util.LoadingTask; import github.daneren2005.dsub.util.UserUtil; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.adapter.PlaylistAdapter; +import github.daneren2005.dsub.view.UpdateView; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -public class SelectPlaylistFragment extends SelectListFragment<Playlist> { +public class SelectPlaylistFragment extends SelectRecyclerFragment<Playlist> { private static final String TAG = SelectPlaylistFragment.class.getSimpleName(); @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + if (Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_LARGE_ALBUM_ART, true)) { + largeAlbums = true; + } + } - MenuInflater inflater = context.getMenuInflater(); + @Override + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Playlist> updateView, Playlist playlist) { if (Util.isOffline(context)) { - inflater.inflate(R.menu.select_playlist_context_offline, menu); + menuInflater.inflate(R.menu.select_playlist_context_offline, menu); } else { - inflater.inflate(R.menu.select_playlist_context, menu); + menuInflater.inflate(R.menu.select_playlist_context, menu); - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Playlist playlist = (Playlist) listView.getItemAtPosition(info.position); if(SyncUtil.isSyncedPlaylist(context, playlist.getId())) { menu.removeItem(R.id.playlist_menu_sync); } else { menu.removeItem(R.id.playlist_menu_stop_sync); } - + if(!ServerInfo.checkServerVersion(context, "1.8")) { menu.removeItem(R.id.playlist_update_info); } else if(playlist.getPublic() != null && playlist.getPublic() == true && playlist.getId().indexOf(".m3u") == -1 && !UserUtil.getCurrentUsername(context).equals(playlist.getOwner())) { @@ -67,48 +75,14 @@ public class SelectPlaylistFragment extends SelectListFragment<Playlist> { } @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Playlist playlist = (Playlist) listView.getItemAtPosition(info.position); - - SubsonicFragment fragment; - Bundle args; - FragmentTransaction trans; + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Playlist> updateView, Playlist playlist) { switch (menuItem.getItemId()) { - case R.id.playlist_menu_download: - downloadPlaylist(playlist.getId(), playlist.getName(), false, true, false, false, true); - break; case R.id.playlist_menu_sync: syncPlaylist(playlist); break; case R.id.playlist_menu_stop_sync: stopSyncPlaylist(playlist); break; - case R.id.playlist_menu_play_now: - fragment = new SelectDirectoryFragment(); - args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); - args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); - fragment.setArguments(args); - - replaceFragment(fragment); - break; - case R.id.playlist_menu_play_shuffled: - fragment = new SelectDirectoryFragment(); - args = new Bundle(); - args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); - args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); - args.putBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); - args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); - fragment.setArguments(args); - - replaceFragment(fragment); - break; case R.id.playlist_menu_delete: deletePlaylist(playlist); break; @@ -118,10 +92,9 @@ public class SelectPlaylistFragment extends SelectListFragment<Playlist> { case R.id.playlist_update_info: updatePlaylistInfo(playlist); break; - default: - return false; } - return true; + + return false; } @Override @@ -130,8 +103,31 @@ public class SelectPlaylistFragment extends SelectListFragment<Playlist> { } @Override - public ArrayAdapter getAdapter(List<Playlist> playlists) { - return new PlaylistAdapter(context, playlists); + public SectionAdapter<Playlist> getAdapter(List<Playlist> playlists) { + List<Playlist> mine = new ArrayList<>(); + List<Playlist> shared = new ArrayList<>(); + + String currentUsername = UserUtil.getCurrentUsername(context); + for(Playlist playlist: playlists) { + if(playlist.getOwner() == null || playlist.getOwner().equals(currentUsername)) { + mine.add(playlist); + } else { + shared.add(playlist); + } + } + + if(shared.isEmpty()) { + return new PlaylistAdapter(context, playlists, getImageLoader(), largeAlbums, this); + } else { + Resources res = context.getResources(); + List<String> headers = Arrays.asList(res.getString(R.string.playlist_mine), res.getString(R.string.playlist_shared)); + + List<List<Playlist>> sections = new ArrayList<>(); + sections.add(mine); + sections.add(shared); + + return new PlaylistAdapter(context, headers, sections, getImageLoader(), largeAlbums, this); + } } @Override @@ -149,9 +145,7 @@ public class SelectPlaylistFragment extends SelectListFragment<Playlist> { } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - Playlist playlist = (Playlist) parent.getItemAtPosition(position); - + public void onItemClicked(Playlist playlist) { SubsonicFragment fragment = new SelectDirectoryFragment(); Bundle args = new Bundle(); args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); @@ -179,8 +173,7 @@ public class SelectPlaylistFragment extends SelectListFragment<Playlist> { @Override protected void done(Void result) { - adapter.remove(playlist); - adapter.notifyDataSetChanged(); + adapter.removeItem(playlist); Util.toast(context, context.getResources().getString(R.string.menu_deleted_playlist, playlist.getName())); } @@ -201,12 +194,33 @@ public class SelectPlaylistFragment extends SelectListFragment<Playlist> { } private void displayPlaylistInfo(final Playlist playlist) { - String message = "Owner: " + playlist.getOwner() + "\nComments: " + - ((playlist.getComment() == null) ? "" : playlist.getComment()) + - "\nSong Count: " + playlist.getSongCount() + - ((playlist.getPublic() == null) ? "" : ("\nPublic: " + playlist.getPublic())) + - "\nCreation Date: " + playlist.getCreated().replace('T', ' '); - Util.info(context, playlist.getName(), message); + List<Integer> headers = new ArrayList<>(); + List<String> details = new ArrayList<>(); + + if(playlist.getOwner() != null) { + headers.add(R.string.details_owner); + details.add(playlist.getOwner()); + } + + if(playlist.getComment() != null) { + headers.add(R.string.details_comments); + details.add(playlist.getComment()); + } + + headers.add(R.string.details_song_count); + details.add(playlist.getSongCount()); + + if(playlist.getPublic() != null) { + headers.add(R.string.details_public); + details.add(Boolean.toString(playlist.getPublic())); + } + + if(playlist.getCreated() != null) { + headers.add(R.string.details_created); + details.add(Util.formatDate(context, playlist.getCreated())); + } + + Util.showDetailsDialog(context, R.string.details_title_playlist, headers, details); } private void updatePlaylistInfo(final Playlist playlist) { diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java index 3a564f1c..381453c0 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java @@ -1,33 +1,30 @@ /* - This file is part of Subsonic. - - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. - - Copyright 2010 (C) Sindre Mehus - */ + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ package github.daneren2005.dsub.fragments; -import android.app.AlertDialog; +import android.support.v7.app.AlertDialog; import android.content.DialogInterface; import android.os.Bundle; import android.view.ContextMenu; +import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.TextView; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.PodcastChannel; import github.daneren2005.dsub.service.MusicService; @@ -42,15 +39,12 @@ import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.UserUtil; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.adapter.PodcastChannelAdapter; +import github.daneren2005.dsub.view.UpdateView; import java.util.ArrayList; import java.util.List; -/** - * - * @author Scott - */ -public class SelectPodcastsFragment extends SelectListFragment<PodcastChannel> { +public class SelectPodcastsFragment extends SelectRecyclerFragment<PodcastChannel> { private static final String TAG = SelectPodcastsFragment.class.getSimpleName(); @Override @@ -70,38 +64,26 @@ public class SelectPodcastsFragment extends SelectListFragment<PodcastChannel> { return false; } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - android.view.MenuInflater inflater = context.getMenuInflater(); + @Override + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<PodcastChannel> updateView, PodcastChannel podcast) { if(!Util.isOffline(context) && UserUtil.canPodcast()) { - inflater.inflate(R.menu.select_podcasts_context, menu); + menuInflater.inflate(R.menu.select_podcasts_context, menu); - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - PodcastChannel podcast = (PodcastChannel) listView.getItemAtPosition(info.position); if(SyncUtil.isSyncedPodcast(context, podcast.getId())) { menu.removeItem(R.id.podcast_menu_sync); } else { menu.removeItem(R.id.podcast_menu_stop_sync); } } else { - inflater.inflate(R.menu.select_podcasts_context_offline, menu); + menuInflater.inflate(R.menu.select_podcasts_context_offline, menu); } recreateContextMenu(menu); } @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - PodcastChannel channel = (PodcastChannel) listView.getItemAtPosition(info.position); - + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<PodcastChannel> updateView, PodcastChannel channel) { switch (menuItem.getItemId()) { case R.id.podcast_menu_sync: syncPodcast(channel); @@ -116,7 +98,7 @@ public class SelectPodcastsFragment extends SelectListFragment<PodcastChannel> { deletePodcast(channel); break; } - + return true; } @@ -126,8 +108,8 @@ public class SelectPodcastsFragment extends SelectListFragment<PodcastChannel> { } @Override - public ArrayAdapter getAdapter(List<PodcastChannel> channels) { - return new PodcastChannelAdapter(context, channels); + public SectionAdapter getAdapter(List<PodcastChannel> channels) { + return new PodcastChannelAdapter(context, channels, this); } @Override @@ -141,9 +123,7 @@ public class SelectPodcastsFragment extends SelectListFragment<PodcastChannel> { } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - PodcastChannel channel = (PodcastChannel) parent.getItemAtPosition(position); - + public void onItemClicked(PodcastChannel channel) { if("error".equals(channel.getStatus())) { Util.toast(context, context.getResources().getString(R.string.select_podcasts_invalid_podcast_channel, channel.getErrorMessage() == null ? "error" : channel.getErrorMessage())); } else if("downloading".equals(channel.getStatus())) { @@ -159,7 +139,7 @@ public class SelectPodcastsFragment extends SelectListFragment<PodcastChannel> { replaceFragment(fragment); } } - + public void refreshPodcasts() { new SilentBackgroundTask<Void>(context) { @Override @@ -234,13 +214,29 @@ public class SelectPodcastsFragment extends SelectListFragment<PodcastChannel> { } private void displayPodcastInfo(final PodcastChannel channel) { - String message = ((channel.getName()) == null ? "" : "Title: " + channel.getName()) + - "\nURL: " + channel.getUrl() + - "\nStatus: " + channel.getStatus() + - ((channel.getErrorMessage()) == null ? "" : "\nError Message: " + channel.getErrorMessage()) + - ((channel.getDescription()) == null ? "" : "\n\nDescription: " + channel.getDescription()); - - Util.info(context, channel.getName(), message); + List<Integer> headers = new ArrayList<>(); + List<String> details = new ArrayList<>(); + + if(channel.getName() != null) { + headers.add(R.string.details_title); + details.add(channel.getName()); + } + + headers.add(R.string.details_url); + details.add(channel.getUrl()); + headers.add(R.string.details_status); + details.add(channel.getStatus()); + + if(channel.getErrorMessage() != null) { + headers.add(R.string.details_error); + details.add(channel.getErrorMessage()); + } + if(channel.getDescription() != null) { + headers.add(R.string.details_description); + details.add(channel.getDescription()); + } + + Util.showDetailsDialog(context, R.string.details_title_podcast, headers, details); } private void deletePodcast(final PodcastChannel channel) { @@ -258,8 +254,7 @@ public class SelectPodcastsFragment extends SelectListFragment<PodcastChannel> { @Override protected void done(Void result) { - adapter.remove(channel); - adapter.notifyDataSetChanged(); + adapter.removeItem(channel); Util.toast(context, context.getResources().getString(R.string.select_podcasts_deleted, channel.getName())); } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java new file mode 100644 index 00000000..adf22484 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectRecyclerFragment.java @@ -0,0 +1,206 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.fragments; + +import android.os.Bundle; +import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.RecyclerView; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; +import github.daneren2005.dsub.service.MusicService; +import github.daneren2005.dsub.service.MusicServiceFactory; +import github.daneren2005.dsub.util.Constants; +import github.daneren2005.dsub.util.ProgressListener; +import github.daneren2005.dsub.util.TabBackgroundTask; +import github.daneren2005.dsub.view.FastScroller; + +public abstract class SelectRecyclerFragment<T> extends SubsonicFragment implements SectionAdapter.OnItemClickedListener<T> { + private static final String TAG = SelectRecyclerFragment.class.getSimpleName(); + protected RecyclerView recyclerView; + protected FastScroller fastScroller; + protected SectionAdapter<T> adapter; + protected UpdateTask currentTask; + protected List<T> objects; + protected boolean serialize = true; + protected boolean largeAlbums = false; + protected int columns; + protected boolean pullToRefresh = true; + protected boolean backgroundUpdate = true; + + @Override + public void onCreate(Bundle bundle) { + super.onCreate(bundle); + + if(bundle != null && serialize) { + objects = (List<T>) bundle.getSerializable(Constants.FRAGMENT_LIST); + } + columns = context.getResources().getInteger(R.integer.Grid_Columns); + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + if(serialize) { + outState.putSerializable(Constants.FRAGMENT_LIST, (Serializable) objects); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { + rootView = inflater.inflate(R.layout.abstract_recycler_fragment, container, false); + + refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); + refreshLayout.setOnRefreshListener(this); + + recyclerView = (RecyclerView) rootView.findViewById(R.id.fragment_recycler); + fastScroller = (FastScroller) rootView.findViewById(R.id.fragment_fast_scroller); + setupLayoutManager(); + + if(pullToRefresh) { + setupScrollList(recyclerView); + } else { + refreshLayout.setEnabled(false); + } + + if(objects == null) { + refresh(false); + } else { + recyclerView.setAdapter(adapter = getAdapter(objects)); + } + + return rootView; + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { + if(!primaryFragment) { + return; + } + + menuInflater.inflate(getOptionsMenu(), menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + return super.onOptionsItemSelected(item); + } + + @Override + protected void refresh(final boolean refresh) { + int titleRes = getTitleResource(); + if(titleRes != 0) { + setTitle(getTitleResource()); + } + if(backgroundUpdate) { + recyclerView.setVisibility(View.GONE); + } + + // Cancel current running task before starting another one + if(currentTask != null) { + currentTask.cancel(); + } + + currentTask = new UpdateTask(this, refresh); + + if(backgroundUpdate) { + currentTask.execute(); + } else { + objects = new ArrayList<T>(); + + try { + objects = getObjects(null, refresh, null); + } catch (Exception x) { + Log.e(TAG, "Failed to load", x); + } + + currentTask.done(objects); + } + } + + protected SectionAdapter getCurrentAdapter() { + return adapter; + } + + private void setupLayoutManager() { + setupLayoutManager(recyclerView, largeAlbums); + } + + public abstract int getOptionsMenu(); + public abstract SectionAdapter<T> getAdapter(List<T> objs); + public abstract List<T> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception; + public abstract int getTitleResource(); + + public void onFinishRefresh() { + + } + + private class UpdateTask extends TabBackgroundTask<List<T>> { + private boolean refresh; + + public UpdateTask(SubsonicFragment fragment, boolean refresh) { + super(fragment); + this.refresh = refresh; + } + + @Override + public List<T> doInBackground() throws Exception { + MusicService musicService = MusicServiceFactory.getMusicService(context); + + objects = new ArrayList<T>(); + + try { + objects = getObjects(musicService, refresh, this); + } catch (Exception x) { + Log.e(TAG, "Failed to load", x); + } + + return objects; + } + + @Override + public void done(List<T> result) { + if (result != null && !result.isEmpty()) { + recyclerView.setAdapter(adapter = getAdapter(result)); + if(adapter instanceof FastScroller.BubbleTextGetter) { + if(!fastScroller.isAttached()) { + fastScroller.attachRecyclerView(recyclerView); + } + } else if(fastScroller.isAttached()) { + fastScroller.detachRecyclerView(); + } + + onFinishRefresh(); + recyclerView.setVisibility(View.VISIBLE); + } else { + setEmpty(true); + } + + currentTask = null; + } + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectShareFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectShareFragment.java index 07cd3bef..65723618 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectShareFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectShareFragment.java @@ -1,13 +1,28 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + package github.daneren2005.dsub.fragments; -import android.app.AlertDialog; +import android.support.v7.app.AlertDialog; import android.content.DialogInterface; import android.os.Bundle; import android.view.ContextMenu; +import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.CompoundButton; import android.widget.DatePicker; @@ -17,6 +32,7 @@ import java.util.Date; import java.util.List; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.Share; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.MusicServiceFactory; @@ -27,30 +43,19 @@ import github.daneren2005.dsub.util.LoadingTask; import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.Util; import github.daneren2005.dsub.adapter.ShareAdapter; +import github.daneren2005.dsub.view.UpdateView; -/** - * Created by Scott on 12/28/13. - */ -public class SelectShareFragment extends SelectListFragment<Share> { +public class SelectShareFragment extends SelectRecyclerFragment<Share> { private static final String TAG = SelectShareFragment.class.getSimpleName(); @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - android.view.MenuInflater inflater = context.getMenuInflater(); - inflater.inflate(R.menu.select_share_context, menu); + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Share> updateView, Share item) { + menuInflater.inflate(R.menu.select_share_context, menu); recreateContextMenu(menu); } @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Share share = (Share) listView.getItemAtPosition(info.position); - + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Share> updateView, Share share) { switch (menuItem.getItemId()) { case R.id.share_menu_share: shareExternal(share); @@ -75,8 +80,8 @@ public class SelectShareFragment extends SelectListFragment<Share> { } @Override - public ArrayAdapter getAdapter(List<Share> objs) { - return new ShareAdapter(context, objs); + public SectionAdapter getAdapter(List<Share> objs) { + return new ShareAdapter(context, objs, this); } @Override @@ -90,9 +95,7 @@ public class SelectShareFragment extends SelectListFragment<Share> { } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - Share share = (Share) parent.getItemAtPosition(position); - + public void onItemClicked(Share share) { SubsonicFragment fragment = new SelectDirectoryFragment(); Bundle args = new Bundle(); args.putSerializable(Constants.INTENT_EXTRA_NAME_SHARE, share); @@ -193,8 +196,7 @@ public class SelectShareFragment extends SelectListFragment<Share> { @Override protected void done(Void result) { - adapter.remove(share); - adapter.notifyDataSetChanged(); + adapter.removeItem(share); Util.toast(context, context.getResources().getString(R.string.share_deleted, share.getName())); } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectVideoFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectVideoFragment.java index b4d34ff9..0a79b3d5 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectVideoFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectVideoFragment.java @@ -16,28 +16,33 @@ package github.daneren2005.dsub.fragments; import android.view.ContextMenu; +import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; -import android.widget.ArrayAdapter; import java.util.List; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.EntryGridAdapter; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.adapter.EntryAdapter; +import github.daneren2005.dsub.view.UpdateView; -public class SelectVideoFragment extends SelectListFragment<MusicDirectory.Entry> { +public class SelectVideoFragment extends SelectRecyclerFragment<MusicDirectory.Entry> { @Override public int getOptionsMenu() { return R.menu.empty; } @Override - public ArrayAdapter getAdapter(List<MusicDirectory.Entry> objs) { - return new EntryAdapter(context, null, objs, false); + public SectionAdapter getAdapter(List<MusicDirectory.Entry> objs) { + SectionAdapter adapter = new EntryGridAdapter(context, objs, null, false); + adapter.setOnItemClickedListener(this); + return adapter; } @Override @@ -52,31 +57,18 @@ public class SelectVideoFragment extends SelectListFragment<MusicDirectory.Entry } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - MusicDirectory.Entry entry = (MusicDirectory.Entry) parent.getItemAtPosition(position); + public void onItemClicked(MusicDirectory.Entry entry) { playVideo(entry); } @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Object entry = listView.getItemAtPosition(info.position); - - onCreateContextMenu(menu, view, menuInfo, entry); + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<MusicDirectory.Entry> updateView, MusicDirectory.Entry item) { + onCreateContextMenuSupport(menu, menuInflater, updateView, item); recreateContextMenu(menu); } @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if (menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Object entry = listView.getItemAtPosition(info.position); - + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<MusicDirectory.Entry> updateView, MusicDirectory.Entry entry) { return onContextItemSelected(menuItem, entry); } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SelectYearFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SelectYearFragment.java index dc19acad..22676d8b 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SelectYearFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SelectYearFragment.java @@ -1,24 +1,24 @@ /* - This file is part of Subsonic. - + This file is part of Subsonic. Subsonic is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - Subsonic is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. - - Copyright 2010 (C) Sindre Mehus + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson */ + package github.daneren2005.dsub.fragments; import android.os.Bundle; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; @@ -27,14 +27,21 @@ import java.util.ArrayList; import java.util.List; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.BasicListAdapter; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.ProgressListener; +import github.daneren2005.dsub.view.UpdateView; + +public class SelectYearFragment extends SelectRecyclerFragment<String> { -/** - * Created by Scott on 12/23/13. - */ -public class SelectYearFragment extends SelectListFragment<Integer> { + public SelectYearFragment() { + super(); + pullToRefresh = false; + serialize = false; + backgroundUpdate = false; + } @Override public int getOptionsMenu() { @@ -42,15 +49,15 @@ public class SelectYearFragment extends SelectListFragment<Integer> { } @Override - public ArrayAdapter getAdapter(List<Integer> objs) { - return new ArrayAdapter<Integer>(context, android.R.layout.simple_list_item_1, objs); + public SectionAdapter getAdapter(List<String> objs) { + return new BasicListAdapter(context, objs, this); } @Override - public List<Integer> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { - List<Integer> decades = new ArrayList<Integer>(); + public List<String> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { + List<String> decades = new ArrayList<>(); for(int i = 2010; i >= 1920; i -= 10) { - decades.add(i); + decades.add(String.valueOf(i)); } return decades; @@ -62,17 +69,23 @@ public class SelectYearFragment extends SelectListFragment<Integer> { } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - Integer decade = (Integer) parent.getItemAtPosition(position); - + public void onItemClicked(String decade) { SubsonicFragment fragment = new SelectDirectoryFragment(); Bundle args = new Bundle(); args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, "years"); args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20); args.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0); - args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA, Integer.toString(decade)); + args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA, decade); fragment.setArguments(args); replaceFragment(fragment); } + + @Override + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<String> updateView, String item) {} + + @Override + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<String> updateView, String item) { + return false; + } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SimilarArtistFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SimilarArtistFragment.java index 79e759cc..5677e445 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SimilarArtistFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SimilarArtistFragment.java @@ -16,13 +16,13 @@ package github.daneren2005.dsub.fragments; import android.os.Bundle; -import android.view.ContextMenu; +import android.view.Menu; +import android.view.MenuInflater; import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.ArtistAdapter; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.Artist; import github.daneren2005.dsub.domain.ArtistInfo; import github.daneren2005.dsub.domain.MusicDirectory; @@ -32,13 +32,13 @@ import github.daneren2005.dsub.service.MusicServiceFactory; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.adapter.ArtistAdapter; +import github.daneren2005.dsub.view.UpdateView; import java.net.URLEncoder; import java.util.LinkedList; import java.util.List; -public class SimilarArtistFragment extends SelectListFragment<Artist> { +public class SimilarArtistFragment extends SelectRecyclerFragment<Artist> { private static final String TAG = SimilarArtistFragment.class.getSimpleName(); private ArtistInfo info; private String artistId; @@ -52,6 +52,18 @@ public class SimilarArtistFragment extends SelectListFragment<Artist> { } @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { + super.onCreateOptionsMenu(menu, menuInflater); + if(!primaryFragment) { + return; + } + + if(info.getMissingArtists().isEmpty()) { + menu.removeItem(R.id.menu_show_missing); + } + } + + @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_play_now: @@ -69,30 +81,18 @@ public class SimilarArtistFragment extends SelectListFragment<Artist> { } @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Object entry = listView.getItemAtPosition(info.position); - onCreateContextMenu(menu, view, menuInfo, entry); - + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<Artist> updateView, Artist item) { + onCreateContextMenuSupport(menu, menuInflater, updateView, item); recreateContextMenu(menu); } @Override - public boolean onContextItemSelected(MenuItem menuItem) { - if(menuItem.getGroupId() != getSupportTag()) { - return false; - } - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Artist artist = (Artist) listView.getItemAtPosition(info.position); + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<Artist> updateView, Artist artist) { return onContextItemSelected(menuItem, artist); } @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - Artist artist = (Artist) parent.getItemAtPosition(position); + public void onItemClicked(Artist artist) { SubsonicFragment fragment = new SelectDirectoryFragment(); Bundle args = new Bundle(); args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); @@ -109,8 +109,8 @@ public class SimilarArtistFragment extends SelectListFragment<Artist> { } @Override - public ArrayAdapter getAdapter(List<Artist> objects) { - return new ArtistAdapter(context, objects); + public SectionAdapter getAdapter(List<Artist> objects) { + return new ArtistAdapter(context, objects, this); } @Override diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java index 109983ba..e7d44e6d 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/SubsonicFragment.java @@ -18,8 +18,9 @@ */ package github.daneren2005.dsub.fragments; +import android.annotation.TargetApi; import android.app.Activity; -import android.app.AlertDialog; +import android.support.v7.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -28,12 +29,15 @@ import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.media.MediaMetadataRetriever; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.StatFs; import android.support.v4.app.Fragment; import android.support.v4.widget.SwipeRefreshLayout; +import android.support.v7.widget.GridLayoutManager; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.util.Log; -import android.view.ContextMenu; import android.view.GestureDetector; import android.view.Menu; import android.view.MenuInflater; @@ -41,7 +45,6 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; -import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; @@ -49,9 +52,9 @@ import android.widget.EditText; import android.widget.RatingBar; import android.widget.TextView; import github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.DownloadActivity; import github.daneren2005.dsub.activity.SubsonicActivity; import github.daneren2005.dsub.activity.SubsonicFragmentActivity; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.Artist; import github.daneren2005.dsub.domain.Bookmark; import github.daneren2005.dsub.domain.Genre; @@ -70,15 +73,16 @@ import github.daneren2005.dsub.service.ServerTooOldException; import github.daneren2005.dsub.util.Constants; import github.daneren2005.dsub.util.FileUtil; import github.daneren2005.dsub.util.ImageLoader; +import github.daneren2005.dsub.util.MenuUtil; import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.LoadingTask; import github.daneren2005.dsub.util.UserUtil; import github.daneren2005.dsub.util.Util; -import github.daneren2005.dsub.view.AlbumCell; import github.daneren2005.dsub.view.AlbumView; import github.daneren2005.dsub.view.ArtistEntryView; import github.daneren2005.dsub.view.ArtistView; +import github.daneren2005.dsub.view.GridSpacingDecoration; import github.daneren2005.dsub.view.PlaylistSongView; import github.daneren2005.dsub.view.SongView; import github.daneren2005.dsub.view.UpdateView; @@ -101,7 +105,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR private static final String TAG = SubsonicFragment.class.getSimpleName(); private static int TAG_INC = 10; private int tag; - + protected SubsonicActivity context; protected CharSequence title = null; protected CharSequence subtitle = null; @@ -116,7 +120,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR protected boolean artistOverride = false; protected SwipeRefreshLayout refreshLayout; protected boolean firstRun; - + public SubsonicFragment() { super(); tag = TAG_INC++; @@ -171,10 +175,10 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.menu_shuffle: + case R.id.menu_global_shuffle: onShuffleRequested(); return true; - case R.id.menu_search: + case R.id.menu_global_search: context.onSearchRequested(); return true; case R.id.menu_exit: @@ -183,23 +187,50 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR case R.id.menu_refresh: refresh(); return true; + case R.id.menu_play_now: + playNow(false, false); + return true; + case R.id.menu_play_last: + playNow(false, true); + return true; + case R.id.menu_play_next: + playNow(false, true, true); + return true; + case R.id.menu_shuffle: + playNow(true, false); + return true; + case R.id.menu_download: + downloadBackground(false); + clearSelected(); + return true; + case R.id.menu_cache: + downloadBackground(true); + clearSelected(); + return true; + case R.id.menu_delete: + delete(); + clearSelected(); + return true; + case R.id.menu_add_playlist: + List<Entry> songs = getSelectedEntries(); + addToPlaylist(songs); + clearSelected(); + return true; } return false; } - - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo, Object selected) { - MenuInflater inflater = context.getMenuInflater(); + public void onCreateContextMenuSupport(Menu menu, MenuInflater menuInflater, UpdateView updateView, Object selected) { if(selected instanceof Entry) { Entry entry = (Entry) selected; if(entry instanceof PodcastEpisode && !entry.isVideo()) { if(Util.isOffline(context)) { - inflater.inflate(R.menu.select_podcast_episode_context_offline, menu); + menuInflater.inflate(R.menu.select_podcast_episode_context_offline, menu); } else { - inflater.inflate(R.menu.select_podcast_episode_context, menu); - + menuInflater.inflate(R.menu.select_podcast_episode_context, menu); + if(entry.getBookmark() == null) { menu.removeItem(R.id.bookmark_menu_delete); } @@ -207,10 +238,10 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR } else if (entry.isDirectory()) { if(Util.isOffline(context)) { - inflater.inflate(R.menu.select_album_context_offline, menu); + menuInflater.inflate(R.menu.select_album_context_offline, menu); } else { - inflater.inflate(R.menu.select_album_context, menu); + menuInflater.inflate(R.menu.select_album_context, menu); if(Util.isTagBrowsing(context)) { menu.removeItem(R.id.menu_rate); @@ -219,11 +250,11 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR menu.findItem(entry.isDirectory() ? R.id.album_menu_star : R.id.song_menu_star).setTitle(entry.isStarred() ? R.string.common_unstar : R.string.common_star); } else if(!entry.isVideo()) { if(Util.isOffline(context)) { - inflater.inflate(R.menu.select_song_context_offline, menu); + menuInflater.inflate(R.menu.select_song_context_offline, menu); } else { - inflater.inflate(R.menu.select_song_context, menu); - + menuInflater.inflate(R.menu.select_song_context, menu); + if(entry.getBookmark() == null) { menu.removeItem(R.id.bookmark_menu_delete); } @@ -231,112 +262,27 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR menu.findItem(entry.isDirectory() ? R.id.album_menu_star : R.id.song_menu_star).setTitle(entry.isStarred() ? R.string.common_unstar : R.string.common_star); } else { if(Util.isOffline(context)) { - inflater.inflate(R.menu.select_video_context_offline, menu); + menuInflater.inflate(R.menu.select_video_context_offline, menu); } else { - inflater.inflate(R.menu.select_video_context, menu); + menuInflater.inflate(R.menu.select_video_context, menu); } } } else if(selected instanceof Artist) { Artist artist = (Artist) selected; if(Util.isOffline(context)) { - inflater.inflate(R.menu.select_artist_context_offline, menu); - } - else { - inflater.inflate(R.menu.select_artist_context, menu); + menuInflater.inflate(R.menu.select_artist_context_offline, menu); + } else { + menuInflater.inflate(R.menu.select_artist_context, menu); menu.findItem(R.id.artist_menu_star).setTitle(artist.isStarred() ? R.string.common_unstar : R.string.common_star); } } - hideMenuItems(menu, (AdapterView.AdapterContextMenuInfo) menuInfo); - } - - protected void hideMenuItems(ContextMenu menu, AdapterView.AdapterContextMenuInfo info) { - if(!ServerInfo.checkServerVersion(context, "1.8")) { - menu.setGroupVisible(R.id.server_1_8, false); - menu.setGroupVisible(R.id.hide_star, false); - } - if(!ServerInfo.checkServerVersion(context, "1.9")) { - menu.setGroupVisible(R.id.server_1_9, false); - } - if(!ServerInfo.checkServerVersion(context, "1.10.1")) { - menu.setGroupVisible(R.id.server_1_10, false); - } - - SharedPreferences prefs = Util.getPreferences(context); - if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_PLAY_NEXT, true)) { - menu.setGroupVisible(R.id.hide_play_next, false); - } - if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_PLAY_LAST, true)) { - menu.setGroupVisible(R.id.hide_play_last, false); - } - if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_STAR, true)) { - menu.setGroupVisible(R.id.hide_star, false); - } - if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_SHARED, true) || !UserUtil.canShare()) { - menu.setGroupVisible(R.id.hide_share, false); - } - if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_RATING, true)) { - menu.setGroupVisible(R.id.hide_rating, false); - } - - if(!Util.isOffline(context)) { - // If we are looking at a standard song view, get downloadFile to cache what options to show - if(info.targetView instanceof SongView) { - SongView songView = (SongView) info.targetView; - DownloadFile downloadFile = songView.getDownloadFile(); - - try { - if(downloadFile != null) { - if(downloadFile.isWorkDone()) { - // Remove permanent cache menu if already perma cached - if(downloadFile.isSaved()) { - menu.removeItem(R.id.song_menu_pin); - } - - // Remove cache option no matter what if already downloaded - menu.removeItem(R.id.song_menu_download); - } else { - // Remove delete option if nothing to delete - menu.removeItem(R.id.song_menu_delete); - } - } - } catch(Exception e) { - Log.w(TAG, "Failed to lookup downloadFile info", e); - } - } - // Apply similar logic to album views - else if(info.targetView instanceof AlbumCell || info.targetView instanceof AlbumView - || info.targetView instanceof ArtistView || info.targetView instanceof ArtistEntryView) { - File folder = null; - int id = 0; - if(info.targetView instanceof AlbumCell) { - folder = ((AlbumCell) info.targetView).getFile(); - id = R.id.album_menu_delete; - } else if(info.targetView instanceof AlbumView) { - folder = ((AlbumView) info.targetView).getFile(); - id = R.id.album_menu_delete; - } else if(info.targetView instanceof ArtistView) { - folder = ((ArtistView) info.targetView).getFile(); - id = R.id.artist_menu_delete; - } else if(info.targetView instanceof ArtistEntryView) { - folder = ((ArtistEntryView) info.targetView).getFile(); - id = R.id.artist_menu_delete; - } - - try { - if(folder != null && !folder.exists()) { - menu.removeItem(id); - } - } catch(Exception e) { - Log.w(TAG, "Failed to lookup album directory info", e); - } - } - } + MenuUtil.hideMenuItems(context, menu); } - protected void recreateContextMenu(ContextMenu menu) { + protected void recreateContextMenu(Menu menu) { List<MenuItem> menuItems = new ArrayList<MenuItem>(); for(int i = 0; i < menu.size(); i++) { MenuItem item = menu.getItem(i); @@ -364,54 +310,15 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR case R.id.artist_menu_play_shuffled: downloadRecursively(artist.getId(), false, false, true, true, false); break; - case R.id.artist_menu_play_next: - downloadRecursively(artist.getId(), false, true, false, false, false, true); - break; case R.id.artist_menu_play_last: downloadRecursively(artist.getId(), false, true, false, false, false); break; - case R.id.artist_menu_download: - downloadRecursively(artist.getId(), false, true, false, false, true); - break; - case R.id.artist_menu_pin: - downloadRecursively(artist.getId(), true, true, false, false, true); - break; - case R.id.artist_menu_delete: - deleteRecursively(artist); - break; case R.id.artist_menu_star: toggleStarred(artist); break; - case R.id.album_menu_play_now: - artistOverride = true; - downloadRecursively(entry.getId(), false, false, true, false, false); - break; - case R.id.album_menu_play_shuffled: - artistOverride = true; - downloadRecursively(entry.getId(), false, false, true, true, false); - break; - case R.id.album_menu_play_next: - artistOverride = true; - downloadRecursively(entry.getId(), false, true, false, false, false, true); - break; - case R.id.album_menu_play_last: - artistOverride = true; - downloadRecursively(entry.getId(), false, true, false, false, false); - break; - case R.id.album_menu_download: - artistOverride = true; - downloadRecursively(entry.getId(), false, true, false, false, true); - break; - case R.id.album_menu_pin: - artistOverride = true; - downloadRecursively(entry.getId(), true, true, false, false, true); - break; case R.id.album_menu_star: toggleStarred(entry); break; - case R.id.album_menu_delete: - deleteRecursively(entry); - break; case R.id.album_menu_info: displaySongInfo(entry); break; @@ -421,21 +328,12 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR case R.id.album_menu_share: createShare(songs); break; - case R.id.song_menu_play_now: - playNow(songs); - break; - case R.id.song_menu_play_next: - getDownloadService().download(songs, false, false, true, false); - break; case R.id.song_menu_play_last: getDownloadService().download(songs, false, false, false, false); break; case R.id.song_menu_download: getDownloadService().downloadBackground(songs, false); break; - case R.id.song_menu_pin: - getDownloadService().downloadBackground(songs, true); - break; case R.id.song_menu_delete: getDownloadService().delete(songs); break; @@ -475,7 +373,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR return true; } - + public void replaceFragment(SubsonicFragment fragment) { replaceFragment(fragment, true); } @@ -492,7 +390,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR public int getSupportTag() { return tag; } - + public void setPrimaryFragment(boolean primary) { primaryFragment = primary; if(primary) { @@ -631,6 +529,83 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR R.color.holo_red_light); } } + protected void setupScrollList(final RecyclerView recyclerView) { + if(!context.isTouchscreen()) { + refreshLayout.setEnabled(false); + } else { + recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrollStateChanged(RecyclerView recyclerView, int newState) { + super.onScrollStateChanged(recyclerView, newState); + } + + @Override + public void onScrolled(RecyclerView recyclerView, int dx, int dy) { + refreshLayout.setEnabled(!recyclerView.canScrollVertically(-1)); + } + }); + + refreshLayout.setColorScheme( + R.color.holo_blue_light, + R.color.holo_orange_light, + R.color.holo_green_light, + R.color.holo_red_light); + } + } + + public void setupLayoutManager(RecyclerView recyclerView, boolean largeAlbums) { + recyclerView.setLayoutManager(getLayoutManager(recyclerView, largeAlbums)); + } + public RecyclerView.LayoutManager getLayoutManager(RecyclerView recyclerView, boolean largeCells) { + if(largeCells) { + return getGridLayoutManager(recyclerView); + } else { + return getLinearLayoutManager(); + } + } + public GridLayoutManager getGridLayoutManager(RecyclerView recyclerView) { + final int columns = getRecyclerColumnCount(); + GridLayoutManager gridLayoutManager = new GridLayoutManager(context, columns); + + GridLayoutManager.SpanSizeLookup spanSizeLookup = getSpanSizeLookup(columns); + if(spanSizeLookup != null) { + gridLayoutManager.setSpanSizeLookup(spanSizeLookup); + } + RecyclerView.ItemDecoration itemDecoration = getItemDecoration(); + if(itemDecoration != null) { + recyclerView.addItemDecoration(itemDecoration); + } + return gridLayoutManager; + } + public LinearLayoutManager getLinearLayoutManager() { + LinearLayoutManager layoutManager = new LinearLayoutManager(context); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + return layoutManager; + } + public GridLayoutManager.SpanSizeLookup getSpanSizeLookup(final int columns) { + return new GridLayoutManager.SpanSizeLookup() { + @Override + public int getSpanSize(int position) { + SectionAdapter adapter = getCurrentAdapter(); + if(adapter != null) { + int viewType = getCurrentAdapter().getItemViewType(position); + if (viewType == SectionAdapter.VIEW_TYPE_HEADER) { + return columns; + } else { + return 1; + } + } else { + return 1; + } + } + }; + } + public RecyclerView.ItemDecoration getItemDecoration() { + return new GridSpacingDecoration(); + } + public int getRecyclerColumnCount() { + return context.getResources().getInteger(R.integer.Grid_Columns); + } protected void warnIfStorageUnavailable() { if (!Util.isExternalStoragePresent()) { @@ -650,9 +625,12 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR protected void onShuffleRequested() { if(Util.isOffline(context)) { - Intent intent = new Intent(context, DownloadActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); - Util.startActivityWithoutTransition(context, intent); + DownloadService downloadService = getDownloadService(); + if(downloadService == null) { + return; + } + downloadService.setShufflePlayEnabled(true); + context.openNowPlaying(); return; } @@ -691,21 +669,21 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.shuffle_pick_genre) - .setItems(names.toArray(new CharSequence[names.size()]), new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if(which == 0) { - genreCombo.setText(""); - } else { - genreCombo.setText(finalNames.get(which)); - } - } - }); + .setItems(names.toArray(new CharSequence[names.size()]), new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + if(which == 0) { + genreCombo.setText(""); + } else { + genreCombo.setText(finalNames.get(which)); + } + } + }); AlertDialog dialog = builder.create(); dialog.show(); } @Override - protected void error(Throwable error) { + protected void error(Throwable error) { String msg; if (error instanceof OfflineException || error instanceof ServerTooOldException) { msg = getErrorMessage(error); @@ -731,31 +709,34 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.shuffle_title) - .setView(dialogView) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - Intent intent = new Intent(context, DownloadActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); - String genre; - if(useCombo) { - genre = genreCombo.getText().toString(); - } else { - genre = genreBox.getText().toString(); + .setView(dialogView) + .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + String genre; + if (useCombo) { + genre = genreCombo.getText().toString(); + } else { + genre = genreBox.getText().toString(); + } + String startYear = startYearBox.getText().toString(); + String endYear = endYearBox.getText().toString(); + + SharedPreferences.Editor editor = prefs.edit(); + editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, startYear); + editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, endYear); + editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, genre); + editor.commit(); + + DownloadService downloadService = getDownloadService(); + if (downloadService == null) { + return; + } + downloadService.setShufflePlayEnabled(true); + context.openNowPlaying(); } - String startYear = startYearBox.getText().toString(); - String endYear = endYearBox.getText().toString(); - - SharedPreferences.Editor editor = prefs.edit(); - editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_START_YEAR, startYear); - editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_END_YEAR, endYear); - editor.putString(Constants.PREFERENCES_KEY_SHUFFLE_GENRE, genre); - editor.commit(); - - Util.startActivityWithoutTransition(context, intent); - } - }) - .setNegativeButton(R.string.common_cancel, null); + }) + .setNegativeButton(R.string.common_cancel, null); AlertDialog dialog = builder.create(); dialog.show(); } @@ -763,6 +744,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR public void toggleStarred(Entry entry) { toggleStarred(entry, null); } + public void toggleStarred(final Entry entry, final OnStarChange onStarChange) { final boolean starred = !entry.isStarred(); entry.setStarred(starred); @@ -868,9 +850,11 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR protected void downloadPlaylist(final String id, final String name, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background) { downloadRecursively(id, name, false, save, append, autoplay, shuffle, background); } + protected void downloadRecursively(final String id, final String name, final boolean isDirectory, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background) { downloadRecursively(id, name, isDirectory, save, append, autoplay, shuffle, background, false); } + protected void downloadRecursively(final String id, final String name, final boolean isDirectory, final boolean save, final boolean append, final boolean autoplay, final boolean shuffle, final boolean background, final boolean playNext) { new RecursiveLoader(context) { @Override @@ -906,7 +890,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR playNowOverride = true; return false; } - + if (!append && !background) { downloadService.clear(); } @@ -994,7 +978,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR MusicService musicService = MusicServiceFactory.getMusicService(context); List<Playlist> playlists = new ArrayList<Playlist>(); playlists.addAll(musicService.getPlaylists(false, context, this)); - + // Iterate through and remove all non owned public playlists Iterator<Playlist> it = playlists.iterator(); while(it.hasNext()) { @@ -1003,7 +987,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR it.remove(); } } - + return playlists; } @@ -1016,7 +1000,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR @Override public View getView(int position, View convertView, ViewGroup parent) { Playlist playlist = getItem(position); - + // Create new if not getting a convert view to use PlaylistSongView view; if(convertView instanceof PlaylistSongView) { @@ -1033,21 +1017,21 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.playlist_add_to) - .setAdapter(playlistAdapter, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - if (which > 0) { - addToPlaylist(playlists.get(which), songs); - } else { - createNewPlaylist(songs, false); + .setAdapter(playlistAdapter, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int which) { + if (which > 0) { + addToPlaylist(playlists.get(which), songs); + } else { + createNewPlaylist(songs, false); + } } - } - }); + }); AlertDialog dialog = builder.create(); dialog.show(); } @Override - protected void error(Throwable error) { + protected void error(Throwable error) { String msg; if (error instanceof OfflineException || error instanceof ServerTooOldException) { msg = getErrorMessage(error); @@ -1075,7 +1059,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR } @Override - protected void error(Throwable error) { + protected void error(Throwable error) { String msg; if (error instanceof OfflineException || error instanceof ServerTooOldException) { msg = getErrorMessage(error); @@ -1087,7 +1071,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR } }.execute(); } - + protected void createNewPlaylist(final List<Entry> songs, final boolean getSuggestion) { View layout = context.getLayoutInflater().inflate(R.layout.save_playlist, null); final EditText playlistNameView = (EditText) layout.findViewById(R.id.save_playlist_name); @@ -1115,34 +1099,34 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.download_playlist_title) - .setMessage(R.string.download_playlist_name) - .setView(layout) - .setPositiveButton(R.string.common_save, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - String playlistName = String.valueOf(playlistNameView.getText()); - if(overwriteCheckBox.isChecked()) { - overwritePlaylist(songs, playlistName, getDownloadService().getSuggestedPlaylistId()); - } else { - createNewPlaylist(songs, playlistName); - - if(getSuggestion) { - DownloadService downloadService = getDownloadService(); - if(downloadService != null) { - downloadService.setSuggestedPlaylistName(playlistName, null); + .setMessage(R.string.download_playlist_name) + .setView(layout) + .setPositiveButton(R.string.common_save, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + String playlistName = String.valueOf(playlistNameView.getText()); + if(overwriteCheckBox.isChecked()) { + overwritePlaylist(songs, playlistName, getDownloadService().getSuggestedPlaylistId()); + } else { + createNewPlaylist(songs, playlistName); + + if(getSuggestion) { + DownloadService downloadService = getDownloadService(); + if(downloadService != null) { + downloadService.setSuggestedPlaylistName(playlistName, null); + } } } } - } - }) - .setNegativeButton(R.string.common_cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }) - .setCancelable(true); - + }) + .setNegativeButton(R.string.common_cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }) + .setCancelable(true); + AlertDialog dialog = builder.create(); dialog.show(); } @@ -1184,7 +1168,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR } @Override - protected void error(Throwable error) { + protected void error(Throwable error) { String msg; if (error instanceof OfflineException || error instanceof ServerTooOldException) { msg = getErrorMessage(error); @@ -1209,12 +1193,12 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR if(file.exists()) { MediaMetadataRetriever metadata = new MediaMetadataRetriever(); metadata.setDataSource(file.getAbsolutePath()); - + String tmp = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); duration = Integer.parseInt((tmp != null) ? tmp : "0") / 1000; format = FileUtil.getExtension(file.getName()); size = file.length(); - + // If no duration try to read bitrate tag if(duration == null) { tmp = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE); @@ -1224,7 +1208,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR // Divide by 1000 so in kbps bitrate = (int) (size / duration) / 1000 * 8; } - + if(Util.isOffline(context)) { song.setGenre(metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE)); String year = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_YEAR); @@ -1236,57 +1220,85 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR } } - String msg = ""; + List<Integer> headers = new ArrayList<>(); + List<String> details = new ArrayList<>(); if(song instanceof PodcastEpisode) { - msg += "Podcast: " + song.getArtist() + "\nStatus: " + ((PodcastEpisode)song).getStatus(); + headers.add(R.string.details_podcast); + details.add(song.getArtist()); + + headers.add(R.string.details_status); + details.add(((PodcastEpisode)song).getStatus()); } else if(!song.isVideo()) { if(song.getArtist() != null && !"".equals(song.getArtist())) { - msg += "Artist: " + song.getArtist(); + headers.add(R.string.details_artist); + details.add(song.getArtist()); } if(song.getAlbum() != null && !"".equals(song.getAlbum())) { - msg += "\nAlbum: " + song.getAlbum(); + headers.add(R.string.details_album); + details.add(song.getAlbum()); } } if(song.getTrack() != null && song.getTrack() != 0) { - msg += "\nTrack: " + song.getTrack(); + headers.add(R.string.details_track); + details.add(Integer.toString(song.getTrack())); } if(song.getGenre() != null && !"".equals(song.getGenre())) { - msg += "\nGenre: " + song.getGenre(); + headers.add(R.string.details_genre); + details.add(song.getGenre()); } if(song.getYear() != null && song.getYear() != 0) { - msg += "\nYear: " + song.getYear(); + headers.add(R.string.details_year); + details.add(Integer.toString(song.getYear())); } if(!Util.isOffline(context) && song.getSuffix() != null) { - msg += "\nServer Format: " + song.getSuffix(); + headers.add(R.string.details_server_format); + details.add(song.getSuffix()); + if(song.getBitRate() != null && song.getBitRate() != 0) { - msg += "\nServer Bitrate: " + song.getBitRate() + " kbps"; + headers.add(R.string.details_server_bitrate); + details.add(song.getBitRate() + " kbps"); } } if(format != null && !"".equals(format)) { - msg += "\nCached Format: " + format; + headers.add(R.string.details_cached_format); + details.add(format); } if(bitrate != null && bitrate != 0) { - msg += "\nCached Bitrate: " + bitrate + " kbps"; + headers.add(R.string.details_cached_bitrate); + details.add(bitrate + " kbps"); } if(size != 0) { - msg += "\nSize: " + Util.formatLocalizedBytes(size, context); + headers.add(R.string.details_size); + details.add(Util.formatLocalizedBytes(size, context)); } if(song.getDuration() != null && song.getDuration() != 0) { - msg += "\nLength: " + Util.formatDuration(song.getDuration()); + headers.add(R.string.details_length); + details.add(Util.formatDuration(song.getDuration())); } if(song.getBookmark() != null) { - msg += "\nBookmark Position: " + Util.formatDuration(song.getBookmark().getPosition() / 1000); + headers.add(R.string.details_bookmark_position); + details.add(Util.formatDuration(song.getBookmark().getPosition() / 1000)); } if(song.getRating() != 0) { - msg += "\nRating: " + song.getRating() + " stars"; + headers.add(R.string.details_rating); + details.add(song.getRating() + " stars"); } if(song instanceof PodcastEpisode) { - msg += "\n\nDescription: " + song.getAlbum(); + headers.add(R.string.details_description); + details.add(song.getAlbum()); } - Util.info(context, song.getTitle(), msg); + int title; + if(song.isDirectory()) { + title = R.string.details_title_album; + } else if(song instanceof PodcastEpisode) { + title = R.string.details_title_podcast; + } else { + title = R.string.details_title_song; + } + Util.showDetailsDialog(context, title, headers, details); } - + protected void playVideo(Entry entry) { if(entryExists(entry)) { playExternalPlayer(entry); @@ -1315,7 +1327,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR intent.putExtra(Intent.EXTRA_TITLE, entry.getTitle()); List<ResolveInfo> intents = context.getPackageManager() - .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); + .queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); if(intents != null && intents.size() > 0) { startActivity(intent); }else { @@ -1373,11 +1385,12 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR public void deleteRecursively(Artist artist) { deleteRecursively(FileUtil.getArtistDirectory(context, artist)); } - + public void deleteRecursively(Entry album) { deleteRecursively(FileUtil.getAlbumDirectory(context, album)); } + public void deleteRecursively(final File dir) { if(dir == null) { return; @@ -1434,6 +1447,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR replaceFragment(fragment, true); } + public void showAlbum(Entry entry) { SubsonicFragment fragment = new SelectDirectoryFragment(); Bundle args = new Bundle(); @@ -1490,7 +1504,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR intent.putExtra(Intent.EXTRA_TEXT, share.getUrl()); context.startActivity(Intent.createChooser(intent, context.getResources().getString(R.string.share_via))); } - + public GestureDetector getGestureDetector() { return gestureScanner; } @@ -1498,6 +1512,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR protected void playBookmark(List<Entry> songs, Entry song) { playBookmark(songs, song, null, null); } + protected void playBookmark(final List<Entry> songs, final Entry song, final String playlistName, final String playlistId) { final Integer position = song.getBookmark().getPosition(); @@ -1515,7 +1530,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR public void onClick(DialogInterface dialog, int id) { final Bookmark oldBookmark = song.getBookmark(); song.setBookmark(null); - + new SilentBackgroundTask<Void>(context) { @Override protected Void doInBackground() throws Throwable { @@ -1528,7 +1543,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR @Override protected void error(Throwable error) { song.setBookmark(oldBookmark); - + String msg; if (error instanceof OfflineException || error instanceof ServerTooOldException) { msg = getErrorMessage(error); @@ -1546,26 +1561,37 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR AlertDialog dialog = builder.create(); dialog.show(); } - + protected void playNow(List<Entry> entries) { playNow(entries, null, null); } - protected void playNow(List<Entry> entries, String playlistName, String playlistId) { - Entry bookmark = null; - for(Entry entry: entries) { - if(entry.getBookmark() != null) { - bookmark = entry; - break; + protected void playNow(final List<Entry> entries, final String playlistName, final String playlistId) { + new RecursiveLoader(context) { + @Override + protected Boolean doInBackground() throws Throwable { + getSongsRecursively(entries, songs); + return null; } - } - - // If no bookmark found, just play from start - if(bookmark == null) { - playNow(entries, 0, playlistName, playlistId); - } else { - // If bookmark found, then give user choice to start from there or to start over - playBookmark(entries, bookmark, playlistName, playlistId); - } + + @Override + protected void done(Boolean result) { + Entry bookmark = null; + for(Entry entry: songs) { + if(entry.getBookmark() != null) { + bookmark = entry; + break; + } + } + + // If no bookmark found, just play from start + if(bookmark == null) { + playNow(songs, 0, playlistName, playlistId); + } else { + // If bookmark found, then give user choice to start from there or to start over + playBookmark(songs, bookmark, playlistName, playlistId); + } + } + }.execute(); } protected void playNow(List<Entry> entries, int position) { playNow(entries, position, null, null); @@ -1574,9 +1600,11 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR Entry selected = entries.isEmpty() ? null : entries.get(0); playNow(entries, selected, position, playlistName, playlistId); } + protected void playNow(List<Entry> entries, Entry song, int position) { playNow(entries, song, position, null, null); } + protected void playNow(final List<Entry> entries, final Entry song, final int position, final String playlistName, final String playlistId) { new LoadingTask<Void>(context) { @Override @@ -1585,22 +1613,22 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR if(downloadService == null) { return null; } - + downloadService.clear(); downloadService.download(entries, false, true, true, false, entries.indexOf(song), position); downloadService.setSuggestedPlaylistName(playlistName, playlistId); return null; } - + @Override protected void done(Void result) { - Util.startActivityWithoutTransition(context, DownloadActivity.class); + context.openNowPlaying(); } }.execute(); } - protected void deleteBookmark(final MusicDirectory.Entry entry, final ArrayAdapter adapter) { + protected void deleteBookmark(final MusicDirectory.Entry entry, final SectionAdapter adapter) { Util.confirmDialog(context, R.string.bookmark_delete_title, entry.getTitle(), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { @@ -1626,8 +1654,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR @Override protected void done(Void result) { if (adapter != null) { - adapter.remove(entry); - adapter.notifyDataSetChanged(); + adapter.removeItem(entry); } Util.toast(context, context.getResources().getString(R.string.bookmark_deleted, entry.getTitle())); } @@ -1657,19 +1684,19 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR View layout = context.getLayoutInflater().inflate(R.layout.rating, null); final RatingBar ratingBar = (RatingBar) layout.findViewById(R.id.rating_bar); ratingBar.setRating((float) entry.getRating()); - + AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(context.getResources().getString(R.string.rating_title, entry.getTitle())) - .setView(layout) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - int rating = (int) ratingBar.getRating(); - setRating(entry, rating, onRatingChange); - } - }) - .setNegativeButton(R.string.common_cancel, null); - + .setView(layout) + .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + int rating = (int) ratingBar.getRating(); + setRating(entry, rating, onRatingChange); + } + }) + .setNegativeButton(R.string.common_cancel, null); + AlertDialog dialog = builder.create(); dialog.show(); } @@ -1684,7 +1711,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR if(onRatingChange != null) { onRatingChange.ratingChange(rating); } - + new SilentBackgroundTask<Void>(context) { @Override protected Void doInBackground() throws Throwable { @@ -1711,7 +1738,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR if(onRatingChange != null) { onRatingChange.ratingChange(oldRating); } - + String msg; if (error instanceof OfflineException || error instanceof ServerTooOldException) { msg = getErrorMessage(error); @@ -1723,16 +1750,134 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR } }.execute(); } - + + protected SectionAdapter getCurrentAdapter() { return null; } + public void stopActionMode() { + SectionAdapter adapter = getCurrentAdapter(); + if(adapter != null) { + adapter.stopActionMode(); + } + } + protected void clearSelected() { + if(getCurrentAdapter() != null) { + getCurrentAdapter().clearSelected(); + } + } + protected List<Entry> getSelectedEntries() { + return getCurrentAdapter().getSelected(); + } + + protected void playNow(final boolean shuffle, final boolean append) { + playNow(shuffle, append, false); + } + protected void playNow(final boolean shuffle, final boolean append, final boolean playNext) { + List<Entry> songs = getSelectedEntries(); + if(!songs.isEmpty()) { + download(songs, append, false, !append, playNext, shuffle); + clearSelected(); + } + } + + protected void download(List<Entry> entries, boolean append, boolean save, boolean autoplay, boolean playNext, boolean shuffle) { + download(entries, append, save, autoplay, playNext, shuffle, null, null); + } + protected void download(final List<Entry> entries, final boolean append, final boolean save, final boolean autoplay, final boolean playNext, final boolean shuffle, final String playlistName, final String playlistId) { + final DownloadService downloadService = getDownloadService(); + if (downloadService == null) { + return; + } + warnIfStorageUnavailable(); + + // Conditions for using play now button + if(!append && !save && autoplay && !playNext && !shuffle) { + // Call playNow which goes through and tries to use bookmark information + playNow(entries, playlistName, playlistId); + return; + } + + RecursiveLoader onValid = new RecursiveLoader(context) { + @Override + protected Boolean doInBackground() throws Throwable { + if (!append) { + getDownloadService().clear(); + } + getSongsRecursively(entries, songs); + + downloadService.download(songs, save, autoplay, playNext, shuffle); + if (playlistName != null) { + downloadService.setSuggestedPlaylistName(playlistName, playlistId); + } else { + downloadService.setSuggestedPlaylistName(null, null); + } + return null; + } + + @Override + protected void done(Boolean result) { + if (autoplay) { + context.openNowPlaying(); + } else if (save) { + Util.toast(context, + context.getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size())); + } else if (append) { + Util.toast(context, + context.getResources().getQuantityString(R.plurals.select_album_n_songs_added, songs.size(), songs.size())); + } + } + }; + + executeOnValid(onValid); + } + protected void executeOnValid(RecursiveLoader onValid) { + onValid.execute(); + } + protected void downloadBackground(final boolean save) { + List<Entry> songs = getSelectedEntries(); + if(!songs.isEmpty()) { + downloadBackground(save, songs); + } + } + + protected void downloadBackground(final boolean save, final List<Entry> entries) { + if (getDownloadService() == null) { + return; + } + + warnIfStorageUnavailable(); + new RecursiveLoader(context) { + @Override + protected Boolean doInBackground() throws Throwable { + getSongsRecursively(entries, songs); + getDownloadService().downloadBackground(songs, save); + return null; + } + + @Override + protected void done(Boolean result) { + Util.toast(context, context.getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size())); + } + }.execute(); + } + + protected void delete() { + List<Entry> songs = getSelectedEntries(); + if(!songs.isEmpty()) { + DownloadService downloadService = getDownloadService(); + if(downloadService != null) { + downloadService.delete(songs); + } + } + } + protected abstract class EntryInstanceUpdater { private Entry entry; - + public EntryInstanceUpdater(Entry entry) { this.entry = entry; } - + public abstract void update(Entry found); - + public void execute() { DownloadService downloadService = getDownloadService(); if(downloadService != null && !entry.isDirectory()) { @@ -1745,12 +1890,12 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR serializeChanges = true; } } - + if(serializeChanges) { downloadService.serializeQueue(); } } - + Entry find = UpdateView.findEntry(entry); if(find != null) { update(find); @@ -1769,22 +1914,26 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR protected MusicService musicService; protected static final int MAX_SONGS = 500; protected boolean playNowOverride = false; - protected List<Entry> songs; + protected List<Entry> songs = new ArrayList<>(); public RecursiveLoader(Activity context) { super(context); + musicService = MusicServiceFactory.getMusicService(context); } + protected void getSongsRecursively(List<Entry> entry) throws Exception { + getSongsRecursively(entry, songs); + } + protected void getSongsRecursively(List<Entry> entry, List<Entry> songs) throws Exception { + MusicDirectory dir = new MusicDirectory(); + dir.addChildren(entry); + getSongsRecursively(dir, songs); + } protected void getSongsRecursively(MusicDirectory parent, List<Entry> songs) throws Exception { if (songs.size() > MAX_SONGS) { return; } - for (Entry song : parent.getChildren(false, true)) { - if (!song.isVideo() && song.getRating() != 1) { - songs.add(song); - } - } for (Entry dir : parent.getChildren(true, false)) { if(dir.getRating() == 1) { continue; @@ -1798,6 +1947,12 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR } getSongsRecursively(musicDirectory, songs); } + + for (Entry song : parent.getChildren(false, true)) { + if (!song.isVideo() && song.getRating() != 1) { + songs.add(song); + } + } } @Override @@ -1810,7 +1965,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR } if(result) { - Util.startActivityWithoutTransition(context, DownloadActivity.class); + context.openNowPlaying(); } } } diff --git a/app/src/main/java/github/daneren2005/dsub/fragments/UserFragment.java b/app/src/main/java/github/daneren2005/dsub/fragments/UserFragment.java index 00c7c603..bdd0472b 100644 --- a/app/src/main/java/github/daneren2005/dsub/fragments/UserFragment.java +++ b/app/src/main/java/github/daneren2005/dsub/fragments/UserFragment.java @@ -15,71 +15,33 @@ package github.daneren2005.dsub.fragments; -import android.app.Activity; import android.os.Bundle; -import android.support.v4.widget.SwipeRefreshLayout; -import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.TextView; + +import java.util.List; import github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.SubsonicActivity; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.ServerInfo; import github.daneren2005.dsub.domain.User; +import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.util.Constants; -import github.daneren2005.dsub.util.ImageLoader; +import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.UserUtil; import github.daneren2005.dsub.adapter.SettingsAdapter; +import github.daneren2005.dsub.view.UpdateView; -public class UserFragment extends SubsonicFragment{ - private ListView listView; +public class UserFragment extends SelectRecyclerFragment<User.Setting>{ private User user; @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { - rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false); - - refreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.refresh_layout); - refreshLayout.setEnabled(false); - + public void onCreate(Bundle bundle) { + super.onCreate(bundle); Bundle args = getArguments(); user = (User) args.getSerializable(Constants.INTENT_EXTRA_NAME_ID); - - listView = (ListView)rootView.findViewById(R.id.fragment_list); - createHeader(); - listView.setAdapter(new SettingsAdapter(context, user.getSettings(), UserUtil.isCurrentAdmin() && ServerInfo.checkServerVersion(context, "1.10"))); - - setTitle(user.getUsername()); - - return rootView; - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - ((SubsonicActivity) activity).supportInvalidateOptionsMenu(); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { - // For some reason this is called before onAttach - if(!primaryFragment || context == null) { - return; - } - - if(UserUtil.isCurrentAdmin() && ServerInfo.checkServerVersion(context, "1.10")) { - menuInflater.inflate(R.menu.user, menu); - } else if(UserUtil.isCurrentRole(User.SETTINGS)) { - menuInflater.inflate(R.menu.user_user, menu); - } else { - menuInflater.inflate(R.menu.empty, menu); - } + pullToRefresh = false; } @Override @@ -103,23 +65,43 @@ public class UserFragment extends SubsonicFragment{ return false; } - private void createHeader() { - View header = LayoutInflater.from(context).inflate(R.layout.user_header, listView, false); + @Override + public int getOptionsMenu() { + if(UserUtil.isCurrentAdmin() && ServerInfo.checkServerVersion(context, "1.10")) { + return R.menu.user; + } else if(UserUtil.isCurrentRole(User.SETTINGS)) { + return R.menu.user_user; + } else { + return R.menu.empty; + } + } + + @Override + public SectionAdapter<User.Setting> getAdapter(List<User.Setting> objs) { + return new SettingsAdapter(context, user, getImageLoader(), UserUtil.isCurrentAdmin() && ServerInfo.checkServerVersion(context, "1.10")); + } - final ImageLoader imageLoader = getImageLoader(); - ImageView coverArtView = (ImageView) header.findViewById(R.id.user_avatar); - imageLoader.loadAvatar(context, coverArtView, user.getUsername()); + @Override + public List<User.Setting> getObjects(MusicService musicService, boolean refresh, ProgressListener listener) throws Exception { + return user.getSettings(); + } - TextView usernameView = (TextView) header.findViewById(R.id.user_username); - usernameView.setText(user.getUsername()); + @Override + public int getTitleResource() { + setTitle(user.getUsername()); + return 0; + } - final TextView emailView = (TextView) header.findViewById(R.id.user_email); - if(user.getEmail() != null) { - emailView.setText(user.getEmail()); - } else { - emailView.setVisibility(View.GONE); - } + @Override + public void onItemClicked(User.Setting item) { + + } + + @Override + public void onCreateContextMenu(Menu menu, MenuInflater menuInflater, UpdateView<User.Setting> updateView, User.Setting item) {} - listView.addHeaderView(header); + @Override + public boolean onContextItemSelected(MenuItem menuItem, UpdateView<User.Setting> updateView, User.Setting item) { + return false; } } diff --git a/app/src/main/java/github/daneren2005/dsub/provider/DSubWidgetProvider.java b/app/src/main/java/github/daneren2005/dsub/provider/DSubWidgetProvider.java index 444b6cff..83733618 100644 --- a/app/src/main/java/github/daneren2005/dsub/provider/DSubWidgetProvider.java +++ b/app/src/main/java/github/daneren2005/dsub/provider/DSubWidgetProvider.java @@ -39,7 +39,6 @@ import android.util.Log; import android.view.View; import android.widget.RemoteViews; import github.daneren2005.dsub.R; -import github.daneren2005.dsub.activity.DownloadActivity; import github.daneren2005.dsub.activity.SubsonicActivity; import github.daneren2005.dsub.activity.SubsonicFragmentActivity; import github.daneren2005.dsub.domain.MusicDirectory; @@ -209,9 +208,9 @@ public class DSubWidgetProvider extends AppWidgetProvider { // Set correct drawable for pause state if (playing) { - views.setImageViewResource(R.id.control_play, R.drawable.ic_appwidget_music_pause); + views.setImageViewResource(R.id.control_play, R.drawable.media_pause_dark); } else { - views.setImageViewResource(R.id.control_play, R.drawable.ic_appwidget_music_play); + views.setImageViewResource(R.id.control_play, R.drawable.media_start_dark); } // Set the cover art @@ -270,9 +269,7 @@ public class DSubWidgetProvider extends AppWidgetProvider { /** * Link up various button actions using {@link PendingIntent}. * - * @param playerActive True if player is active in background, which means - * widget click will launch {@link DownloadActivity}, - * otherwise we launch {@link github.daneren2005.dsub.activity.SubsonicFragmentActivity}. + * @param playerActive @param playerActive True if player is active in background. Launch {@link github.daneren2005.dsub.activity.SubsonicFragmentActivity}. */ private void linkButtons(Context context, RemoteViews views, boolean playerActive) { Intent intent = new Intent(context, SubsonicFragmentActivity.class); diff --git a/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java b/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java index 3bc7f2a3..f053c215 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/CachedMusicService.java @@ -51,7 +51,6 @@ import github.daneren2005.dsub.domain.SearchCritera; import github.daneren2005.dsub.domain.SearchResult; import github.daneren2005.dsub.domain.Share; import github.daneren2005.dsub.domain.User; -import github.daneren2005.dsub.util.Pair; import github.daneren2005.dsub.util.SilentBackgroundTask; import github.daneren2005.dsub.util.ProgressListener; import github.daneren2005.dsub.util.TimeLimitedCache; @@ -384,9 +383,9 @@ public class CachedMusicService implements MusicService { } @Override - public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception { + public MusicDirectory getAlbumList(String type, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception { try { - MusicDirectory dir = musicService.getAlbumList(type, size, offset, context, progressListener); + MusicDirectory dir = musicService.getAlbumList(type, size, offset, refresh, context, progressListener); // Do some serialization updates for changes to recently added if ("newest".equals(type) && offset == 0) { @@ -490,6 +489,10 @@ public class CachedMusicService implements MusicService { return dir; } catch(IOException e) { Log.w(TAG, "Failed to refresh album list: ", e); + if(refresh) { + throw e; + } + MusicDirectory dir = FileUtil.deserialize(context, getCacheName(context, type, Integer.toString(offset)), MusicDirectory.class); if(dir == null) { @@ -507,12 +510,17 @@ public class CachedMusicService implements MusicService { } @Override - public MusicDirectory getAlbumList(String type, String extra, int size, int offset, Context context, ProgressListener progressListener) throws Exception { + public MusicDirectory getAlbumList(String type, String extra, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception { try { - MusicDirectory dir = musicService.getAlbumList(type, extra, size, offset, context, progressListener); + MusicDirectory dir = musicService.getAlbumList(type, extra, size, offset, refresh, context, progressListener); FileUtil.serialize(context, dir, getCacheName(context, type + extra, Integer.toString(offset))); return dir; } catch(IOException e) { + Log.w(TAG, "Failed to refresh album list: ", e); + if(refresh) { + throw e; + } + MusicDirectory dir = FileUtil.deserialize(context, getCacheName(context, type + extra, Integer.toString(offset)), MusicDirectory.class); if(dir == null) { diff --git a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java index ae2eb073..211cf0d7 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/DownloadService.java @@ -139,6 +139,7 @@ public class DownloadService extends Service { private boolean removePlayed; private boolean shufflePlay; private boolean artistRadio; + private final List<OnSongChangedListener> onSongChangedListeners = new ArrayList<>(); private long revision; private static DownloadService instance; private String suggestedPlaylistName; @@ -156,6 +157,7 @@ public class DownloadService extends Service { private Timer sleepTimer; private int timerDuration; + private long timerStart; private boolean autoPlayStart = false; private MediaRouteManager mediaRouter; @@ -362,7 +364,6 @@ public class DownloadService extends Service { } } setNextPlaying(); - revision++; } else { int size = size(); int index = getCurrentPlayingIndex(); @@ -378,8 +379,9 @@ public class DownloadService extends Service { if(!autoplay && (size - 1) == index) { setNextPlaying(); } - revision++; } + revision++; + onSongsChanged(); updateRemotePlaylist(); if(shuffle) { @@ -543,6 +545,7 @@ public class DownloadService extends Service { currentPlayingIndex = 0; } revision++; + onSongsChanged(); lifecycleSupport.serializeDownloadQueue(); updateRemotePlaylist(); setNextPlaying(); @@ -601,10 +604,6 @@ public class DownloadService extends Service { return downloadFile; } - public synchronized void clear() { - clear(true); - } - public synchronized void clearBackground() { if(currentDownloading != null && backgroundDownloadList.contains(currentDownloading)) { currentDownloading.cancelDownload(); @@ -666,6 +665,9 @@ public class DownloadService extends Service { return downloadList.size(); } + public synchronized void clear() { + clear(true); + } public synchronized void clear(boolean serialize) { // Delete podcast if fully listened to int position = getPlayerPosition(); @@ -694,7 +696,7 @@ public class DownloadService extends Service { reset(); downloadList.clear(); - revision++; + onSongsChanged(); if (currentDownloading != null && !backgroundDownloadList.contains(currentDownloading)) { currentDownloading.cancelDownload(); currentDownloading = null; @@ -733,12 +735,23 @@ public class DownloadService extends Service { currentPlayingIndex = downloadList.indexOf(currentPlaying); backgroundDownloadList.remove(downloadFile); revision++; + onSongsChanged(); lifecycleSupport.serializeDownloadQueue(); updateRemotePlaylist(); if(downloadFile == nextPlaying) { setNextPlaying(); } } + public synchronized void removeBackground(DownloadFile downloadFile) { + if (downloadFile == currentDownloading && downloadFile != currentPlaying && downloadFile != nextPlaying) { + currentDownloading.cancelDownload(); + currentDownloading = null; + } + + backgroundDownloadList.remove(downloadFile); + revision++; + checkDownloads(); + } public synchronized void delete(List<MusicDirectory.Entry> songs) { for (MusicDirectory.Entry song : songs) { @@ -779,6 +792,7 @@ public class DownloadService extends Service { Util.broadcastNewTrackInfo(this, null); Notifications.hidePlayingNotification(this, this, handler); } + onSongChanged(); } synchronized void setNextPlaying() { @@ -886,11 +900,15 @@ public class DownloadService extends Service { public synchronized void play(int index) { play(index, true); } + public synchronized void play(DownloadFile downloadFile) { + play(downloadList.indexOf(downloadFile)); + } private synchronized void play(int index, boolean start) { play(index, start, 0); } private synchronized void play(int index, boolean start, int position) { int size = this.size(); + cachedPosition = 0; if (index < 0 || index >= size) { reset(); if(index >= size && size != 0) { @@ -1271,6 +1289,7 @@ public class DownloadService extends Service { positionCache.stop(); positionCache = null; } + onStateUpdate(); } private class PositionCache implements Runnable { @@ -1305,6 +1324,7 @@ public class DownloadService extends Service { subtractNextPosition = 0; } } + onSongProgress(); Thread.sleep(1000L); } catch(Exception e) { @@ -1790,6 +1810,11 @@ public class DownloadService extends Service { } }, timerDuration * 60 * 1000); + timerStart = System.currentTimeMillis(); + } + + public int getSleepTimeRemaining() { + return (int) (timerStart + (timerDuration * 60 * 1000) - System.currentTimeMillis()) / 1000; } public void stopSleepTimer() { @@ -1818,6 +1843,10 @@ public class DownloadService extends Service { applyReplayGain(mediaPlayer, currentPlaying); } + public synchronized void swap(boolean mainList, DownloadFile from, DownloadFile to) { + List<DownloadFile> list = mainList ? downloadList : backgroundDownloadList; + swap(mainList, list.indexOf(from), list.indexOf(to)); + } public synchronized void swap(boolean mainList, int from, int to) { List<DownloadFile> list = mainList ? downloadList : backgroundDownloadList; int max = list.size(); @@ -1972,12 +2001,18 @@ public class DownloadService extends Service { } private synchronized void checkRemovePlayed() { + boolean changed = false; SharedPreferences prefs = Util.getPreferences(this); int keepCount = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_KEEP_PLAYED_CNT, "0")); while(currentPlayingIndex > keepCount) { downloadList.remove(0); currentPlayingIndex = downloadList.indexOf(currentPlaying); + changed = true; + } + + if(changed) { revision++; + onSongsChanged(); } } @@ -2015,6 +2050,7 @@ public class DownloadService extends Service { currentPlayingIndex = downloadList.indexOf(currentPlaying); if (revisionBefore != revision) { + onSongsChanged(); updateRemotePlaylist(); } @@ -2056,6 +2092,7 @@ public class DownloadService extends Service { currentPlayingIndex = downloadList.indexOf(currentPlaying); if (revisionBefore != revision) { + onSongsChanged(); updateRemotePlaylist(); } @@ -2323,6 +2360,87 @@ public class DownloadService extends Service { } } + public void addOnSongChangedListener(OnSongChangedListener listener) { + addOnSongChangedListener(listener, false); + } + public void addOnSongChangedListener(OnSongChangedListener listener, boolean run) { + int index = onSongChangedListeners.indexOf(listener); + if(index == -1) { + onSongChangedListeners.add(listener); + } + + if(run) { + onSongsChanged(); + onSongProgress(); + onStateUpdate(); + } + } + public void removeOnSongChangeListener(OnSongChangedListener listener) { + int index = onSongChangedListeners.indexOf(listener); + if(index != -1) { + onSongChangedListeners.remove(index); + } + } + + private void onSongChanged() { + final long atRevision = revision; + for(final OnSongChangedListener listener: onSongChangedListeners) { + handler.post(new Runnable() { + @Override + public void run() { + if(revision == atRevision) { + listener.onSongChanged(currentPlaying, currentPlayingIndex); + } + } + }); + } + + if(playerState != STARTED) { + onSongProgress(); + } + } + private void onSongsChanged() { + final long atRevision = revision; + for(final OnSongChangedListener listener: onSongChangedListeners) { + handler.post(new Runnable() { + @Override + public void run() { + if(revision == atRevision) { + listener.onSongsChanged(downloadList, currentPlaying, currentPlayingIndex); + } + } + }); + } + } + private void onSongProgress() { + final long atRevision = revision; + final Integer duration = getPlayerDuration(); + final boolean isSeekable = isSeekable(); + for(final OnSongChangedListener listener: onSongChangedListeners) { + handler.post(new Runnable() { + @Override + public void run() { + if(revision == atRevision) { + listener.onSongProgress(currentPlaying, cachedPosition, duration, isSeekable); + } + } + }); + } + } + private void onStateUpdate() { + final long atRevision = revision; + for(final OnSongChangedListener listener: onSongChangedListeners) { + handler.post(new Runnable() { + @Override + public void run() { + if(revision == atRevision) { + listener.onStateUpdate(currentPlaying, playerState); + } + } + }); + } + } + private class BufferTask extends SilentBackgroundTask<Void> { private final DownloadFile downloadFile; private final int position; @@ -2426,4 +2544,11 @@ public class DownloadService extends Service { return "CheckCompletionTask (" + downloadFile + ")"; } } + + public interface OnSongChangedListener { + void onSongChanged(DownloadFile currentPlaying, int currentPlayingIndex); + void onSongsChanged(List<DownloadFile> songs, DownloadFile currentPlaying, int currentPlayingIndex); + void onSongProgress(DownloadFile currentPlaying, int millisPlayed, Integer duration, boolean isSeekable); + void onStateUpdate(DownloadFile downloadFile, PlayerState playerState); + } } diff --git a/app/src/main/java/github/daneren2005/dsub/service/MusicService.java b/app/src/main/java/github/daneren2005/dsub/service/MusicService.java index 4d014462..0cc8d484 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/MusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/MusicService.java @@ -90,9 +90,9 @@ public interface MusicService { void scrobble(String id, boolean submission, Context context, ProgressListener progressListener) throws Exception; - MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception; + MusicDirectory getAlbumList(String type, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception; - MusicDirectory getAlbumList(String type, String extra, int size, int offset, Context context, ProgressListener progressListener) throws Exception; + MusicDirectory getAlbumList(String type, String extra, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception; MusicDirectory getRandomSongs(int size, String artistId, Context context, ProgressListener progressListener) throws Exception; MusicDirectory getRandomSongs(int size, String folder, String genre, String startYear, String endYear, Context context, ProgressListener progressListener) throws Exception; diff --git a/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java b/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java index b4105d07..82716fa8 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/OfflineMusicService.java @@ -380,8 +380,46 @@ public class OfflineMusicService implements MusicService { for(File file: fileList) { if(FileUtil.isPlaylistFile(file)) { String id = file.getName(); - String filename = server + ": " + FileUtil.getBaseName(id); - Playlist playlist = new Playlist(server, filename); + String filename = FileUtil.getBaseName(id); + String name = server + ": " + filename; + Playlist playlist = new Playlist(server, name); + playlist.setComment(filename); + + Reader reader = null; + BufferedReader buffer = null; + try { + int songCount = 0; + reader = new FileReader(file); + buffer = new BufferedReader(reader); + + String line = buffer.readLine(); + while( (line = buffer.readLine()) != null ){ + // No matter what, end file can't have .complete in it + line = line.replace(".complete", ""); + File entryFile = new File(line); + + // Don't add file to playlist if it doesn't exist as cached or pinned! + File checkFile = entryFile; + if(!checkFile.exists()) { + // If normal file doens't exist, check if .complete version does + checkFile = new File(entryFile.getParent(), FileUtil.getBaseName(entryFile.getName()) + + ".complete." + FileUtil.getExtension(entryFile.getName())); + } + + String entryName = getName(entryFile); + if(checkFile.exists() && entryName != null){ + songCount++; + } + } + + playlist.setSongCount(Integer.toString(songCount)); + } catch(Exception e) { + Log.w(TAG, "Failed to count songs in playlist", e); + } finally { + Util.close(buffer); + Util.close(reader); + } + playlists.add(playlist); } } @@ -523,12 +561,12 @@ public class OfflineMusicService implements MusicService { } @Override - public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception { + public MusicDirectory getAlbumList(String type, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception { throw new OfflineException(ERRORMSG); } @Override - public MusicDirectory getAlbumList(String type, String extra, int size, int offset, Context context, ProgressListener progressListener) throws Exception { + public MusicDirectory getAlbumList(String type, String extra, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception { throw new OfflineException(ERRORMSG); } @@ -684,10 +722,16 @@ public class OfflineMusicService implements MusicService { for(File file: dir.listFiles()) { BufferedReader br = new BufferedReader(new FileReader(file)); while ((line = br.readLine()) != null && !"".equals(line)) { + String[] parts = line.split("\t"); + PodcastChannel channel = new PodcastChannel(); - channel.setId(line); - channel.setName(line); + channel.setId(parts[0]); + channel.setName(parts[0]); channel.setStatus("completed"); + + if(parts.length > 1) { + channel.setUrl(parts[1]); + } if(FileUtil.getPodcastDirectory(context, channel).exists() && !channels.contains(channel)) { channels.add(channel); diff --git a/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java b/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java index 459c8c9e..78a7ec51 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java +++ b/app/src/main/java/github/daneren2005/dsub/service/RESTMusicService.java @@ -522,7 +522,7 @@ public class RESTMusicService implements MusicService { } @Override - public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception { + public MusicDirectory getAlbumList(String type, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception { List<String> names = new ArrayList<String>(); List<Object> values = new ArrayList<Object>(); @@ -553,7 +553,7 @@ public class RESTMusicService implements MusicService { } @Override - public MusicDirectory getAlbumList(String type, String extra, int size, int offset, Context context, ProgressListener progressListener) throws Exception { + public MusicDirectory getAlbumList(String type, String extra, int size, int offset, boolean refresh, Context context, ProgressListener progressListener) throws Exception { checkServerVersion(context, "1.10.1", "This type of album list is not supported"); List<String> names = new ArrayList<String>(); @@ -1204,7 +1204,7 @@ public class RESTMusicService implements MusicService { String content = ""; for(PodcastChannel channel: channels) { - content += channel.getName() + "\n"; + content += channel.getName() + "\t" + channel.getUrl() + "\n"; } File file = FileUtil.getPodcastFile(context, Util.getServerName(context, getInstance(context))); diff --git a/app/src/main/java/github/daneren2005/dsub/service/parser/PlaylistsParser.java b/app/src/main/java/github/daneren2005/dsub/service/parser/PlaylistsParser.java index 6f01d510..69e5af64 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/parser/PlaylistsParser.java +++ b/app/src/main/java/github/daneren2005/dsub/service/parser/PlaylistsParser.java @@ -22,7 +22,6 @@ import android.content.Context; import github.daneren2005.dsub.domain.Playlist; import github.daneren2005.dsub.util.ProgressListener; -import github.daneren2005.dsub.adapter.PlaylistAdapter; import org.xmlpull.v1.XmlPullParser; import java.io.Reader; @@ -64,7 +63,7 @@ public class PlaylistsParser extends AbstractParser { validate(); - return PlaylistAdapter.PlaylistComparator.sort(result); + return Playlist.PlaylistComparator.sort(result); } }
\ No newline at end of file diff --git a/app/src/main/java/github/daneren2005/dsub/service/sync/MostRecentSyncAdapter.java b/app/src/main/java/github/daneren2005/dsub/service/sync/MostRecentSyncAdapter.java index f7a8634e..8da83be1 100644 --- a/app/src/main/java/github/daneren2005/dsub/service/sync/MostRecentSyncAdapter.java +++ b/app/src/main/java/github/daneren2005/dsub/service/sync/MostRecentSyncAdapter.java @@ -23,18 +23,14 @@ import android.annotation.TargetApi; import android.content.Context; import android.util.Log; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.domain.PodcastEpisode; -import github.daneren2005.dsub.service.DownloadFile; import github.daneren2005.dsub.util.FileUtil; import github.daneren2005.dsub.util.Notifications; import github.daneren2005.dsub.util.SyncUtil; -import github.daneren2005.dsub.util.SyncUtil.SyncSet; import github.daneren2005.dsub.util.Util; /** @@ -56,7 +52,7 @@ public class MostRecentSyncAdapter extends SubsonicSyncAdapter { public void onExecuteSync(Context context, int instance) { try { ArrayList<String> syncedList = SyncUtil.getSyncedMostRecent(context, instance); - MusicDirectory albumList = musicService.getAlbumList("newest", 20, 0, context, null); + MusicDirectory albumList = musicService.getAlbumList("newest", 20, 0, tagBrowsing, context, null); List<String> updated = new ArrayList<String>(); boolean firstRun = false; if(syncedList.size() == 0) { diff --git a/app/src/main/java/github/daneren2005/dsub/util/Constants.java b/app/src/main/java/github/daneren2005/dsub/util/Constants.java index b3dd173b..5c477ad9 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Constants.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Constants.java @@ -173,6 +173,8 @@ public final class Constants { public static final String MAIN_BACK_STACK = "backStackIds"; public static final String MAIN_BACK_STACK_SIZE = "backStackIdsSize"; + public static final String MAIN_NOW_PLAYING = "nowPlayingId"; + public static final String MAIN_SLIDE_PANEL_STATE = "slidePanelState"; public static final String FRAGMENT_LIST = "fragmentList"; public static final String FRAGMENT_LIST2 = "fragmentList2"; public static final String FRAGMENT_EXTRA = "fragmentExtra"; diff --git a/app/src/main/java/github/daneren2005/dsub/util/DrawableTint.java b/app/src/main/java/github/daneren2005/dsub/util/DrawableTint.java new file mode 100644 index 00000000..2da72579 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/util/DrawableTint.java @@ -0,0 +1,90 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.util; + +import android.content.Context; +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.TypedValue; + +import java.util.HashMap; +import java.util.Map; +import java.util.WeakHashMap; + +import github.daneren2005.dsub.R; + +public class DrawableTint { + private static final Map<Integer, Integer> attrMap = new HashMap<>(); + private static final WeakHashMap<Integer, Drawable> tintedDrawables = new WeakHashMap<>(); + + public static Drawable getTintedDrawable(Context context, @DrawableRes int drawableRes) { + return getTintedDrawable(context, drawableRes, R.attr.colorAccent); + } + public static Drawable getTintedDrawable(Context context, @DrawableRes int drawableRes, @AttrRes int colorAttr) { + if(tintedDrawables.containsKey(drawableRes)) { + return tintedDrawables.get(drawableRes); + } + + int color = getColorRes(context, colorAttr); + Drawable background = context.getResources().getDrawable(drawableRes); + background.setColorFilter(color, PorterDuff.Mode.SRC_IN); + tintedDrawables.put(drawableRes, background); + return background; + } + public static int getColorRes(Context context, @AttrRes int colorAttr) { + int color; + if(attrMap.containsKey(colorAttr)) { + color = attrMap.get(colorAttr); + } else { + TypedValue typedValue = new TypedValue(); + Resources.Theme theme = context.getTheme(); + theme.resolveAttribute(colorAttr, typedValue, true); + color = typedValue.data; + attrMap.put(colorAttr, color); + } + + return color; + } + public static int getDrawableRes(Context context, @AttrRes int drawableAttr) { + if(attrMap.containsKey(drawableAttr)) { + return attrMap.get(drawableAttr); + } else { + int[] attrs = new int[]{drawableAttr}; + TypedArray typedArray = context.obtainStyledAttributes(attrs); + @DrawableRes int drawableRes = typedArray.getResourceId(0, 0); + typedArray.recycle(); + attrMap.put(drawableAttr, drawableRes); + return drawableRes; + } + } + public static Drawable getTintedAttrDrawable(Context context, @AttrRes int drawableAttr, @AttrRes int colorAttr) { + if(tintedDrawables.containsKey(drawableAttr)) { + return getTintedDrawable(context, attrMap.get(drawableAttr), colorAttr); + } + + @DrawableRes int drawableRes = getDrawableRes(context, drawableAttr); + return getTintedDrawable(context, drawableRes, colorAttr); + } + + public static void wipeTintCache() { + attrMap.clear(); + tintedDrawables.clear(); + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/util/FileUtil.java b/app/src/main/java/github/daneren2005/dsub/util/FileUtil.java index 990eae06..332f775c 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/FileUtil.java +++ b/app/src/main/java/github/daneren2005/dsub/util/FileUtil.java @@ -182,19 +182,25 @@ public class FileUtil { } public static File getAlbumArtFile(Context context, MusicDirectory.Entry entry) { - File albumDir = getAlbumDirectory(context, entry); - File artFile; - File albumFile = getAlbumArtFile(albumDir); - File hexFile = getHexAlbumArtFile(context, albumDir); - if(albumDir.exists()) { - if(hexFile.exists()) { - hexFile.renameTo(albumFile); + if(entry.getId().indexOf("pl-") == -1) { + File albumDir = getAlbumDirectory(context, entry); + File artFile; + File albumFile = getAlbumArtFile(albumDir); + File hexFile = getHexAlbumArtFile(context, albumDir); + if (albumDir.exists()) { + if (hexFile.exists()) { + hexFile.renameTo(albumFile); + } + artFile = albumFile; + } else { + artFile = hexFile; } - artFile = albumFile; + return artFile; } else { - artFile = hexFile; + File playlistDir = getAlbumArtDirectory(context); + Log.d(TAG, entry.getTitle() + " => " + Util.md5Hex("pl-" + entry.getTitle())); + return new File(playlistDir, Util.md5Hex("pl-" + entry.getTitle()) + ".jpeg"); } - return artFile; } public static File getAlbumArtFile(File albumDir) { @@ -741,23 +747,28 @@ public class FileUtil { return index == -1 ? name : name.substring(0, index); } - public static Pair<Long, Long> getUsedSize(Context context, File file) { + public static Long[] getUsedSize(Context context, File file) { long number = 0L; + long permanent = 0L; long size = 0L; if(file.isFile()) { if(isMediaFile(file)) { - return new Pair<Long, Long>(1L, file.length()); + if(file.getAbsolutePath().indexOf(".complete") == -1) { + permanent++; + } + return new Long[] {1L, permanent, file.length()}; } else { - return new Pair<Long, Long>(0L, 0L); + return new Long[] {0L, 0L, 0L}; } } else { for (File child : FileUtil.listFiles(file)) { - Pair<Long, Long> pair = getUsedSize(context, child); - number += pair.getFirst(); - size += pair.getSecond(); + Long[] pair = getUsedSize(context, child); + number += pair[0]; + permanent += pair[1]; + size += pair[2]; } - return new Pair<Long, Long>(number, size); + return new Long[] {number, permanent, size}; } } diff --git a/app/src/main/java/github/daneren2005/dsub/util/ImageLoader.java b/app/src/main/java/github/daneren2005/dsub/util/ImageLoader.java index 7ba2064b..8b027d70 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/ImageLoader.java +++ b/app/src/main/java/github/daneren2005/dsub/util/ImageLoader.java @@ -42,6 +42,7 @@ import android.widget.TextView; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.ArtistInfo; import github.daneren2005.dsub.domain.MusicDirectory; +import github.daneren2005.dsub.domain.Playlist; import github.daneren2005.dsub.domain.ServerInfo; import github.daneren2005.dsub.service.MusicService; import github.daneren2005.dsub.service.MusicServiceFactory; @@ -190,8 +191,11 @@ public class ImageLoader { } public SilentBackgroundTask loadImage(View view, MusicDirectory.Entry entry, boolean large, boolean crossfade) { - // TODO: If we know this a artist, try to load artist info instead int size = large ? imageSizeLarge : imageSizeDefault; + return loadImage(view, entry, large, size, crossfade); + } + public SilentBackgroundTask loadImage(View view, MusicDirectory.Entry entry, boolean large, int size, boolean crossfade) { + // TODO: If we know this a artist, try to load artist info instead if(entry != null && !entry.isAlbum() && ServerInfo.checkServerVersion(context, "1.11") && !Util.isOffline(context)) { SilentBackgroundTask task = new ArtistImageTask(view.getContext(), entry, size, imageSizeLarge, large, view, crossfade); task.execute(); @@ -222,7 +226,7 @@ public class ImageLoader { } if (!large) { - setImage(view, Util.createDrawableFromBitmap(context, null), false); + setImage(view, null, false); } ImageTask task = new ViewImageTask(view.getContext(), entry, size, imageSizeLarge, large, view, crossfade); task.execute(); @@ -246,6 +250,7 @@ public class ImageLoader { setImage(view, drawable, true); return null; } + setImage(view, null, false); SilentBackgroundTask<Void> task = new ViewUrlTask(view.getContext(), view, url, size); task.execute(); @@ -274,18 +279,42 @@ public class ImageLoader { } public SilentBackgroundTask<Void> loadAvatar(Context context, ImageView view, String username) { + if(username == null) { + view.setImageResource(R.drawable.ic_social_person); + return null; + } + Bitmap bitmap = cache.get(username); if (bitmap != null && !bitmap.isRecycled()) { Drawable drawable = Util.createDrawableFromBitmap(this.context, bitmap); view.setImageDrawable(drawable); return null; } + view.setImageDrawable(null); SilentBackgroundTask<Void> task = new AvatarTask(context, view, username); task.execute(); return task; } + public SilentBackgroundTask loadImage(View view, Playlist playlist, boolean large, boolean crossfade) { + MusicDirectory.Entry entry = new MusicDirectory.Entry(); + String id; + if(Util.isOffline(context)) { + id = "pl-" + playlist.getName(); + entry.setTitle(playlist.getComment()); + } else { + id = "pl-" + playlist.getId(); + entry.setTitle(playlist.getName()); + } + entry.setId(id); + entry.setCoverArt(id); + // So this isn't treated as a artist + entry.setParent(""); + + return loadImage(view, entry, large, crossfade); + } + private String getKey(String coverArtId, int size) { return coverArtId + size; } @@ -379,12 +408,16 @@ public class ImageLoader { try { MusicService musicService = MusicServiceFactory.getMusicService(mContext); Bitmap bitmap = musicService.getCoverArt(mContext, mEntry, mSize, null, this); - String key = getKey(mEntry.getCoverArt(), mSize); - cache.put(key, bitmap); - // Make sure key is the most recently "used" - cache.get(key); - if(mIsNowPlaying) { - nowPlaying = bitmap; + if(bitmap != null) { + String key = getKey(mEntry.getCoverArt(), mSize); + cache.put(key, bitmap); + // Make sure key is the most recently "used" + cache.get(key); + if (mIsNowPlaying) { + nowPlaying = bitmap; + } + } else { + bitmap = getUnknownImage(mEntry, mSize); } mDrawable = Util.createDrawableFromBitmap(mContext, bitmap); @@ -582,7 +615,6 @@ public class ImageLoader { } } catch (Throwable x) { Log.e(TAG, "Failed to download album art.", x); - cancelled.set(true); } return null; @@ -592,6 +624,8 @@ public class ImageLoader { protected void done(Void result) { if(mDrawable != null) { mView.setImageDrawable(mDrawable); + } else { + mView.setImageResource(R.drawable.ic_social_person); } } } diff --git a/app/src/main/java/github/daneren2005/dsub/util/MenuUtil.java b/app/src/main/java/github/daneren2005/dsub/util/MenuUtil.java new file mode 100644 index 00000000..cd899bb4 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/util/MenuUtil.java @@ -0,0 +1,55 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.util; + +import android.content.Context; +import android.content.SharedPreferences; +import android.view.Menu; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.ServerInfo; + +public final class MenuUtil { + public static void hideMenuItems(Context context, Menu menu) { + if(!ServerInfo.checkServerVersion(context, "1.8")) { + menu.setGroupVisible(R.id.server_1_8, false); + menu.setGroupVisible(R.id.hide_star, false); + } + if(!ServerInfo.checkServerVersion(context, "1.9")) { + menu.setGroupVisible(R.id.server_1_9, false); + } + if(!ServerInfo.checkServerVersion(context, "1.10.1")) { + menu.setGroupVisible(R.id.server_1_10, false); + } + + SharedPreferences prefs = Util.getPreferences(context); + if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_PLAY_NEXT, true)) { + menu.setGroupVisible(R.id.hide_play_next, false); + } + if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_PLAY_LAST, true)) { + menu.setGroupVisible(R.id.hide_play_last, false); + } + if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_STAR, true)) { + menu.setGroupVisible(R.id.hide_star, false); + } + if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_SHARED, true) || !UserUtil.canShare()) { + menu.setGroupVisible(R.id.hide_share, false); + } + if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_RATING, true)) { + menu.setGroupVisible(R.id.hide_rating, false); + } + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/util/Notifications.java b/app/src/main/java/github/daneren2005/dsub/util/Notifications.java index d078d77e..ac812a53 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Notifications.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Notifications.java @@ -148,10 +148,10 @@ public final class Notifications { 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_play); + rv.setImageViewResource(R.id.control_pause, playing ? R.drawable.notification_pause : R.drawable.notification_start); } else { - rv.setImageViewResource(R.id.control_previous, playing ? R.drawable.notification_pause : R.drawable.notification_play); - rv.setImageViewResource(R.id.control_pause, R.drawable.notification_next); + rv.setImageViewResource(R.id.control_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); } } @@ -260,10 +260,9 @@ public final class Notifications { cancelPI); Intent notificationIntent = new Intent(context, SubsonicFragmentActivity.class); - notificationIntent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true); notificationIntent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW, true); notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP); - builder.setContentIntent(PendingIntent.getActivity(context, 1, notificationIntent, 0)); + builder.setContentIntent(PendingIntent.getActivity(context, 2, notificationIntent, 0)); final Notification notification = builder.build(); downloadShowing = true; diff --git a/app/src/main/java/github/daneren2005/dsub/util/UserUtil.java b/app/src/main/java/github/daneren2005/dsub/util/UserUtil.java index 29618424..d758c4c9 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/UserUtil.java +++ b/app/src/main/java/github/daneren2005/dsub/util/UserUtil.java @@ -16,18 +16,22 @@ package github.daneren2005.dsub.util; import android.app.Activity; -import android.app.AlertDialog; +import android.support.v7.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.support.v7.app.ActionBarActivity; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.util.Log; import android.view.View; +import android.view.WindowManager; import android.widget.ArrayAdapter; import android.widget.ListView; import android.widget.TextView; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.adapter.SectionAdapter; import github.daneren2005.dsub.domain.User; import github.daneren2005.dsub.fragments.SubsonicFragment; import github.daneren2005.dsub.service.DownloadService; @@ -182,6 +186,7 @@ public final class UserUtil { .setCancelable(true); AlertDialog dialog = builder.create(); + dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); dialog.show(); } } @@ -247,7 +252,6 @@ public final class UserUtil { protected Void doInBackground() throws Throwable { MusicService musicService = MusicServiceFactory.getMusicService(context); musicService.updateUser(user, context, null); - user.setSettings(user.getSettings()); return null; } @@ -326,7 +330,7 @@ public final class UserUtil { }); } - public static void deleteUser(final Context context, final User user, final ArrayAdapter adapter) { + public static void deleteUser(final Context context, final User user, final SectionAdapter adapter) { Util.confirmDialog(context, R.string.common_delete, user.getUsername(), new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { @@ -341,8 +345,7 @@ public final class UserUtil { @Override protected void done(Void v) { if(adapter != null) { - adapter.remove(user); - adapter.notifyDataSetChanged(); + adapter.removeItem(user); } Util.toast(context, context.getResources().getString(R.string.admin_delete_user_success, user.getUsername())); @@ -378,8 +381,11 @@ public final class UserUtil { final TextView usernameView = (TextView) layout.findViewById(R.id.username); final TextView emailView = (TextView) layout.findViewById(R.id.email); final TextView passwordView = (TextView) layout.findViewById(R.id.password); - final ListView listView = (ListView) layout.findViewById(R.id.settings_list); - listView.setAdapter(new SettingsAdapter(context, user, true)); + final RecyclerView recyclerView = (RecyclerView) layout.findViewById(R.id.settings_list); + LinearLayoutManager layoutManager = new LinearLayoutManager(context); + layoutManager.setOrientation(LinearLayoutManager.VERTICAL); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setAdapter(new SettingsAdapter(context, user, null, true)); AlertDialog.Builder builder = new AlertDialog.Builder(context); builder.setTitle(R.string.menu_add_user) diff --git a/app/src/main/java/github/daneren2005/dsub/util/Util.java b/app/src/main/java/github/daneren2005/dsub/util/Util.java index 032facd6..ff962488 100644 --- a/app/src/main/java/github/daneren2005/dsub/util/Util.java +++ b/app/src/main/java/github/daneren2005/dsub/util/Util.java @@ -19,7 +19,8 @@ package github.daneren2005.dsub.util; import android.annotation.TargetApi; import android.app.Activity; -import android.app.AlertDialog; +import android.support.annotation.StringRes; +import android.support.v7.app.AlertDialog; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; @@ -45,12 +46,18 @@ import android.text.method.LinkMovementMethod; import android.text.util.Linkify; import android.util.Log; import android.view.Gravity; +import android.widget.ArrayAdapter; +import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.activity.SettingsActivity; +import github.daneren2005.dsub.activity.SubsonicFragmentActivity; +import github.daneren2005.dsub.adapter.DetailsAdapter; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.PlayerState; import github.daneren2005.dsub.domain.RepeatMode; +import github.daneren2005.dsub.domain.ServerInfo; import github.daneren2005.dsub.receiver.MediaButtonIntentReceiver; import github.daneren2005.dsub.service.DownloadService; @@ -68,10 +75,14 @@ import java.lang.reflect.Method; import java.security.MessageDigest; import java.text.DecimalFormat; import java.text.NumberFormat; +import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Arrays; import java.util.Date; +import java.util.List; import java.util.Locale; +import java.util.TimeZone; /** * @author Sindre Mehus @@ -249,6 +260,32 @@ public final class Util { SharedPreferences prefs = getPreferences(context); return prefs.getString(Constants.PREFERENCES_KEY_THEME, null); } + public static int getThemeRes(Context context) { + return getThemeRes(context, getTheme(context)); + } + public static int getThemeRes(Context context, String theme) { + if(context instanceof SubsonicFragmentActivity || context instanceof SettingsActivity) { + if ("dark".equals(theme)) { + return R.style.Theme_DSub_Dark_No_Actionbar; + } else if ("black".equals(theme)) { + return R.style.Theme_DSub_Black_No_Actionbar; + } else if ("holo".equals(theme)) { + return R.style.Theme_DSub_Holo_No_Actionbar; + } else { + return R.style.Theme_DSub_Light_No_Actionbar; + } + } else { + if ("dark".equals(theme)) { + return R.style.Theme_DSub_Dark; + } else if ("black".equals(theme)) { + return R.style.Theme_DSub_Black; + } else if ("holo".equals(theme)) { + return R.style.Theme_DSub_Holo; + } else { + return R.style.Theme_DSub_Light; + } + } + } public static void setTheme(Context context, String theme) { SharedPreferences.Editor editor = getPreferences(context).edit(); editor.putString(Constants.PREFERENCES_KEY_THEME, theme); @@ -256,15 +293,7 @@ public final class Util { } public static void applyTheme(Context context, String theme) { - if ("dark".equals(theme)) { - context.setTheme(R.style.Theme_DSub_Dark); - } else if ("black".equals(theme)) { - context.setTheme(R.style.Theme_DSub_Black); - } else if ("holo".equals(theme)) { - context.setTheme(R.style.Theme_DSub_Holo); - } else { - context.setTheme(R.style.Theme_DSub_Light); - } + context.setTheme(getThemeRes(context, theme)); SharedPreferences prefs = Util.getPreferences(context); if(prefs.getBoolean(Constants.PREFERENCES_KEY_OVERRIDE_SYSTEM_LANGUAGE, false)) { @@ -276,7 +305,7 @@ public final class Util { public static boolean getDisplayTrack(Context context) { SharedPreferences prefs = getPreferences(context); - return prefs.getBoolean(Constants.PREFERENCES_KEY_DISPLAY_TRACK, false); + return prefs.getBoolean(Constants.PREFERENCES_KEY_DISPLAY_TRACK, true); } public static int getMaxBitrate(Context context) { @@ -809,6 +838,19 @@ public final class Util { return builder.toString(); } + public static String formatDate(Context context, String dateString) { + try { + boolean isDateNormalized = ServerInfo.checkServerVersion(context, "1.11"); + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH); + if (isDateNormalized) { + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + } + + return formatDate(dateFormat.parse(dateString)); + } catch(ParseException e) { + return dateString; + } + } public static String formatDate(Date date) { if(date == null) { return "Never"; @@ -1101,6 +1143,32 @@ public final class Util { ((TextView)dialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance()); } + public static void showDetailsDialog(Context context, @StringRes int title, List<Integer> headers, List<String> details) { + List<String> headerStrings = new ArrayList<>(); + for(@StringRes Integer res: headers) { + headerStrings.add(context.getResources().getString(res)); + } + showDetailsDialog(context, context.getResources().getString(title), headerStrings, details); + } + public static void showDetailsDialog(Context context, String title, List<String> headers, List<String> details) { + ListView listView = new ListView(context); + listView.setAdapter(new DetailsAdapter(context, R.layout.details_item, headers, details)); + listView.setDivider(null); + listView.setScrollbarFadingEnabled(false); + + new AlertDialog.Builder(context) + // .setIcon(android.R.drawable.ic_dialog_info) + .setTitle(title) + .setView(listView) + .setPositiveButton(R.string.common_close, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int i) { + dialog.dismiss(); + } + }) + .show(); + } + public static void sleepQuietly(long millis) { try { Thread.sleep(millis); @@ -1141,15 +1209,6 @@ public final class Util { } } - public static int getAttribute(Context context, int attr) { - int res; - int[] attrs = new int[] {attr}; - TypedArray typedArray = context.obtainStyledAttributes(attrs); - res = typedArray.getResourceId(0, 0); - typedArray.recycle(); - return res; - } - public static void registerMediaButtonEventReceiver(Context context) { // Only do it if enabled in the settings. diff --git a/app/src/main/java/github/daneren2005/dsub/view/AlbumCell.java b/app/src/main/java/github/daneren2005/dsub/view/AlbumCell.java deleted file mode 100644 index 8707ece7..00000000 --- a/app/src/main/java/github/daneren2005/dsub/view/AlbumCell.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - This file is part of Subsonic. - Subsonic is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - Subsonic is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with Subsonic. If not, see <http://www.gnu.org/licenses/>. - Copyright 2014 (C) Scott Jackson -*/ - -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.RatingBar; -import android.widget.TextView; - -import java.io.File; - -import github.daneren2005.dsub.R; -import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.ImageLoader; - -public class AlbumCell extends UpdateView { - private static final String TAG = AlbumCell.class.getSimpleName(); - - private Context context; - private MusicDirectory.Entry album; - private File file; - - private View coverArtView; - private TextView titleView; - private TextView artistView; - private boolean showArtist = true; - - public AlbumCell(Context context) { - super(context); - this.context = context; - LayoutInflater.from(context).inflate(R.layout.album_cell_item, this, true); - - coverArtView = findViewById(R.id.album_coverart); - titleView = (TextView) findViewById(R.id.album_title); - artistView = (TextView) findViewById(R.id.album_artist); - - ratingBar = (RatingBar) findViewById(R.id.album_rating); - ratingBar.setFocusable(false); - starButton = (ImageButton) findViewById(R.id.album_star); - starButton.setFocusable(false); - moreButton = (ImageView) findViewById(R.id.album_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); - } - - public void setShowArtist(boolean showArtist) { - this.showArtist = showArtist; - } - - protected void setObjectImpl(Object obj1, Object obj2) { - this.album = (MusicDirectory.Entry) obj1; - titleView.setText(album.getAlbumDisplay()); - String artist = ""; - if(showArtist) { - artist = album.getArtist(); - if (artist == null) { - artist = ""; - } - if (album.getYear() != null) { - artist += " - " + album.getYear(); - } - } else if(album.getYear() != null) { - artist += album.getYear(); - } - artistView.setText(album.getArtist() == null ? "" : artist); - imageTask = ((ImageLoader)obj2).loadImage(coverArtView, album, false, true); - file = null; - } - - @Override - protected void updateBackground() { - if(file == null) { - file = FileUtil.getAlbumDirectory(context, album); - } - - exists = file.exists(); - isStarred = album.isStarred(); - isRated = album.getRating(); - } - - public MusicDirectory.Entry getEntry() { - return album; - } - - public File getFile() { - return file; - } -} diff --git a/app/src/main/java/github/daneren2005/dsub/view/AlbumListCountView.java b/app/src/main/java/github/daneren2005/dsub/view/AlbumListCountView.java new file mode 100644 index 00000000..1ae9ef8e --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/view/AlbumListCountView.java @@ -0,0 +1,130 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.view; + +import android.content.Context; +import android.content.SharedPreferences; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; + +import java.util.ArrayList; + +import github.daneren2005.dsub.R; +import github.daneren2005.dsub.domain.MusicDirectory; +import github.daneren2005.dsub.service.MusicService; +import github.daneren2005.dsub.service.MusicServiceFactory; +import github.daneren2005.dsub.util.Constants; +import github.daneren2005.dsub.util.FileUtil; +import github.daneren2005.dsub.util.Util; + +public class AlbumListCountView extends UpdateView2<Integer, Void> { + private final String TAG = AlbumListCountView.class.getSimpleName(); + + private TextView titleView; + private TextView countView; + private int startCount; + private int count = 0; + + public AlbumListCountView(Context context) { + super(context, false); + this.context = context; + LayoutInflater.from(context).inflate(R.layout.basic_count_item, this, true); + + titleView = (TextView) findViewById(R.id.basic_count_name); + countView = (TextView) findViewById(R.id.basic_count_count); + } + + protected void setObjectImpl(Integer albumListString, Void dummy) { + titleView.setText(albumListString); + + SharedPreferences prefs = Util.getPreferences(context); + startCount = prefs.getInt(Constants.PREFERENCES_KEY_RECENT_COUNT + Util.getActiveServer(context), 0); + count = startCount; + update(); + } + + @Override + protected void updateBackground() { + try { + String recentAddedFile = Util.getCacheName(context, "recent_count"); + ArrayList<String> recents = FileUtil.deserialize(context, recentAddedFile, ArrayList.class); + if (recents == null) { + recents = new ArrayList<String>(); + } + + MusicService musicService = MusicServiceFactory.getMusicService(context); + MusicDirectory recentlyAdded = musicService.getAlbumList("newest", 20, 0, false, context, null); + + // If first run, just put everything in it and return 0 + boolean firstRun = recents.isEmpty(); + + // Count how many new albums are in the list + count = 0; + for (MusicDirectory.Entry album : recentlyAdded.getChildren()) { + if (!recents.contains(album.getId())) { + recents.add(album.getId()); + count++; + } + } + + // Keep recents list from growing infinitely + while (recents.size() > 40) { + recents.remove(0); + } + FileUtil.serialize(context, recents, recentAddedFile); + + if (!firstRun) { + // Add the old count which will get cleared out after viewing recents + count += startCount; + SharedPreferences.Editor editor = Util.getPreferences(context).edit(); + editor.putInt(Constants.PREFERENCES_KEY_RECENT_COUNT + Util.getActiveServer(context), count); + editor.commit(); + } + } catch(Exception e) { + Log.w(TAG, "Failed to refresh most recent count", e); + } + } + + @Override + protected void update() { + // Update count display with appropriate information + if(count <= 0) { + countView.setVisibility(View.GONE); + } else { + String displayName; + if(count < 10) { + displayName = "0" + count; + } else { + displayName = "" + count; + } + + countView.setText(displayName); + countView.setVisibility(View.VISIBLE); + } + } + + @Override + public void onClick() { + SharedPreferences.Editor editor = Util.getPreferences(context).edit(); + editor.putInt(Constants.PREFERENCES_KEY_RECENT_COUNT + Util.getActiveServer(context), 0); + editor.commit(); + + count = 0; + update(); + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/view/AlbumView.java b/app/src/main/java/github/daneren2005/dsub/view/AlbumView.java index bd54ea1e..e521babf 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/AlbumView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/AlbumView.java @@ -16,10 +16,10 @@ Copyright 2009 (C) Sindre Mehus */ + package github.daneren2005.dsub.view; import android.content.Context; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageButton; @@ -30,75 +30,76 @@ import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.util.FileUtil; import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.util.Util; + import java.io.File; -import java.util.List; -/** - * Used to display albums in a {@code ListView}. - * - * @author Sindre Mehus - */ -public class AlbumView extends UpdateView { +public class AlbumView extends UpdateView2<MusicDirectory.Entry, ImageLoader> { private static final String TAG = AlbumView.class.getSimpleName(); - private Context context; - private MusicDirectory.Entry album; private File file; - + private View coverArtView; private TextView titleView; private TextView artistView; - private View coverArtView; + private boolean showArtist = true; - public AlbumView(Context context) { + public AlbumView(Context context, boolean cell) { super(context); - this.context = context; - LayoutInflater.from(context).inflate(R.layout.album_list_item, this, true); + if(cell) { + LayoutInflater.from(context).inflate(R.layout.album_cell_item, this, true); + } else { + LayoutInflater.from(context).inflate(R.layout.album_list_item, this, true); + } + + coverArtView = findViewById(R.id.album_coverart); titleView = (TextView) findViewById(R.id.album_title); artistView = (TextView) findViewById(R.id.album_artist); - coverArtView = findViewById(R.id.album_coverart); + ratingBar = (RatingBar) findViewById(R.id.album_rating); + ratingBar.setFocusable(false); starButton = (ImageButton) findViewById(R.id.album_star); starButton.setFocusable(false); + moreButton = (ImageView) findViewById(R.id.more_button); - moreButton = (ImageView) findViewById(R.id.album_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); + checkable = true; + } + + public void setShowArtist(boolean showArtist) { + this.showArtist = showArtist; } - protected void setObjectImpl(Object obj1, Object obj2) { - this.album = (MusicDirectory.Entry) obj1; + protected void setObjectImpl(MusicDirectory.Entry album, ImageLoader imageLoader) { titleView.setText(album.getAlbumDisplay()); - String artist = album.getArtist(); - if(artist == null) { - artist = ""; - } - if(album.getYear() != null) { - artist += " - " + album.getYear(); + String artist = ""; + if(showArtist) { + artist = album.getArtist(); + if (artist == null) { + artist = ""; + } + if (album.getYear() != null) { + artist += " - " + album.getYear(); + } + } else if(album.getYear() != null) { + artist += album.getYear(); } - artistView.setText(artist); - artistView.setVisibility(album.getArtist() == null ? View.GONE : View.VISIBLE); - imageTask = ((ImageLoader)obj2).loadImage(coverArtView, album, false, true); + artistView.setText(album.getArtist() == null ? "" : artist); + imageTask = imageLoader.loadImage(coverArtView, album, false, true); file = null; } @Override protected void updateBackground() { if(file == null) { - file = FileUtil.getAlbumDirectory(context, album); + file = FileUtil.getAlbumDirectory(context, item); } exists = file.exists(); - isStarred = album.isStarred(); - isRated = album.getRating(); + isStarred = item.isStarred(); + isRated = item.getRating(); } public MusicDirectory.Entry getEntry() { - return album; + return item; } public File getFile() { diff --git a/app/src/main/java/github/daneren2005/dsub/view/ArtistEntryView.java b/app/src/main/java/github/daneren2005/dsub/view/ArtistEntryView.java index 71bdeb78..f6a6adb3 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/ArtistEntryView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/ArtistEntryView.java @@ -19,7 +19,6 @@ package github.daneren2005.dsub.view; import android.content.Context; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.ImageButton; @@ -28,26 +27,21 @@ import android.widget.TextView; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.util.FileUtil; -import github.daneren2005.dsub.util.ImageLoader; -import github.daneren2005.dsub.util.Util; + import java.io.File; /** * Used to display albums in a {@code ListView}. * * @author Sindre Mehus */ -public class ArtistEntryView extends UpdateView { +public class ArtistEntryView extends UpdateView<MusicDirectory.Entry> { private static final String TAG = ArtistEntryView.class.getSimpleName(); - private Context context; - private MusicDirectory.Entry artist; private File file; - private TextView titleView; public ArtistEntryView(Context context) { super(context); - this.context = context; LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true); titleView = (TextView) findViewById(R.id.item_name); @@ -61,8 +55,7 @@ public class ArtistEntryView extends UpdateView { }); } - protected void setObjectImpl(Object obj) { - this.artist = (MusicDirectory.Entry) obj; + protected void setObjectImpl(MusicDirectory.Entry artist) { titleView.setText(artist.getTitle()); file = FileUtil.getArtistDirectory(context, artist); } @@ -70,7 +63,7 @@ public class ArtistEntryView extends UpdateView { @Override protected void updateBackground() { exists = file.exists(); - isStarred = artist.isStarred(); + isStarred = item.isStarred(); } public File getFile() { diff --git a/app/src/main/java/github/daneren2005/dsub/view/ArtistView.java b/app/src/main/java/github/daneren2005/dsub/view/ArtistView.java index c255be69..d86c5d26 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/ArtistView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/ArtistView.java @@ -35,18 +35,14 @@ import java.io.File; * * @author Sindre Mehus */ -public class ArtistView extends UpdateView { +public class ArtistView extends UpdateView<Artist> { private static final String TAG = ArtistView.class.getSimpleName(); - - private Context context; - private Artist artist; - private File file; + private File file; private TextView titleView; public ArtistView(Context context) { super(context); - this.context = context; LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true); titleView = (TextView) findViewById(R.id.item_name); @@ -60,8 +56,7 @@ public class ArtistView extends UpdateView { }); } - protected void setObjectImpl(Object obj) { - this.artist = (Artist) obj; + protected void setObjectImpl(Artist artist) { titleView.setText(artist.getName()); file = FileUtil.getArtistDirectory(context, artist); } @@ -69,7 +64,7 @@ public class ArtistView extends UpdateView { @Override protected void updateBackground() { exists = file.exists(); - isStarred = artist.isStarred(); + isStarred = item.isStarred(); } public File getFile() { diff --git a/app/src/main/java/github/daneren2005/dsub/view/BasicHeaderView.java b/app/src/main/java/github/daneren2005/dsub/view/BasicHeaderView.java new file mode 100644 index 00000000..01aa42e1 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/view/BasicHeaderView.java @@ -0,0 +1,40 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.view; + +import android.content.Context; +import android.view.LayoutInflater; +import android.widget.TextView; + +import github.daneren2005.dsub.R; + +public class BasicHeaderView extends UpdateView<String> { + TextView nameView; + + public BasicHeaderView(Context context) { + this(context, R.layout.basic_header); + } + public BasicHeaderView(Context context, int layout) { + super(context, false); + + LayoutInflater.from(context).inflate(layout, this, true); + nameView = (TextView) findViewById(R.id.item_name); + } + + protected void setObjectImpl(String string) { + nameView.setText(string); + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/view/BasicListView.java b/app/src/main/java/github/daneren2005/dsub/view/BasicListView.java new file mode 100644 index 00000000..ca7e8993 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/view/BasicListView.java @@ -0,0 +1,44 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.view; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; + +import github.daneren2005.dsub.R; + +public class BasicListView extends UpdateView<String> { + private TextView titleView; + + public BasicListView(Context context) { + super(context, false); + LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true); + + titleView = (TextView) findViewById(R.id.item_name); + starButton = (ImageButton) findViewById(R.id.item_star); + starButton.setFocusable(false); + moreButton = (ImageView) findViewById(R.id.item_more); + moreButton.setVisibility(View.GONE); + } + + protected void setObjectImpl(String string) { + titleView.setText(string); + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/view/ChangeLog.java b/app/src/main/java/github/daneren2005/dsub/view/ChangeLog.java index 096583c7..e3d24485 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/ChangeLog.java +++ b/app/src/main/java/github/daneren2005/dsub/view/ChangeLog.java @@ -42,7 +42,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; -import android.app.AlertDialog; +import android.support.v7.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; diff --git a/app/src/main/java/github/daneren2005/dsub/view/ErrorDialog.java b/app/src/main/java/github/daneren2005/dsub/view/ErrorDialog.java index 0b9d05a0..3d6eaa52 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/ErrorDialog.java +++ b/app/src/main/java/github/daneren2005/dsub/view/ErrorDialog.java @@ -19,7 +19,7 @@ package github.daneren2005.dsub.view; import android.app.Activity; -import android.app.AlertDialog; +import android.support.v7.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; diff --git a/app/src/main/java/github/daneren2005/dsub/view/FastScroller.java b/app/src/main/java/github/daneren2005/dsub/view/FastScroller.java new file mode 100644 index 00000000..1cc11c08 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/view/FastScroller.java @@ -0,0 +1,216 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.view; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +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.util.AttributeSet; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +import github.daneren2005.dsub.R; + +import static android.support.v7.widget.RecyclerView.OnScrollListener; + +public class FastScroller extends LinearLayout { + private static final String TAG = FastScroller.class.getSimpleName(); + private static final int BUBBLE_ANIMATION_DURATION = 100; + private static final int TRACK_SNAP_RANGE = 5; + + private TextView bubble; + private View handle; + private RecyclerView recyclerView; + private final ScrollListener scrollListener = new ScrollListener(); + private int height; + + private ObjectAnimator currentAnimator = null; + + public FastScroller(final Context context,final AttributeSet attrs,final int defStyleAttr) { + super(context,attrs,defStyleAttr); + initialise(context); + } + + public FastScroller(final Context context) { + super(context); + initialise(context); + } + + public FastScroller(final Context context,final AttributeSet attrs) { + super(context, attrs); + initialise(context); + } + + private void initialise(Context context) { + setOrientation(HORIZONTAL); + setClipChildren(false); + LayoutInflater inflater = LayoutInflater.from(context); + inflater.inflate(R.layout.fast_scroller,this,true); + bubble = (TextView)findViewById(R.id.fastscroller_bubble); + handle = findViewById(R.id.fastscroller_handle); + bubble.setVisibility(INVISIBLE); + setVisibility(GONE); + } + + @Override + protected void onSizeChanged(int w,int h,int oldw,int oldh) { + super.onSizeChanged(w,h,oldw,oldh); + height = h; + } + + @Override + public boolean onTouchEvent(@NonNull MotionEvent event) { + final int action = event.getAction(); + switch(action) + { + case MotionEvent.ACTION_DOWN: + if(event.getX()<handle.getX()) + return false; + if(currentAnimator != null) + currentAnimator.cancel(); + if(bubble.getVisibility() == INVISIBLE) + showBubble(); + handle.setSelected(true); + case MotionEvent.ACTION_MOVE: + final float y = event.getY(); + setBubbleAndHandlePosition(y); + setRecyclerViewPosition(y); + return true; + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + handle.setSelected(false); + hideBubble(); + return true; + } + return super.onTouchEvent(event); + } + + public void attachRecyclerView(RecyclerView recyclerView) { + this.recyclerView = recyclerView; + recyclerView.addOnScrollListener(scrollListener); + recyclerView.setVerticalScrollBarEnabled(false); + setVisibility(View.VISIBLE); + } + public void detachRecyclerView() { + recyclerView.removeOnScrollListener(scrollListener); + recyclerView.setVerticalScrollBarEnabled(true); + recyclerView = null; + setVisibility(View.GONE); + } + public boolean isAttached() { + return recyclerView != null; + } + + private void setRecyclerViewPosition(float y) { + if(recyclerView != null) + { + int itemCount = recyclerView.getAdapter().getItemCount(); + float proportion; + if(handle.getY() == 0) + proportion = 0f; + else if(handle.getY()+handle.getHeight()>=height-TRACK_SNAP_RANGE) + proportion = 1f; + else + proportion = y/(float)height; + int targetPos = getValueInRange(0,itemCount-1,(int)(proportion*(float)itemCount)); + ((LinearLayoutManager)recyclerView.getLayoutManager()).scrollToPositionWithOffset(targetPos,0); + + try { + String bubbleText = ((BubbleTextGetter) recyclerView.getAdapter()).getTextToShowInBubble(targetPos); + bubble.setText(bubbleText); + } catch(Exception e) { + Log.e(TAG, "Item count: " + itemCount); + Log.e(TAG, "Error getting text for bubble", e); + } + } + } + + private int getValueInRange(int min,int max,int value) { + int minimum = Math.max(min,value); + return Math.min(minimum,max); + } + + private void setBubbleAndHandlePosition(float y) { + int bubbleHeight = bubble.getHeight(); + int handleHeight = handle.getHeight(); + handle.setY(getValueInRange(0,height-handleHeight,(int)(y-handleHeight/2))); + bubble.setY(getValueInRange(0,height-bubbleHeight-handleHeight/2,(int)(y-bubbleHeight))); + } + + private void showBubble() { + AnimatorSet animatorSet = new AnimatorSet(); + bubble.setVisibility(VISIBLE); + if(currentAnimator != null) + currentAnimator.cancel(); + currentAnimator = ObjectAnimator.ofFloat(bubble,"alpha",0f,1f).setDuration(BUBBLE_ANIMATION_DURATION); + currentAnimator.start(); + } + + private void hideBubble() { + if(currentAnimator != null) + currentAnimator.cancel(); + currentAnimator = ObjectAnimator.ofFloat(bubble,"alpha",1f,0f).setDuration(BUBBLE_ANIMATION_DURATION); + currentAnimator.addListener(new AnimatorListenerAdapter(){ + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + bubble.setVisibility(INVISIBLE); + currentAnimator = null; + } + + @Override + public void onAnimationCancel(Animator animation) { + super.onAnimationCancel(animation); + bubble.setVisibility(INVISIBLE); + currentAnimator = null; + } + }); + currentAnimator.start(); + } + + private class ScrollListener extends OnScrollListener { + @Override + public void onScrolled(RecyclerView rv,int dx,int dy) { + View firstVisibleView = recyclerView.getChildAt(0); + int firstVisiblePosition = recyclerView.getChildPosition(firstVisibleView); + int visibleRange = recyclerView.getChildCount(); + int lastVisiblePosition = firstVisiblePosition+visibleRange; + int itemCount = recyclerView.getAdapter().getItemCount(); + int position; + if(firstVisiblePosition == 0) + position = 0; + else if(lastVisiblePosition == itemCount) + position = itemCount; + else + position = (int)(((float)firstVisiblePosition/(((float)itemCount-(float)visibleRange)))*(float)itemCount); + float proportion = (float)position/(float)itemCount; + setBubbleAndHandlePosition(height*proportion); + } + } + + public interface BubbleTextGetter { + String getTextToShowInBubble(int position); + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/view/GenreView.java b/app/src/main/java/github/daneren2005/dsub/view/GenreView.java index 8dbcf89d..b29aefba 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/GenreView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/GenreView.java @@ -25,7 +25,7 @@ import android.widget.TextView; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.Genre; -public class GenreView extends UpdateView { +public class GenreView extends UpdateView<Genre> { private static final String TAG = GenreView.class.getSimpleName(); private TextView titleView; @@ -41,8 +41,7 @@ public class GenreView extends UpdateView { albumsView = (TextView) findViewById(R.id.genre_albums); } - public void setObjectImpl(Object obj) { - Genre genre = (Genre) obj; + public void setObjectImpl(Genre genre) { titleView.setText(genre.getName()); if(genre.getAlbumCount() != null) { diff --git a/app/src/main/java/github/daneren2005/dsub/view/GridSpacingDecoration.java b/app/src/main/java/github/daneren2005/dsub/view/GridSpacingDecoration.java new file mode 100644 index 00000000..2d7f4c44 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/view/GridSpacingDecoration.java @@ -0,0 +1,103 @@ +/* + This file is part of Subsonic. + Subsonic is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + Subsonic is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with Subsonic. If not, see <http://www.gnu.org/licenses/>. + Copyright 2015 (C) Scott Jackson +*/ + +package github.daneren2005.dsub.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; + +public class GridSpacingDecoration extends RecyclerView.ItemDecoration { + + @Override + public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { + super.getItemOffsets(outRect, view, parent, state); + + int spacing = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, view.getResources().getDisplayMetrics()); + int halfSpacing = spacing / 2; + + int childCount = parent.getChildCount(); + int childIndex = parent.getChildPosition(view); + // Not an actual child (ie: during delete event) + if(childIndex == -1) { + return; + } + int spanCount = getTotalSpan(view, parent); + int spanIndex = childIndex % spanCount; + int spanSize = getSpanSize(parent, childIndex); + + /* INVALID SPAN */ + if (spanCount < 1 || spanSize > 1) return; + + outRect.top = halfSpacing; + outRect.bottom = halfSpacing; + outRect.left = halfSpacing; + outRect.right = halfSpacing; + + if (isTopEdge(childIndex, spanCount)) { + outRect.top = spacing; + } + + if (isLeftEdge(spanIndex, spanCount)) { + outRect.left = spacing; + } + + if (isRightEdge(spanIndex, spanCount)) { + outRect.right = spacing; + } + + if (isBottomEdge(childIndex, childCount, spanCount)) { + outRect.bottom = spacing; + } + } + + protected int getTotalSpan(View view, RecyclerView parent) { + RecyclerView.LayoutManager mgr = parent.getLayoutManager(); + if (mgr instanceof GridLayoutManager) { + return ((GridLayoutManager) mgr).getSpanCount(); + } + + return -1; + } + protected int getSpanSize(RecyclerView parent, int childIndex) { + RecyclerView.LayoutManager mgr = parent.getLayoutManager(); + if (mgr instanceof GridLayoutManager) { + GridLayoutManager.SpanSizeLookup lookup = ((GridLayoutManager) mgr).getSpanSizeLookup(); + if(lookup != null) { + return lookup.getSpanSize(childIndex); + } + } + + return 1; + } + + protected boolean isLeftEdge(int spanIndex, int spanCount) { + return spanIndex == 0; + } + + protected boolean isRightEdge(int spanIndex, int spanCount) { + return spanIndex == spanCount - 1; + } + + protected boolean isTopEdge(int childIndex, int spanCount) { + return childIndex < spanCount; + } + + protected boolean isBottomEdge(int childIndex, int childCount, int spanCount) { + return childIndex >= childCount - spanCount; + } +} diff --git a/app/src/main/java/github/daneren2005/dsub/view/HeaderGridView.java b/app/src/main/java/github/daneren2005/dsub/view/HeaderGridView.java deleted file mode 100644 index 8a82f353..00000000 --- a/app/src/main/java/github/daneren2005/dsub/view/HeaderGridView.java +++ /dev/null @@ -1,836 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package github.daneren2005.dsub.view; - -import android.annotation.TargetApi; -import android.content.Context; -import android.database.DataSetObservable; -import android.database.DataSetObserver; -import android.os.Build; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; -import android.view.ViewGroup; -import android.widget.*; - -import java.lang.reflect.Field; -import java.util.ArrayList; - -/** - * A {@link GridView} that supports adding header rows in a - * very similar way to {@link android.widget.ListView}. - * See {@link HeaderGridView#addHeaderView(View, Object, boolean)} - * See {@link HeaderGridView#addFooterView(View, Object, boolean)} - */ -public class HeaderGridView extends GridView { - private static final String TAG = HeaderGridView.class.getSimpleName(); - public static boolean DEBUG = false; - - /** - * A class that represents a fixed view in a list, for example a header at the top - * or a footer at the bottom. - */ - private static class FixedViewInfo { - /** - * The view to add to the grid - */ - public View view; - public ViewGroup viewContainer; - /** - * The data backing the view. This is returned from {@link ListAdapter#getItem(int)}. - */ - public Object data; - /** - * <code>true</code> if the fixed view should be selectable in the grid - */ - public boolean isSelectable; - } - - private int mNumColumns = AUTO_FIT; - private View mViewForMeasureRowHeight = null; - private int mRowHeight = -1; - private static final String LOG_TAG = HeaderGridView.class.getSimpleName(); - - private ArrayList<FixedViewInfo> mHeaderViewInfos = new ArrayList<FixedViewInfo>(); - private ArrayList<FixedViewInfo> mFooterViewInfos = new ArrayList<FixedViewInfo>(); - - private void initHeaderGridView() { - } - - public HeaderGridView(Context context) { - super(context); - initHeaderGridView(); - } - - public HeaderGridView(Context context, AttributeSet attrs) { - super(context, attrs); - initHeaderGridView(); - } - - public HeaderGridView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - initHeaderGridView(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - ListAdapter adapter = getAdapter(); - if (adapter != null && adapter instanceof HeaderViewGridAdapter) { - ((HeaderViewGridAdapter) adapter).setNumColumns(getNumColumnsCompatible()); - ((HeaderViewGridAdapter) adapter).setRowHeight(getRowHeight()); - } - } - - @Override - public void setClipChildren(boolean clipChildren) { - // Ignore, since the header rows depend on not being clipped - } - - /** - * Do not call this method unless you know how it works. - * - * @param clipChildren - */ - public void setClipChildrenSupper(boolean clipChildren) { - super.setClipChildren(false); - } - - /** - * Add a fixed view to appear at the top of the grid. If addHeaderView is - * called more than once, the views will appear in the order they were - * added. Views added using this call can take focus if they want. - * <p/> - * NOTE: Call this before calling setAdapter. This is so HeaderGridView can wrap - * the supplied cursor with one that will also account for header views. - * - * @param v The view to add. - */ - public void addHeaderView(View v) { - addHeaderView(v, null, true); - } - - /** - * Add a fixed view to appear at the top of the grid. If addHeaderView is - * called more than once, the views will appear in the order they were - * added. Views added using this call can take focus if they want. - * <p/> - * NOTE: Call this before calling setAdapter. This is so HeaderGridView can wrap - * the supplied cursor with one that will also account for header views. - * - * @param v The view to add. - * @param data Data to associate with this view - * @param isSelectable whether the item is selectable - */ - public void addHeaderView(View v, Object data, boolean isSelectable) { - ListAdapter adapter = getAdapter(); - if (adapter != null && !(adapter instanceof HeaderViewGridAdapter)) { - throw new IllegalStateException( - "Cannot add header view to grid -- setAdapter has already been called."); - } - - ViewGroup.LayoutParams lyp = v.getLayoutParams(); - - FixedViewInfo info = new FixedViewInfo(); - FrameLayout fl = new FullWidthFixedViewLayout(getContext()); - - if (lyp != null) { - v.setLayoutParams(new FrameLayout.LayoutParams(lyp.width, lyp.height)); - fl.setLayoutParams(new AbsListView.LayoutParams(lyp.width, lyp.height)); - } - fl.addView(v); - info.view = v; - info.viewContainer = fl; - info.data = data; - info.isSelectable = isSelectable; - mHeaderViewInfos.add(info); - // in the case of re-adding a header view, or adding one later on, - // we need to notify the observer - if (adapter != null) { - ((HeaderViewGridAdapter) adapter).notifyDataSetChanged(); - } - } - - public void addFooterView(View v) { - addFooterView(v, null, true); - } - - public void addFooterView(View v, Object data, boolean isSelectable) { - ListAdapter mAdapter = getAdapter(); - if (mAdapter != null && !(mAdapter instanceof HeaderViewGridAdapter)) { - throw new IllegalStateException( - "Cannot add header view to grid -- setAdapter has already been called."); - } - - ViewGroup.LayoutParams lyp = v.getLayoutParams(); - - FixedViewInfo info = new FixedViewInfo(); - FrameLayout fl = new FullWidthFixedViewLayout(getContext()); - - if (lyp != null) { - v.setLayoutParams(new FrameLayout.LayoutParams(lyp.width, lyp.height)); - fl.setLayoutParams(new AbsListView.LayoutParams(lyp.width, lyp.height)); - } - fl.addView(v); - info.view = v; - info.viewContainer = fl; - info.data = data; - info.isSelectable = isSelectable; - mFooterViewInfos.add(info); - - if (mAdapter != null) { - ((HeaderViewGridAdapter) mAdapter).notifyDataSetChanged(); - } - } - - public int getHeaderViewCount() { - return mHeaderViewInfos.size(); - } - - public int getFooterViewCount() { - return mFooterViewInfos.size(); - } - - /** - * Removes a previously-added header view. - * - * @param v The view to remove - * @return true if the view was removed, false if the view was not a header - * view - */ - public boolean removeHeaderView(View v) { - if (mHeaderViewInfos.size() > 0) { - boolean result = false; - ListAdapter adapter = getAdapter(); - if (adapter != null && ((HeaderViewGridAdapter) adapter).removeHeader(v)) { - result = true; - } - removeFixedViewInfo(v, mHeaderViewInfos); - return result; - } - return false; - } - - /** - * Removes a previously-added footer view. - * - * @param v The view to remove - * @return true if the view was removed, false if the view was not a header - * view - */ - public boolean removeFooterView(View v) { - if (mFooterViewInfos.size() > 0) { - boolean result = false; - ListAdapter adapter = getAdapter(); - if (adapter != null && ((HeaderViewGridAdapter) adapter).removeFooter(v)) { - result = true; - } - removeFixedViewInfo(v, mFooterViewInfos); - return result; - } - return false; - } - - private void removeFixedViewInfo(View v, ArrayList<FixedViewInfo> where) { - int len = where.size(); - for (int i = 0; i < len; ++i) { - FixedViewInfo info = where.get(i); - if (info.view == v) { - where.remove(i); - break; - } - } - } - - @TargetApi(11) - private int getNumColumnsCompatible() { - if (Build.VERSION.SDK_INT >= 11) { - return super.getNumColumns(); - } else { - try { - Field numColumns = GridView.class.getSuperclass().getDeclaredField("mNumColumns"); - numColumns.setAccessible(true); - return numColumns.getInt(this); - } catch (Exception e) { - if (mNumColumns != -1) { - return mNumColumns; - } else { - return 2; - } - } - } - } - - @TargetApi(16) - private int getColumnWidthCompatible() { - if (Build.VERSION.SDK_INT >= 16) { - return super.getColumnWidth(); - } else { - try { - Field numColumns = getClass().getSuperclass().getDeclaredField("mColumnWidth"); - numColumns.setAccessible(true); - return numColumns.getInt(this); - } catch (NoSuchFieldException e) { - throw new RuntimeException(e); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - } - - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); - mViewForMeasureRowHeight = null; - } - - public void invalidateRowHeight() { - mRowHeight = -1; - } - - public int getHeaderHeight(int row) { - if (row >= 0) { - return mHeaderViewInfos.get(row).view.getMeasuredHeight(); - } - - return 0; - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - public int getVerticalSpacing(){ - int value = 0; - - try { - int currentapiVersion = android.os.Build.VERSION.SDK_INT; - if (currentapiVersion < Build.VERSION_CODES.JELLY_BEAN){ - Field field = this.getClass().getSuperclass().getDeclaredField("mVerticalSpacing"); - field.setAccessible(true); - value = field.getInt(this); - } else{ - value = super.getVerticalSpacing(); - } - - }catch (Exception ex){ - - } - - return value; - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - public int getHorizontalSpacing(){ - int value = 0; - - try { - int currentapiVersion = android.os.Build.VERSION.SDK_INT; - if (currentapiVersion < Build.VERSION_CODES.JELLY_BEAN){ - Field field = this.getClass().getSuperclass().getDeclaredField("mHorizontalSpacing"); - field.setAccessible(true); - value = field.getInt(this); - } else{ - value = super.getHorizontalSpacing(); - } - - }catch (Exception ex){ - - } - - return value; - } - - public int getRowHeight() { - if (mRowHeight > 0) { - // return mRowHeight; - } - ListAdapter adapter = getAdapter(); - int numColumns = getNumColumnsCompatible(); - - // adapter has not been set or has no views in it; - if (adapter == null || adapter.getCount() <= numColumns * (mHeaderViewInfos.size() + mFooterViewInfos.size()) || numColumns == -1) { - return -1; - } - int mColumnWidth = getColumnWidthCompatible(); - View view = getAdapter().getView(numColumns * mHeaderViewInfos.size(), mViewForMeasureRowHeight, this); - AbsListView.LayoutParams p = (AbsListView.LayoutParams) view.getLayoutParams(); - if (p == null) { - p = new AbsListView.LayoutParams(-1, -2, 0); - view.setLayoutParams(p); - } - int childHeightSpec = getChildMeasureSpec( - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, p.height); - int childWidthSpec = getChildMeasureSpec( - MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY), 0, p.width); - view.measure(childWidthSpec, childHeightSpec); - mViewForMeasureRowHeight = view; - mRowHeight = view.getMeasuredHeight(); - return mRowHeight; - } - - @TargetApi(11) - public void tryToScrollToBottomSmoothly() { - int lastPos = getAdapter().getCount() - 1; - if (Build.VERSION.SDK_INT >= 11) { - smoothScrollToPositionFromTop(lastPos, 0); - } else { - setSelection(lastPos); - } - } - - @TargetApi(11) - public void tryToScrollToBottomSmoothly(int duration) { - int lastPos = getAdapter().getCount() - 1; - if (Build.VERSION.SDK_INT >= 11) { - smoothScrollToPositionFromTop(lastPos, 0, duration); - } else { - setSelection(lastPos); - } - } - - @Override - public void setAdapter(ListAdapter adapter) { - if (mHeaderViewInfos.size() > 0 || mFooterViewInfos.size() > 0) { - HeaderViewGridAdapter headerViewGridAdapter = new HeaderViewGridAdapter(mHeaderViewInfos, mFooterViewInfos, adapter); - int numColumns = getNumColumnsCompatible(); - if (numColumns > 1) { - headerViewGridAdapter.setNumColumns(numColumns); - } - headerViewGridAdapter.setRowHeight(getRowHeight()); - super.setAdapter(headerViewGridAdapter); - } else { - super.setAdapter(adapter); - } - } - - /** - * full width - */ - private class FullWidthFixedViewLayout extends FrameLayout { - - public FullWidthFixedViewLayout(Context context) { - super(context); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - int realLeft = HeaderGridView.this.getPaddingLeft() + getPaddingLeft(); - // Try to make where it should be, from left, full width - if (realLeft != left) { - offsetLeftAndRight(realLeft - left); - } - super.onLayout(changed, left, top, right, bottom); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - int targetWidth = HeaderGridView.this.getMeasuredWidth() - - HeaderGridView.this.getPaddingLeft() - - HeaderGridView.this.getPaddingRight(); - widthMeasureSpec = MeasureSpec.makeMeasureSpec(targetWidth, - MeasureSpec.getMode(widthMeasureSpec)); - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - } - - @Override - public void setNumColumns(int numColumns) { - super.setNumColumns(numColumns); - mNumColumns = numColumns; - ListAdapter adapter = getAdapter(); - if (adapter != null && adapter instanceof HeaderViewGridAdapter) { - ((HeaderViewGridAdapter) adapter).setNumColumns(numColumns); - } - } - - /** - * ListAdapter used when a HeaderGridView has header views. This ListAdapter - * wraps another one and also keeps track of the header views and their - * associated data objects. - * <p>This is intended as a base class; you will probably not need to - * use this class directly in your own code. - */ - private static class HeaderViewGridAdapter extends BaseAdapter implements WrapperListAdapter, Filterable { - // This is used to notify the container of updates relating to number of columns - // or headers changing, which changes the number of placeholders needed - private final DataSetObservable mDataSetObservable = new DataSetObservable(); - private final ListAdapter mAdapter; - static final ArrayList<FixedViewInfo> EMPTY_INFO_LIST = - new ArrayList<FixedViewInfo>(); - - // This ArrayList is assumed to NOT be null. - ArrayList<FixedViewInfo> mHeaderViewInfos; - ArrayList<FixedViewInfo> mFooterViewInfos; - private int mNumColumns = 1; - private int mRowHeight = -1; - boolean mAreAllFixedViewsSelectable; - private final boolean mIsFilterable; - private boolean mCachePlaceHoldView = true; - // From Recycle Bin or calling getView, this a question... - private boolean mCacheFirstHeaderView = false; - - public HeaderViewGridAdapter(ArrayList<FixedViewInfo> headerViewInfos, ArrayList<FixedViewInfo> footViewInfos, ListAdapter adapter) { - mAdapter = adapter; - mIsFilterable = adapter instanceof Filterable; - if (headerViewInfos == null) { - mHeaderViewInfos = EMPTY_INFO_LIST; - } else { - mHeaderViewInfos = headerViewInfos; - } - - if (footViewInfos == null) { - mFooterViewInfos = EMPTY_INFO_LIST; - } else { - mFooterViewInfos = footViewInfos; - } - mAreAllFixedViewsSelectable = areAllListInfosSelectable(mHeaderViewInfos) - && areAllListInfosSelectable(mFooterViewInfos); - } - - public void setNumColumns(int numColumns) { - if (numColumns < 1) { - return; - } - if (mNumColumns != numColumns) { - mNumColumns = numColumns; - notifyDataSetChanged(); - } - } - - public void setRowHeight(int height) { - mRowHeight = height; - } - - public int getHeadersCount() { - return mHeaderViewInfos.size(); - } - - public int getFootersCount() { - return mFooterViewInfos.size(); - } - - @Override - public boolean isEmpty() { - return (mAdapter == null || mAdapter.isEmpty()) && getHeadersCount() == 0 && getFootersCount() == 0; - } - - private boolean areAllListInfosSelectable(ArrayList<FixedViewInfo> infos) { - if (infos != null) { - for (FixedViewInfo info : infos) { - if (!info.isSelectable) { - return false; - } - } - } - return true; - } - - public boolean removeHeader(View v) { - for (int i = 0; i < mHeaderViewInfos.size(); i++) { - FixedViewInfo info = mHeaderViewInfos.get(i); - if (info.view == v) { - mHeaderViewInfos.remove(i); - mAreAllFixedViewsSelectable = - areAllListInfosSelectable(mHeaderViewInfos) && areAllListInfosSelectable(mFooterViewInfos); - mDataSetObservable.notifyChanged(); - return true; - } - } - return false; - } - - public boolean removeFooter(View v) { - for (int i = 0; i < mFooterViewInfos.size(); i++) { - FixedViewInfo info = mFooterViewInfos.get(i); - if (info.view == v) { - mFooterViewInfos.remove(i); - mAreAllFixedViewsSelectable = - areAllListInfosSelectable(mHeaderViewInfos) && areAllListInfosSelectable(mFooterViewInfos); - mDataSetObservable.notifyChanged(); - return true; - } - } - return false; - } - - @Override - public int getCount() { - if (mAdapter != null) { - return (getFootersCount() + getHeadersCount()) * mNumColumns + getAdapterAndPlaceHolderCount(); - } else { - return (getFootersCount() + getHeadersCount()) * mNumColumns; - } - } - - @Override - public boolean areAllItemsEnabled() { - if (mAdapter != null) { - return mAreAllFixedViewsSelectable && mAdapter.areAllItemsEnabled(); - } else { - return true; - } - } - - private int getAdapterAndPlaceHolderCount() { - final int adapterCount = (int) (Math.ceil(1f * mAdapter.getCount() / mNumColumns) * mNumColumns); - return adapterCount; - } - - @Override - public boolean isEnabled(int position) { - // Header (negative positions will throw an IndexOutOfBoundsException) - int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - if (position < numHeadersAndPlaceholders) { - return position % mNumColumns == 0 - && mHeaderViewInfos.get(position / mNumColumns).isSelectable; - } - - // Adapter - final int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = 0; - if (mAdapter != null) { - adapterCount = getAdapterAndPlaceHolderCount(); - if (adjPosition < adapterCount) { - return adjPosition < mAdapter.getCount() && mAdapter.isEnabled(adjPosition); - } - } - - // Footer (off-limits positions will throw an IndexOutOfBoundsException) - final int footerPosition = adjPosition - adapterCount; - return footerPosition % mNumColumns == 0 - && mFooterViewInfos.get(footerPosition / mNumColumns).isSelectable; - } - - @Override - public Object getItem(int position) { - // Header (negative positions will throw an ArrayIndexOutOfBoundsException) - int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - if (position < numHeadersAndPlaceholders) { - if (position % mNumColumns == 0) { - return mHeaderViewInfos.get(position / mNumColumns).data; - } - return null; - } - - // Adapter - final int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = 0; - if (mAdapter != null) { - adapterCount = getAdapterAndPlaceHolderCount(); - if (adjPosition < adapterCount) { - if (adjPosition < mAdapter.getCount()) { - return mAdapter.getItem(adjPosition); - } else { - return null; - } - } - } - - // Footer (off-limits positions will throw an IndexOutOfBoundsException) - final int footerPosition = adjPosition - adapterCount; - if (footerPosition % mNumColumns == 0) { - return mFooterViewInfos.get(footerPosition).data; - } else { - return null; - } - } - - @Override - public long getItemId(int position) { - int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - if (mAdapter != null && position >= numHeadersAndPlaceholders) { - int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = mAdapter.getCount(); - if (adjPosition < adapterCount) { - return mAdapter.getItemId(adjPosition); - } - } - return -1; - } - - @Override - public boolean hasStableIds() { - if (mAdapter != null) { - return mAdapter.hasStableIds(); - } - return false; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (DEBUG) { - Log.d(LOG_TAG, String.format("getView: %s, reused: %s", position, convertView == null)); - } - // Header (negative positions will throw an ArrayIndexOutOfBoundsException) - int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - if (position < numHeadersAndPlaceholders) { - View headerViewContainer = mHeaderViewInfos - .get(position / mNumColumns).viewContainer; - if (position % mNumColumns == 0) { - return headerViewContainer; - } else { - if (convertView == null) { - convertView = new View(parent.getContext()); - } - // We need to do this because GridView uses the height of the last item - // in a row to determine the height for the entire row. - convertView.setVisibility(View.INVISIBLE); - convertView.setMinimumHeight(headerViewContainer.getHeight()); - return convertView; - } - } - // Adapter - final int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = 0; - if (mAdapter != null) { - adapterCount = getAdapterAndPlaceHolderCount(); - if (adjPosition < adapterCount) { - if (adjPosition < mAdapter.getCount()) { - View view = mAdapter.getView(adjPosition, convertView, parent); - return view; - } else { - if (convertView == null) { - convertView = new View(parent.getContext()); - } - convertView.setVisibility(View.INVISIBLE); - convertView.setMinimumHeight(mRowHeight); - return convertView; - } - } - } - // Footer - final int footerPosition = adjPosition - adapterCount; - if (footerPosition < getCount()) { - View footViewContainer = mFooterViewInfos - .get(footerPosition / mNumColumns).viewContainer; - if (position % mNumColumns == 0) { - return footViewContainer; - } else { - if (convertView == null) { - convertView = new View(parent.getContext()); - } - // We need to do this because GridView uses the height of the last item - // in a row to determine the height for the entire row. - convertView.setVisibility(View.INVISIBLE); - convertView.setMinimumHeight(footViewContainer.getHeight()); - return convertView; - } - } - throw new ArrayIndexOutOfBoundsException(position); - } - - @Override - public int getItemViewType(int position) { - - final int numHeadersAndPlaceholders = getHeadersCount() * mNumColumns; - final int adapterViewTypeStart = mAdapter == null ? 0 : mAdapter.getViewTypeCount() - 1; - int type = AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER; - if (mCachePlaceHoldView) { - // Header - if (position < numHeadersAndPlaceholders) { - if (position == 0) { - if (mCacheFirstHeaderView) { - type = adapterViewTypeStart + mHeaderViewInfos.size() + mFooterViewInfos.size() + 1 + 1; - } - } - if (position % mNumColumns != 0) { - type = adapterViewTypeStart + (position / mNumColumns + 1); - } - } - } - - // Adapter - final int adjPosition = position - numHeadersAndPlaceholders; - int adapterCount = 0; - if (mAdapter != null) { - adapterCount = getAdapterAndPlaceHolderCount(); - if (adjPosition >= 0 && adjPosition < adapterCount) { - if (adjPosition < mAdapter.getCount()) { - type = mAdapter.getItemViewType(adjPosition); - } else { - if (mCachePlaceHoldView) { - type = adapterViewTypeStart + mHeaderViewInfos.size() + 1; - } - } - } - } - - if (mCachePlaceHoldView) { - // Footer - final int footerPosition = adjPosition - adapterCount; - if (footerPosition >= 0 && footerPosition < getCount() && (footerPosition % mNumColumns) != 0) { - type = adapterViewTypeStart + mHeaderViewInfos.size() + 1 + (footerPosition / mNumColumns + 1); - } - } - if (DEBUG) { - Log.d(LOG_TAG, String.format("getItemViewType: pos: %s, result: %s", position, type, mCachePlaceHoldView, mCacheFirstHeaderView)); - } - return type; - } - - /** - * content view, content view holder, header[0], header and footer placeholder(s) - * - * @return - */ - @Override - public int getViewTypeCount() { - int count = mAdapter == null ? 1 : mAdapter.getViewTypeCount(); - if (mCachePlaceHoldView) { - int offset = mHeaderViewInfos.size() + 1 + mFooterViewInfos.size(); - if (mCacheFirstHeaderView) { - offset += 1; - } - count += offset; - } - if (DEBUG) { - Log.d(LOG_TAG, String.format("getViewTypeCount: %s", count)); - } - return count; - } - - @Override - public void registerDataSetObserver(DataSetObserver observer) { - mDataSetObservable.registerObserver(observer); - if (mAdapter != null) { - mAdapter.registerDataSetObserver(observer); - } - } - - @Override - public void unregisterDataSetObserver(DataSetObserver observer) { - mDataSetObservable.unregisterObserver(observer); - if (mAdapter != null) { - mAdapter.unregisterDataSetObserver(observer); - } - } - - @Override - public Filter getFilter() { - if (mIsFilterable) { - return ((Filterable) mAdapter).getFilter(); - } - return null; - } - - @Override - public ListAdapter getWrappedAdapter() { - return mAdapter; - } - - public void notifyDataSetChanged() { - mDataSetObservable.notifyChanged(); - } - } -} diff --git a/app/src/main/java/github/daneren2005/dsub/view/PlaylistSongView.java b/app/src/main/java/github/daneren2005/dsub/view/PlaylistSongView.java index 0264a785..581b92e4 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/PlaylistSongView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/PlaylistSongView.java @@ -34,16 +34,12 @@ import github.daneren2005.dsub.util.FileUtil; import github.daneren2005.dsub.util.SyncUtil; import github.daneren2005.dsub.util.Util; -public class PlaylistSongView extends UpdateView { +public class PlaylistSongView extends UpdateView2<Playlist, List<MusicDirectory.Entry>> { private static final String TAG = PlaylistSongView.class.getSimpleName(); - private Context context; - private Playlist playlist; - private TextView titleView; private TextView countView; private int count = 0; - private List<MusicDirectory.Entry> songs; public PlaylistSongView(Context context) { super(context, false); @@ -54,9 +50,7 @@ public class PlaylistSongView extends UpdateView { countView = (TextView) findViewById(R.id.basic_count_count); } - protected void setObjectImpl(Object obj1, Object obj2) { - this.playlist = (Playlist) obj1; - this.songs = (List<MusicDirectory.Entry>) obj2; + protected void setObjectImpl(Playlist playlist, List<MusicDirectory.Entry> songs) { count = 0; titleView.setText(playlist.getName()); // Make sure to hide initially so it's not present briefly before update @@ -69,11 +63,11 @@ public class PlaylistSongView extends UpdateView { count = 0; // Don't try to lookup playlist for Create New - if(!"-1".equals(playlist.getId())) { - MusicDirectory cache = FileUtil.deserialize(context, Util.getCacheName(context, "playlist", playlist.getId()), MusicDirectory.class); + if(!"-1".equals(item.getId())) { + MusicDirectory cache = FileUtil.deserialize(context, Util.getCacheName(context, "playlist", item.getId()), MusicDirectory.class); if(cache != null) { // Try to find song instances in the given playlists - for(MusicDirectory.Entry song: songs) { + for(MusicDirectory.Entry song: item2) { if(cache.getChildren().contains(song)) { count++; } diff --git a/app/src/main/java/github/daneren2005/dsub/view/PlaylistView.java b/app/src/main/java/github/daneren2005/dsub/view/PlaylistView.java index 25613984..b8fa3b80 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/PlaylistView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/PlaylistView.java @@ -21,11 +21,11 @@ package github.daneren2005.dsub.view; import android.content.Context; import android.view.LayoutInflater; import android.view.View; -import android.widget.ImageButton; import android.widget.ImageView; import android.widget.TextView; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.Playlist; +import github.daneren2005.dsub.util.ImageLoader; import github.daneren2005.dsub.util.SyncUtil; /** @@ -33,37 +33,31 @@ import github.daneren2005.dsub.util.SyncUtil; * * @author Sindre Mehus */ -public class PlaylistView extends UpdateView { +public class PlaylistView extends UpdateView<Playlist> { private static final String TAG = PlaylistView.class.getSimpleName(); - private Context context; - private Playlist playlist; - + private View coverArtView; private TextView titleView; + private ImageLoader imageLoader; - public PlaylistView(Context context) { + public PlaylistView(Context context, ImageLoader imageLoader, boolean largeCell) { super(context); - this.context = context; - LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true); + LayoutInflater.from(context).inflate(largeCell ? R.layout.playlist_cell_item : R.layout.playlist_list_item, this, true); + + coverArtView = findViewById(R.id.playlist_coverart); + titleView = (TextView) findViewById(R.id.playlist_title); + moreButton = (ImageView) findViewById(R.id.more_button); - titleView = (TextView) findViewById(R.id.item_name); - starButton = (ImageButton) findViewById(R.id.item_star); - starButton.setFocusable(false); - moreButton = (ImageView) findViewById(R.id.item_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); + this.imageLoader = imageLoader; } - protected void setObjectImpl(Object obj) { - this.playlist = (Playlist) obj; + protected void setObjectImpl(Playlist playlist) { titleView.setText(playlist.getName()); + imageTask = imageLoader.loadImage(coverArtView, playlist, false, true); } @Override protected void updateBackground() { - pinned = SyncUtil.isSyncedPlaylist(context, playlist.getId()); + pinned = SyncUtil.isSyncedPlaylist(context, item.getId()); } } diff --git a/app/src/main/java/github/daneren2005/dsub/view/PodcastChannelView.java b/app/src/main/java/github/daneren2005/dsub/view/PodcastChannelView.java index ada8019e..4878ad67 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/PodcastChannelView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/PodcastChannelView.java @@ -30,18 +30,14 @@ import github.daneren2005.dsub.util.SyncUtil; import github.daneren2005.dsub.util.FileUtil; import java.io.File; -public class PodcastChannelView extends UpdateView { +public class PodcastChannelView extends UpdateView<PodcastChannel> { private static final String TAG = PodcastChannelView.class.getSimpleName(); - private Context context; - private PodcastChannel channel; private File file; - private TextView titleView; public PodcastChannelView(Context context) { super(context); - this.context = context; LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true); titleView = (TextView) findViewById(R.id.item_name); @@ -55,8 +51,7 @@ public class PodcastChannelView extends UpdateView { }); } - protected void setObjectImpl(Object obj) { - channel = (PodcastChannel) obj; + protected void setObjectImpl(PodcastChannel channel) { if(channel.getName() != null) { titleView.setText(channel.getName()); } else { @@ -67,7 +62,7 @@ public class PodcastChannelView extends UpdateView { @Override protected void updateBackground() { - if(SyncUtil.isSyncedPodcast(context, channel.getId())) { + if(SyncUtil.isSyncedPodcast(context, item.getId())) { if(exists) { shaded = false; exists = false; diff --git a/app/src/main/java/github/daneren2005/dsub/view/SettingView.java b/app/src/main/java/github/daneren2005/dsub/view/SettingView.java index 1c78706e..d46dc5d2 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/SettingView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/SettingView.java @@ -17,34 +17,42 @@ package github.daneren2005.dsub.view; import android.content.Context; import android.view.LayoutInflater; -import android.view.View; -import android.widget.CheckedTextView; +import android.widget.CheckBox; +import android.widget.CompoundButton; +import android.widget.TextView; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.User; import static github.daneren2005.dsub.domain.User.Setting; -public class SettingView extends UpdateView { - Setting setting; - - CheckedTextView view; +public class SettingView extends UpdateView2<Setting, Boolean> { + private final TextView titleView; + private final CheckBox checkBox; public SettingView(Context context) { super(context, false); this.context = context; - LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_multiple_choice, this, true); + LayoutInflater.from(context).inflate(R.layout.basic_choice_item, this, true); - view = (CheckedTextView) findViewById(android.R.id.text1); + titleView = (TextView) findViewById(R.id.item_name); + checkBox = (CheckBox) findViewById(R.id.item_checkbox); + checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + if(item != null) { + item.setValue(isChecked); + } + } + }); + checkBox.setClickable(false); } - protected void setObjectImpl(Object obj, Object editable) { - this.setting = (Setting) obj; - + protected void setObjectImpl(Setting setting, Boolean isEditable) { // Can't edit non-role parts String name = setting.getName(); if(name.indexOf("Role") == -1) { - editable = false; + item2 = false; } int res = -1; @@ -74,29 +82,28 @@ public class SettingView extends UpdateView { res = R.string.admin_role_lastfm; } else { // Last resort to display the raw value - view.setText(name); + titleView.setText(name); } if(res != -1) { - view.setText(res); + titleView.setText(res); } if(setting.getValue()) { - view.setChecked(setting.getValue()); + checkBox.setChecked(setting.getValue()); } else { - view.setChecked(false); + checkBox.setChecked(false); } - if((Boolean) editable) { - view.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - view.toggle(); - setting.setValue(view.isChecked()); - } - }); - } else { - view.setOnClickListener(null); - } + checkBox.setEnabled(item2); + } + + @Override + public boolean isCheckable() { + return item2; + } + + public void setChecked(boolean checked) { + checkBox.setChecked(checked); } } diff --git a/app/src/main/java/github/daneren2005/dsub/view/ShareView.java b/app/src/main/java/github/daneren2005/dsub/view/ShareView.java index bfb5b198..12294369 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/ShareView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/ShareView.java @@ -31,7 +31,7 @@ import java.util.Locale; import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.Share; -public class ShareView extends UpdateView { +public class ShareView extends UpdateView<Share> { private static final String TAG = ShareView.class.getSimpleName(); private TextView titleView; @@ -53,8 +53,7 @@ public class ShareView extends UpdateView { }); } - public void setObjectImpl(Object obj) { - Share share = (Share) obj; + public void setObjectImpl(Share share) { titleView.setText(share.getName()); if(share.getExpires() != null) { descriptionView.setText(context.getResources().getString(R.string.share_expires, new SimpleDateFormat("E MMM d, yyyy", Locale.ENGLISH).format(share.getExpires()))); diff --git a/app/src/main/java/github/daneren2005/dsub/view/SongView.java b/app/src/main/java/github/daneren2005/dsub/view/SongView.java index 2fbaedc3..b9c5fa50 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/SongView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/SongView.java @@ -29,6 +29,7 @@ import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.PodcastEpisode; import github.daneren2005.dsub.service.DownloadService; import github.daneren2005.dsub.service.DownloadFile; +import github.daneren2005.dsub.util.DrawableTint; import github.daneren2005.dsub.util.Util; import java.io.File; @@ -38,20 +39,17 @@ import java.io.File; * * @author Sindre Mehus */ -public class SongView extends UpdateView implements Checkable { - private static final String TAG = SongView.class.getSimpleName(); +public class SongView extends UpdateView2<MusicDirectory.Entry, Boolean> { + private static final String TAG = SongView.class.getSimpleName(); - private MusicDirectory.Entry song; - - private CheckedTextView checkedTextView; - private TextView titleTextView; - private TextView artistTextView; - private TextView durationTextView; - private TextView statusTextView; + private TextView titleTextView; + private TextView artistTextView; + private TextView durationTextView; + private TextView statusTextView; private ImageView statusImageView; private ImageView bookmarkButton; private View bottomRowView; - + private DownloadService downloadService; private long revision = -1; private DownloadFile downloadFile; @@ -68,35 +66,28 @@ public class SongView extends UpdateView implements Checkable { private boolean isBookmarked = false; private boolean bookmarked = false; - public SongView(Context context) { - super(context); - LayoutInflater.from(context).inflate(R.layout.song_list_item, this, true); + public SongView(Context context) { + super(context); + LayoutInflater.from(context).inflate(R.layout.song_list_item, this, true); - checkedTextView = (CheckedTextView) findViewById(R.id.song_check); - titleTextView = (TextView) findViewById(R.id.song_title); - artistTextView = (TextView) findViewById(R.id.song_artist); - durationTextView = (TextView) findViewById(R.id.song_duration); - statusTextView = (TextView) findViewById(R.id.song_status); + titleTextView = (TextView) findViewById(R.id.song_title); + artistTextView = (TextView) findViewById(R.id.song_artist); + durationTextView = (TextView) findViewById(R.id.song_duration); + statusTextView = (TextView) findViewById(R.id.song_status); statusImageView = (ImageView) findViewById(R.id.song_status_icon); ratingBar = (RatingBar) findViewById(R.id.song_rating); - starButton = (ImageButton) findViewById(R.id.song_star); - starButton.setFocusable(false); + starButton = (ImageButton) findViewById(R.id.song_star); + starButton.setFocusable(false); bookmarkButton = (ImageButton) findViewById(R.id.song_bookmark); bookmarkButton.setFocusable(false); - moreButton = (ImageView) findViewById(R.id.artist_more); - moreButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View v) { - v.showContextMenu(); - } - }); + moreButton = (ImageView) findViewById(R.id.more_button); bottomRowView = findViewById(R.id.song_bottom); - } + } + + public void setObjectImpl(MusicDirectory.Entry song, Boolean checkable) { + this.checkable = checkable; - public void setObjectImpl(Object obj1, Object obj2) { - this.song = (MusicDirectory.Entry) obj1; - boolean checkable = (Boolean) obj2; - - StringBuilder artist = new StringBuilder(40); + StringBuilder artist = new StringBuilder(40); boolean isPodcast = song instanceof PodcastEpisode; if(!song.isVideo() || isPodcast) { @@ -110,11 +101,11 @@ public class SongView extends UpdateView implements Checkable { else if(song.getArtist() != null) { artist.append(song.getArtist()); } - + if(isPodcast) { String status = ((PodcastEpisode) song).getStatus(); int statusRes = -1; - + if("error".equals(status)) { statusRes = R.string.song_details_error; } else if("skipped".equals(status)) { @@ -122,7 +113,7 @@ public class SongView extends UpdateView implements Checkable { } else if("downloading".equals(status)) { statusRes = R.string.song_details_downloading; } - + if(statusRes != -1) { artist.append(" ("); artist.append(getContext().getString(statusRes)); @@ -136,16 +127,15 @@ public class SongView extends UpdateView implements Checkable { bottomRowView.setVisibility(View.GONE); statusTextView.setText(Util.formatDuration(song.getDuration())); } - + String title = song.getTitle(); Integer track = song.getTrack(); if(track != null && Util.getDisplayTrack(context)) { title = String.format("%02d", track) + " " + title; } - titleTextView.setText(title); + titleTextView.setText(title); artistTextView.setText(artist); - checkedTextView.setVisibility(checkable && !song.isVideo() ? View.VISIBLE : View.GONE); this.setBackgroundColor(0x00000000); ratingBar.setVisibility(View.GONE); @@ -155,28 +145,28 @@ public class SongView extends UpdateView implements Checkable { loaded = false; dontChangeDownloadFile = false; } - + public void setDownloadFile(DownloadFile downloadFile) { this.downloadFile = downloadFile; dontChangeDownloadFile = true; } - + public DownloadFile getDownloadFile() { return downloadFile; } - + @Override protected void updateBackground() { - if (downloadService == null) { + if (downloadService == null) { downloadService = DownloadService.getInstance(); if(downloadService == null) { return; } - } + } long newRevision = downloadService.getDownloadListUpdateRevision(); if((revision != newRevision && dontChangeDownloadFile == false) || downloadFile == null) { - downloadFile = downloadService.forSong(song); + downloadFile = downloadService.forSong(item); revision = newRevision; } @@ -184,28 +174,31 @@ public class SongView extends UpdateView implements Checkable { isSaved = downloadFile.isSaved(); partialFile = downloadFile.getPartialFile(); partialFileExists = partialFile.exists(); - isStarred = song.isStarred(); - isBookmarked = song.getBookmark() != null; - isRated = song.getRating(); - + isStarred = item.isStarred(); + isBookmarked = item.getBookmark() != null; + isRated = item.getRating(); + // Check if needs to load metadata: check against all fields that we know are null in offline mode - if(song.getBitRate() == null && song.getDuration() == null && song.getDiscNumber() == null && isWorkDone) { - song.loadMetadata(downloadFile.getCompleteFile()); + if(item.getBitRate() == null && item.getDuration() == null && item.getDiscNumber() == null && isWorkDone) { + item.loadMetadata(downloadFile.getCompleteFile()); loaded = true; } } @Override - protected void update() { + protected void update() { if(loaded) { - setObjectImpl(song, checkedTextView.getVisibility() == View.VISIBLE); + setObjectImpl(item, item2); + } + if (downloadService == null || downloadFile == null) { + return; } - if (downloadService == null || downloadFile == null) { - return; - } - if(song.isStarred()) { + if(item.isStarred()) { if(!starred) { + if(starButton.getDrawable() == null) { + starButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_toggle_star)); + } starButton.setVisibility(View.VISIBLE); starred = true; } @@ -216,13 +209,13 @@ public class SongView extends UpdateView implements Checkable { } } - if (isWorkDone) { + if (isWorkDone) { int moreImage = isSaved ? R.drawable.download_pinned : R.drawable.download_cached; if(moreImage != this.moreImage) { moreButton.setImageResource(moreImage); this.moreImage = moreImage; } - } else if(this.moreImage != R.drawable.download_none_light) { + } else if(this.moreImage != R.drawable.download_none_light) { int[] attrs = new int[] {R.attr.download_none}; TypedArray typedArray = context.obtainStyledAttributes(attrs); moreButton.setImageResource(typedArray.getResourceId(0, 0)); @@ -230,7 +223,7 @@ public class SongView extends UpdateView implements Checkable { this.moreImage = R.drawable.download_none_light; } - if (downloadFile.isDownloading() && !downloadFile.isDownloadCancelled() && partialFileExists) { + if (downloadFile.isDownloading() && !downloadFile.isDownloadCancelled() && partialFileExists) { double percentage = (partialFile.length() * 100.0) / downloadFile.getEstimatedSize(); percentage = Math.min(percentage, 100); statusTextView.setText((int)percentage + " %"); @@ -238,29 +231,33 @@ public class SongView extends UpdateView implements Checkable { statusImageView.setVisibility(View.VISIBLE); rightImage = true; } - } else if(rightImage) { - statusTextView.setText(null); + } else if(rightImage) { + statusTextView.setText(null); statusImageView.setVisibility(View.GONE); rightImage = false; - } + } - boolean playing = downloadService.getCurrentPlaying() == downloadFile; - if (playing) { + boolean playing = downloadService.getCurrentPlaying() == downloadFile; + if (playing) { if(!this.playing) { this.playing = playing; int[] attrs = new int[] {R.attr.media_button_start}; TypedArray typedArray = context.obtainStyledAttributes(attrs); - titleTextView.setCompoundDrawablesWithIntrinsicBounds(typedArray.getResourceId(0, 0), 0, 0, 0); + titleTextView.setCompoundDrawablesWithIntrinsicBounds(typedArray.getResourceId(0, 0), 0, 0, 0); } - } else { + } else { if(this.playing) { this.playing = playing; - titleTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); + titleTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); } } if(isBookmarked) { if(!bookmarked) { + if(bookmarkButton.getDrawable() == null) { + bookmarkButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_menu_bookmark_selected)); + } + bookmarkButton.setVisibility(View.VISIBLE); bookmarked = true; } @@ -295,24 +292,9 @@ public class SongView extends UpdateView implements Checkable { rating = isRated; } - } - - @Override - public void setChecked(boolean b) { - checkedTextView.setChecked(b); - } - - @Override - public boolean isChecked() { - return checkedTextView.isChecked(); - } - - @Override - public void toggle() { - checkedTextView.toggle(); - } + } public MusicDirectory.Entry getEntry() { - return song; + return item; } } diff --git a/app/src/main/java/github/daneren2005/dsub/view/UnscrollableGridView.java b/app/src/main/java/github/daneren2005/dsub/view/UnscrollableGridView.java deleted file mode 100644 index 3047d5d7..00000000 --- a/app/src/main/java/github/daneren2005/dsub/view/UnscrollableGridView.java +++ /dev/null @@ -1,128 +0,0 @@ -package github.daneren2005.dsub.view; - -import android.annotation.TargetApi; -import android.content.Context; -import android.os.Build; -import android.util.AttributeSet; -import android.util.Log; -import android.view.View; -import android.widget.AbsListView; -import android.widget.GridView; -import android.widget.ListAdapter; - -import java.lang.reflect.Field; - -/** - * Created by Scott on 4/26/2014. - */ -public class UnscrollableGridView extends GridView { - private static final String TAG = UnscrollableGridView.class.getSimpleName(); - - public UnscrollableGridView(Context context) { - super(context); - } - - public UnscrollableGridView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public UnscrollableGridView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - @Override - public int getColumnWidth() { - // This method will be called from onMeasure() too. - // It's better to use getMeasuredWidth(), as it is safe in this case. - - int hSpacing = 20; - try { - Field field = GridView.class.getDeclaredField("mHorizontalSpacing"); - field.setAccessible(true); - hSpacing = field.getInt(this); - } catch(Exception e) { - - } - - final int totalHorizontalSpacing = getNumColumnsCompat() > 0 ? (getNumColumnsCompat() - 1) * hSpacing : 0; - return (getMeasuredWidth() - getPaddingLeft() - getPaddingRight() - totalHorizontalSpacing) / getNumColumnsCompat(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - // Sets the padding for this view. - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - - final int measuredWidth = getMeasuredWidth(); - final int childWidth = getColumnWidth(); - int childHeight = 0; - - // If there's an adapter, use it to calculate the height of this view. - final ListAdapter adapter = getAdapter(); - final int count; - - // There shouldn't be any inherent size (due to padding) if there are no child views. - if (adapter == null || (count = adapter.getCount()) == 0) { - setMeasuredDimension(0, 0); - return; - } - - // Get the first child from the adapter. - final View child = adapter.getView(0, null, this); - if (child != null) { - // Set a default LayoutParams on the child, if it doesn't have one on its own. - AbsListView.LayoutParams params = (AbsListView.LayoutParams) child.getLayoutParams(); - if (params == null) { - params = new AbsListView.LayoutParams(AbsListView.LayoutParams.WRAP_CONTENT, - AbsListView.LayoutParams.WRAP_CONTENT); - child.setLayoutParams(params); - } - - // Measure the exact width of the child, and the height based on the width. - // Note: the child takes care of calculating its height. - int childWidthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY); - int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - child.measure(childWidthSpec, childHeightSpec); - childHeight = child.getMeasuredHeight(); - } - - int vSpacing = 10; - try { - Field field = GridView.class.getDeclaredField("mVerticalSpacing"); - field.setAccessible(true); - vSpacing = field.getInt(this); - } catch(Exception e) { - - } - - // Number of rows required to 'mTotal' items. - final int rows = (int) Math.ceil((double) getCount() / getNumColumnsCompat()); - final int childrenHeight = childHeight * rows; - final int totalVerticalSpacing = rows > 0 ? (rows - 1) * vSpacing : 0; - - // Total height of this view. - final int measuredHeight = Math.abs(childrenHeight + getPaddingTop() + getPaddingBottom() + totalVerticalSpacing); - setMeasuredDimension(measuredWidth, measuredHeight); - } - - private int getNumColumnsCompat() { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - return getNumColumnsCompat11(); - } else { - int columns = 0; - int children = getChildCount(); - if (children > 0) { - int width = getChildAt(0).getMeasuredWidth(); - if (width > 0) { - columns = getWidth() / width; - } - } - return columns > 0 ? columns : AUTO_FIT; - } - } - - @TargetApi(Build.VERSION_CODES.HONEYCOMB) - private int getNumColumnsCompat11() { - return getNumColumns(); - } -} diff --git a/app/src/main/java/github/daneren2005/dsub/view/UpdateView.java b/app/src/main/java/github/daneren2005/dsub/view/UpdateView.java index f9c62121..fd74c872 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/UpdateView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/UpdateView.java @@ -20,9 +20,10 @@ package github.daneren2005.dsub.view; import android.content.Context; import android.content.res.TypedArray; -import android.graphics.Color; +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; @@ -37,20 +38,21 @@ import java.util.List; import java.util.WeakHashMap; import github.daneren2005.dsub.domain.MusicDirectory; -import github.daneren2005.dsub.util.ImageLoader; import github.daneren2005.dsub.R; +import github.daneren2005.dsub.util.DrawableTint; import github.daneren2005.dsub.util.SilentBackgroundTask; -public class UpdateView extends LinearLayout { +public abstract class UpdateView<T> extends LinearLayout { private static final String TAG = UpdateView.class.getSimpleName(); private static final WeakHashMap<UpdateView, ?> INSTANCES = new WeakHashMap<UpdateView, Object>(); - private static Handler backgroundHandler; - private static Handler uiHandler; + protected static Handler backgroundHandler; + protected static Handler uiHandler; private static Runnable updateRunnable; private static int activeActivities = 0; protected Context context; + protected T item; protected RatingBar ratingBar; protected ImageButton starButton; protected ImageView moreButton; @@ -63,8 +65,10 @@ public class UpdateView extends LinearLayout { protected int isRated = 0; protected int rating = 0; protected SilentBackgroundTask<Void> imageTask = null; + protected Drawable startBackgroundDrawable; protected final boolean autoUpdate; + protected boolean checkable; public UpdateView(Context context) { this(context, true); @@ -75,8 +79,8 @@ public class UpdateView extends LinearLayout { this.autoUpdate = autoUpdate; setLayoutParams(new AbsListView.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT)); + ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT)); if(autoUpdate) { INSTANCES.put(this, null); @@ -89,37 +93,16 @@ public class UpdateView extends LinearLayout { } - public void setObject(Object obj) { + public void setObject(T obj) { + item = obj; setObjectImpl(obj); updateBackground(); update(); } - public void setObject(Object obj1, Object obj2) { - if(imageTask != null) { - imageTask.cancel(); - imageTask = null; - } - - setObjectImpl(obj1, obj2); - backgroundHandler.post(new Runnable() { - @Override - public void run() { - updateBackground(); - uiHandler.post(new Runnable() { - @Override - public void run() { - update(); - } - }); - } - }); - } - protected void setObjectImpl(Object obj) { - - } - protected void setObjectImpl(Object obj1, Object obj2) { - + public void setObject(T obj1, Object obj2) { + setObject(obj1, null); } + protected abstract void setObjectImpl(T obj); private static synchronized void startUpdater() { if(uiHandler != null) { @@ -224,8 +207,6 @@ public class UpdateView extends LinearLayout { MusicDirectory.Entry check = null; if(view instanceof SongView) { check = ((SongView) view).getEntry(); - } else if(view instanceof AlbumCell) { - check = ((AlbumCell) view).getEntry(); } else if(view instanceof AlbumView) { check = ((AlbumView) view).getEntry(); } @@ -261,6 +242,9 @@ public class UpdateView extends LinearLayout { if(starButton != null) { if(isStarred) { if(!starred) { + if(starButton.getDrawable() == null) { + starButton.setImageDrawable(DrawableTint.getTintedDrawable(context, R.drawable.ic_toggle_star)); + } starButton.setVisibility(View.VISIBLE); starred = true; } @@ -283,4 +267,55 @@ public class UpdateView extends LinearLayout { rating = isRated; } } + + public boolean isCheckable() { + return checkable; + } + public void setChecked(boolean checked) { + View child = getChildAt(0); + if (checked && startBackgroundDrawable == null) { + startBackgroundDrawable = child.getBackground(); + child.setBackgroundColor(DrawableTint.getColorRes(context, R.attr.colorPrimary)); + } else if (!checked && startBackgroundDrawable != null) { + child.setBackgroundDrawable(startBackgroundDrawable); + startBackgroundDrawable = null; + } + } + + public void onClick() { + + } + + public static class UpdateViewHolder<T> extends RecyclerView.ViewHolder { + private UpdateView updateView; + private View view; + private T item; + + public UpdateViewHolder(UpdateView itemView) { + super(itemView); + + this.updateView = itemView; + this.view = itemView; + } + + // Different is so that call is not ambiguous + public UpdateViewHolder(View view, boolean different) { + super(view); + this.view = view; + } + + public UpdateView<T> getUpdateView() { + return updateView; + } + public View getView() { + return view; + } + public void setItem(T item) { + this.item = item; + } + public T getItem() { + return item; + } + } } + diff --git a/app/src/main/java/github/daneren2005/dsub/view/UpdateView2.java b/app/src/main/java/github/daneren2005/dsub/view/UpdateView2.java new file mode 100644 index 00000000..0f0b5455 --- /dev/null +++ b/app/src/main/java/github/daneren2005/dsub/view/UpdateView2.java @@ -0,0 +1,47 @@ +package github.daneren2005.dsub.view; + +import android.content.Context; + +public abstract class UpdateView2<T1, T2> extends UpdateView<T1> { + protected T2 item2; + + public UpdateView2(Context context) { + super(context); + } + + public UpdateView2(Context context, boolean autoUpdate) { + super(context, autoUpdate); + } + + public final void setObject(T1 obj1) { + setObject(obj1, null); + } + @Override + public void setObject(T1 obj1, Object obj2) { + item = obj1; + item2 = (T2) obj2; + if(imageTask != null) { + imageTask.cancel(); + imageTask = null; + } + + setObjectImpl(item, item2); + backgroundHandler.post(new Runnable() { + @Override + public void run() { + updateBackground(); + uiHandler.post(new Runnable() { + @Override + public void run() { + update(); + } + }); + } + }); + } + + protected final void setObjectImpl(T1 obj1) { + setObjectImpl(obj1, null); + } + protected abstract void setObjectImpl(T1 obj1, T2 obj2); +} diff --git a/app/src/main/java/github/daneren2005/dsub/view/UserView.java b/app/src/main/java/github/daneren2005/dsub/view/UserView.java index dec8dbef..a97d755b 100644 --- a/app/src/main/java/github/daneren2005/dsub/view/UserView.java +++ b/app/src/main/java/github/daneren2005/dsub/view/UserView.java @@ -25,15 +25,12 @@ import github.daneren2005.dsub.R; import github.daneren2005.dsub.domain.User; import github.daneren2005.dsub.util.ImageLoader; -public class UserView extends UpdateView { - private User user; - +public class UserView extends UpdateView2<User, ImageLoader> { private TextView usernameView; private ImageView avatarView; public UserView(Context context) { super(context, false); - this.context = context; LayoutInflater.from(context).inflate(R.layout.user_list_item, this, true); usernameView = (TextView) findViewById(R.id.item_name); @@ -46,9 +43,8 @@ public class UserView extends UpdateView { }); } - protected void setObjectImpl(Object obj, Object obj2) { - this.user = (User) obj; + protected void setObjectImpl(User user, ImageLoader imageLoader) { usernameView.setText(user.getUsername()); - imageTask = ((ImageLoader)obj2).loadAvatar(context, avatarView, user.getUsername()); + imageTask = imageLoader.loadAvatar(context, avatarView, user.getUsername()); } } diff --git a/app/src/main/res/drawable-hdpi-v11/notification_close.png b/app/src/main/res/drawable-hdpi-v11/notification_close.png Binary files differdeleted file mode 100644 index 254e130f..00000000 --- a/app/src/main/res/drawable-hdpi-v11/notification_close.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi-v11/notification_next.png b/app/src/main/res/drawable-hdpi-v11/notification_next.png Binary files differdeleted file mode 100644 index 59239305..00000000 --- a/app/src/main/res/drawable-hdpi-v11/notification_next.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi-v11/notification_pause.png b/app/src/main/res/drawable-hdpi-v11/notification_pause.png Binary files differdeleted file mode 100644 index cbd61795..00000000 --- a/app/src/main/res/drawable-hdpi-v11/notification_pause.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi-v11/notification_play.png b/app/src/main/res/drawable-hdpi-v11/notification_play.png Binary files differdeleted file mode 100644 index 78b4d5bf..00000000 --- a/app/src/main/res/drawable-hdpi-v11/notification_play.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi-v11/notification_previous.png b/app/src/main/res/drawable-hdpi-v11/notification_previous.png Binary files differdeleted file mode 100644 index 556eaec3..00000000 --- a/app/src/main/res/drawable-hdpi-v11/notification_previous.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi-v11/stat_notify_download.png b/app/src/main/res/drawable-hdpi-v11/stat_notify_download.png Binary files differdeleted file mode 100644 index 48ca6924..00000000 --- a/app/src/main/res/drawable-hdpi-v11/stat_notify_download.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi-v11/stat_notify_playing.png b/app/src/main/res/drawable-hdpi-v11/stat_notify_playing.png Binary files differdeleted file mode 100644 index 78b4d5bf..00000000 --- a/app/src/main/res/drawable-hdpi-v11/stat_notify_playing.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi-v11/stat_notify_sync.png b/app/src/main/res/drawable-hdpi-v11/stat_notify_sync.png Binary files differdeleted file mode 100644 index f1ff1eb2..00000000 --- a/app/src/main/res/drawable-hdpi-v11/stat_notify_sync.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/action_toggle_list_dark.png b/app/src/main/res/drawable-hdpi/action_toggle_list_dark.png Binary files differindex d0ec1a5d..67056a69 100644 --- a/app/src/main/res/drawable-hdpi/action_toggle_list_dark.png +++ b/app/src/main/res/drawable-hdpi/action_toggle_list_dark.png diff --git a/app/src/main/res/drawable-hdpi/action_toggle_list_light.png b/app/src/main/res/drawable-hdpi/action_toggle_list_light.png Binary files differindex 60ec88be..77c3d03a 100644 --- a/app/src/main/res/drawable-hdpi/action_toggle_list_light.png +++ b/app/src/main/res/drawable-hdpi/action_toggle_list_light.png diff --git a/app/src/main/res/drawable-hdpi/download_none_dark.png b/app/src/main/res/drawable-hdpi/download_none_dark.png Binary files differindex a074c10d..faa25eba 100644 --- a/app/src/main/res/drawable-hdpi/download_none_dark.png +++ b/app/src/main/res/drawable-hdpi/download_none_dark.png diff --git a/app/src/main/res/drawable-hdpi/download_none_light.png b/app/src/main/res/drawable-hdpi/download_none_light.png Binary files differindex 21544e5f..470e5181 100644 --- a/app/src/main/res/drawable-hdpi/download_none_light.png +++ b/app/src/main/res/drawable-hdpi/download_none_light.png diff --git a/app/src/main/res/drawable-hdpi/downloading_dark.png b/app/src/main/res/drawable-hdpi/downloading_dark.png Binary files differindex 3ccb1837..b38e0130 100644 --- a/app/src/main/res/drawable-hdpi/downloading_dark.png +++ b/app/src/main/res/drawable-hdpi/downloading_dark.png diff --git a/app/src/main/res/drawable-hdpi/downloading_light.png b/app/src/main/res/drawable-hdpi/downloading_light.png Binary files differindex 07be3016..f8293ba6 100644 --- a/app/src/main/res/drawable-hdpi/downloading_light.png +++ b/app/src/main/res/drawable-hdpi/downloading_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_action_add_dark.png b/app/src/main/res/drawable-hdpi/ic_action_add_dark.png Binary files differindex 81d535d5..b1fbbf8c 100644 --- a/app/src/main/res/drawable-hdpi/ic_action_add_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_action_add_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_action_add_light.png b/app/src/main/res/drawable-hdpi/ic_action_add_light.png Binary files differindex 0e4f3347..6cceea30 100644 --- a/app/src/main/res/drawable-hdpi/ic_action_add_light.png +++ b/app/src/main/res/drawable-hdpi/ic_action_add_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_action_artist.png b/app/src/main/res/drawable-hdpi/ic_action_artist.png Binary files differindex 40c9a7fb..99f97ed9 100644 --- a/app/src/main/res/drawable-hdpi/ic_action_artist.png +++ b/app/src/main/res/drawable-hdpi/ic_action_artist.png diff --git a/app/src/main/res/drawable-hdpi/ic_action_rating_bad_dark.png b/app/src/main/res/drawable-hdpi/ic_action_rating_bad_dark.png Binary files differindex 855709e9..b21ef12a 100644 --- a/app/src/main/res/drawable-hdpi/ic_action_rating_bad_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_action_rating_bad_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_action_rating_bad_light.png b/app/src/main/res/drawable-hdpi/ic_action_rating_bad_light.png Binary files differindex 34199d3a..ab8eb54c 100644 --- a/app/src/main/res/drawable-hdpi/ic_action_rating_bad_light.png +++ b/app/src/main/res/drawable-hdpi/ic_action_rating_bad_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_action_rating_bad_selected.png b/app/src/main/res/drawable-hdpi/ic_action_rating_bad_selected.png Binary files differindex c57aba50..911eea25 100644 --- a/app/src/main/res/drawable-hdpi/ic_action_rating_bad_selected.png +++ b/app/src/main/res/drawable-hdpi/ic_action_rating_bad_selected.png diff --git a/app/src/main/res/drawable-hdpi/ic_action_rating_good_dark.png b/app/src/main/res/drawable-hdpi/ic_action_rating_good_dark.png Binary files differindex fa91e699..f79fcbcd 100644 --- a/app/src/main/res/drawable-hdpi/ic_action_rating_good_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_action_rating_good_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_action_rating_good_light.png b/app/src/main/res/drawable-hdpi/ic_action_rating_good_light.png Binary files differindex 3427d770..67b30364 100644 --- a/app/src/main/res/drawable-hdpi/ic_action_rating_good_light.png +++ b/app/src/main/res/drawable-hdpi/ic_action_rating_good_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_action_rating_good_selected.png b/app/src/main/res/drawable-hdpi/ic_action_rating_good_selected.png Binary files differindex 34d53153..09417791 100644 --- a/app/src/main/res/drawable-hdpi/ic_action_rating_good_selected.png +++ b/app/src/main/res/drawable-hdpi/ic_action_rating_good_selected.png diff --git a/app/src/main/res/drawable-hdpi/ic_action_song.png b/app/src/main/res/drawable-hdpi/ic_action_song.png Binary files differindex 95342f76..fd686916 100644 --- a/app/src/main/res/drawable-hdpi/ic_action_song.png +++ b/app/src/main/res/drawable-hdpi/ic_action_song.png diff --git a/app/src/main/res/drawable-hdpi/ic_action_volume_dark.png b/app/src/main/res/drawable-hdpi/ic_action_volume_dark.png Binary files differdeleted file mode 100644 index 62550655..00000000 --- a/app/src/main/res/drawable-hdpi/ic_action_volume_dark.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/ic_action_volume_light.png b/app/src/main/res/drawable-hdpi/ic_action_volume_light.png Binary files differdeleted file mode 100644 index 1b1d182c..00000000 --- a/app/src/main/res/drawable-hdpi/ic_action_volume_light.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/ic_appwidget_music_next.png b/app/src/main/res/drawable-hdpi/ic_appwidget_music_next.png Binary files differdeleted file mode 100644 index 99d28766..00000000 --- a/app/src/main/res/drawable-hdpi/ic_appwidget_music_next.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/ic_appwidget_music_pause.png b/app/src/main/res/drawable-hdpi/ic_appwidget_music_pause.png Binary files differdeleted file mode 100644 index a05a8c50..00000000 --- a/app/src/main/res/drawable-hdpi/ic_appwidget_music_pause.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/ic_appwidget_music_play.png b/app/src/main/res/drawable-hdpi/ic_appwidget_music_play.png Binary files differdeleted file mode 100644 index a754b920..00000000 --- a/app/src/main/res/drawable-hdpi/ic_appwidget_music_play.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/ic_appwidget_music_previous.png b/app/src/main/res/drawable-hdpi/ic_appwidget_music_previous.png Binary files differdeleted file mode 100644 index 7fb3921b..00000000 --- a/app/src/main/res/drawable-hdpi/ic_appwidget_music_previous.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/ic_menu_add_person_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_add_person_dark.png Binary files differindex 971048d5..57695423 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_add_person_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_add_person_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_add_person_light.png b/app/src/main/res/drawable-hdpi/ic_menu_add_person_light.png Binary files differindex f94446d0..25c801a3 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_add_person_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_add_person_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_admin_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_admin_dark.png Binary files differindex 76da5ade..b97c9a95 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_admin_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_admin_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_admin_light.png b/app/src/main/res/drawable-hdpi/ic_menu_admin_light.png Binary files differindex 5431889c..927000f2 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_admin_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_admin_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_bookmark_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_bookmark_dark.png Binary files differindex e7cd08e4..e149a6e5 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_bookmark_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_bookmark_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_bookmark_light.png b/app/src/main/res/drawable-hdpi/ic_menu_bookmark_light.png Binary files differindex fdb46da3..c9ece7c0 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_bookmark_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_bookmark_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_bookmark_selected.png b/app/src/main/res/drawable-hdpi/ic_menu_bookmark_selected.png Binary files differindex 5a33d60c..27696f5b 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_bookmark_selected.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_bookmark_selected.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_chat_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_chat_dark.png Binary files differindex 75363fce..5914cb1f 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_chat_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_chat_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_chat_light.png b/app/src/main/res/drawable-hdpi/ic_menu_chat_light.png Binary files differindex e28933e4..6ba671b3 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_chat_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_chat_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_chat_send_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_chat_send_dark.png Binary files differindex c0e9b372..369616c2 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_chat_send_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_chat_send_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_chat_send_light.png b/app/src/main/res/drawable-hdpi/ic_menu_chat_send_light.png Binary files differindex ebcfe9e8..c3ba80f5 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_chat_send_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_chat_send_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_download_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_download_dark.png Binary files differindex 872b73c0..5f32ced1 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_download_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_download_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_download_light.png b/app/src/main/res/drawable-hdpi/ic_menu_download_light.png Binary files differindex f8818490..fc71ad5e 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_download_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_download_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_library_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_library_dark.png Binary files differindex 717cb3e1..8e0b524d 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_library_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_library_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_library_light.png b/app/src/main/res/drawable-hdpi/ic_menu_library_light.png Binary files differindex 17a45d77..bf85f004 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_library_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_library_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_password_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_password_dark.png Binary files differindex 67fa3e84..6ea36c62 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_password_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_password_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_password_light.png b/app/src/main/res/drawable-hdpi/ic_menu_password_light.png Binary files differindex bd99c01f..97809dc8 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_password_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_password_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_playlist_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_playlist_dark.png Binary files differindex 8e3babc7..0bb68014 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_playlist_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_playlist_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_playlist_light.png b/app/src/main/res/drawable-hdpi/ic_menu_playlist_light.png Binary files differindex 4131dba4..7f3edf77 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_playlist_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_playlist_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_podcast_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_podcast_dark.png Binary files differindex d1d62d03..9bf78633 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_podcast_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_podcast_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_podcast_light.png b/app/src/main/res/drawable-hdpi/ic_menu_podcast_light.png Binary files differindex 4ce1b787..092729c9 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_podcast_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_podcast_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_radio_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_radio_dark.png Binary files differindex a801dce0..71c5f4e6 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_radio_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_radio_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_radio_light.png b/app/src/main/res/drawable-hdpi/ic_menu_radio_light.png Binary files differindex b723d574..fe0e47d2 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_radio_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_radio_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_refresh_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_refresh_dark.png Binary files differindex 2795cfa9..ac0b40e5 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_refresh_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_refresh_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_refresh_light.png b/app/src/main/res/drawable-hdpi/ic_menu_refresh_light.png Binary files differindex 86d1b042..328aac5d 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_refresh_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_refresh_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_remove_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_remove_dark.png Binary files differindex 878b378a..d59656fa 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_remove_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_remove_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_remove_light.png b/app/src/main/res/drawable-hdpi/ic_menu_remove_light.png Binary files differindex ece5ad8d..e8b5e90d 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_remove_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_remove_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_save_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_save_dark.png Binary files differindex b80828bf..a8dc7e04 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_save_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_save_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_save_light.png b/app/src/main/res/drawable-hdpi/ic_menu_save_light.png Binary files differindex a3a5e23a..68feedd1 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_save_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_save_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_search_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_search_dark.png Binary files differindex ef2b3013..9e944a26 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_search_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_search_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_search_light.png b/app/src/main/res/drawable-hdpi/ic_menu_search_light.png Binary files differindex 756937df..9810302b 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_search_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_search_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_settings_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_settings_dark.png Binary files differindex d6dd17ec..23e0c73b 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_settings_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_settings_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_settings_light.png b/app/src/main/res/drawable-hdpi/ic_menu_settings_light.png Binary files differindex 70c29951..252611a4 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_settings_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_settings_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_share_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_share_dark.png Binary files differindex 218aa864..b0f4b790 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_share_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_share_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_share_light.png b/app/src/main/res/drawable-hdpi/ic_menu_share_light.png Binary files differindex cfd19d43..b4995456 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_share_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_share_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_shuffle_dark.png b/app/src/main/res/drawable-hdpi/ic_menu_shuffle_dark.png Binary files differindex f77cfed2..8a82733d 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_shuffle_dark.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_shuffle_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_menu_shuffle_light.png b/app/src/main/res/drawable-hdpi/ic_menu_shuffle_light.png Binary files differindex ded93939..bc7408c7 100644 --- a/app/src/main/res/drawable-hdpi/ic_menu_shuffle_light.png +++ b/app/src/main/res/drawable-hdpi/ic_menu_shuffle_light.png diff --git a/app/src/main/res/drawable-hdpi/ic_social_person.png b/app/src/main/res/drawable-hdpi/ic_social_person.png Binary files differindex 0a0a5ff2..c8ebd5cd 100644 --- a/app/src/main/res/drawable-hdpi/ic_social_person.png +++ b/app/src/main/res/drawable-hdpi/ic_social_person.png diff --git a/app/src/main/res/drawable-hdpi/ic_stat_star.png b/app/src/main/res/drawable-hdpi/ic_stat_star.png Binary files differdeleted file mode 100644 index 67ad40f5..00000000 --- a/app/src/main/res/drawable-hdpi/ic_stat_star.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/ic_toggle_star.png b/app/src/main/res/drawable-hdpi/ic_toggle_star.png Binary files differnew file mode 100644 index 00000000..f9ef8772 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/ic_toggle_star.png diff --git a/app/src/main/res/drawable-hdpi/ic_toggle_star_outline_dark.png b/app/src/main/res/drawable-hdpi/ic_toggle_star_outline_dark.png Binary files differnew file mode 100644 index 00000000..87a0d5c5 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/ic_toggle_star_outline_dark.png diff --git a/app/src/main/res/drawable-hdpi/ic_toggle_star_outline_light.png b/app/src/main/res/drawable-hdpi/ic_toggle_star_outline_light.png Binary files differnew file mode 100644 index 00000000..b679803f --- /dev/null +++ b/app/src/main/res/drawable-hdpi/ic_toggle_star_outline_light.png diff --git a/app/src/main/res/drawable-hdpi/launch.png b/app/src/main/res/drawable-hdpi/launch.png Binary files differindex 0c77b9b4..36f7b683 100644 --- a/app/src/main/res/drawable-hdpi/launch.png +++ b/app/src/main/res/drawable-hdpi/launch.png diff --git a/app/src/main/res/drawable-hdpi/main_offline_dark.png b/app/src/main/res/drawable-hdpi/main_offline_dark.png Binary files differindex a594530d..63652624 100644 --- a/app/src/main/res/drawable-hdpi/main_offline_dark.png +++ b/app/src/main/res/drawable-hdpi/main_offline_dark.png diff --git a/app/src/main/res/drawable-hdpi/main_offline_light.png b/app/src/main/res/drawable-hdpi/main_offline_light.png Binary files differindex cabca581..43a11661 100644 --- a/app/src/main/res/drawable-hdpi/main_offline_light.png +++ b/app/src/main/res/drawable-hdpi/main_offline_light.png diff --git a/app/src/main/res/drawable-hdpi/main_select_server_dark.png b/app/src/main/res/drawable-hdpi/main_select_server_dark.png Binary files differindex e3a9dd5d..f55c5f46 100644 --- a/app/src/main/res/drawable-hdpi/main_select_server_dark.png +++ b/app/src/main/res/drawable-hdpi/main_select_server_dark.png diff --git a/app/src/main/res/drawable-hdpi/main_select_server_light.png b/app/src/main/res/drawable-hdpi/main_select_server_light.png Binary files differindex 4606410d..f52082ab 100644 --- a/app/src/main/res/drawable-hdpi/main_select_server_light.png +++ b/app/src/main/res/drawable-hdpi/main_select_server_light.png diff --git a/app/src/main/res/drawable-hdpi/main_select_tabs_dark.png b/app/src/main/res/drawable-hdpi/main_select_tabs_dark.png Binary files differnew file mode 100644 index 00000000..67d47d64 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/main_select_tabs_dark.png diff --git a/app/src/main/res/drawable-hdpi/main_select_tabs_light.png b/app/src/main/res/drawable-hdpi/main_select_tabs_light.png Binary files differnew file mode 100644 index 00000000..c05b3779 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/main_select_tabs_light.png diff --git a/app/src/main/res/drawable-hdpi/media_backward_dark.png b/app/src/main/res/drawable-hdpi/media_backward_dark.png Binary files differindex b1dde4f5..deae7a8d 100644 --- a/app/src/main/res/drawable-hdpi/media_backward_dark.png +++ b/app/src/main/res/drawable-hdpi/media_backward_dark.png diff --git a/app/src/main/res/drawable-hdpi/media_backward_light.png b/app/src/main/res/drawable-hdpi/media_backward_light.png Binary files differindex 3e277267..11a3b225 100644 --- a/app/src/main/res/drawable-hdpi/media_backward_light.png +++ b/app/src/main/res/drawable-hdpi/media_backward_light.png diff --git a/app/src/main/res/drawable-hdpi/media_forward_dark.png b/app/src/main/res/drawable-hdpi/media_forward_dark.png Binary files differindex eb2546c7..b60f240d 100644 --- a/app/src/main/res/drawable-hdpi/media_forward_dark.png +++ b/app/src/main/res/drawable-hdpi/media_forward_dark.png diff --git a/app/src/main/res/drawable-hdpi/media_forward_light.png b/app/src/main/res/drawable-hdpi/media_forward_light.png Binary files differindex 185e3c39..cb4b70cf 100644 --- a/app/src/main/res/drawable-hdpi/media_forward_light.png +++ b/app/src/main/res/drawable-hdpi/media_forward_light.png diff --git a/app/src/main/res/drawable-hdpi/media_pause_dark.png b/app/src/main/res/drawable-hdpi/media_pause_dark.png Binary files differindex b057588e..fdf1c1a2 100644 --- a/app/src/main/res/drawable-hdpi/media_pause_dark.png +++ b/app/src/main/res/drawable-hdpi/media_pause_dark.png diff --git a/app/src/main/res/drawable-hdpi/media_pause_light.png b/app/src/main/res/drawable-hdpi/media_pause_light.png Binary files differindex e01815e3..fdd2276f 100644 --- a/app/src/main/res/drawable-hdpi/media_pause_light.png +++ b/app/src/main/res/drawable-hdpi/media_pause_light.png diff --git a/app/src/main/res/drawable-hdpi/media_repeat_all.png b/app/src/main/res/drawable-hdpi/media_repeat_all.png Binary files differdeleted file mode 100644 index c2255058..00000000 --- a/app/src/main/res/drawable-hdpi/media_repeat_all.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/media_repeat_all_dark.png b/app/src/main/res/drawable-hdpi/media_repeat_all_dark.png Binary files differnew file mode 100644 index 00000000..995bbaa4 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/media_repeat_all_dark.png diff --git a/app/src/main/res/drawable-hdpi/media_repeat_all_light.png b/app/src/main/res/drawable-hdpi/media_repeat_all_light.png Binary files differnew file mode 100644 index 00000000..6dfa1024 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/media_repeat_all_light.png diff --git a/app/src/main/res/drawable-hdpi/media_repeat_off.png b/app/src/main/res/drawable-hdpi/media_repeat_off.png Binary files differdeleted file mode 100644 index 10315ab3..00000000 --- a/app/src/main/res/drawable-hdpi/media_repeat_off.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/media_repeat_off_dark.png b/app/src/main/res/drawable-hdpi/media_repeat_off_dark.png Binary files differnew file mode 100644 index 00000000..ce34c67d --- /dev/null +++ b/app/src/main/res/drawable-hdpi/media_repeat_off_dark.png diff --git a/app/src/main/res/drawable-hdpi/media_repeat_off_light.png b/app/src/main/res/drawable-hdpi/media_repeat_off_light.png Binary files differindex 39408bec..0211df57 100644 --- a/app/src/main/res/drawable-hdpi/media_repeat_off_light.png +++ b/app/src/main/res/drawable-hdpi/media_repeat_off_light.png diff --git a/app/src/main/res/drawable-hdpi/media_repeat_single.png b/app/src/main/res/drawable-hdpi/media_repeat_single.png Binary files differdeleted file mode 100644 index 6d280e7a..00000000 --- a/app/src/main/res/drawable-hdpi/media_repeat_single.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/media_repeat_single_dark.png b/app/src/main/res/drawable-hdpi/media_repeat_single_dark.png Binary files differnew file mode 100644 index 00000000..55321dc9 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/media_repeat_single_dark.png diff --git a/app/src/main/res/drawable-hdpi/media_repeat_single_light.png b/app/src/main/res/drawable-hdpi/media_repeat_single_light.png Binary files differnew file mode 100644 index 00000000..0879d340 --- /dev/null +++ b/app/src/main/res/drawable-hdpi/media_repeat_single_light.png diff --git a/app/src/main/res/drawable-hdpi/media_start_dark.png b/app/src/main/res/drawable-hdpi/media_start_dark.png Binary files differindex dbfd337a..6ac4d556 100644 --- a/app/src/main/res/drawable-hdpi/media_start_dark.png +++ b/app/src/main/res/drawable-hdpi/media_start_dark.png diff --git a/app/src/main/res/drawable-hdpi/media_start_light.png b/app/src/main/res/drawable-hdpi/media_start_light.png Binary files differindex e4310efc..3395873a 100644 --- a/app/src/main/res/drawable-hdpi/media_start_light.png +++ b/app/src/main/res/drawable-hdpi/media_start_light.png diff --git a/app/src/main/res/drawable-hdpi/media_stop_dark.png b/app/src/main/res/drawable-hdpi/media_stop_dark.png Binary files differindex 5ceb39f3..33fca4c5 100644 --- a/app/src/main/res/drawable-hdpi/media_stop_dark.png +++ b/app/src/main/res/drawable-hdpi/media_stop_dark.png diff --git a/app/src/main/res/drawable-hdpi/media_stop_light.png b/app/src/main/res/drawable-hdpi/media_stop_light.png Binary files differindex 8deca73e..947f220d 100644 --- a/app/src/main/res/drawable-hdpi/media_stop_light.png +++ b/app/src/main/res/drawable-hdpi/media_stop_light.png diff --git a/app/src/main/res/drawable-hdpi/notification_close.png b/app/src/main/res/drawable-hdpi/notification_close.png Binary files differdeleted file mode 100644 index 916c9a0f..00000000 --- a/app/src/main/res/drawable-hdpi/notification_close.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/notification_close_dark.png b/app/src/main/res/drawable-hdpi/notification_close_dark.png Binary files differnew file mode 100644 index 00000000..5f9f2c5a --- /dev/null +++ b/app/src/main/res/drawable-hdpi/notification_close_dark.png diff --git a/app/src/main/res/drawable-hdpi/notification_close_light.png b/app/src/main/res/drawable-hdpi/notification_close_light.png Binary files differnew file mode 100644 index 00000000..11621f1f --- /dev/null +++ b/app/src/main/res/drawable-hdpi/notification_close_light.png diff --git a/app/src/main/res/drawable-hdpi/notification_next.png b/app/src/main/res/drawable-hdpi/notification_next.png Binary files differdeleted file mode 100644 index 078c310f..00000000 --- a/app/src/main/res/drawable-hdpi/notification_next.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/notification_pause.png b/app/src/main/res/drawable-hdpi/notification_pause.png Binary files differdeleted file mode 100644 index 16627e44..00000000 --- a/app/src/main/res/drawable-hdpi/notification_pause.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/notification_play.png b/app/src/main/res/drawable-hdpi/notification_play.png Binary files differdeleted file mode 100644 index 02f38944..00000000 --- a/app/src/main/res/drawable-hdpi/notification_play.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/notification_previous.png b/app/src/main/res/drawable-hdpi/notification_previous.png Binary files differdeleted file mode 100644 index 9d10abd9..00000000 --- a/app/src/main/res/drawable-hdpi/notification_previous.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/now_playing.png b/app/src/main/res/drawable-hdpi/now_playing.png Binary files differdeleted file mode 100644 index 02f38944..00000000 --- a/app/src/main/res/drawable-hdpi/now_playing.png +++ /dev/null diff --git a/app/src/main/res/drawable-hdpi/stat_notify_download.png b/app/src/main/res/drawable-hdpi/stat_notify_download.png Binary files differindex aa1b6c92..48ca6924 100644 --- a/app/src/main/res/drawable-hdpi/stat_notify_download.png +++ b/app/src/main/res/drawable-hdpi/stat_notify_download.png diff --git a/app/src/main/res/drawable-hdpi/stat_notify_playing.png b/app/src/main/res/drawable-hdpi/stat_notify_playing.png Binary files differindex 02f38944..78b4d5bf 100644 --- a/app/src/main/res/drawable-hdpi/stat_notify_playing.png +++ b/app/src/main/res/drawable-hdpi/stat_notify_playing.png diff --git a/app/src/main/res/drawable-hdpi/stat_notify_sync.png b/app/src/main/res/drawable-hdpi/stat_notify_sync.png Binary files differindex 7dbf0e95..f1ff1eb2 100644 --- a/app/src/main/res/drawable-hdpi/stat_notify_sync.png +++ b/app/src/main/res/drawable-hdpi/stat_notify_sync.png diff --git a/app/src/main/res/drawable-mdpi-v11/notification_close.png b/app/src/main/res/drawable-mdpi-v11/notification_close.png Binary files differdeleted file mode 100644 index a056fe61..00000000 --- a/app/src/main/res/drawable-mdpi-v11/notification_close.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi-v11/notification_next.png b/app/src/main/res/drawable-mdpi-v11/notification_next.png Binary files differdeleted file mode 100644 index 7297577f..00000000 --- a/app/src/main/res/drawable-mdpi-v11/notification_next.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi-v11/notification_pause.png b/app/src/main/res/drawable-mdpi-v11/notification_pause.png Binary files differdeleted file mode 100644 index 5d3ca3f2..00000000 --- a/app/src/main/res/drawable-mdpi-v11/notification_pause.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi-v11/notification_play.png b/app/src/main/res/drawable-mdpi-v11/notification_play.png Binary files differdeleted file mode 100644 index 999ce798..00000000 --- a/app/src/main/res/drawable-mdpi-v11/notification_play.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi-v11/notification_previous.png b/app/src/main/res/drawable-mdpi-v11/notification_previous.png Binary files differdeleted file mode 100644 index 55a1f326..00000000 --- a/app/src/main/res/drawable-mdpi-v11/notification_previous.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi-v11/stat_notify_download.png b/app/src/main/res/drawable-mdpi-v11/stat_notify_download.png Binary files differdeleted file mode 100644 index 4164e0fa..00000000 --- a/app/src/main/res/drawable-mdpi-v11/stat_notify_download.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi-v11/stat_notify_playing.png b/app/src/main/res/drawable-mdpi-v11/stat_notify_playing.png Binary files differdeleted file mode 100644 index 999ce798..00000000 --- a/app/src/main/res/drawable-mdpi-v11/stat_notify_playing.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi-v11/stat_notify_sync.png b/app/src/main/res/drawable-mdpi-v11/stat_notify_sync.png Binary files differdeleted file mode 100644 index 3e3c64c0..00000000 --- a/app/src/main/res/drawable-mdpi-v11/stat_notify_sync.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi/action_toggle_list_dark.png b/app/src/main/res/drawable-mdpi/action_toggle_list_dark.png Binary files differindex ace7fcee..39df0cfa 100644 --- a/app/src/main/res/drawable-mdpi/action_toggle_list_dark.png +++ b/app/src/main/res/drawable-mdpi/action_toggle_list_dark.png diff --git a/app/src/main/res/drawable-mdpi/action_toggle_list_light.png b/app/src/main/res/drawable-mdpi/action_toggle_list_light.png Binary files differindex fa6432da..f769e18b 100644 --- a/app/src/main/res/drawable-mdpi/action_toggle_list_light.png +++ b/app/src/main/res/drawable-mdpi/action_toggle_list_light.png diff --git a/app/src/main/res/drawable-mdpi/download_none_dark.png b/app/src/main/res/drawable-mdpi/download_none_dark.png Binary files differindex b6d614fc..373c8c62 100644 --- a/app/src/main/res/drawable-mdpi/download_none_dark.png +++ b/app/src/main/res/drawable-mdpi/download_none_dark.png diff --git a/app/src/main/res/drawable-mdpi/download_none_light.png b/app/src/main/res/drawable-mdpi/download_none_light.png Binary files differindex 2485c570..f8499a06 100644 --- a/app/src/main/res/drawable-mdpi/download_none_light.png +++ b/app/src/main/res/drawable-mdpi/download_none_light.png diff --git a/app/src/main/res/drawable-mdpi/downloading_dark.png b/app/src/main/res/drawable-mdpi/downloading_dark.png Binary files differindex ae6c5c9c..a150679a 100644 --- a/app/src/main/res/drawable-mdpi/downloading_dark.png +++ b/app/src/main/res/drawable-mdpi/downloading_dark.png diff --git a/app/src/main/res/drawable-mdpi/downloading_light.png b/app/src/main/res/drawable-mdpi/downloading_light.png Binary files differindex abd5b748..f42bcf45 100644 --- a/app/src/main/res/drawable-mdpi/downloading_light.png +++ b/app/src/main/res/drawable-mdpi/downloading_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_action_add_dark.png b/app/src/main/res/drawable-mdpi/ic_action_add_dark.png Binary files differindex a4c84f0f..478b2c74 100644 --- a/app/src/main/res/drawable-mdpi/ic_action_add_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_action_add_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_action_add_light.png b/app/src/main/res/drawable-mdpi/ic_action_add_light.png Binary files differindex 86097d84..6bfd5538 100644 --- a/app/src/main/res/drawable-mdpi/ic_action_add_light.png +++ b/app/src/main/res/drawable-mdpi/ic_action_add_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_action_artist.png b/app/src/main/res/drawable-mdpi/ic_action_artist.png Binary files differindex c113cf78..a78beaa5 100644 --- a/app/src/main/res/drawable-mdpi/ic_action_artist.png +++ b/app/src/main/res/drawable-mdpi/ic_action_artist.png diff --git a/app/src/main/res/drawable-mdpi/ic_action_rating_bad_dark.png b/app/src/main/res/drawable-mdpi/ic_action_rating_bad_dark.png Binary files differindex 64f3cd1f..00925d7e 100644 --- a/app/src/main/res/drawable-mdpi/ic_action_rating_bad_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_action_rating_bad_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_action_rating_bad_light.png b/app/src/main/res/drawable-mdpi/ic_action_rating_bad_light.png Binary files differindex d6c8d42a..eb4cc960 100644 --- a/app/src/main/res/drawable-mdpi/ic_action_rating_bad_light.png +++ b/app/src/main/res/drawable-mdpi/ic_action_rating_bad_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_action_rating_bad_selected.png b/app/src/main/res/drawable-mdpi/ic_action_rating_bad_selected.png Binary files differindex 34f5a9de..ac563748 100644 --- a/app/src/main/res/drawable-mdpi/ic_action_rating_bad_selected.png +++ b/app/src/main/res/drawable-mdpi/ic_action_rating_bad_selected.png diff --git a/app/src/main/res/drawable-mdpi/ic_action_rating_good_dark.png b/app/src/main/res/drawable-mdpi/ic_action_rating_good_dark.png Binary files differindex cadfbe1e..4978b140 100644 --- a/app/src/main/res/drawable-mdpi/ic_action_rating_good_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_action_rating_good_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_action_rating_good_light.png b/app/src/main/res/drawable-mdpi/ic_action_rating_good_light.png Binary files differindex 75711920..07382a0a 100644 --- a/app/src/main/res/drawable-mdpi/ic_action_rating_good_light.png +++ b/app/src/main/res/drawable-mdpi/ic_action_rating_good_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_action_rating_good_selected.png b/app/src/main/res/drawable-mdpi/ic_action_rating_good_selected.png Binary files differindex 97d279be..197aa106 100644 --- a/app/src/main/res/drawable-mdpi/ic_action_rating_good_selected.png +++ b/app/src/main/res/drawable-mdpi/ic_action_rating_good_selected.png diff --git a/app/src/main/res/drawable-mdpi/ic_action_song.png b/app/src/main/res/drawable-mdpi/ic_action_song.png Binary files differindex fa9acbde..fda9347c 100644 --- a/app/src/main/res/drawable-mdpi/ic_action_song.png +++ b/app/src/main/res/drawable-mdpi/ic_action_song.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_add_person_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_add_person_dark.png Binary files differindex 7d64f5d3..5487dc44 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_add_person_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_add_person_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_add_person_light.png b/app/src/main/res/drawable-mdpi/ic_menu_add_person_light.png Binary files differindex 55c38c26..ce9a577a 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_add_person_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_add_person_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_admin_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_admin_dark.png Binary files differindex f88f5f15..a416da3d 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_admin_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_admin_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_admin_light.png b/app/src/main/res/drawable-mdpi/ic_menu_admin_light.png Binary files differindex 35cd14f4..2b4082fa 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_admin_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_admin_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_bookmark_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_bookmark_dark.png Binary files differindex 3360f37e..281479af 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_bookmark_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_bookmark_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_bookmark_light.png b/app/src/main/res/drawable-mdpi/ic_menu_bookmark_light.png Binary files differindex b4d916fb..76bfb63c 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_bookmark_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_bookmark_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_bookmark_selected.png b/app/src/main/res/drawable-mdpi/ic_menu_bookmark_selected.png Binary files differindex efcc1afa..9469278e 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_bookmark_selected.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_bookmark_selected.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_chat_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_chat_dark.png Binary files differindex 74d98888..6d3e25ff 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_chat_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_chat_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_chat_light.png b/app/src/main/res/drawable-mdpi/ic_menu_chat_light.png Binary files differindex 468c1220..e28b43f8 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_chat_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_chat_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_chat_send_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_chat_send_dark.png Binary files differindex 91db4a4a..348728a3 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_chat_send_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_chat_send_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_chat_send_light.png b/app/src/main/res/drawable-mdpi/ic_menu_chat_send_light.png Binary files differindex f2a3e724..219a447e 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_chat_send_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_chat_send_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_download_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_download_dark.png Binary files differindex 935bbd45..906e6e93 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_download_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_download_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_download_light.png b/app/src/main/res/drawable-mdpi/ic_menu_download_light.png Binary files differindex cc13d444..7d700cfc 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_download_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_download_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_library_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_library_dark.png Binary files differindex 0102d7ad..bca3b9f0 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_library_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_library_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_library_light.png b/app/src/main/res/drawable-mdpi/ic_menu_library_light.png Binary files differindex a30b4d39..71c10923 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_library_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_library_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_password_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_password_dark.png Binary files differindex 74d0095a..360687bd 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_password_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_password_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_password_light.png b/app/src/main/res/drawable-mdpi/ic_menu_password_light.png Binary files differindex 159f7889..899ad400 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_password_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_password_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_playlist_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_playlist_dark.png Binary files differindex ebf00427..e014786c 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_playlist_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_playlist_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_playlist_light.png b/app/src/main/res/drawable-mdpi/ic_menu_playlist_light.png Binary files differindex e248a488..cd883d3f 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_playlist_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_playlist_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_podcast_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_podcast_dark.png Binary files differindex ad69156a..556d18e1 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_podcast_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_podcast_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_podcast_light.png b/app/src/main/res/drawable-mdpi/ic_menu_podcast_light.png Binary files differindex c15cb03f..c9db2562 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_podcast_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_podcast_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_radio_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_radio_dark.png Binary files differindex bab20118..e40610e0 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_radio_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_radio_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_radio_light.png b/app/src/main/res/drawable-mdpi/ic_menu_radio_light.png Binary files differindex 72578d54..fd25e285 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_radio_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_radio_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_refresh_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_refresh_dark.png Binary files differindex 554c07dc..70d64009 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_refresh_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_refresh_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_refresh_light.png b/app/src/main/res/drawable-mdpi/ic_menu_refresh_light.png Binary files differindex a2d90c16..a7b66b88 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_refresh_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_refresh_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_remove_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_remove_dark.png Binary files differindex 5ba24546..30d7b7db 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_remove_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_remove_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_remove_light.png b/app/src/main/res/drawable-mdpi/ic_menu_remove_light.png Binary files differindex 93483b6c..9e5a6b65 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_remove_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_remove_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_save_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_save_dark.png Binary files differindex 89aa17cc..67240244 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_save_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_save_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_save_light.png b/app/src/main/res/drawable-mdpi/ic_menu_save_light.png Binary files differindex dcb3a2f6..eb5ef08b 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_save_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_save_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_search_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_search_dark.png Binary files differindex 076085c5..a24b79b8 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_search_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_search_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_search_light.png b/app/src/main/res/drawable-mdpi/ic_menu_search_light.png Binary files differindex 026c8498..f70bef02 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_search_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_search_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_settings_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_settings_dark.png Binary files differindex fc2bf8c3..52d23ead 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_settings_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_settings_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_settings_light.png b/app/src/main/res/drawable-mdpi/ic_menu_settings_light.png Binary files differindex 0e65c682..46b49af0 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_settings_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_settings_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_share_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_share_dark.png Binary files differindex c37aadba..ea7ef5e6 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_share_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_share_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_share_light.png b/app/src/main/res/drawable-mdpi/ic_menu_share_light.png Binary files differindex 72eeb598..9c49ac5f 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_share_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_share_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_shuffle_dark.png b/app/src/main/res/drawable-mdpi/ic_menu_shuffle_dark.png Binary files differindex 7007fde5..0e078ebb 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_shuffle_dark.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_shuffle_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_menu_shuffle_light.png b/app/src/main/res/drawable-mdpi/ic_menu_shuffle_light.png Binary files differindex 4d07c3b4..46c3382b 100644 --- a/app/src/main/res/drawable-mdpi/ic_menu_shuffle_light.png +++ b/app/src/main/res/drawable-mdpi/ic_menu_shuffle_light.png diff --git a/app/src/main/res/drawable-mdpi/ic_social_person.png b/app/src/main/res/drawable-mdpi/ic_social_person.png Binary files differindex c09313d8..dc081000 100644 --- a/app/src/main/res/drawable-mdpi/ic_social_person.png +++ b/app/src/main/res/drawable-mdpi/ic_social_person.png diff --git a/app/src/main/res/drawable-mdpi/ic_toggle_star.png b/app/src/main/res/drawable-mdpi/ic_toggle_star.png Binary files differnew file mode 100644 index 00000000..6d949fd0 --- /dev/null +++ b/app/src/main/res/drawable-mdpi/ic_toggle_star.png diff --git a/app/src/main/res/drawable-mdpi/ic_toggle_star_outline_dark.png b/app/src/main/res/drawable-mdpi/ic_toggle_star_outline_dark.png Binary files differnew file mode 100644 index 00000000..72231a73 --- /dev/null +++ b/app/src/main/res/drawable-mdpi/ic_toggle_star_outline_dark.png diff --git a/app/src/main/res/drawable-mdpi/ic_toggle_star_outline_light.png b/app/src/main/res/drawable-mdpi/ic_toggle_star_outline_light.png Binary files differnew file mode 100644 index 00000000..85a184bc --- /dev/null +++ b/app/src/main/res/drawable-mdpi/ic_toggle_star_outline_light.png diff --git a/app/src/main/res/drawable-mdpi/launch.png b/app/src/main/res/drawable-mdpi/launch.png Binary files differindex 88887e94..9117c4c2 100644 --- a/app/src/main/res/drawable-mdpi/launch.png +++ b/app/src/main/res/drawable-mdpi/launch.png diff --git a/app/src/main/res/drawable-mdpi/main_offline_dark.png b/app/src/main/res/drawable-mdpi/main_offline_dark.png Binary files differindex 4990fb8e..b44735fb 100644 --- a/app/src/main/res/drawable-mdpi/main_offline_dark.png +++ b/app/src/main/res/drawable-mdpi/main_offline_dark.png diff --git a/app/src/main/res/drawable-mdpi/main_offline_light.png b/app/src/main/res/drawable-mdpi/main_offline_light.png Binary files differindex e70ec1c2..831e90ce 100644 --- a/app/src/main/res/drawable-mdpi/main_offline_light.png +++ b/app/src/main/res/drawable-mdpi/main_offline_light.png diff --git a/app/src/main/res/drawable-mdpi/main_select_server_dark.png b/app/src/main/res/drawable-mdpi/main_select_server_dark.png Binary files differindex 119b1573..8ec92b49 100644 --- a/app/src/main/res/drawable-mdpi/main_select_server_dark.png +++ b/app/src/main/res/drawable-mdpi/main_select_server_dark.png diff --git a/app/src/main/res/drawable-mdpi/main_select_server_light.png b/app/src/main/res/drawable-mdpi/main_select_server_light.png Binary files differindex 7d8dad34..3ab758fe 100644 --- a/app/src/main/res/drawable-mdpi/main_select_server_light.png +++ b/app/src/main/res/drawable-mdpi/main_select_server_light.png diff --git a/app/src/main/res/drawable-mdpi/main_select_tabs_dark.png b/app/src/main/res/drawable-mdpi/main_select_tabs_dark.png Binary files differnew file mode 100644 index 00000000..a77f8933 --- /dev/null +++ b/app/src/main/res/drawable-mdpi/main_select_tabs_dark.png diff --git a/app/src/main/res/drawable-mdpi/main_select_tabs_light.png b/app/src/main/res/drawable-mdpi/main_select_tabs_light.png Binary files differnew file mode 100644 index 00000000..48fff01a --- /dev/null +++ b/app/src/main/res/drawable-mdpi/main_select_tabs_light.png diff --git a/app/src/main/res/drawable-mdpi/media_backward_dark.png b/app/src/main/res/drawable-mdpi/media_backward_dark.png Binary files differindex 4f2233a1..445760de 100644 --- a/app/src/main/res/drawable-mdpi/media_backward_dark.png +++ b/app/src/main/res/drawable-mdpi/media_backward_dark.png diff --git a/app/src/main/res/drawable-mdpi/media_backward_light.png b/app/src/main/res/drawable-mdpi/media_backward_light.png Binary files differindex 425f2df7..f970f58b 100644 --- a/app/src/main/res/drawable-mdpi/media_backward_light.png +++ b/app/src/main/res/drawable-mdpi/media_backward_light.png diff --git a/app/src/main/res/drawable-mdpi/media_forward_dark.png b/app/src/main/res/drawable-mdpi/media_forward_dark.png Binary files differindex 1641c0fa..6ee523fb 100644 --- a/app/src/main/res/drawable-mdpi/media_forward_dark.png +++ b/app/src/main/res/drawable-mdpi/media_forward_dark.png diff --git a/app/src/main/res/drawable-mdpi/media_forward_light.png b/app/src/main/res/drawable-mdpi/media_forward_light.png Binary files differindex 2e66868f..df83d06f 100644 --- a/app/src/main/res/drawable-mdpi/media_forward_light.png +++ b/app/src/main/res/drawable-mdpi/media_forward_light.png diff --git a/app/src/main/res/drawable-mdpi/media_pause_dark.png b/app/src/main/res/drawable-mdpi/media_pause_dark.png Binary files differindex 3580dab4..00bada96 100644 --- a/app/src/main/res/drawable-mdpi/media_pause_dark.png +++ b/app/src/main/res/drawable-mdpi/media_pause_dark.png diff --git a/app/src/main/res/drawable-mdpi/media_pause_light.png b/app/src/main/res/drawable-mdpi/media_pause_light.png Binary files differindex 7e9ade73..fcb7723b 100644 --- a/app/src/main/res/drawable-mdpi/media_pause_light.png +++ b/app/src/main/res/drawable-mdpi/media_pause_light.png diff --git a/app/src/main/res/drawable-mdpi/media_repeat_all_dark.png b/app/src/main/res/drawable-mdpi/media_repeat_all_dark.png Binary files differnew file mode 100644 index 00000000..07c0a285 --- /dev/null +++ b/app/src/main/res/drawable-mdpi/media_repeat_all_dark.png diff --git a/app/src/main/res/drawable-mdpi/media_repeat_all_light.png b/app/src/main/res/drawable-mdpi/media_repeat_all_light.png Binary files differnew file mode 100644 index 00000000..1126d157 --- /dev/null +++ b/app/src/main/res/drawable-mdpi/media_repeat_all_light.png diff --git a/app/src/main/res/drawable-mdpi/media_repeat_off_dark.png b/app/src/main/res/drawable-mdpi/media_repeat_off_dark.png Binary files differnew file mode 100644 index 00000000..8f9e8008 --- /dev/null +++ b/app/src/main/res/drawable-mdpi/media_repeat_off_dark.png diff --git a/app/src/main/res/drawable-mdpi/media_repeat_off_light.png b/app/src/main/res/drawable-mdpi/media_repeat_off_light.png Binary files differnew file mode 100644 index 00000000..50e3231a --- /dev/null +++ b/app/src/main/res/drawable-mdpi/media_repeat_off_light.png diff --git a/app/src/main/res/drawable-mdpi/media_repeat_single_dark.png b/app/src/main/res/drawable-mdpi/media_repeat_single_dark.png Binary files differnew file mode 100644 index 00000000..2cf5534c --- /dev/null +++ b/app/src/main/res/drawable-mdpi/media_repeat_single_dark.png diff --git a/app/src/main/res/drawable-mdpi/media_repeat_single_light.png b/app/src/main/res/drawable-mdpi/media_repeat_single_light.png Binary files differnew file mode 100644 index 00000000..ac3deca5 --- /dev/null +++ b/app/src/main/res/drawable-mdpi/media_repeat_single_light.png diff --git a/app/src/main/res/drawable-mdpi/media_start_dark.png b/app/src/main/res/drawable-mdpi/media_start_dark.png Binary files differindex a2f198ae..56775074 100644 --- a/app/src/main/res/drawable-mdpi/media_start_dark.png +++ b/app/src/main/res/drawable-mdpi/media_start_dark.png diff --git a/app/src/main/res/drawable-mdpi/media_start_light.png b/app/src/main/res/drawable-mdpi/media_start_light.png Binary files differindex d69107ba..aefeb72e 100644 --- a/app/src/main/res/drawable-mdpi/media_start_light.png +++ b/app/src/main/res/drawable-mdpi/media_start_light.png diff --git a/app/src/main/res/drawable-mdpi/media_stop_dark.png b/app/src/main/res/drawable-mdpi/media_stop_dark.png Binary files differindex 944482e6..1d03b294 100644 --- a/app/src/main/res/drawable-mdpi/media_stop_dark.png +++ b/app/src/main/res/drawable-mdpi/media_stop_dark.png diff --git a/app/src/main/res/drawable-mdpi/media_stop_light.png b/app/src/main/res/drawable-mdpi/media_stop_light.png Binary files differindex ff1932a1..15840f8d 100644 --- a/app/src/main/res/drawable-mdpi/media_stop_light.png +++ b/app/src/main/res/drawable-mdpi/media_stop_light.png diff --git a/app/src/main/res/drawable-mdpi/notification_close.png b/app/src/main/res/drawable-mdpi/notification_close.png Binary files differdeleted file mode 100644 index 2a8f9a36..00000000 --- a/app/src/main/res/drawable-mdpi/notification_close.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi/notification_close_dark.png b/app/src/main/res/drawable-mdpi/notification_close_dark.png Binary files differnew file mode 100644 index 00000000..51a02d23 --- /dev/null +++ b/app/src/main/res/drawable-mdpi/notification_close_dark.png diff --git a/app/src/main/res/drawable-mdpi/notification_close_light.png b/app/src/main/res/drawable-mdpi/notification_close_light.png Binary files differnew file mode 100644 index 00000000..75bf1407 --- /dev/null +++ b/app/src/main/res/drawable-mdpi/notification_close_light.png diff --git a/app/src/main/res/drawable-mdpi/notification_next.png b/app/src/main/res/drawable-mdpi/notification_next.png Binary files differdeleted file mode 100644 index f85d45a5..00000000 --- a/app/src/main/res/drawable-mdpi/notification_next.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi/notification_pause.png b/app/src/main/res/drawable-mdpi/notification_pause.png Binary files differdeleted file mode 100644 index 06c3cf9d..00000000 --- a/app/src/main/res/drawable-mdpi/notification_pause.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi/notification_play.png b/app/src/main/res/drawable-mdpi/notification_play.png Binary files differdeleted file mode 100644 index 0248c1cc..00000000 --- a/app/src/main/res/drawable-mdpi/notification_play.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi/notification_previous.png b/app/src/main/res/drawable-mdpi/notification_previous.png Binary files differdeleted file mode 100644 index 167d7d05..00000000 --- a/app/src/main/res/drawable-mdpi/notification_previous.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi/now_playing.png b/app/src/main/res/drawable-mdpi/now_playing.png Binary files differdeleted file mode 100644 index 0248c1cc..00000000 --- a/app/src/main/res/drawable-mdpi/now_playing.png +++ /dev/null diff --git a/app/src/main/res/drawable-mdpi/stat_notify_download.png b/app/src/main/res/drawable-mdpi/stat_notify_download.png Binary files differindex 4c2a22de..4164e0fa 100644 --- a/app/src/main/res/drawable-mdpi/stat_notify_download.png +++ b/app/src/main/res/drawable-mdpi/stat_notify_download.png diff --git a/app/src/main/res/drawable-mdpi/stat_notify_playing.png b/app/src/main/res/drawable-mdpi/stat_notify_playing.png Binary files differindex 0248c1cc..999ce798 100644 --- a/app/src/main/res/drawable-mdpi/stat_notify_playing.png +++ b/app/src/main/res/drawable-mdpi/stat_notify_playing.png diff --git a/app/src/main/res/drawable-mdpi/stat_notify_sync.png b/app/src/main/res/drawable-mdpi/stat_notify_sync.png Binary files differindex 35a06857..3e3c64c0 100644 --- a/app/src/main/res/drawable-mdpi/stat_notify_sync.png +++ b/app/src/main/res/drawable-mdpi/stat_notify_sync.png diff --git a/app/src/main/res/drawable-v22/notification_backward.xml b/app/src/main/res/drawable-v22/notification_backward.xml new file mode 100644 index 00000000..ffebb00c --- /dev/null +++ b/app/src/main/res/drawable-v22/notification_backward.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<bitmap + xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/media_backward_light"/>
\ No newline at end of file diff --git a/app/src/main/res/drawable-v22/notification_close.xml b/app/src/main/res/drawable-v22/notification_close.xml new file mode 100644 index 00000000..4a934278 --- /dev/null +++ b/app/src/main/res/drawable-v22/notification_close.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<bitmap + xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/notification_close_light"/>
\ No newline at end of file diff --git a/app/src/main/res/drawable-v22/notification_forward.xml b/app/src/main/res/drawable-v22/notification_forward.xml new file mode 100644 index 00000000..0d3c93d5 --- /dev/null +++ b/app/src/main/res/drawable-v22/notification_forward.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<bitmap + xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/media_forward_light"/>
\ No newline at end of file diff --git a/app/src/main/res/drawable-v22/notification_pause.xml b/app/src/main/res/drawable-v22/notification_pause.xml new file mode 100644 index 00000000..330260ff --- /dev/null +++ b/app/src/main/res/drawable-v22/notification_pause.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<bitmap + xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/media_pause_light"/>
\ No newline at end of file diff --git a/app/src/main/res/drawable-v22/notification_start.xml b/app/src/main/res/drawable-v22/notification_start.xml new file mode 100644 index 00000000..75e23c08 --- /dev/null +++ b/app/src/main/res/drawable-v22/notification_start.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<bitmap + xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/media_start_light"/>
\ No newline at end of file diff --git a/app/src/main/res/drawable-xhdpi-v11/notification_close.png b/app/src/main/res/drawable-xhdpi-v11/notification_close.png Binary files differdeleted file mode 100644 index f1013578..00000000 --- a/app/src/main/res/drawable-xhdpi-v11/notification_close.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi-v11/notification_next.png b/app/src/main/res/drawable-xhdpi-v11/notification_next.png Binary files differdeleted file mode 100644 index ad070680..00000000 --- a/app/src/main/res/drawable-xhdpi-v11/notification_next.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi-v11/notification_pause.png b/app/src/main/res/drawable-xhdpi-v11/notification_pause.png Binary files differdeleted file mode 100644 index 709602aa..00000000 --- a/app/src/main/res/drawable-xhdpi-v11/notification_pause.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi-v11/notification_play.png b/app/src/main/res/drawable-xhdpi-v11/notification_play.png Binary files differdeleted file mode 100644 index e2bafa6a..00000000 --- a/app/src/main/res/drawable-xhdpi-v11/notification_play.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi-v11/notification_previous.png b/app/src/main/res/drawable-xhdpi-v11/notification_previous.png Binary files differdeleted file mode 100644 index d22488cb..00000000 --- a/app/src/main/res/drawable-xhdpi-v11/notification_previous.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi-v11/stat_notify_download.png b/app/src/main/res/drawable-xhdpi-v11/stat_notify_download.png Binary files differdeleted file mode 100644 index 96ceb383..00000000 --- a/app/src/main/res/drawable-xhdpi-v11/stat_notify_download.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi-v11/stat_notify_playing.png b/app/src/main/res/drawable-xhdpi-v11/stat_notify_playing.png Binary files differdeleted file mode 100644 index e2bafa6a..00000000 --- a/app/src/main/res/drawable-xhdpi-v11/stat_notify_playing.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi-v11/stat_notify_sync.png b/app/src/main/res/drawable-xhdpi-v11/stat_notify_sync.png Binary files differdeleted file mode 100644 index b723bf54..00000000 --- a/app/src/main/res/drawable-xhdpi-v11/stat_notify_sync.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi/action_toggle_list_dark.png b/app/src/main/res/drawable-xhdpi/action_toggle_list_dark.png Binary files differindex 92003c6b..08a9bedc 100644 --- a/app/src/main/res/drawable-xhdpi/action_toggle_list_dark.png +++ b/app/src/main/res/drawable-xhdpi/action_toggle_list_dark.png diff --git a/app/src/main/res/drawable-xhdpi/action_toggle_list_light.png b/app/src/main/res/drawable-xhdpi/action_toggle_list_light.png Binary files differindex a4007ea5..c74cf4e9 100644 --- a/app/src/main/res/drawable-xhdpi/action_toggle_list_light.png +++ b/app/src/main/res/drawable-xhdpi/action_toggle_list_light.png diff --git a/app/src/main/res/drawable-xhdpi/download_none_dark.png b/app/src/main/res/drawable-xhdpi/download_none_dark.png Binary files differindex 7be3c2a4..c648d8c3 100644 --- a/app/src/main/res/drawable-xhdpi/download_none_dark.png +++ b/app/src/main/res/drawable-xhdpi/download_none_dark.png diff --git a/app/src/main/res/drawable-xhdpi/download_none_light.png b/app/src/main/res/drawable-xhdpi/download_none_light.png Binary files differindex 817651d7..19ad0b6d 100644 --- a/app/src/main/res/drawable-xhdpi/download_none_light.png +++ b/app/src/main/res/drawable-xhdpi/download_none_light.png diff --git a/app/src/main/res/drawable-xhdpi/downloading_dark.png b/app/src/main/res/drawable-xhdpi/downloading_dark.png Binary files differindex 3f14bdf4..4e909ded 100644 --- a/app/src/main/res/drawable-xhdpi/downloading_dark.png +++ b/app/src/main/res/drawable-xhdpi/downloading_dark.png diff --git a/app/src/main/res/drawable-xhdpi/downloading_light.png b/app/src/main/res/drawable-xhdpi/downloading_light.png Binary files differindex 643c15d0..d00a731b 100644 --- a/app/src/main/res/drawable-xhdpi/downloading_light.png +++ b/app/src/main/res/drawable-xhdpi/downloading_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_action_add_dark.png b/app/src/main/res/drawable-xhdpi/ic_action_add_dark.png Binary files differindex 93eae7c6..e94e8136 100644 --- a/app/src/main/res/drawable-xhdpi/ic_action_add_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_action_add_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_action_add_light.png b/app/src/main/res/drawable-xhdpi/ic_action_add_light.png Binary files differindex 1ebdb432..13e8df83 100644 --- a/app/src/main/res/drawable-xhdpi/ic_action_add_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_action_add_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_action_artist.png b/app/src/main/res/drawable-xhdpi/ic_action_artist.png Binary files differindex 2dff43ea..dbddd0cd 100644 --- a/app/src/main/res/drawable-xhdpi/ic_action_artist.png +++ b/app/src/main/res/drawable-xhdpi/ic_action_artist.png diff --git a/app/src/main/res/drawable-xhdpi/ic_action_rating_bad_dark.png b/app/src/main/res/drawable-xhdpi/ic_action_rating_bad_dark.png Binary files differindex 1393be0c..8552fb61 100644 --- a/app/src/main/res/drawable-xhdpi/ic_action_rating_bad_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_action_rating_bad_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_action_rating_bad_light.png b/app/src/main/res/drawable-xhdpi/ic_action_rating_bad_light.png Binary files differindex fc1959b6..3cc99d4e 100644 --- a/app/src/main/res/drawable-xhdpi/ic_action_rating_bad_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_action_rating_bad_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_action_rating_bad_selected.png b/app/src/main/res/drawable-xhdpi/ic_action_rating_bad_selected.png Binary files differindex cf7802d5..98494b1f 100644 --- a/app/src/main/res/drawable-xhdpi/ic_action_rating_bad_selected.png +++ b/app/src/main/res/drawable-xhdpi/ic_action_rating_bad_selected.png diff --git a/app/src/main/res/drawable-xhdpi/ic_action_rating_good_dark.png b/app/src/main/res/drawable-xhdpi/ic_action_rating_good_dark.png Binary files differindex 249ea9ec..abb63162 100644 --- a/app/src/main/res/drawable-xhdpi/ic_action_rating_good_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_action_rating_good_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_action_rating_good_light.png b/app/src/main/res/drawable-xhdpi/ic_action_rating_good_light.png Binary files differindex c8a776b0..cab7d3bc 100644 --- a/app/src/main/res/drawable-xhdpi/ic_action_rating_good_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_action_rating_good_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_action_rating_good_selected.png b/app/src/main/res/drawable-xhdpi/ic_action_rating_good_selected.png Binary files differindex c6770221..f5065d18 100644 --- a/app/src/main/res/drawable-xhdpi/ic_action_rating_good_selected.png +++ b/app/src/main/res/drawable-xhdpi/ic_action_rating_good_selected.png diff --git a/app/src/main/res/drawable-xhdpi/ic_action_song.png b/app/src/main/res/drawable-xhdpi/ic_action_song.png Binary files differindex 29fd3a2d..8b37957b 100644 --- a/app/src/main/res/drawable-xhdpi/ic_action_song.png +++ b/app/src/main/res/drawable-xhdpi/ic_action_song.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_add_person_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_add_person_dark.png Binary files differindex 30c78e5a..e3173c8e 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_add_person_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_add_person_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_add_person_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_add_person_light.png Binary files differindex b3fb3808..fcc29eac 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_add_person_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_add_person_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_admin_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_admin_dark.png Binary files differindex 09f90c15..23382dd4 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_admin_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_admin_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_admin_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_admin_light.png Binary files differindex 4bd3beaf..ce1ea09f 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_admin_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_admin_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_bookmark_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_bookmark_dark.png Binary files differindex 18f71365..7a396f68 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_bookmark_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_bookmark_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_bookmark_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_bookmark_light.png Binary files differindex d5776317..c91134e7 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_bookmark_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_bookmark_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_bookmark_selected.png b/app/src/main/res/drawable-xhdpi/ic_menu_bookmark_selected.png Binary files differindex 353b7b79..1a1df81b 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_bookmark_selected.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_bookmark_selected.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_chat_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_chat_dark.png Binary files differindex 28318219..4b1fbce1 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_chat_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_chat_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_chat_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_chat_light.png Binary files differindex dcc95dcb..573da8cc 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_chat_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_chat_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_chat_send_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_chat_send_dark.png Binary files differindex c0a5a3eb..71803911 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_chat_send_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_chat_send_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_chat_send_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_chat_send_light.png Binary files differindex f9c3b9bb..ee24b99b 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_chat_send_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_chat_send_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_download_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_download_dark.png Binary files differindex 6b6c65df..a0c2883d 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_download_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_download_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_download_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_download_light.png Binary files differindex c8caf90b..2bbcd586 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_download_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_download_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_library_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_library_dark.png Binary files differindex b1612f65..f72c1f56 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_library_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_library_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_library_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_library_light.png Binary files differindex 1f93c8f2..3b10e425 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_library_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_library_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_password_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_password_dark.png Binary files differindex d1fc0a97..c27eaa8b 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_password_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_password_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_password_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_password_light.png Binary files differindex 1cbf085c..28839c0d 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_password_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_password_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_playlist_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_playlist_dark.png Binary files differindex fd6cd498..8ef42cc2 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_playlist_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_playlist_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_playlist_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_playlist_light.png Binary files differindex e7e510d0..906b6910 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_playlist_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_playlist_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_podcast_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_podcast_dark.png Binary files differindex 40469b46..ae1c4bfb 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_podcast_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_podcast_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_podcast_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_podcast_light.png Binary files differindex 3748526a..98be14e4 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_podcast_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_podcast_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_radio_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_radio_dark.png Binary files differindex 3a4114a3..452295f8 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_radio_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_radio_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_radio_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_radio_light.png Binary files differindex 5bcc9261..322addf2 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_radio_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_radio_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_refresh_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_refresh_dark.png Binary files differindex b6801006..572961b6 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_refresh_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_refresh_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_refresh_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_refresh_light.png Binary files differindex 38943f82..4ddf9be0 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_refresh_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_refresh_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_remove_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_remove_dark.png Binary files differindex 09ce75e2..48178b93 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_remove_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_remove_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_remove_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_remove_light.png Binary files differindex 94f7c8c1..a082b324 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_remove_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_remove_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_save_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_save_dark.png Binary files differindex 1612fd0a..90ff86d6 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_save_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_save_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_save_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_save_light.png Binary files differindex 5dcd75d7..822a43ad 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_save_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_save_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_search_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_search_dark.png Binary files differindex 1ae3dff0..5b056c28 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_search_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_search_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_search_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_search_light.png Binary files differindex 705074bd..ccdfb3fd 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_search_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_search_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_settings_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_settings_dark.png Binary files differindex ae917587..f1d37805 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_settings_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_settings_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_settings_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_settings_light.png Binary files differindex 29f961b2..bc85e33d 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_settings_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_settings_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_share_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_share_dark.png Binary files differindex 41073d1f..ab21695b 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_share_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_share_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_share_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_share_light.png Binary files differindex 36f9f55f..aea52347 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_share_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_share_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_shuffle_dark.png b/app/src/main/res/drawable-xhdpi/ic_menu_shuffle_dark.png Binary files differindex e3a31a84..b4050e3d 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_shuffle_dark.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_shuffle_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_menu_shuffle_light.png b/app/src/main/res/drawable-xhdpi/ic_menu_shuffle_light.png Binary files differindex 14eb942c..068618b2 100644 --- a/app/src/main/res/drawable-xhdpi/ic_menu_shuffle_light.png +++ b/app/src/main/res/drawable-xhdpi/ic_menu_shuffle_light.png diff --git a/app/src/main/res/drawable-xhdpi/ic_social_person.png b/app/src/main/res/drawable-xhdpi/ic_social_person.png Binary files differindex ed333afe..8f4f9aff 100644 --- a/app/src/main/res/drawable-xhdpi/ic_social_person.png +++ b/app/src/main/res/drawable-xhdpi/ic_social_person.png diff --git a/app/src/main/res/drawable-xhdpi/ic_toggle_star.png b/app/src/main/res/drawable-xhdpi/ic_toggle_star.png Binary files differnew file mode 100644 index 00000000..5c54298c --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/ic_toggle_star.png diff --git a/app/src/main/res/drawable-xhdpi/ic_toggle_star_outline_dark.png b/app/src/main/res/drawable-xhdpi/ic_toggle_star_outline_dark.png Binary files differnew file mode 100644 index 00000000..aa7e381e --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/ic_toggle_star_outline_dark.png diff --git a/app/src/main/res/drawable-xhdpi/ic_toggle_star_outline_light.png b/app/src/main/res/drawable-xhdpi/ic_toggle_star_outline_light.png Binary files differnew file mode 100644 index 00000000..6ff994be --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/ic_toggle_star_outline_light.png diff --git a/app/src/main/res/drawable-xhdpi/launch.png b/app/src/main/res/drawable-xhdpi/launch.png Binary files differindex 0f647dfa..4146ebe4 100644 --- a/app/src/main/res/drawable-xhdpi/launch.png +++ b/app/src/main/res/drawable-xhdpi/launch.png diff --git a/app/src/main/res/drawable-xhdpi/main_offline_dark.png b/app/src/main/res/drawable-xhdpi/main_offline_dark.png Binary files differindex 231e4715..a701eb2f 100644 --- a/app/src/main/res/drawable-xhdpi/main_offline_dark.png +++ b/app/src/main/res/drawable-xhdpi/main_offline_dark.png diff --git a/app/src/main/res/drawable-xhdpi/main_offline_light.png b/app/src/main/res/drawable-xhdpi/main_offline_light.png Binary files differindex 87937fcb..1ad05f81 100644 --- a/app/src/main/res/drawable-xhdpi/main_offline_light.png +++ b/app/src/main/res/drawable-xhdpi/main_offline_light.png diff --git a/app/src/main/res/drawable-xhdpi/main_select_server_dark.png b/app/src/main/res/drawable-xhdpi/main_select_server_dark.png Binary files differindex b84f1851..46008d71 100644 --- a/app/src/main/res/drawable-xhdpi/main_select_server_dark.png +++ b/app/src/main/res/drawable-xhdpi/main_select_server_dark.png diff --git a/app/src/main/res/drawable-xhdpi/main_select_server_light.png b/app/src/main/res/drawable-xhdpi/main_select_server_light.png Binary files differindex ee154cc7..237b6204 100644 --- a/app/src/main/res/drawable-xhdpi/main_select_server_light.png +++ b/app/src/main/res/drawable-xhdpi/main_select_server_light.png diff --git a/app/src/main/res/drawable-xhdpi/main_select_tabs_dark.png b/app/src/main/res/drawable-xhdpi/main_select_tabs_dark.png Binary files differnew file mode 100644 index 00000000..ac0f6b4c --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/main_select_tabs_dark.png diff --git a/app/src/main/res/drawable-xhdpi/main_select_tabs_light.png b/app/src/main/res/drawable-xhdpi/main_select_tabs_light.png Binary files differnew file mode 100644 index 00000000..94e10842 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/main_select_tabs_light.png diff --git a/app/src/main/res/drawable-xhdpi/media_backward_dark.png b/app/src/main/res/drawable-xhdpi/media_backward_dark.png Binary files differindex 3c9921a8..d46da023 100644 --- a/app/src/main/res/drawable-xhdpi/media_backward_dark.png +++ b/app/src/main/res/drawable-xhdpi/media_backward_dark.png diff --git a/app/src/main/res/drawable-xhdpi/media_backward_light.png b/app/src/main/res/drawable-xhdpi/media_backward_light.png Binary files differindex aafd76fa..18821229 100644 --- a/app/src/main/res/drawable-xhdpi/media_backward_light.png +++ b/app/src/main/res/drawable-xhdpi/media_backward_light.png diff --git a/app/src/main/res/drawable-xhdpi/media_forward_dark.png b/app/src/main/res/drawable-xhdpi/media_forward_dark.png Binary files differindex b082b3a6..a49131a9 100644 --- a/app/src/main/res/drawable-xhdpi/media_forward_dark.png +++ b/app/src/main/res/drawable-xhdpi/media_forward_dark.png diff --git a/app/src/main/res/drawable-xhdpi/media_forward_light.png b/app/src/main/res/drawable-xhdpi/media_forward_light.png Binary files differindex 20772843..b44d2601 100644 --- a/app/src/main/res/drawable-xhdpi/media_forward_light.png +++ b/app/src/main/res/drawable-xhdpi/media_forward_light.png diff --git a/app/src/main/res/drawable-xhdpi/media_pause_dark.png b/app/src/main/res/drawable-xhdpi/media_pause_dark.png Binary files differindex aafdd4aa..575592d2 100644 --- a/app/src/main/res/drawable-xhdpi/media_pause_dark.png +++ b/app/src/main/res/drawable-xhdpi/media_pause_dark.png diff --git a/app/src/main/res/drawable-xhdpi/media_pause_light.png b/app/src/main/res/drawable-xhdpi/media_pause_light.png Binary files differindex 2639777d..a456b695 100644 --- a/app/src/main/res/drawable-xhdpi/media_pause_light.png +++ b/app/src/main/res/drawable-xhdpi/media_pause_light.png diff --git a/app/src/main/res/drawable-xhdpi/media_repeat_all_dark.png b/app/src/main/res/drawable-xhdpi/media_repeat_all_dark.png Binary files differnew file mode 100644 index 00000000..db5a1dec --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/media_repeat_all_dark.png diff --git a/app/src/main/res/drawable-xhdpi/media_repeat_all_light.png b/app/src/main/res/drawable-xhdpi/media_repeat_all_light.png Binary files differnew file mode 100644 index 00000000..10f8ab1a --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/media_repeat_all_light.png diff --git a/app/src/main/res/drawable-xhdpi/media_repeat_off_dark.png b/app/src/main/res/drawable-xhdpi/media_repeat_off_dark.png Binary files differnew file mode 100644 index 00000000..58ff008a --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/media_repeat_off_dark.png diff --git a/app/src/main/res/drawable-xhdpi/media_repeat_off_light.png b/app/src/main/res/drawable-xhdpi/media_repeat_off_light.png Binary files differnew file mode 100644 index 00000000..95f96e24 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/media_repeat_off_light.png diff --git a/app/src/main/res/drawable-xhdpi/media_repeat_single_dark.png b/app/src/main/res/drawable-xhdpi/media_repeat_single_dark.png Binary files differnew file mode 100644 index 00000000..22ad9fa0 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/media_repeat_single_dark.png diff --git a/app/src/main/res/drawable-xhdpi/media_repeat_single_light.png b/app/src/main/res/drawable-xhdpi/media_repeat_single_light.png Binary files differnew file mode 100644 index 00000000..ae07a07c --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/media_repeat_single_light.png diff --git a/app/src/main/res/drawable-xhdpi/media_start_dark.png b/app/src/main/res/drawable-xhdpi/media_start_dark.png Binary files differindex 9e63c90b..35136a95 100644 --- a/app/src/main/res/drawable-xhdpi/media_start_dark.png +++ b/app/src/main/res/drawable-xhdpi/media_start_dark.png diff --git a/app/src/main/res/drawable-xhdpi/media_start_light.png b/app/src/main/res/drawable-xhdpi/media_start_light.png Binary files differindex 2ff8c399..5f580848 100644 --- a/app/src/main/res/drawable-xhdpi/media_start_light.png +++ b/app/src/main/res/drawable-xhdpi/media_start_light.png diff --git a/app/src/main/res/drawable-xhdpi/media_stop_dark.png b/app/src/main/res/drawable-xhdpi/media_stop_dark.png Binary files differindex 9cb32909..1599def7 100644 --- a/app/src/main/res/drawable-xhdpi/media_stop_dark.png +++ b/app/src/main/res/drawable-xhdpi/media_stop_dark.png diff --git a/app/src/main/res/drawable-xhdpi/media_stop_light.png b/app/src/main/res/drawable-xhdpi/media_stop_light.png Binary files differindex edf13ccf..df087b58 100644 --- a/app/src/main/res/drawable-xhdpi/media_stop_light.png +++ b/app/src/main/res/drawable-xhdpi/media_stop_light.png diff --git a/app/src/main/res/drawable-xhdpi/notification_close.png b/app/src/main/res/drawable-xhdpi/notification_close.png Binary files differdeleted file mode 100644 index 4230842e..00000000 --- a/app/src/main/res/drawable-xhdpi/notification_close.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi/notification_close_dark.png b/app/src/main/res/drawable-xhdpi/notification_close_dark.png Binary files differnew file mode 100644 index 00000000..8a445bc5 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/notification_close_dark.png diff --git a/app/src/main/res/drawable-xhdpi/notification_close_light.png b/app/src/main/res/drawable-xhdpi/notification_close_light.png Binary files differnew file mode 100644 index 00000000..223e0680 --- /dev/null +++ b/app/src/main/res/drawable-xhdpi/notification_close_light.png diff --git a/app/src/main/res/drawable-xhdpi/notification_next.png b/app/src/main/res/drawable-xhdpi/notification_next.png Binary files differdeleted file mode 100644 index 44dbbd12..00000000 --- a/app/src/main/res/drawable-xhdpi/notification_next.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi/notification_pause.png b/app/src/main/res/drawable-xhdpi/notification_pause.png Binary files differdeleted file mode 100644 index e8d8c535..00000000 --- a/app/src/main/res/drawable-xhdpi/notification_pause.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi/notification_play.png b/app/src/main/res/drawable-xhdpi/notification_play.png Binary files differdeleted file mode 100644 index 532041fa..00000000 --- a/app/src/main/res/drawable-xhdpi/notification_play.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi/notification_previous.png b/app/src/main/res/drawable-xhdpi/notification_previous.png Binary files differdeleted file mode 100644 index 87ee8d2f..00000000 --- a/app/src/main/res/drawable-xhdpi/notification_previous.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi/now_playing.png b/app/src/main/res/drawable-xhdpi/now_playing.png Binary files differdeleted file mode 100644 index 532041fa..00000000 --- a/app/src/main/res/drawable-xhdpi/now_playing.png +++ /dev/null diff --git a/app/src/main/res/drawable-xhdpi/stat_notify_download.png b/app/src/main/res/drawable-xhdpi/stat_notify_download.png Binary files differindex bd4cb567..96ceb383 100644 --- a/app/src/main/res/drawable-xhdpi/stat_notify_download.png +++ b/app/src/main/res/drawable-xhdpi/stat_notify_download.png diff --git a/app/src/main/res/drawable-xhdpi/stat_notify_playing.png b/app/src/main/res/drawable-xhdpi/stat_notify_playing.png Binary files differindex 532041fa..e2bafa6a 100644 --- a/app/src/main/res/drawable-xhdpi/stat_notify_playing.png +++ b/app/src/main/res/drawable-xhdpi/stat_notify_playing.png diff --git a/app/src/main/res/drawable-xhdpi/stat_notify_sync.png b/app/src/main/res/drawable-xhdpi/stat_notify_sync.png Binary files differindex 6da882a2..b723bf54 100644 --- a/app/src/main/res/drawable-xhdpi/stat_notify_sync.png +++ b/app/src/main/res/drawable-xhdpi/stat_notify_sync.png diff --git a/app/src/main/res/drawable-xxhdpi-v11/notification_close.png b/app/src/main/res/drawable-xxhdpi-v11/notification_close.png Binary files differdeleted file mode 100644 index c3ac026a..00000000 --- a/app/src/main/res/drawable-xxhdpi-v11/notification_close.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi-v11/notification_next.png b/app/src/main/res/drawable-xxhdpi-v11/notification_next.png Binary files differdeleted file mode 100644 index 06911082..00000000 --- a/app/src/main/res/drawable-xxhdpi-v11/notification_next.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi-v11/notification_pause.png b/app/src/main/res/drawable-xxhdpi-v11/notification_pause.png Binary files differdeleted file mode 100644 index 1513f9d9..00000000 --- a/app/src/main/res/drawable-xxhdpi-v11/notification_pause.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi-v11/notification_play.png b/app/src/main/res/drawable-xxhdpi-v11/notification_play.png Binary files differdeleted file mode 100644 index 9138a760..00000000 --- a/app/src/main/res/drawable-xxhdpi-v11/notification_play.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi-v11/notification_previous.png b/app/src/main/res/drawable-xxhdpi-v11/notification_previous.png Binary files differdeleted file mode 100644 index b4456c16..00000000 --- a/app/src/main/res/drawable-xxhdpi-v11/notification_previous.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi-v11/stat_notify_download.png b/app/src/main/res/drawable-xxhdpi-v11/stat_notify_download.png Binary files differdeleted file mode 100644 index b2dc5651..00000000 --- a/app/src/main/res/drawable-xxhdpi-v11/stat_notify_download.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi-v11/stat_notify_playing.png b/app/src/main/res/drawable-xxhdpi-v11/stat_notify_playing.png Binary files differdeleted file mode 100644 index 9138a760..00000000 --- a/app/src/main/res/drawable-xxhdpi-v11/stat_notify_playing.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi-v11/stat_notify_sync.png b/app/src/main/res/drawable-xxhdpi-v11/stat_notify_sync.png Binary files differdeleted file mode 100644 index 61f6a331..00000000 --- a/app/src/main/res/drawable-xxhdpi-v11/stat_notify_sync.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi/action_toggle_list_dark.png b/app/src/main/res/drawable-xxhdpi/action_toggle_list_dark.png Binary files differindex 598fc312..40e3d20c 100644 --- a/app/src/main/res/drawable-xxhdpi/action_toggle_list_dark.png +++ b/app/src/main/res/drawable-xxhdpi/action_toggle_list_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/action_toggle_list_light.png b/app/src/main/res/drawable-xxhdpi/action_toggle_list_light.png Binary files differindex ceb3fade..1d928683 100644 --- a/app/src/main/res/drawable-xxhdpi/action_toggle_list_light.png +++ b/app/src/main/res/drawable-xxhdpi/action_toggle_list_light.png diff --git a/app/src/main/res/drawable-xxhdpi/download_none_dark.png b/app/src/main/res/drawable-xxhdpi/download_none_dark.png Binary files differindex a0cb8a41..6ca7a048 100644 --- a/app/src/main/res/drawable-xxhdpi/download_none_dark.png +++ b/app/src/main/res/drawable-xxhdpi/download_none_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/download_none_light.png b/app/src/main/res/drawable-xxhdpi/download_none_light.png Binary files differindex 7a1639ef..188f597b 100644 --- a/app/src/main/res/drawable-xxhdpi/download_none_light.png +++ b/app/src/main/res/drawable-xxhdpi/download_none_light.png diff --git a/app/src/main/res/drawable-xxhdpi/downloading_dark.png b/app/src/main/res/drawable-xxhdpi/downloading_dark.png Binary files differindex afc4bf84..b9261880 100644 --- a/app/src/main/res/drawable-xxhdpi/downloading_dark.png +++ b/app/src/main/res/drawable-xxhdpi/downloading_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/downloading_light.png b/app/src/main/res/drawable-xxhdpi/downloading_light.png Binary files differindex ba31a979..d2189f97 100644 --- a/app/src/main/res/drawable-xxhdpi/downloading_light.png +++ b/app/src/main/res/drawable-xxhdpi/downloading_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_add_dark.png b/app/src/main/res/drawable-xxhdpi/ic_action_add_dark.png Binary files differindex 70495672..86791667 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_action_add_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_action_add_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_add_light.png b/app/src/main/res/drawable-xxhdpi/ic_action_add_light.png Binary files differindex 9322b136..56423938 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_action_add_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_action_add_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_artist.png b/app/src/main/res/drawable-xxhdpi/ic_action_artist.png Binary files differnew file mode 100644 index 00000000..d6de9a53 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/ic_action_artist.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_rating_bad_dark.png b/app/src/main/res/drawable-xxhdpi/ic_action_rating_bad_dark.png Binary files differindex d784b239..5fe1fd79 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_action_rating_bad_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_action_rating_bad_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_rating_bad_light.png b/app/src/main/res/drawable-xxhdpi/ic_action_rating_bad_light.png Binary files differindex a1484d25..71e6e89c 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_action_rating_bad_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_action_rating_bad_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_rating_bad_selected.png b/app/src/main/res/drawable-xxhdpi/ic_action_rating_bad_selected.png Binary files differindex 13218a08..945bb594 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_action_rating_bad_selected.png +++ b/app/src/main/res/drawable-xxhdpi/ic_action_rating_bad_selected.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_rating_good_dark.png b/app/src/main/res/drawable-xxhdpi/ic_action_rating_good_dark.png Binary files differindex a332a632..1f0eeeba 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_action_rating_good_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_action_rating_good_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_rating_good_light.png b/app/src/main/res/drawable-xxhdpi/ic_action_rating_good_light.png Binary files differindex 2ef75765..aa384864 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_action_rating_good_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_action_rating_good_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_rating_good_selected.png b/app/src/main/res/drawable-xxhdpi/ic_action_rating_good_selected.png Binary files differindex bb444806..273615ea 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_action_rating_good_selected.png +++ b/app/src/main/res/drawable-xxhdpi/ic_action_rating_good_selected.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_song.png b/app/src/main/res/drawable-xxhdpi/ic_action_song.png Binary files differnew file mode 100644 index 00000000..61764ada --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/ic_action_song.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_add_person_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_add_person_dark.png Binary files differindex 446985ea..3bd18cf6 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_add_person_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_add_person_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_add_person_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_add_person_light.png Binary files differindex 0f1d36bc..a03c47cd 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_add_person_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_add_person_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_admin_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_admin_dark.png Binary files differindex 0e57c9ed..eef6b1b7 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_admin_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_admin_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_admin_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_admin_light.png Binary files differindex 63ab2f83..7607ff50 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_admin_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_admin_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_bookmark_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_bookmark_dark.png Binary files differindex 2523e14c..ab4d7813 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_bookmark_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_bookmark_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_bookmark_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_bookmark_light.png Binary files differindex 9e8c4591..56d843cf 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_bookmark_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_bookmark_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_bookmark_selected.png b/app/src/main/res/drawable-xxhdpi/ic_menu_bookmark_selected.png Binary files differindex a1890fbb..d24f485d 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_bookmark_selected.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_bookmark_selected.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_chat_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_chat_dark.png Binary files differindex 60efb47d..8c812ea2 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_chat_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_chat_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_chat_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_chat_light.png Binary files differindex 02c89560..f98778bc 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_chat_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_chat_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_chat_send_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_chat_send_dark.png Binary files differindex b86ca3d3..175bd408 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_chat_send_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_chat_send_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_chat_send_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_chat_send_light.png Binary files differindex 048b8aac..50264195 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_chat_send_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_chat_send_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_download_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_download_dark.png Binary files differindex 03ddef9f..b036349e 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_download_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_download_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_download_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_download_light.png Binary files differindex c487580c..c200374b 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_download_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_download_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_library_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_library_dark.png Binary files differindex 02a4f3f2..c713a51c 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_library_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_library_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_library_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_library_light.png Binary files differindex 52ce8203..b4963b6a 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_library_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_library_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_password_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_password_dark.png Binary files differindex a7cd1a6d..2e2c9871 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_password_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_password_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_password_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_password_light.png Binary files differindex 5670a209..030b5349 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_password_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_password_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_playlist_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_playlist_dark.png Binary files differindex 2c955eee..ce8c3f74 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_playlist_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_playlist_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_playlist_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_playlist_light.png Binary files differindex d1877328..3c13f320 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_playlist_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_playlist_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_podcast_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_podcast_dark.png Binary files differindex a748dc60..edea04f0 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_podcast_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_podcast_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_podcast_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_podcast_light.png Binary files differindex efa7b037..4438f48e 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_podcast_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_podcast_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_radio_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_radio_dark.png Binary files differindex 0c63afbe..76f06842 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_radio_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_radio_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_radio_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_radio_light.png Binary files differindex 133772f8..24361a07 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_radio_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_radio_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_refresh_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_refresh_dark.png Binary files differindex 0e5616bd..42263563 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_refresh_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_refresh_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_refresh_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_refresh_light.png Binary files differindex 7dea70df..7120a613 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_refresh_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_refresh_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_remove_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_remove_dark.png Binary files differindex d5952ea0..355a712c 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_remove_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_remove_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_remove_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_remove_light.png Binary files differindex c814869e..3f4528ab 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_remove_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_remove_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_save_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_save_dark.png Binary files differindex acb264ec..7b161b23 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_save_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_save_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_save_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_save_light.png Binary files differindex fcd18ccd..63355b57 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_save_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_save_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_search_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_search_dark.png Binary files differindex 500ac03a..dd5c2b8d 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_search_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_search_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_search_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_search_light.png Binary files differindex fa64f9e8..4a85a4cd 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_search_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_search_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_settings_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_settings_dark.png Binary files differindex ded5dbb5..7cb7726a 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_settings_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_settings_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_settings_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_settings_light.png Binary files differindex cd242306..628d1dac 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_settings_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_settings_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_share_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_share_dark.png Binary files differindex 1fa12609..16dcb752 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_share_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_share_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_share_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_share_light.png Binary files differindex 7511340b..6ca84b0c 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_share_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_share_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_shuffle_dark.png b/app/src/main/res/drawable-xxhdpi/ic_menu_shuffle_dark.png Binary files differindex b53733df..742896cd 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_shuffle_dark.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_shuffle_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_menu_shuffle_light.png b/app/src/main/res/drawable-xxhdpi/ic_menu_shuffle_light.png Binary files differindex 4d5dff32..9ba34839 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_menu_shuffle_light.png +++ b/app/src/main/res/drawable-xxhdpi/ic_menu_shuffle_light.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_social_person.png b/app/src/main/res/drawable-xxhdpi/ic_social_person.png Binary files differindex f81dc6a4..80acdf79 100644 --- a/app/src/main/res/drawable-xxhdpi/ic_social_person.png +++ b/app/src/main/res/drawable-xxhdpi/ic_social_person.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_toggle_star.png b/app/src/main/res/drawable-xxhdpi/ic_toggle_star.png Binary files differnew file mode 100644 index 00000000..4db2a37c --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/ic_toggle_star.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_toggle_star_outline_dark.png b/app/src/main/res/drawable-xxhdpi/ic_toggle_star_outline_dark.png Binary files differnew file mode 100644 index 00000000..8ee1a446 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/ic_toggle_star_outline_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_toggle_star_outline_light.png b/app/src/main/res/drawable-xxhdpi/ic_toggle_star_outline_light.png Binary files differnew file mode 100644 index 00000000..17672e93 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/ic_toggle_star_outline_light.png diff --git a/app/src/main/res/drawable-xxhdpi/launch.png b/app/src/main/res/drawable-xxhdpi/launch.png Binary files differindex cae4f99a..c409c9ef 100644 --- a/app/src/main/res/drawable-xxhdpi/launch.png +++ b/app/src/main/res/drawable-xxhdpi/launch.png diff --git a/app/src/main/res/drawable-xxhdpi/main_offline_dark.png b/app/src/main/res/drawable-xxhdpi/main_offline_dark.png Binary files differindex c415e0a5..70779d92 100644 --- a/app/src/main/res/drawable-xxhdpi/main_offline_dark.png +++ b/app/src/main/res/drawable-xxhdpi/main_offline_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/main_offline_light.png b/app/src/main/res/drawable-xxhdpi/main_offline_light.png Binary files differindex b7e1c380..a887ecb1 100644 --- a/app/src/main/res/drawable-xxhdpi/main_offline_light.png +++ b/app/src/main/res/drawable-xxhdpi/main_offline_light.png diff --git a/app/src/main/res/drawable-xxhdpi/main_select_server_dark.png b/app/src/main/res/drawable-xxhdpi/main_select_server_dark.png Binary files differindex b85e3a1e..9591df95 100644 --- a/app/src/main/res/drawable-xxhdpi/main_select_server_dark.png +++ b/app/src/main/res/drawable-xxhdpi/main_select_server_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/main_select_server_light.png b/app/src/main/res/drawable-xxhdpi/main_select_server_light.png Binary files differindex 8fc39eff..7523034a 100644 --- a/app/src/main/res/drawable-xxhdpi/main_select_server_light.png +++ b/app/src/main/res/drawable-xxhdpi/main_select_server_light.png diff --git a/app/src/main/res/drawable-xxhdpi/main_select_tabs_dark.png b/app/src/main/res/drawable-xxhdpi/main_select_tabs_dark.png Binary files differnew file mode 100644 index 00000000..58922eb4 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/main_select_tabs_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/main_select_tabs_light.png b/app/src/main/res/drawable-xxhdpi/main_select_tabs_light.png Binary files differnew file mode 100644 index 00000000..5b7c876a --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/main_select_tabs_light.png diff --git a/app/src/main/res/drawable-xxhdpi/media_backward_dark.png b/app/src/main/res/drawable-xxhdpi/media_backward_dark.png Binary files differindex 5b6c6148..0037079a 100644 --- a/app/src/main/res/drawable-xxhdpi/media_backward_dark.png +++ b/app/src/main/res/drawable-xxhdpi/media_backward_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/media_backward_light.png b/app/src/main/res/drawable-xxhdpi/media_backward_light.png Binary files differindex 32f7d3bc..139f777c 100644 --- a/app/src/main/res/drawable-xxhdpi/media_backward_light.png +++ b/app/src/main/res/drawable-xxhdpi/media_backward_light.png diff --git a/app/src/main/res/drawable-xxhdpi/media_forward_dark.png b/app/src/main/res/drawable-xxhdpi/media_forward_dark.png Binary files differindex ca4ee295..009f0121 100644 --- a/app/src/main/res/drawable-xxhdpi/media_forward_dark.png +++ b/app/src/main/res/drawable-xxhdpi/media_forward_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/media_forward_light.png b/app/src/main/res/drawable-xxhdpi/media_forward_light.png Binary files differindex 208e46e9..518b4bdc 100644 --- a/app/src/main/res/drawable-xxhdpi/media_forward_light.png +++ b/app/src/main/res/drawable-xxhdpi/media_forward_light.png diff --git a/app/src/main/res/drawable-xxhdpi/media_pause_dark.png b/app/src/main/res/drawable-xxhdpi/media_pause_dark.png Binary files differindex 4b5aacbc..78fc1490 100644 --- a/app/src/main/res/drawable-xxhdpi/media_pause_dark.png +++ b/app/src/main/res/drawable-xxhdpi/media_pause_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/media_pause_light.png b/app/src/main/res/drawable-xxhdpi/media_pause_light.png Binary files differindex 111f6d00..dace7590 100644 --- a/app/src/main/res/drawable-xxhdpi/media_pause_light.png +++ b/app/src/main/res/drawable-xxhdpi/media_pause_light.png diff --git a/app/src/main/res/drawable-xxhdpi/media_repeat_all_dark.png b/app/src/main/res/drawable-xxhdpi/media_repeat_all_dark.png Binary files differnew file mode 100644 index 00000000..34b0cb10 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/media_repeat_all_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/media_repeat_all_light.png b/app/src/main/res/drawable-xxhdpi/media_repeat_all_light.png Binary files differnew file mode 100644 index 00000000..981dd1b0 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/media_repeat_all_light.png diff --git a/app/src/main/res/drawable-xxhdpi/media_repeat_off_dark.png b/app/src/main/res/drawable-xxhdpi/media_repeat_off_dark.png Binary files differnew file mode 100644 index 00000000..05595e80 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/media_repeat_off_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/media_repeat_off_light.png b/app/src/main/res/drawable-xxhdpi/media_repeat_off_light.png Binary files differnew file mode 100644 index 00000000..c53f512c --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/media_repeat_off_light.png diff --git a/app/src/main/res/drawable-xxhdpi/media_repeat_single_dark.png b/app/src/main/res/drawable-xxhdpi/media_repeat_single_dark.png Binary files differnew file mode 100644 index 00000000..09f57c28 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/media_repeat_single_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/media_repeat_single_light.png b/app/src/main/res/drawable-xxhdpi/media_repeat_single_light.png Binary files differnew file mode 100644 index 00000000..290bcda7 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/media_repeat_single_light.png diff --git a/app/src/main/res/drawable-xxhdpi/media_start_dark.png b/app/src/main/res/drawable-xxhdpi/media_start_dark.png Binary files differindex 641ad544..a2f1edcc 100644 --- a/app/src/main/res/drawable-xxhdpi/media_start_dark.png +++ b/app/src/main/res/drawable-xxhdpi/media_start_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/media_start_light.png b/app/src/main/res/drawable-xxhdpi/media_start_light.png Binary files differindex a6286203..9a885f23 100644 --- a/app/src/main/res/drawable-xxhdpi/media_start_light.png +++ b/app/src/main/res/drawable-xxhdpi/media_start_light.png diff --git a/app/src/main/res/drawable-xxhdpi/media_stop_dark.png b/app/src/main/res/drawable-xxhdpi/media_stop_dark.png Binary files differindex 9a9c432a..630709a9 100644 --- a/app/src/main/res/drawable-xxhdpi/media_stop_dark.png +++ b/app/src/main/res/drawable-xxhdpi/media_stop_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/media_stop_light.png b/app/src/main/res/drawable-xxhdpi/media_stop_light.png Binary files differindex 79eb8d95..c85bd3aa 100644 --- a/app/src/main/res/drawable-xxhdpi/media_stop_light.png +++ b/app/src/main/res/drawable-xxhdpi/media_stop_light.png diff --git a/app/src/main/res/drawable-xxhdpi/notification_close.png b/app/src/main/res/drawable-xxhdpi/notification_close.png Binary files differdeleted file mode 100644 index 022a6780..00000000 --- a/app/src/main/res/drawable-xxhdpi/notification_close.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi/notification_close_dark.png b/app/src/main/res/drawable-xxhdpi/notification_close_dark.png Binary files differnew file mode 100644 index 00000000..c9a0393f --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/notification_close_dark.png diff --git a/app/src/main/res/drawable-xxhdpi/notification_close_light.png b/app/src/main/res/drawable-xxhdpi/notification_close_light.png Binary files differnew file mode 100644 index 00000000..10102a30 --- /dev/null +++ b/app/src/main/res/drawable-xxhdpi/notification_close_light.png diff --git a/app/src/main/res/drawable-xxhdpi/notification_next.png b/app/src/main/res/drawable-xxhdpi/notification_next.png Binary files differdeleted file mode 100644 index dfe129db..00000000 --- a/app/src/main/res/drawable-xxhdpi/notification_next.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi/notification_pause.png b/app/src/main/res/drawable-xxhdpi/notification_pause.png Binary files differdeleted file mode 100644 index 9c952207..00000000 --- a/app/src/main/res/drawable-xxhdpi/notification_pause.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi/notification_play.png b/app/src/main/res/drawable-xxhdpi/notification_play.png Binary files differdeleted file mode 100644 index 4ee0a5eb..00000000 --- a/app/src/main/res/drawable-xxhdpi/notification_play.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi/notification_previous.png b/app/src/main/res/drawable-xxhdpi/notification_previous.png Binary files differdeleted file mode 100644 index e6908126..00000000 --- a/app/src/main/res/drawable-xxhdpi/notification_previous.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi/now_playing.png b/app/src/main/res/drawable-xxhdpi/now_playing.png Binary files differdeleted file mode 100644 index 4ee0a5eb..00000000 --- a/app/src/main/res/drawable-xxhdpi/now_playing.png +++ /dev/null diff --git a/app/src/main/res/drawable-xxhdpi/stat_notify_download.png b/app/src/main/res/drawable-xxhdpi/stat_notify_download.png Binary files differindex 9d9a7f3e..b2dc5651 100644 --- a/app/src/main/res/drawable-xxhdpi/stat_notify_download.png +++ b/app/src/main/res/drawable-xxhdpi/stat_notify_download.png diff --git a/app/src/main/res/drawable-xxhdpi/stat_notify_playing.png b/app/src/main/res/drawable-xxhdpi/stat_notify_playing.png Binary files differindex 4ee0a5eb..9138a760 100644 --- a/app/src/main/res/drawable-xxhdpi/stat_notify_playing.png +++ b/app/src/main/res/drawable-xxhdpi/stat_notify_playing.png diff --git a/app/src/main/res/drawable-xxhdpi/stat_notify_sync.png b/app/src/main/res/drawable-xxhdpi/stat_notify_sync.png Binary files differindex 89fe6525..61f6a331 100644 --- a/app/src/main/res/drawable-xxhdpi/stat_notify_sync.png +++ b/app/src/main/res/drawable-xxhdpi/stat_notify_sync.png diff --git a/app/src/main/res/drawable-xxxhdpi/action_toggle_list_dark.png b/app/src/main/res/drawable-xxxhdpi/action_toggle_list_dark.png Binary files differnew file mode 100644 index 00000000..6cce6bb0 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/action_toggle_list_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/action_toggle_list_light.png b/app/src/main/res/drawable-xxxhdpi/action_toggle_list_light.png Binary files differnew file mode 100644 index 00000000..e2ac61bd --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/action_toggle_list_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/download_none_dark.png b/app/src/main/res/drawable-xxxhdpi/download_none_dark.png Binary files differnew file mode 100644 index 00000000..bb44441a --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/download_none_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/download_none_light.png b/app/src/main/res/drawable-xxxhdpi/download_none_light.png Binary files differnew file mode 100644 index 00000000..2aae0dc5 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/download_none_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/downloading_dark.png b/app/src/main/res/drawable-xxxhdpi/downloading_dark.png Binary files differnew file mode 100644 index 00000000..1236129d --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/downloading_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/downloading_light.png b/app/src/main/res/drawable-xxxhdpi/downloading_light.png Binary files differnew file mode 100644 index 00000000..0640da5e --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/downloading_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_add_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_action_add_dark.png Binary files differnew file mode 100644 index 00000000..1958de16 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_action_add_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_add_light.png b/app/src/main/res/drawable-xxxhdpi/ic_action_add_light.png Binary files differnew file mode 100644 index 00000000..dd788676 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_action_add_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_artist.png b/app/src/main/res/drawable-xxxhdpi/ic_action_artist.png Binary files differnew file mode 100644 index 00000000..0087d403 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_action_artist.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_rating_bad_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_action_rating_bad_dark.png Binary files differnew file mode 100644 index 00000000..3f08bdde --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_action_rating_bad_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_rating_bad_light.png b/app/src/main/res/drawable-xxxhdpi/ic_action_rating_bad_light.png Binary files differnew file mode 100644 index 00000000..545e4570 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_action_rating_bad_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_rating_bad_selected.png b/app/src/main/res/drawable-xxxhdpi/ic_action_rating_bad_selected.png Binary files differnew file mode 100644 index 00000000..f585ba00 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_action_rating_bad_selected.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_rating_good_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_action_rating_good_dark.png Binary files differnew file mode 100644 index 00000000..af9dcfbb --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_action_rating_good_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_rating_good_light.png b/app/src/main/res/drawable-xxxhdpi/ic_action_rating_good_light.png Binary files differnew file mode 100644 index 00000000..9ed5d62c --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_action_rating_good_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_rating_good_selected.png b/app/src/main/res/drawable-xxxhdpi/ic_action_rating_good_selected.png Binary files differnew file mode 100644 index 00000000..9ee267f7 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_action_rating_good_selected.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_song.png b/app/src/main/res/drawable-xxxhdpi/ic_action_song.png Binary files differnew file mode 100644 index 00000000..4b81fcca --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_action_song.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_add_person_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_add_person_dark.png Binary files differnew file mode 100644 index 00000000..11c2d02b --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_add_person_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_add_person_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_add_person_light.png Binary files differnew file mode 100644 index 00000000..49377a5c --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_add_person_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_admin_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_admin_dark.png Binary files differnew file mode 100644 index 00000000..ea10506f --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_admin_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_admin_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_admin_light.png Binary files differnew file mode 100644 index 00000000..c9923c2d --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_admin_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_bookmark_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_bookmark_dark.png Binary files differnew file mode 100644 index 00000000..4651e2ce --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_bookmark_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_bookmark_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_bookmark_light.png Binary files differnew file mode 100644 index 00000000..08050801 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_bookmark_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_bookmark_selected.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_bookmark_selected.png Binary files differnew file mode 100644 index 00000000..bbec912b --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_bookmark_selected.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_chat_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_chat_dark.png Binary files differnew file mode 100644 index 00000000..194601c3 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_chat_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_chat_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_chat_light.png Binary files differnew file mode 100644 index 00000000..bb831238 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_chat_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_chat_send_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_chat_send_dark.png Binary files differnew file mode 100644 index 00000000..105f9766 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_chat_send_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_chat_send_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_chat_send_light.png Binary files differnew file mode 100644 index 00000000..97ca8c04 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_chat_send_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_download_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_download_dark.png Binary files differnew file mode 100644 index 00000000..121242ad --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_download_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_download_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_download_light.png Binary files differnew file mode 100644 index 00000000..b6df4cf9 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_download_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_library_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_library_dark.png Binary files differnew file mode 100644 index 00000000..e597eb21 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_library_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_library_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_library_light.png Binary files differnew file mode 100644 index 00000000..354b8ada --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_library_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_password_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_password_dark.png Binary files differnew file mode 100644 index 00000000..b091c6e0 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_password_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_password_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_password_light.png Binary files differnew file mode 100644 index 00000000..0d0953d4 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_password_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_playlist_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_playlist_dark.png Binary files differnew file mode 100644 index 00000000..2f1728ce --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_playlist_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_playlist_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_playlist_light.png Binary files differnew file mode 100644 index 00000000..a7938237 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_playlist_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_podcast_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_podcast_dark.png Binary files differnew file mode 100644 index 00000000..a3b11830 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_podcast_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_podcast_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_podcast_light.png Binary files differnew file mode 100644 index 00000000..0f74e59b --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_podcast_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_radio_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_radio_dark.png Binary files differnew file mode 100644 index 00000000..722752d8 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_radio_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_radio_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_radio_light.png Binary files differnew file mode 100644 index 00000000..4c239975 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_radio_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_refresh_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_refresh_dark.png Binary files differnew file mode 100644 index 00000000..a751d126 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_refresh_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_refresh_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_refresh_light.png Binary files differnew file mode 100644 index 00000000..8cfc17d0 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_refresh_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_remove_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_remove_dark.png Binary files differnew file mode 100644 index 00000000..c308a140 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_remove_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_remove_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_remove_light.png Binary files differnew file mode 100644 index 00000000..7b5b5985 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_remove_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_save_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_save_dark.png Binary files differnew file mode 100644 index 00000000..1b465773 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_save_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_save_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_save_light.png Binary files differnew file mode 100644 index 00000000..8bf03337 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_save_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_search_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_search_dark.png Binary files differnew file mode 100644 index 00000000..06843471 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_search_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_search_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_search_light.png Binary files differnew file mode 100644 index 00000000..2653c039 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_search_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_settings_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_settings_dark.png Binary files differnew file mode 100644 index 00000000..6f4ae03f --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_settings_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_settings_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_settings_light.png Binary files differnew file mode 100644 index 00000000..7686c7a3 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_settings_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_share_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_share_dark.png Binary files differnew file mode 100644 index 00000000..e90908e4 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_share_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_share_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_share_light.png Binary files differnew file mode 100644 index 00000000..aebbe3a6 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_share_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_shuffle_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_shuffle_dark.png Binary files differnew file mode 100644 index 00000000..ed6b7519 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_shuffle_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_menu_shuffle_light.png b/app/src/main/res/drawable-xxxhdpi/ic_menu_shuffle_light.png Binary files differnew file mode 100644 index 00000000..bfea1673 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_menu_shuffle_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_social_person.png b/app/src/main/res/drawable-xxxhdpi/ic_social_person.png Binary files differnew file mode 100644 index 00000000..f6dd5501 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_social_person.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_toggle_star.png b/app/src/main/res/drawable-xxxhdpi/ic_toggle_star.png Binary files differnew file mode 100644 index 00000000..6116210d --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_toggle_star.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_toggle_star_outline_dark.png b/app/src/main/res/drawable-xxxhdpi/ic_toggle_star_outline_dark.png Binary files differnew file mode 100644 index 00000000..ddc2a190 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_toggle_star_outline_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_toggle_star_outline_light.png b/app/src/main/res/drawable-xxxhdpi/ic_toggle_star_outline_light.png Binary files differnew file mode 100644 index 00000000..d0048a00 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/ic_toggle_star_outline_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/main_offline_dark.png b/app/src/main/res/drawable-xxxhdpi/main_offline_dark.png Binary files differnew file mode 100644 index 00000000..75e4c54e --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/main_offline_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/main_offline_light.png b/app/src/main/res/drawable-xxxhdpi/main_offline_light.png Binary files differnew file mode 100644 index 00000000..c461f09f --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/main_offline_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/main_select_server_dark.png b/app/src/main/res/drawable-xxxhdpi/main_select_server_dark.png Binary files differnew file mode 100644 index 00000000..cb26d6d2 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/main_select_server_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/main_select_server_light.png b/app/src/main/res/drawable-xxxhdpi/main_select_server_light.png Binary files differnew file mode 100644 index 00000000..996eae7c --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/main_select_server_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/main_select_tabs_dark.png b/app/src/main/res/drawable-xxxhdpi/main_select_tabs_dark.png Binary files differnew file mode 100644 index 00000000..169ca0f5 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/main_select_tabs_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/main_select_tabs_light.png b/app/src/main/res/drawable-xxxhdpi/main_select_tabs_light.png Binary files differnew file mode 100644 index 00000000..da74fa7b --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/main_select_tabs_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_backward_dark.png b/app/src/main/res/drawable-xxxhdpi/media_backward_dark.png Binary files differnew file mode 100644 index 00000000..2b2b3710 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_backward_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_backward_light.png b/app/src/main/res/drawable-xxxhdpi/media_backward_light.png Binary files differnew file mode 100644 index 00000000..247dd016 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_backward_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_forward_dark.png b/app/src/main/res/drawable-xxxhdpi/media_forward_dark.png Binary files differnew file mode 100644 index 00000000..e8432b66 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_forward_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_forward_light.png b/app/src/main/res/drawable-xxxhdpi/media_forward_light.png Binary files differnew file mode 100644 index 00000000..9ec784c4 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_forward_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_pause_dark.png b/app/src/main/res/drawable-xxxhdpi/media_pause_dark.png Binary files differnew file mode 100644 index 00000000..767494c6 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_pause_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_pause_light.png b/app/src/main/res/drawable-xxxhdpi/media_pause_light.png Binary files differnew file mode 100644 index 00000000..dfaf4097 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_pause_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_repeat_all_dark.png b/app/src/main/res/drawable-xxxhdpi/media_repeat_all_dark.png Binary files differnew file mode 100644 index 00000000..5a61ad86 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_repeat_all_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_repeat_all_light.png b/app/src/main/res/drawable-xxxhdpi/media_repeat_all_light.png Binary files differnew file mode 100644 index 00000000..9a0cca6d --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_repeat_all_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_repeat_off_dark.png b/app/src/main/res/drawable-xxxhdpi/media_repeat_off_dark.png Binary files differnew file mode 100644 index 00000000..cdac547a --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_repeat_off_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_repeat_off_light.png b/app/src/main/res/drawable-xxxhdpi/media_repeat_off_light.png Binary files differnew file mode 100644 index 00000000..c5b3abe7 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_repeat_off_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_repeat_single_dark.png b/app/src/main/res/drawable-xxxhdpi/media_repeat_single_dark.png Binary files differnew file mode 100644 index 00000000..ce3d0d6d --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_repeat_single_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_repeat_single_light.png b/app/src/main/res/drawable-xxxhdpi/media_repeat_single_light.png Binary files differnew file mode 100644 index 00000000..d58a2523 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_repeat_single_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_start_dark.png b/app/src/main/res/drawable-xxxhdpi/media_start_dark.png Binary files differnew file mode 100644 index 00000000..1b0d9c68 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_start_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_start_light.png b/app/src/main/res/drawable-xxxhdpi/media_start_light.png Binary files differnew file mode 100644 index 00000000..a68b910d --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_start_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_stop_dark.png b/app/src/main/res/drawable-xxxhdpi/media_stop_dark.png Binary files differnew file mode 100644 index 00000000..0e783322 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_stop_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/media_stop_light.png b/app/src/main/res/drawable-xxxhdpi/media_stop_light.png Binary files differnew file mode 100644 index 00000000..c9793500 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/media_stop_light.png diff --git a/app/src/main/res/drawable-xxxhdpi/notification_close_dark.png b/app/src/main/res/drawable-xxxhdpi/notification_close_dark.png Binary files differnew file mode 100644 index 00000000..08b0792e --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/notification_close_dark.png diff --git a/app/src/main/res/drawable-xxxhdpi/notification_close_light.png b/app/src/main/res/drawable-xxxhdpi/notification_close_light.png Binary files differnew file mode 100644 index 00000000..ef0d48f0 --- /dev/null +++ b/app/src/main/res/drawable-xxxhdpi/notification_close_light.png diff --git a/app/src/main/res/drawable/drawer_header.jpg b/app/src/main/res/drawable/drawer_header.jpg Binary files differnew file mode 100644 index 00000000..f54a30e2 --- /dev/null +++ b/app/src/main/res/drawable/drawer_header.jpg diff --git a/app/src/main/res/drawable/fast_scroller_bubble.xml b/app/src/main/res/drawable/fast_scroller_bubble.xml new file mode 100644 index 00000000..02dfee5b --- /dev/null +++ b/app/src/main/res/drawable/fast_scroller_bubble.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + + <corners + android:topLeftRadius="44dp" + android:topRightRadius="44dp" + android:bottomLeftRadius="44dp" + android:bottomRightRadius="0px"/> + + <solid android:color="#FF0288D1"/> + + <size + android:height="88dp" + android:width="88dp"/> +</shape>
\ No newline at end of file diff --git a/app/src/main/res/drawable/fast_scroller_handle.xml b/app/src/main/res/drawable/fast_scroller_handle.xml new file mode 100644 index 00000000..e1744ceb --- /dev/null +++ b/app/src/main/res/drawable/fast_scroller_handle.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<selector xmlns:android="http://schemas.android.com/apk/res/android"> + <item android:state_selected="true"> + <shape android:shape="rectangle"> + <corners android:radius="2dp"/> + + <solid android:color="#FF0288D1"/> + + <size + android:height="32dp" + android:width="4dp"/> + </shape> + </item> + + <item> + <shape android:shape="rectangle"> + <corners android:radius="2dp"/> + + <solid android:color="#FF737373"/> + + <size + android:height="32dp" + android:width="4dp"/> + </shape> + </item> +</selector>
\ No newline at end of file diff --git a/app/src/main/res/drawable/notification_backward.xml b/app/src/main/res/drawable/notification_backward.xml new file mode 100644 index 00000000..f5fd965b --- /dev/null +++ b/app/src/main/res/drawable/notification_backward.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<bitmap + xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/media_backward_dark"/>
\ No newline at end of file diff --git a/app/src/main/res/drawable/notification_close.xml b/app/src/main/res/drawable/notification_close.xml new file mode 100644 index 00000000..67a5696f --- /dev/null +++ b/app/src/main/res/drawable/notification_close.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<bitmap + xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/notification_close_dark"/>
\ No newline at end of file diff --git a/app/src/main/res/drawable/notification_divider.xml b/app/src/main/res/drawable/notification_divider.xml new file mode 100644 index 00000000..95d50aa7 --- /dev/null +++ b/app/src/main/res/drawable/notification_divider.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<shape xmlns:android="http://schemas.android.com/apk/res/android"> + <size android:width="1dip" /> + <solid android:color="@android:color/darker_gray" /> +</shape>
\ No newline at end of file diff --git a/app/src/main/res/drawable/notification_forward.xml b/app/src/main/res/drawable/notification_forward.xml new file mode 100644 index 00000000..5dd10008 --- /dev/null +++ b/app/src/main/res/drawable/notification_forward.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<bitmap + xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/media_forward_dark"/>
\ No newline at end of file diff --git a/app/src/main/res/drawable/notification_pause.xml b/app/src/main/res/drawable/notification_pause.xml new file mode 100644 index 00000000..c71a997c --- /dev/null +++ b/app/src/main/res/drawable/notification_pause.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<bitmap + xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/media_pause_dark"/>
\ No newline at end of file diff --git a/app/src/main/res/drawable/notification_start.xml b/app/src/main/res/drawable/notification_start.xml new file mode 100644 index 00000000..b31b4f86 --- /dev/null +++ b/app/src/main/res/drawable/notification_start.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<bitmap + xmlns:android="http://schemas.android.com/apk/res/android" + android:src="@drawable/media_start_dark"/>
\ No newline at end of file diff --git a/app/src/main/res/layout-large-land/abstract_fragment_container.xml b/app/src/main/res/layout-large-land/abstract_fragment_container.xml index 5e3b1561..3901710f 100644 --- a/app/src/main/res/layout-large-land/abstract_fragment_container.xml +++ b/app/src/main/res/layout-large-land/abstract_fragment_container.xml @@ -2,8 +2,8 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="match_parent" - android:layout_height="0px" - android:layout_weight="1"> + android:layout_height="match_parent" + android:layout_marginTop="?attr/actionBarSize"> <FrameLayout android:id="@+id/fragment_container" diff --git a/app/src/main/res/layout/abstract_activity.xml b/app/src/main/res/layout/abstract_activity.xml index be65e437..56db1439 100644 --- a/app/src/main/res/layout/abstract_activity.xml +++ b/app/src/main/res/layout/abstract_activity.xml @@ -1,21 +1,22 @@ <?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/drawer_layout" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:fitsSystemWindows="true"> + <!-- The main content view --> <FrameLayout android:id="@+id/content_frame" android:layout_width="match_parent" android:layout_height="match_parent"/> + <!-- The navigation drawer --> - <ListView android:id="@+id/left_drawer" - android:layout_width="240dp" - android:layout_height="match_parent" - android:layout_gravity="start" - android:choiceMode="singleChoice" - android:divider="@android:color/transparent" - android:dividerHeight="0dp" - android:background="?android:windowBackground"/> + <android.support.design.widget.NavigationView + android:id="@+id/left_drawer" + android:layout_width="wrap_content" + android:layout_height="match_parent" + android:layout_gravity="start"/> </android.support.v4.widget.DrawerLayout> diff --git a/app/src/main/res/layout/abstract_fragment_activity.xml b/app/src/main/res/layout/abstract_fragment_activity.xml index d9c99f2f..04e6ec81 100644 --- a/app/src/main/res/layout/abstract_fragment_activity.xml +++ b/app/src/main/res/layout/abstract_fragment_activity.xml @@ -1,84 +1,133 @@ -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" +<com.sothree.slidinguppanel.SlidingUpPanelLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:sothree="http://schemas.android.com/apk/res-auto" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:id="@+id/slide_up_panel" android:layout_width="match_parent" android:layout_height="match_parent" - android:gravity="center_horizontal" - android:orientation="vertical" > + android:gravity="bottom" + sothree:umanoPanelHeight="?attr/actionBarSize" + sothree:umanoShadowHeight="4dp" + sothree:umanoDragView="@+id/slide_up_swipe_target"> - <include layout="@layout/abstract_fragment_container" /> + <FrameLayout + android:layout_width="match_parent" + android:layout_height="match_parent"> - <View - android:layout_width="fill_parent" - android:layout_height="1px" - android:background="@color/dividerColor"/> + <android.support.v7.widget.Toolbar + android:id="@+id/main_toolbar" + android:layout_height="?attr/actionBarSize" + android:layout_width="match_parent" + android:background="?attr/colorPrimary" + android:elevation="4dp" + android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" + app:popupTheme="?attr/actionbarPopupStyle"/> + + <include layout="@layout/abstract_fragment_container"/> + </FrameLayout> <LinearLayout - android:id="@+id/bottom_bar" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - style="@style/BasicButton" - android:orientation="horizontal"> - - <github.daneren2005.dsub.view.RecyclingImageView - android:id="@+id/album_art" - android:layout_width="50dip" - android:layout_height="50dip" - android:layout_gravity="left|center" - android:scaleType="fitStart"/> - - <LinearLayout - android:layout_width="0dp" + android:id="@+id/slide_up_frame" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <FrameLayout + android:id="@+id/slide_up_swipe_target" + android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - android:layout_weight="1" - android:orientation="vertical" - android:paddingLeft="8dip"> + android:background="?attr/colorPrimary"> - <TextView - android:id="@+id/track_name" - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textColor="?android:textColorPrimary" - android:singleLine="true" - android:textAppearance="?android:attr/textAppearanceSmall" - android:textSize="13sp" - android:text="@string/search.artists"/> - - <TextView - android:id="@+id/artist_name" + <android.support.v7.widget.Toolbar + android:id="@+id/now_playing_toolbar" + android:layout_height="?attr/actionBarSize" + android:layout_width="match_parent" + android:elevation="4dp" + android:visibility="gone" + app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" + app:popupTheme="?attr/actionbarPopupStyle"/> + + <LinearLayout + android:id="@+id/bottom_bar" + android:layout_width="fill_parent" android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:textColor="?android:textColorSecondary" - android:singleLine="true" - android:textAppearance="?android:attr/textAppearanceSmall" - android:textSize="12sp" - android:text="@string/search.albums"/> - </LinearLayout> - - <LinearLayout - android:layout_height="wrap_content" - android:layout_width="0dp" - android:layout_weight="1"> - - <ImageButton - style="@style/PlaybackControl.Small" - android:id="@+id/download_previous" - android:src="?attr/media_button_backward" - android:layout_width="0dp" - android:layout_weight="1"/> - - <ImageButton - style="@style/PlaybackControl.Small" - android:id="@+id/download_start" - android:src="?attr/media_button_start" - android:layout_width="0dp" - android:layout_weight="1"/> - - <ImageButton - style="@style/PlaybackControl.Small" - android:id="@+id/download_next" - android:src="?attr/media_button_forward" - android:layout_width="0dp" - android:layout_weight="1"/> - </LinearLayout> + style="@style/BasicButton" + android:orientation="horizontal" + android:elevation="4dp"> + + <github.daneren2005.dsub.view.RecyclingImageView + android:id="@+id/album_art" + android:layout_width="?attr/actionBarSize" + android:layout_height="?attr/actionBarSize" + android:layout_gravity="left|center" + android:scaleType="fitStart"/> + + <LinearLayout + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_gravity="center_vertical" + android:layout_weight="1" + android:orientation="vertical" + android:paddingLeft="8dip"> + + <TextView + android:id="@+id/track_name" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:singleLine="true" + android:text="@string/main.title" + android:ellipsize="marquee" + android:marqueeRepeatLimit="marquee_forever" + android:scrollHorizontally="true" + android:focusable="true" + android:focusableInTouchMode="true" + style="?attr/actionbarTitleStyle"> + + <requestFocus android:focusable="true" + android:focusableInTouchMode="true" + android:duplicateParentState="true" /> + </TextView> + + <TextView + android:id="@+id/artist_name" + android:layout_height="wrap_content" + android:layout_width="wrap_content" + android:singleLine="true" + android:text="@string/main.artist" + style="?attr/actionbarSubtitleStyle"/> + </LinearLayout> + + + <LinearLayout + android:layout_height="fill_parent" + android:layout_width="0dp" + android:layout_weight="1"> + + <ImageButton + style="@style/PlaybackControl.BottomBar" + android:id="@+id/download_previous" + android:src="?attr/actionbar_backward" + android:padding="2dp"/> + + <ImageButton + style="@style/PlaybackControl.BottomBar" + android:id="@+id/download_start" + android:src="?attr/actionbar_start"/> + + <ImageButton + style="@style/PlaybackControl.BottomBar" + android:id="@+id/download_next" + android:src="?attr/actionbar_forward" + android:padding="2dp"/> + </LinearLayout> + </LinearLayout> + </FrameLayout> + + <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/now_playing_fragment_container" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1" + android:clickable="true"/> </LinearLayout> -</LinearLayout>
\ No newline at end of file +</com.sothree.slidinguppanel.SlidingUpPanelLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/abstract_fragment_container.xml b/app/src/main/res/layout/abstract_fragment_container.xml index 61e17d1d..f13356c4 100644 --- a/app/src/main/res/layout/abstract_fragment_container.xml +++ b/app/src/main/res/layout/abstract_fragment_container.xml @@ -2,5 +2,5 @@ <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fragment_container" android:layout_width="match_parent" - android:layout_height="0px" - android:layout_weight="1"/>
\ No newline at end of file + android:layout_height="match_parent" + android:layout_marginTop="?attr/actionBarSize"/>
\ No newline at end of file diff --git a/app/src/main/res/layout/abstract_list_fragment.xml b/app/src/main/res/layout/abstract_recycler_fragment.xml index 618a7341..0e0c87f4 100644 --- a/app/src/main/res/layout/abstract_list_fragment.xml +++ b/app/src/main/res/layout/abstract_recycler_fragment.xml @@ -10,17 +10,23 @@ android:layout_height="fill_parent" android:orientation="vertical" > - <View - android:layout_width="fill_parent" - android:layout_height="1px" - android:background="@color/dividerColor"/> - - <ListView - android:id="@+id/fragment_list" + <RelativeLayout android:layout_width="fill_parent" android:layout_height="0dip" - android:layout_weight="1.0" - android:fastScrollEnabled="true"/> + android:layout_weight="1.0"> + + <android.support.v7.widget.RecyclerView + android:id="@+id/fragment_recycler" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:scrollbars="vertical"/> + + <github.daneren2005.dsub.view.FastScroller + android:id="@+id/fragment_fast_scroller" + android:layout_width="wrap_content" + android:layout_height="fill_parent" + android:layout_alignParentRight="true"/> + </RelativeLayout> <include layout="@layout/tab_progress" /> </LinearLayout> diff --git a/app/src/main/res/layout/actionbar_spinner.xml b/app/src/main/res/layout/actionbar_spinner.xml index 22055901..4d9f95a4 100644 --- a/app/src/main/res/layout/actionbar_spinner.xml +++ b/app/src/main/res/layout/actionbar_spinner.xml @@ -1,13 +1,14 @@ <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:gravity="fill_horizontal" > - <Spinner - android:id="@+id/spinner" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:prompt="@string/common.appname" - /> + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:gravity="fill_horizontal" > + + <Spinner + android:id="@+id/spinner" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:prompt="@string/common.appname" + android:background="@drawable/abc_spinner_mtrl_am_alpha"/> </RelativeLayout> diff --git a/app/src/main/res/layout/album_cell_item.xml b/app/src/main/res/layout/album_cell_item.xml index 3f708e63..244c6f1f 100644 --- a/app/src/main/res/layout/album_cell_item.xml +++ b/app/src/main/res/layout/album_cell_item.xml @@ -2,7 +2,8 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:background="?attr/selectableItemBackground"> <RelativeLayout android:layout_width="match_parent" @@ -66,10 +67,10 @@ <ImageButton android:id="@+id/album_star" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_width="@dimen/Star.Small" + android:layout_height="@dimen/Star.Small" + android:scaleType="fitCenter" android:layout_gravity="right|center_vertical" - android:src="@drawable/ic_stat_star" android:background="@android:color/transparent" android:focusable="false" android:visibility="gone"/> @@ -77,7 +78,7 @@ </LinearLayout> <ImageView - android:id="@+id/album_more" + android:id="@+id/more_button" android:src="?attr/download_none" android:layout_width="wrap_content" android:layout_height="wrap_content" diff --git a/app/src/main/res/layout/album_list_header.xml b/app/src/main/res/layout/album_list_header.xml new file mode 100644 index 00000000..e78d0ace --- /dev/null +++ b/app/src/main/res/layout/album_list_header.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:orientation="horizontal"> + + <TextView + android:id="@+id/item_name" + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:background="@android:color/transparent" + android:textColor="?attr/colorAccent" + android:textStyle="bold" + android:paddingLeft="6dp" + android:paddingRight="6dp" + android:paddingTop="8dp" + android:paddingBottom="8dp"/> + + <CheckBox + android:id="@+id/item_checkbox" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/main.albums_per_folder" + android:layout_marginRight="6dp" + android:layout_gravity="right" + android:textColor="?android:textColorPrimary"/> +</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/album_list_item.xml b/app/src/main/res/layout/album_list_item.xml index 0ee92edd..ba892365 100644 --- a/app/src/main/res/layout/album_list_item.xml +++ b/app/src/main/res/layout/album_list_item.xml @@ -3,7 +3,8 @@ android:id="@id/drag_handle" android:orientation="horizontal" android:layout_width="fill_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground"> <RelativeLayout android:layout_width="@dimen/AlbumArt.Small" @@ -43,29 +44,31 @@ android:textAppearance="?android:attr/textAppearanceMedium" android:singleLine="true" android:ellipsize="marquee" - android:paddingBottom="6dip"/> + android:paddingBottom="6dip" + android:textColor="?android:textColorPrimary"/> <TextView android:id="@+id/album_artist" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceSmall" - android:singleLine="true"/> + android:singleLine="true" + android:textColor="?android:textColorSecondary"/> </LinearLayout> <ImageButton android:id="@+id/album_star" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_width="@dimen/Star.Small" + android:layout_height="@dimen/Star.Small" + android:scaleType="fitCenter" android:layout_gravity="right|center_vertical" - android:src="@drawable/ic_stat_star" android:background="@android:color/transparent" android:focusable="false" android:visibility="gone"/> <ImageView - android:id="@+id/album_more" + android:id="@+id/more_button" android:src="?attr/download_none" android:layout_width="wrap_content" android:layout_height="fill_parent" diff --git a/app/src/main/res/layout/appwidget4x1.xml b/app/src/main/res/layout/appwidget4x1.xml index 8f52c872..86ddade0 100644 --- a/app/src/main/res/layout/appwidget4x1.xml +++ b/app/src/main/res/layout/appwidget4x1.xml @@ -30,7 +30,7 @@ android:clickable="true" android:focusable="true" android:orientation="vertical" - style="@style/BasicButton"> + style="@style/NotificationButton"> <TextView android:id="@+id/title" @@ -81,8 +81,8 @@ android:layout_height="fill_parent" android:layout_weight="1" android:scaleType="center" - style="@style/BasicButton" - android:src="@drawable/ic_appwidget_music_previous" /> + style="@style/NotificationButton" + android:src="@drawable/media_backward_dark" /> <ImageButton android:id="@+id/control_play" @@ -90,8 +90,8 @@ android:layout_height="fill_parent" android:layout_weight="1" android:scaleType="center" - android:src="@drawable/ic_appwidget_music_play" - style="@style/BasicButton" /> + android:src="@drawable/media_start_dark" + style="@style/NotificationButton" /> <ImageButton android:id="@+id/control_next" @@ -99,8 +99,8 @@ android:layout_height="fill_parent" android:layout_weight="1" android:scaleType="center" - android:src="@drawable/ic_appwidget_music_next" - style="@style/BasicButton" /> + android:src="@drawable/media_forward_dark" + style="@style/NotificationButton" /> </LinearLayout> </LinearLayout> diff --git a/app/src/main/res/layout/appwidget4x2.xml b/app/src/main/res/layout/appwidget4x2.xml index 5763fb01..52d0c15c 100644 --- a/app/src/main/res/layout/appwidget4x2.xml +++ b/app/src/main/res/layout/appwidget4x2.xml @@ -32,7 +32,7 @@ android:orientation="vertical" android:paddingTop="4dip" android:paddingBottom="4dip" - style="@style/BasicButton"> + style="@style/NotificationButton"> <TextView android:id="@+id/title" @@ -104,8 +104,8 @@ android:layout_height="wrap_content" android:layout_weight="1" android:scaleType="center" - style="@style/BasicButton" - android:src="@drawable/ic_appwidget_music_previous" /> + style="@style/NotificationButton" + android:src="@drawable/media_backward_dark" /> <ImageButton android:id="@+id/control_play" @@ -113,8 +113,8 @@ android:layout_height="wrap_content" android:layout_weight="1" android:scaleType="center" - android:src="@drawable/ic_appwidget_music_play" - style="@style/BasicButton" /> + android:src="@drawable/media_start_dark" + style="@style/NotificationButton" /> <ImageButton android:id="@+id/control_next" @@ -122,8 +122,8 @@ android:layout_height="wrap_content" android:layout_weight="1" android:scaleType="center" - android:src="@drawable/ic_appwidget_music_next" - style="@style/BasicButton" /> + android:src="@drawable/media_forward_dark" + style="@style/NotificationButton" /> </LinearLayout> </LinearLayout> diff --git a/app/src/main/res/layout/appwidget4x3.xml b/app/src/main/res/layout/appwidget4x3.xml index 539b9f01..4cfb4b77 100644 --- a/app/src/main/res/layout/appwidget4x3.xml +++ b/app/src/main/res/layout/appwidget4x3.xml @@ -34,7 +34,7 @@ android:orientation="vertical" android:paddingBottom="4dip" android:paddingTop="4dip" - style="@style/BasicButton"> + style="@style/NotificationButton"> <TextView android:id="@+id/title" @@ -86,8 +86,8 @@ android:layout_height="56dip" android:layout_weight="1" android:scaleType="center" - style="@style/BasicButton" - android:src="@drawable/ic_appwidget_music_previous" /> + style="@style/NotificationButton" + android:src="@drawable/media_backward_dark" /> <ImageButton android:id="@+id/control_play" @@ -95,8 +95,8 @@ android:layout_height="56dip" android:layout_weight="1" android:scaleType="center" - android:src="@drawable/ic_appwidget_music_play" - style="@style/BasicButton" /> + android:src="@drawable/media_start_dark" + style="@style/NotificationButton" /> <ImageButton android:id="@+id/control_next" @@ -104,8 +104,8 @@ android:layout_height="56dip" android:layout_weight="1" android:scaleType="center" - android:src="@drawable/ic_appwidget_music_next" - style="@style/BasicButton" /> + android:src="@drawable/media_forward_dark" + style="@style/NotificationButton" /> </LinearLayout> </LinearLayout> diff --git a/app/src/main/res/layout/appwidget4x4.xml b/app/src/main/res/layout/appwidget4x4.xml index 1f2db9e1..681d9252 100644 --- a/app/src/main/res/layout/appwidget4x4.xml +++ b/app/src/main/res/layout/appwidget4x4.xml @@ -35,7 +35,7 @@ android:orientation="vertical" android:paddingTop="4dip" android:paddingBottom="4dip" - style="@style/BasicButton"> + style="@style/NotificationButton"> <TextView android:id="@+id/title" @@ -88,8 +88,8 @@ android:layout_height="56dip" android:layout_weight="1" android:scaleType="center" - style="@style/BasicButton" - android:src="@drawable/ic_appwidget_music_previous" /> + style="@style/NotificationButton" + android:src="@drawable/media_backward_dark" /> <ImageButton android:id="@+id/control_play" @@ -97,8 +97,8 @@ android:layout_height="56dip" android:layout_weight="1" android:scaleType="center" - android:src="@drawable/ic_appwidget_music_play" - style="@style/BasicButton" /> + android:src="@drawable/media_start_dark" + style="@style/NotificationButton" /> <ImageButton android:id="@+id/control_next" @@ -106,8 +106,8 @@ android:layout_height="56dip" android:layout_weight="1" android:scaleType="center" - android:src="@drawable/ic_appwidget_music_next" - style="@style/BasicButton" /> + android:src="@drawable/media_forward_dark" + style="@style/NotificationButton" /> </LinearLayout> </LinearLayout> diff --git a/app/src/main/res/layout/basic_choice_item.xml b/app/src/main/res/layout/basic_choice_item.xml new file mode 100644 index 00000000..e2dc2204 --- /dev/null +++ b/app/src/main/res/layout/basic_choice_item.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground"> + + <TextView + android:id="@+id/item_name" + android:layout_width="0dip" + android:layout_height="?android:attr/listPreferredItemHeight" + android:layout_weight="1" + android:textAppearance="?android:attr/textAppearanceMedium" + android:gravity="left|center_vertical" + android:paddingLeft="6dip" + android:paddingRight="6dip" + android:background="@android:color/transparent" + android:textColor="?android:textColorPrimary"/> + + <CheckBox + android:id="@+id/item_checkbox" + android:layout_width="wrap_content" + android:layout_height="fill_parent" + android:layout_gravity="right|center_vertical" + android:checkMark="?android:attr/listChoiceIndicatorMultiple" + style="@style/MoreButton"/> +</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/basic_count_item.xml b/app/src/main/res/layout/basic_count_item.xml index 08d276db..ce1aa800 100644 --- a/app/src/main/res/layout/basic_count_item.xml +++ b/app/src/main/res/layout/basic_count_item.xml @@ -2,7 +2,7 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:background="@android:color/transparent" + android:background="?attr/selectableItemBackground" android:minHeight="50dip"> <TextView @@ -14,7 +14,8 @@ android:paddingLeft="6dip" android:paddingRight="6dip" android:background="@android:color/transparent" - android:text="Text"/> + android:text="Text" + android:textColor="?android:textColorPrimary"/> <TextView android:id="@+id/basic_count_count" @@ -31,5 +32,6 @@ android:textSize="11sp" android:gravity="right|center_vertical" android:layout_gravity="center_vertical" + android:textColor="?android:textColorPrimary" android:visibility="gone"/> </LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/basic_header.xml b/app/src/main/res/layout/basic_header.xml new file mode 100644 index 00000000..b1f94b33 --- /dev/null +++ b/app/src/main/res/layout/basic_header.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="utf-8"?> +<TextView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/item_name" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:textAppearance="?android:attr/textAppearanceMedium" + android:background="@android:color/transparent" + android:textColor="?attr/colorAccent" + android:textStyle="bold" + android:paddingLeft="6dp" + android:paddingRight="6dp" + android:paddingTop="8dp" + android:paddingBottom="8dp"/>
\ No newline at end of file diff --git a/app/src/main/res/layout/basic_list_item.xml b/app/src/main/res/layout/basic_list_item.xml index 2338f7e0..ea1df8e8 100644 --- a/app/src/main/res/layout/basic_list_item.xml +++ b/app/src/main/res/layout/basic_list_item.xml @@ -3,7 +3,7 @@ android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:background="@android:color/transparent"> + android:background="?attr/selectableItemBackground"> <TextView android:id="@+id/item_name" @@ -15,14 +15,15 @@ android:paddingLeft="6dip" android:paddingRight="6dip" android:minHeight="50dip" - android:background="@android:color/transparent"/> + android:background="@android:color/transparent" + android:textColor="?android:textColorPrimary"/> <ImageButton android:id="@+id/item_star" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_width="@dimen/Star.Small" + android:layout_height="@dimen/Star.Small" + android:scaleType="fitCenter" android:layout_gravity="right|center_vertical" - android:src="@drawable/ic_stat_star" android:background="@android:color/transparent" android:focusable="false" android:visibility="gone"/> diff --git a/app/src/main/res/layout/change_email.xml b/app/src/main/res/layout/change_email.xml index 18ffc765..87d297be 100644 --- a/app/src/main/res/layout/change_email.xml +++ b/app/src/main/res/layout/change_email.xml @@ -15,7 +15,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/admin.change_email_label" /> + android:text="@string/admin.change_email_label" + android:textColor="?android:textColorPrimary"/> <EditText android:id="@+id/new_email" android:inputType="textEmailAddress" diff --git a/app/src/main/res/layout/change_password.xml b/app/src/main/res/layout/change_password.xml index 1a382a6b..d8043c05 100644 --- a/app/src/main/res/layout/change_password.xml +++ b/app/src/main/res/layout/change_password.xml @@ -15,7 +15,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/admin.change_password_label" /> + android:text="@string/admin.change_password_label" + android:textColor="?android:textColorPrimary"/> <EditText android:id="@+id/new_password" android:inputType="textPassword" diff --git a/app/src/main/res/layout/chat_item.xml b/app/src/main/res/layout/chat_item.xml index f31f7988..bf5d81ca 100644 --- a/app/src/main/res/layout/chat_item.xml +++ b/app/src/main/res/layout/chat_item.xml @@ -2,7 +2,8 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground"> <github.daneren2005.dsub.view.RecyclingImageView android:id="@+id/chat_avatar" @@ -34,7 +35,7 @@ android:singleLine="true" android:text="User" android:textAppearance="?android:attr/textAppearanceLarge" - android:textColor="?android:textColorSecondary"/> + android:textColor="?android:textColorPrimary"/> <TextView android:id="@+id/chat_time" @@ -43,7 +44,8 @@ android:layout_marginLeft="6dip" android:singleLine="true" android:text="00:00" - android:textAppearance="?android:attr/textAppearanceSmall" /> + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="?android:textColorSecondary"/> </LinearLayout> <TextView @@ -56,6 +58,7 @@ android:linksClickable="true" android:singleLine="false" android:text="Message Text Goes Here" - android:textAppearance="?android:attr/textAppearanceMedium" /> + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="?android:textColorSecondary"/> </LinearLayout> </LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/chat_item_reverse.xml b/app/src/main/res/layout/chat_item_reverse.xml index b8102193..31875208 100644 --- a/app/src/main/res/layout/chat_item_reverse.xml +++ b/app/src/main/res/layout/chat_item_reverse.xml @@ -2,7 +2,8 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground"> <LinearLayout android:layout_width="0dip" @@ -24,7 +25,8 @@ android:layout_marginRight="6dip" android:singleLine="true" android:text="00:00" - android:textAppearance="?android:attr/textAppearanceSmall" /> + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="?android:textColorSecondary"/> <TextView android:id="@+id/chat_username" @@ -35,7 +37,7 @@ android:singleLine="true" android:text="User" android:textAppearance="?android:attr/textAppearanceLarge" - android:textColor="?android:textColorSecondary"/> + android:textColor="?android:textColorPrimary"/> </LinearLayout> <TextView @@ -49,7 +51,8 @@ android:singleLine="false" android:text="Chat message" android:textAppearance="?android:attr/textAppearanceMedium" - android:layout_gravity="right"/> + android:layout_gravity="right" + android:textColor="?android:textColorSecondary"/> </LinearLayout> <github.daneren2005.dsub.view.RecyclingImageView diff --git a/app/src/main/res/layout/complex_list_item.xml b/app/src/main/res/layout/complex_list_item.xml index 67851eca..143f9af9 100644 --- a/app/src/main/res/layout/complex_list_item.xml +++ b/app/src/main/res/layout/complex_list_item.xml @@ -1,9 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:layout_width="fill_parent" - android:layout_height="?android:attr/listPreferredItemHeight" - android:background="@android:color/transparent"> + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="?android:attr/listPreferredItemHeight" + android:background="?attr/selectableItemBackground"> <LinearLayout android:orientation="vertical" android:layout_width="0dip" @@ -19,22 +19,24 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" - android:background="@android:color/transparent"/> + android:background="@android:color/transparent" + android:textColor="?android:textColorPrimary"/> <TextView android:id="@+id/item_description" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceSmall" - android:background="@android:color/transparent"/> + android:background="@android:color/transparent" + android:textColor="?android:textColorSecondary"/> </LinearLayout> <ImageButton android:id="@+id/item_star" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_width="@dimen/Star.Small" + android:layout_height="@dimen/Star.Small" + android:scaleType="fitCenter" android:layout_gravity="right|center_vertical" - android:src="@drawable/ic_stat_star" android:background="@android:color/transparent" android:focusable="false" android:visibility="gone"/> diff --git a/app/src/main/res/layout/confirm_password.xml b/app/src/main/res/layout/confirm_password.xml index 27ee04ea..9ec61c0a 100644 --- a/app/src/main/res/layout/confirm_password.xml +++ b/app/src/main/res/layout/confirm_password.xml @@ -15,7 +15,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/admin.add_user_password" /> + android:text="@string/admin.add_user_password" + android:textColor="?android:textColorPrimary"/> <EditText android:id="@+id/password" android:inputType="textPassword" diff --git a/app/src/main/res/layout/create_bookmark.xml b/app/src/main/res/layout/create_bookmark.xml index f72b39d8..d6f077c3 100644 --- a/app/src/main/res/layout/create_bookmark.xml +++ b/app/src/main/res/layout/create_bookmark.xml @@ -14,7 +14,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/common.comment" /> + android:text="@string/common.comment" + android:textColor="?android:textColorPrimary"/> <EditText android:id="@+id/comment_text" android:inputType="text" diff --git a/app/src/main/res/layout/create_podcast.xml b/app/src/main/res/layout/create_podcast.xml index 5a2ec970..04e74ec3 100644 --- a/app/src/main/res/layout/create_podcast.xml +++ b/app/src/main/res/layout/create_podcast.xml @@ -14,7 +14,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/select_podcasts.add_url"/> + android:text="@string/select_podcasts.add_url" + android:textColor="?android:textColorPrimary"/> <EditText android:id="@+id/create_podcast_url" android:inputType="textUri" diff --git a/app/src/main/res/layout/create_user.xml b/app/src/main/res/layout/create_user.xml index eac6e5cb..b2d8f6e0 100644 --- a/app/src/main/res/layout/create_user.xml +++ b/app/src/main/res/layout/create_user.xml @@ -22,7 +22,8 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" - android:layout_marginLeft="4dp" /> + android:layout_marginLeft="4dp" + android:textColor="?android:textColorPrimary"/> </LinearLayout> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" @@ -43,7 +44,8 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" - android:layout_marginLeft="4dp" /> + android:layout_marginLeft="4dp" + android:textColor="?android:textColorPrimary"/> </LinearLayout> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" @@ -64,14 +66,14 @@ android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" - android:layout_marginLeft="4dp" /> + android:layout_marginLeft="4dp" + android:textColor="?android:textColorPrimary"/> </LinearLayout> - <ListView + <android.support.v7.widget.RecyclerView android:id="@+id/settings_list" android:layout_width="fill_parent" android:layout_height="0dip" android:layout_weight="1.0" - android:fastScrollEnabled="true"/> - + android:scrollbars="vertical"/> </LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/details_item.xml b/app/src/main/res/layout/details_item.xml new file mode 100644 index 00000000..4ef5fef0 --- /dev/null +++ b/app/src/main/res/layout/details_item.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:padding="8dp"> + + <TextView + android:id="@+id/detail_name" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="?android:textColorPrimary" + android:paddingLeft="14dp" + android:layout_gravity="center_vertical"/> + + <TextView + android:id="@+id/detail_value" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="?android:textColorSecondary" + android:paddingLeft="14dp" + android:layout_gravity="center_vertical"/> + +</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/download_activity.xml b/app/src/main/res/layout/download_activity.xml deleted file mode 100644 index 017e4013..00000000 --- a/app/src/main/res/layout/download_activity.xml +++ /dev/null @@ -1,4 +0,0 @@ -<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/fragment_container" - android:layout_width="match_parent" - android:layout_height="match_parent" />
\ No newline at end of file diff --git a/app/src/main/res/layout/download_media_buttons.xml b/app/src/main/res/layout/download_media_buttons.xml index 1affb164..58fda5c0 100644 --- a/app/src/main/res/layout/download_media_buttons.xml +++ b/app/src/main/res/layout/download_media_buttons.xml @@ -3,11 +3,10 @@ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:background="@android:color/transparent"> + android:layout_height="wrap_content"> <ImageButton - style="@style/PlaybackControl.Small" + style="@style/PlaybackControl" android:id="@+id/download_repeat" android:src="?attr/media_button_repeat_off" android:layout_alignParentLeft="true" @@ -15,7 +14,7 @@ /> <github.daneren2005.dsub.view.AutoRepeatButton - style="@style/PlaybackControl" + style="@style/PlaybackControl.Small" android:id="@+id/download_previous" android:src="?attr/media_button_backward" android:layout_toLeftOf="@+id/download_pause" @@ -23,7 +22,7 @@ /> <ImageButton - style="@style/PlaybackControl" + style="@style/PlaybackControl.Large" android:id="@+id/download_pause" android:src="?attr/media_button_pause" android:layout_centerInParent="true" @@ -31,7 +30,7 @@ /> <ImageButton - style="@style/PlaybackControl" + style="@style/PlaybackControl.Large" android:id="@+id/download_stop" android:src="?attr/media_button_stop" android:layout_centerInParent="true" @@ -39,14 +38,14 @@ /> <ImageButton - style="@style/PlaybackControl" + style="@style/PlaybackControl.Large" android:id="@+id/download_start" android:src="?attr/media_button_start" android:layout_centerInParent="true" /> <github.daneren2005.dsub.view.AutoRepeatButton - style="@style/PlaybackControl" + style="@style/PlaybackControl.Small" android:id="@+id/download_next" android:src="?attr/media_button_forward" android:layout_toRightOf="@+id/download_start" @@ -54,7 +53,7 @@ /> <ImageButton - style="@style/PlaybackControl.Small" + style="@style/PlaybackControl" android:id="@+id/download_toggle_list" android:src="?attr/toggle_list" android:layout_alignParentRight="true" diff --git a/app/src/main/res/layout/download_playlist.xml b/app/src/main/res/layout/download_playlist.xml index 8a73ef3b..7a83330c 100644 --- a/app/src/main/res/layout/download_playlist.xml +++ b/app/src/main/res/layout/download_playlist.xml @@ -1,31 +1,29 @@ <?xml version="1.0" encoding="utf-8"?> - <LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:layout_weight="1"> + xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent" + android:layout_weight="1"> <View - android:layout_width="fill_parent" - android:layout_height="1px" - android:background="@color/dividerColor"/> + android:layout_width="fill_parent" + android:layout_height="1px" + android:background="?attr/colorPrimary"/> <TextView - android:id="@+id/download_empty" - android:text="@string/download.empty" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:padding="10dip"/> + android:id="@+id/download_empty" + android:text="@string/download.empty" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:padding="10dip" + android:textColor="?android:textColorPrimary"/> - <com.mobeta.android.dslv.DragSortListView - style="@style/DragDropListView" + <android.support.v7.widget.RecyclerView android:id="@+id/download_list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:layout_weight="1" - android:cacheColorHint="#00000000" - android:fastScrollEnabled="true"/> + android:scrollbars="vertical"/> </LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/drawer_header.xml b/app/src/main/res/layout/drawer_header.xml new file mode 100644 index 00000000..91fad9fe --- /dev/null +++ b/app/src/main/res/layout/drawer_header.xml @@ -0,0 +1,58 @@ +<?xml version="1.0" encoding="utf-8"?> +<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="178dp" + android:orientation="vertical" + android:weightSum="1" + android:background="@drawable/drawer_header"> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="56dp" + android:orientation="horizontal" + android:layout_alignParentBottom="true" + android:layout_alignParentLeft="true" + android:layout_alignParentStart="true" + android:background="?attr/selectableItemBackground"> + + <LinearLayout + android:orientation="vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content"> + + <TextView + android:id="@+id/header_server_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="16dp" + style="?attr/actionbarTitleStyle"/> + + <TextView + android:id="@+id/header_user_name" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginLeft="16dp" + style="?attr/actionbarSubtitleStyle"/> + </LinearLayout> + + <View + android:layout_width="0dp" + android:layout_height="0dp" + android:layout_weight="1"/> + + <ImageView + android:id="@+id/header_select_image" + android:src="@drawable/main_select_server_dark" + android:layout_gravity="center_vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingRight="20dp"/> + </LinearLayout> + + <de.hdodenhof.circleimageview.CircleImageView + android:id="@+id/header_user_avatar" + android:layout_width="70dp" + android:layout_height="70dp" + android:layout_marginLeft="16dp" + android:layout_marginTop="38dp"/> +</RelativeLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/drawer_list_item.xml b/app/src/main/res/layout/drawer_list_item.xml deleted file mode 100644 index 5f17c9e9..00000000 --- a/app/src/main/res/layout/drawer_list_item.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:paddingTop="8dip" - android:paddingBottom="9dip"> - - <ImageView - android:id="@+id/drawer_icon" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_gravity="left|center_vertical" - android:paddingTop="1dip" - android:paddingBottom="1dip" - android:paddingRight="8dip" - android:paddingLeft="10dip"/> - - <TextView - android:id="@+id/drawer_name" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:textSize="26sp" - android:singleLine="true" - android:textColor="?android:textColorPrimary"/> -</LinearLayout> diff --git a/app/src/main/res/layout/edit_play_action.xml b/app/src/main/res/layout/edit_play_action.xml index a1115da6..95a3d7ff 100644 --- a/app/src/main/res/layout/edit_play_action.xml +++ b/app/src/main/res/layout/edit_play_action.xml @@ -14,7 +14,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/tasker.edit_shuffle_mode" /> + android:text="@string/tasker.edit_shuffle_mode" + android:textColor="?android:textColorPrimary"/> <CheckBox android:id="@+id/edit_shuffle_checkbox" android:layout_width="wrap_content" @@ -33,7 +34,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/tasker.edit_shuffle_start_year" /> + android:text="@string/tasker.edit_shuffle_start_year" + android:textColor="?android:textColorPrimary"/> <CheckBox android:id="@+id/edit_start_year_checkbox" @@ -61,7 +63,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/tasker.edit_shuffle_end_year" /> + android:text="@string/tasker.edit_shuffle_end_year" + android:textColor="?android:textColorPrimary"/> <CheckBox android:id="@+id/edit_end_year_checkbox" @@ -89,7 +92,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/tasker.edit_shuffle_genre"/> + android:text="@string/tasker.edit_shuffle_genre" + android:textColor="?android:textColorPrimary"/> <Button android:id="@+id/edit_genre_spinner" @@ -109,7 +113,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/tasker.edit_server_offline"/> + android:text="@string/tasker.edit_server_offline" + android:textColor="?android:textColorPrimary"/> <Spinner android:id="@+id/edit_offline_spinner" diff --git a/app/src/main/res/layout/equalizer_bar.xml b/app/src/main/res/layout/equalizer_bar.xml index 6dc91565..9e3fab5c 100644 --- a/app/src/main/res/layout/equalizer_bar.xml +++ b/app/src/main/res/layout/equalizer_bar.xml @@ -1,36 +1,33 @@ <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="wrap_content"> + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="wrap_content"> - <TextView - android:id="@+id/equalizer.frequency" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="8dp" - android:layout_alignParentLeft="true" - /> - - <TextView - android:id="@+id/equalizer.level" - android:text="0 dB" - android:textSize="12sp" - android:gravity="right" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:layout_marginTop="8dp" - android:layout_alignParentRight="true" - android:layout_toRightOf="@+id/equalizer.frequency" - /> - - <SeekBar - android:id="@+id/equalizer.bar" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_below="@+id/equalizer.frequency" - /> + <TextView + android:id="@+id/equalizer.frequency" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:layout_alignParentLeft="true" + android:textColor="?android:textColorPrimary"/> + <TextView + android:id="@+id/equalizer.level" + android:text="0 dB" + android:textSize="12sp" + android:gravity="right" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_marginTop="8dp" + android:layout_alignParentRight="true" + android:layout_toRightOf="@+id/equalizer.frequency" + android:textColor="?android:textColorSecondary"/> + <SeekBar + android:id="@+id/equalizer.bar" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:layout_below="@+id/equalizer.frequency"/> </RelativeLayout> diff --git a/app/src/main/res/layout/fast_scroller.xml b/app/src/main/res/layout/fast_scroller.xml new file mode 100644 index 00000000..b2e244e3 --- /dev/null +++ b/app/src/main/res/layout/fast_scroller.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<merge xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:tools="http://schemas.android.com/tools" + android:layout_width="wrap_content" + android:layout_height="match_parent"> + + <TextView + android:id="@+id/fastscroller_bubble" + android:layout_gravity="right|end" + android:gravity="center" + android:textSize="48sp" tools:text="A" + android:layout_width="wrap_content" + android:textColor="#FFffffff" + android:layout_height="wrap_content" + android:background="@drawable/fast_scroller_bubble" + android:visibility="visible"/> + + <ImageView + android:id="@+id/fastscroller_handle" + android:layout_width="wrap_content" + android:layout_marginRight="8dp" + android:layout_marginLeft="8dp" + android:layout_height="wrap_content" + android:src="@drawable/fast_scroller_handle"/> +</merge>
\ No newline at end of file diff --git a/app/src/main/res/layout/genre_list_item.xml b/app/src/main/res/layout/genre_list_item.xml index 6affa24c..fb30e167 100644 --- a/app/src/main/res/layout/genre_list_item.xml +++ b/app/src/main/res/layout/genre_list_item.xml @@ -3,7 +3,7 @@ android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:background="@android:color/transparent"> + android:background="?attr/selectableItemBackground"> <TextView android:id="@+id/genre_name" @@ -17,7 +17,8 @@ android:minHeight="50dip" android:singleLine="true" android:ellipsize="marquee" - android:background="@android:color/transparent"/> + android:background="@android:color/transparent" + android:textColor="?android:textColorPrimary"/> <LinearLayout android:layout_width="wrap_content" @@ -31,12 +32,14 @@ android:id="@+id/genre_songs" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceSmall"/> + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="?android:textColorSecondary"/> <TextView android:id="@+id/genre_albums" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceSmall"/> + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="?android:textColorSecondary"/> </LinearLayout> </LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/grid_view.xml b/app/src/main/res/layout/grid_view.xml deleted file mode 100644 index 599cf92c..00000000 --- a/app/src/main/res/layout/grid_view.xml +++ /dev/null @@ -1,14 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<github.daneren2005.dsub.view.HeaderGridView xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/gridview" - android:layout_width="fill_parent" - android:layout_height="0dip" - android:layout_weight="1.0" - android:numColumns="@integer/Grid.Columns" - android:horizontalSpacing="10dp" - android:verticalSpacing="10dp" - android:gravity="center" - android:stretchMode="columnWidth" - android:padding="24px" - android:fastScrollEnabled="true" - android:scrollbarStyle="outsideOverlay"/>
\ No newline at end of file diff --git a/app/src/main/res/layout/home.xml b/app/src/main/res/layout/home.xml index e5bf5a70..043886a2 100644 --- a/app/src/main/res/layout/home.xml +++ b/app/src/main/res/layout/home.xml @@ -8,7 +8,7 @@ <View android:layout_width="fill_parent" android:layout_height="1px" - android:background="@color/dividerColor"/> + android:background="?attr/colorPrimary"/> <ListView android:id="@+id/main_list" diff --git a/app/src/main/res/layout/jukebox_volume.xml b/app/src/main/res/layout/jukebox_volume.xml deleted file mode 100644 index 0c49f634..00000000 --- a/app/src/main/res/layout/jukebox_volume.xml +++ /dev/null @@ -1,46 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<RelativeLayout - android:background="@drawable/toast_frame" - android:padding="20dip" - android:layout_height="fill_parent" - android:layout_width="fill_parent" - android:orientation="vertical" - android:id="@+id/toast_layout_root" - xmlns:android="http://schemas.android.com/apk/res/android"> - - <TextView - android:layout_height="wrap_content" - android:layout_width="fill_parent" - android:id="@+id/jukebox_volume_title" - android:paddingBottom="12dp" - android:paddingRight="32dp" - android:paddingLeft="32dp" - android:shadowRadius="2.75" - android:shadowColor="#bb000000" - android:textColor="#ffffffff" - android:textAppearance="?android:attr/textAppearanceMedium" - android:text="@string/download.jukebox_volume" - android:gravity="center_horizontal" - android:layout_alignParentTop="true" - android:layout_alignParentRight="true" - android:layout_alignParentLeft="true"/> - - <ImageView - android:layout_height="wrap_content" - android:layout_width="wrap_content" - android:id="@+id/jukebox_volume_image" - android:paddingRight="12dip" - android:layout_alignParentLeft="true" - android:layout_below="@+id/jukebox_volume_title" - android:src="@drawable/ic_action_volume_dark"/> - - <SeekBar - android:layout_height="wrap_content" - android:layout_width="fill_parent" - android:id="@+id/jukebox_volume_progress_bar" - android:paddingBottom="3dp" - android:layout_alignParentRight="true" - android:layout_below="@+id/jukebox_volume_title" - android:layout_toRightOf="@+id/jukebox_volume_image" - android:indeterminate="false"/> -</RelativeLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/lyrics.xml b/app/src/main/res/layout/lyrics.xml index 747727bd..f2aa7c7f 100644 --- a/app/src/main/res/layout/lyrics.xml +++ b/app/src/main/res/layout/lyrics.xml @@ -1,55 +1,54 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="fill_parent"> - - <include layout="@layout/tab_progress"/> - - <ScrollView - android:layout_width="fill_parent" - android:layout_height="0dip" - android:layout_weight="1.0"> - - <LinearLayout - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="fill_parent"> - <TextView - android:id="@+id/lyrics_artist" - android:textAppearance="?android:attr/textAppearanceMedium" - android:gravity="center_horizontal" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:paddingLeft="10dip" - android:paddingRight="10dip" - android:paddingTop="10dip" - android:paddingBottom="4dip" - /> - - <TextView - android:id="@+id/lyrics_title" - android:textAppearance="?android:attr/textAppearanceMedium" - android:gravity="center_horizontal" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:paddingLeft="10dip" - android:paddingRight="10dip" - /> - - <TextView - android:id="@+id/lyrics_text" - android:textAppearance="?android:attr/textAppearanceSmall" - android:gravity="center_horizontal" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:paddingLeft="10dip" - android:paddingRight="10dip" - /> - - </LinearLayout> - - </ScrollView> - + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <include layout="@layout/tab_progress"/> + + <ScrollView + android:layout_width="fill_parent" + android:layout_height="0dip" + android:layout_weight="1.0"> + + <LinearLayout + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> + + <TextView + android:id="@+id/lyrics_artist" + android:textAppearance="?android:attr/textAppearanceMedium" + android:gravity="center_horizontal" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:paddingLeft="10dip" + android:paddingRight="10dip" + android:paddingTop="10dip" + android:paddingBottom="4dip" + android:textColor="?android:textColorPrimary"/> + + <TextView + android:id="@+id/lyrics_title" + android:textAppearance="?android:attr/textAppearanceSmall" + android:gravity="center_horizontal" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:paddingLeft="10dip" + android:paddingRight="10dip" + android:paddingBottom="12dip" + android:textColor="?android:textColorPrimary"/> + + <TextView + android:id="@+id/lyrics_text" + android:textAppearance="?android:attr/textAppearanceSmall" + android:gravity="center_horizontal" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:paddingLeft="10dip" + android:paddingRight="10dip" + android:textColor="?android:textColorSecondary"/> + </LinearLayout> + </ScrollView> </LinearLayout> diff --git a/app/src/main/res/layout/main_buttons.xml b/app/src/main/res/layout/main_buttons.xml deleted file mode 100644 index 95a60409..00000000 --- a/app/src/main/res/layout/main_buttons.xml +++ /dev/null @@ -1,157 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="wrap_content"> - - <LinearLayout - android:id="@+id/main_select_server" - android:orientation="horizontal" - android:paddingTop="2dip" - android:paddingBottom="2dip" - android:paddingLeft="6dp" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:minHeight="?android:attr/listPreferredItemHeight"> - - <ImageView - android:src="?attr/select_server" - android:layout_gravity="center_vertical" - android:layout_width="wrap_content" - android:layout_height="wrap_content"/> - - <LinearLayout - android:orientation="vertical" - android:layout_width="wrap_content" - android:layout_height="wrap_content"> - - <TextView android:id="@+id/main.select_server_1" - android:text="@string/main.select_server" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="10dip" - android:layout_marginTop="6dip" - android:textAppearance="?android:attr/textAppearanceLarge"/> - - <TextView android:id="@+id/main.select_server_2" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:layout_marginLeft="10dip" - android:textAppearance="?android:attr/textAppearanceSmall"/> - - </LinearLayout> - </LinearLayout> - - <TextView - android:id="@+id/main_offline" - android:text="@string/main.offline" - android:drawablePadding="12dip" - android:drawableLeft="?attr/offline_icon" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceMedium" - android:gravity="center_vertical" - android:paddingLeft="6dp" - android:paddingBottom="4dp" - android:minHeight="50dip"/> - - <LinearLayout - android:id="@+id/main_albums" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:orientation="horizontal"> - - <TextView - android:text="@string/main.albums_title" - style="@style/MainAlbumButtonLabel" - android:layout_width="0dp" - android:layout_weight="1" - android:layout_height="fill_parent"/> - - <CheckBox - android:id="@+id/main_albums_per_folder" - android:layout_width="wrap_content" - android:layout_height="wrap_content" - android:text="@string/main.albums_per_folder" - android:layout_marginRight="6dp" - android:layout_gravity="right"/> - </LinearLayout> - - <TextView - android:id="@+id/main_video_section" - android:text="@string/main.videos" - style="@style/MainAlbumButtonLabel" - android:layout_width="0dp" - android:layout_weight="1" - android:layout_height="fill_parent"/> - - <LinearLayout - android:id="@+id/main_albums_newest" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:minHeight="46dip"> - - <TextView - android:layout_width="wrap_content" - android:layout_height="fill_parent" - android:text="@string/main.albums_newest" - style="@style/MainAlbumButton"/> - - <TextView - android:id="@+id/main_albums_recent_count" - android:layout_width="32dp" - android:layout_height="32dp" - android:layout_marginRight="12dp" - android:background="@drawable/ic_number_border" - android:focusable="false" - android:paddingRight="10dp" - android:layout_marginLeft="20px" - android:layout_marginBottom="4px" - android:text="99" - android:textAppearance="?android:attr/textAppearanceSmallPopupMenu" - android:textSize="11sp" - android:gravity="right|center_vertical" - android:layout_gravity="center_vertical" - android:visibility="gone"/> - </LinearLayout> - - <TextView - android:id="@+id/main_albums_recent" - android:text="@string/main.albums_recent" - style="@style/MainAlbumButton"/> - <TextView - android:id="@+id/main_albums_frequent" - android:text="@string/main.albums_frequent" - style="@style/MainAlbumButton"/> - <TextView - android:id="@+id/main_albums_highest" - android:text="@string/main.albums_highest" - style="@style/MainAlbumButton"/> - <TextView - android:id="@+id/main_albums_starred" - android:text="@string/main.albums_starred" - style="@style/MainAlbumButton"/> - <TextView - android:id="@+id/main_albums_genres" - android:text="@string/main.albums_genres" - style="@style/MainAlbumButton"/> - <TextView - android:id="@+id/main_albums_year" - android:text="@string/main.albums_year" - style="@style/MainAlbumButton"/> - <TextView - android:id="@+id/main_albums_random" - android:text="@string/main.albums_random" - style="@style/MainAlbumButton"/> - <TextView - android:id="@+id/main_albums_alphabetical" - android:text="@string/main.albums_alphabetical" - style="@style/MainAlbumButton"/> - - <TextView - android:id="@+id/main_videos" - android:text="@string/main.videos" - style="@style/MainAlbumButton"/> - -</LinearLayout> - diff --git a/app/src/main/res/layout/notification.xml b/app/src/main/res/layout/notification.xml index 12efa4ec..4a89db49 100644 --- a/app/src/main/res/layout/notification.xml +++ b/app/src/main/res/layout/notification.xml @@ -23,7 +23,7 @@ <TextView android:id="@+id/notification_title" - style="@android:style/TextAppearance.StatusBar.EventContent.Title" + style="@style/NotificationText.Title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left" @@ -33,7 +33,7 @@ <TextView android:id="@+id/notification_artist" - style="@android:style/TextAppearance.StatusBar.EventContent" + style="@style/NotificationText.Content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left" @@ -50,34 +50,18 @@ <ImageButton android:id="@+id/control_previous" - android:src="@drawable/notification_previous" - style="@style/BasicButton" - android:layout_width="46dip" - android:layout_height="fill_parent" - android:layout_gravity="center|right" - android:padding="8.0dip" - android:layout_weight="0.0" - android:scaleType="fitCenter"/> + android:src="@drawable/notification_backward" + style="@style/NotificationButton"/> <ImageButton android:id="@+id/control_pause" android:src="@drawable/notification_pause" - style="@style/BasicButton" - android:layout_width="46dip" - android:layout_height="fill_parent" - android:layout_gravity="center|right" - android:padding="8.0dip" - android:layout_weight="0.0" - android:scaleType="fitCenter"/> + style="@style/NotificationButton" + android:layout_width="54dip" + android:padding="0dip"/> <ImageButton android:id="@+id/control_next" - android:src="@drawable/notification_next" - style="@style/BasicButton" - android:layout_width="46dip" - android:layout_height="fill_parent" - android:layout_gravity="center|right" - android:padding="8.0dip" - android:layout_weight="0.0" - android:scaleType="fitCenter"/> + android:src="@drawable/notification_forward" + style="@style/NotificationButton"/> </LinearLayout> diff --git a/app/src/main/res/layout/notification_expanded.xml b/app/src/main/res/layout/notification_expanded.xml index aa9fe759..7b378e12 100644 --- a/app/src/main/res/layout/notification_expanded.xml +++ b/app/src/main/res/layout/notification_expanded.xml @@ -2,7 +2,7 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/statusbar" android:layout_width="fill_parent" - android:layout_height="fill_parent" + android:layout_height="128dp" android:orientation="horizontal" > <ImageView @@ -14,7 +14,7 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" - android:layout_height="wrap_content" + android:layout_height="fill_parent" android:layout_weight="0.0" android:orientation="vertical" android:paddingLeft="11.0dip" > @@ -26,11 +26,11 @@ <TextView android:id="@+id/notification_title" - style="@android:style/TextAppearance.StatusBar.EventContent.Title" + style="@style/NotificationText.Title" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:layout_gravity="left" + android:layout_gravity="left|center_vertical" android:ellipsize="marquee" android:focusable="true" android:singleLine="true" /> @@ -40,15 +40,14 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/notification_close" - style="@style/BasicButton" - android:padding="10dip" + style="@style/NotificationButton" android:layout_gravity="right" - android:visibility="gone"/> + android:visibility="invisible"/> </LinearLayout> <TextView android:id="@+id/notification_artist" - style="@android:style/TextAppearance.StatusBar.EventContent" + style="@style/NotificationText.Content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left" @@ -58,66 +57,43 @@ <TextView android:id="@+id/notification_album" - style="@android:style/TextAppearance.StatusBar.EventContent" + style="@style/NotificationText.Content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="left" android:ellipsize="end" android:scrollHorizontally="true" - android:singleLine="true" /> - - <TextView - android:id="@+id/textView1" - android:layout_width="wrap_content" - android:layout_height="fill_parent" /> + android:singleLine="true" + android:paddingBottom="10dp"/> <ImageView - android:background="?android:dividerHorizontal" + style="@style/NotificationDivider" android:layout_width="fill_parent" - android:layout_height="1.0px"/> + android:layout_height="1dp"/> <LinearLayout - xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" - android:layout_height="wrap_content" + android:layout_height="fill_parent" + android:layout_weight="1" android:orientation="horizontal" android:showDividers="middle" - android:divider="?android:listDivider"> + style="@style/NotificationLayoutDivider"> <ImageButton android:id="@+id/control_previous" - android:layout_width="0dip" - android:layout_height="fill_parent" - android:layout_gravity="center" - android:layout_weight="1" - android:padding="10dip" - style="@style/BasicButton" - android:scaleType="fitCenter" - android:src="@drawable/notification_previous" /> + style="@style/NotificationButton.Expanded" + android:src="@drawable/notification_backward" /> <ImageButton android:id="@+id/control_pause" - android:layout_width="0dip" - android:layout_height="fill_parent" - android:layout_gravity="center" - android:layout_weight="1" - android:padding="10dip" - style="@style/BasicButton" - android:scaleType="fitCenter" + style="@style/NotificationButton.Expanded" android:src="@drawable/notification_pause" /> <ImageButton android:id="@+id/control_next" - android:layout_width="0dip" - android:layout_height="fill_parent" - android:layout_gravity="center" - android:layout_weight="1" - android:padding="10dip" - style="@style/BasicButton" - android:scaleType="fitCenter" - android:src="@drawable/notification_next" /> + style="@style/NotificationButton.Expanded" + android:src="@drawable/notification_forward" /> </LinearLayout> - </LinearLayout> </LinearLayout> diff --git a/app/src/main/res/layout/playlist_cell_item.xml b/app/src/main/res/layout/playlist_cell_item.xml new file mode 100644 index 00000000..7e6ab0cd --- /dev/null +++ b/app/src/main/res/layout/playlist_cell_item.xml @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="vertical" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="?attr/selectableItemBackground"> + + <github.daneren2005.dsub.view.SquareImageView + android:id="@+id/playlist_coverart" + android:layout_width="match_parent" + android:layout_height="match_parent"/> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:paddingTop="4dp" + android:paddingLeft="2dp"> + + <TextView + android:id="@+id/playlist_title" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" + android:textAppearance="?android:attr/textAppearanceMedium" + android:singleLine="true" + android:ellipsize="marquee" + android:textColor="?android:textColorPrimary"/> + + <ImageView + android:id="@+id/more_button" + android:src="?attr/download_none" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="right|center_vertical" + android:paddingRight="2dp" + style="@style/BasicButton"/> + </LinearLayout> +</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/playlist_list_item.xml b/app/src/main/res/layout/playlist_list_item.xml new file mode 100644 index 00000000..c1cc7b3c --- /dev/null +++ b/app/src/main/res/layout/playlist_list_item.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground"> + + <github.daneren2005.dsub.view.RecyclingImageView + android:id="@+id/playlist_coverart" + android:layout_width="@dimen/AlbumArt.Small" + android:layout_height="@dimen/AlbumArt.Small" + android:layout_gravity="left|center_vertical"/> + + <TextView + android:id="@+id/playlist_title" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_gravity="left|center_vertical" + android:paddingLeft="10dip" + android:paddingRight="3dip" + android:textAppearance="?android:attr/textAppearanceMedium" + android:singleLine="true" + android:ellipsize="marquee" + android:textColor="?android:textColorPrimary"/> + + <ImageView + android:id="@+id/more_button" + android:src="?attr/download_none" + android:layout_width="wrap_content" + android:layout_height="fill_parent" + android:layout_gravity="right|center_vertical" + style="@style/MoreButton"/> +</LinearLayout> diff --git a/app/src/main/res/layout/progress.xml b/app/src/main/res/layout/progress.xml index a1904c11..8a299d63 100644 --- a/app/src/main/res/layout/progress.xml +++ b/app/src/main/res/layout/progress.xml @@ -1,20 +1,20 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="horizontal" - android:layout_weight="1" - android:layout_width="0dip" - android:layout_height="fill_parent" - android:padding="10dp"> + android:orientation="horizontal" + android:layout_weight="1" + android:layout_width="0dip" + android:layout_height="fill_parent" + android:padding="10dp"> - <ProgressBar - android:layout_width="wrap_content" - android:layout_height="fill_parent" - android:layout_marginRight="10dp"/> - - <TextView - android:id="@+id/progress_message" - android:text="@string/progress.wait" - android:layout_width="wrap_content" - android:layout_height="fill_parent"/> + <ProgressBar + android:layout_width="wrap_content" + android:layout_height="fill_parent" + android:layout_marginRight="10dp"/> + <TextView + android:id="@+id/progress_message" + android:text="@string/progress.wait" + android:layout_width="wrap_content" + android:layout_height="fill_parent" + android:textColor="?android:textColorPrimary"/> </LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/save_playlist.xml b/app/src/main/res/layout/save_playlist.xml index 8bb21748..9a85d24c 100644 --- a/app/src/main/res/layout/save_playlist.xml +++ b/app/src/main/res/layout/save_playlist.xml @@ -1,17 +1,17 @@ <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/save_playlist_root" - android:padding="10dip" - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="fill_parent"> + android:id="@+id/save_playlist_root" + android:padding="10dip" + android:orientation="vertical" + android:layout_width="fill_parent" + android:layout_height="fill_parent"> - <EditText - android:id="@+id/save_playlist_name" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:inputType="text" - android:singleLine="true"/> + <EditText + android:id="@+id/save_playlist_name" + android:layout_width="fill_parent" + android:layout_height="wrap_content" + android:inputType="text" + android:singleLine="true"/> <CheckBox android:id="@+id/save_playlist_overwrite" @@ -20,7 +20,8 @@ android:text="@string/playlist.overwrite" android:layout_marginLeft="4dp" android:checked="false" - android:visibility="gone"/> + android:visibility="gone" + android:textColor="?android:textColorPrimary"/> </LinearLayout> diff --git a/app/src/main/res/layout/search_buttons.xml b/app/src/main/res/layout/search_buttons.xml deleted file mode 100644 index 699ad341..00000000 --- a/app/src/main/res/layout/search_buttons.xml +++ /dev/null @@ -1,73 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="wrap_content"> - - <TextView - android:id="@+id/search_artists" - android:text="@string/search.artists" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceSmall" - android:textColor="#EFEFEF" - android:textStyle="bold" - android:background="#A5A5A5" - android:gravity="center_vertical" - android:paddingLeft="4dp"/> - - <TextView - android:id="@+id/search_albums" - android:text="@string/search.albums" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceSmall" - android:textColor="#EFEFEF" - android:textStyle="bold" - android:background="#A5A5A5" - android:gravity="center_vertical" - android:paddingLeft="4dp"/> - - <TextView - android:id="@+id/search_songs" - android:text="@string/search.songs" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceSmall" - android:textColor="#EFEFEF" - android:textStyle="bold" - android:background="#A5A5A5" - android:gravity="center_vertical" - android:paddingLeft="4dp"/> - - <TextView - android:id="@+id/search_more_artists" - android:text="@string/search.more" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceSmall" - android:gravity="center" - android:paddingTop="8dp" - android:paddingBottom="8dp"/> - - <TextView - android:id="@+id/search_more_albums" - android:text="@string/search.more" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceSmall" - android:gravity="center" - android:paddingTop="8dp" - android:paddingBottom="8dp"/> - - <TextView - android:id="@+id/search_more_songs" - android:text="@string/search.more" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceSmall" - android:gravity="center" - android:paddingTop="8dp" - android:paddingBottom="8dp"/> - -</LinearLayout> diff --git a/app/src/main/res/layout/seekbar_preference.xml b/app/src/main/res/layout/seekbar_preference.xml index 030b608b..74dad4cd 100644 --- a/app/src/main/res/layout/seekbar_preference.xml +++ b/app/src/main/res/layout/seekbar_preference.xml @@ -9,7 +9,8 @@ android:padding="5dip" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:gravity="right" /> + android:gravity="right" + android:textColor="?android:textColorPrimary"/> <SeekBar android:id="@+id/seek_bar" android:padding="15dip" diff --git a/app/src/main/res/layout/select_album.xml b/app/src/main/res/layout/select_album.xml deleted file mode 100644 index bbdf0e54..00000000 --- a/app/src/main/res/layout/select_album.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/refresh_layout" - android:layout_width="fill_parent" - android:layout_height="fill_parent"> - - <LinearLayout - android:id="@+id/select_album_layout" - android:orientation="vertical" - android:layout_width="fill_parent" - android:layout_height="fill_parent"> - - <View - android:layout_width="fill_parent" - android:layout_height="1px" - android:background="@color/dividerColor"/> - - <include layout="@layout/tab_progress"/> - - <ListView - android:id="@+id/select_album_entries" - android:textFilterEnabled="true" - android:layout_width="fill_parent" - android:layout_height="0dip" - android:layout_weight="1.0" - android:fastScrollEnabled="true"/> - </LinearLayout> -</android.support.v4.widget.SwipeRefreshLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/select_album_header.xml b/app/src/main/res/layout/select_album_header.xml index d028a476..5b2294f0 100644 --- a/app/src/main/res/layout/select_album_header.xml +++ b/app/src/main/res/layout/select_album_header.xml @@ -30,7 +30,8 @@ android:marqueeRepeatLimit="marquee_forever" android:scrollHorizontally="true" android:focusable="true" - android:focusableInTouchMode="true"> + android:focusableInTouchMode="true" + android:textColor="?android:textColorPrimary"> <requestFocus android:focusable="true" android:focusableInTouchMode="true" @@ -44,7 +45,8 @@ android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceMedium" android:singleLine="true" - android:ellipsize="end"/> + android:ellipsize="end" + android:textColor="?android:textColorPrimary"/> <TextView android:text="XX SONGS" @@ -54,7 +56,8 @@ android:paddingTop="14dip" android:textAppearance="?android:attr/textAppearanceSmall" android:singleLine="true" - android:ellipsize="none"/> + android:ellipsize="none" + android:textColor="?android:textColorSecondary"/> <TextView android:text="0:00" @@ -63,7 +66,8 @@ android:layout_height="wrap_content" android:textAppearance="?android:attr/textAppearanceSmall" android:singleLine="true" - android:ellipsize="none"/> + android:ellipsize="none" + android:textColor="?android:textColorSecondary"/> </LinearLayout> @@ -145,9 +149,16 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" - android:textAppearance="?android:attr/textAppearanceMedium"/> + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="?android:textColorPrimary"/> </LinearLayout> </FrameLayout> + + <View + android:layout_width="fill_parent" + android:layout_height="1px" + android:background="?attr/colorPrimary" + android:layout_gravity="bottom"/> </FrameLayout> diff --git a/app/src/main/res/layout/select_artist_header.xml b/app/src/main/res/layout/select_artist_header.xml index 2821ce43..9ec94ff1 100644 --- a/app/src/main/res/layout/select_artist_header.xml +++ b/app/src/main/res/layout/select_artist_header.xml @@ -2,7 +2,9 @@ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" - android:layout_height="wrap_content"> + android:layout_height="wrap_content" + android:background="?attr/selectableItemBackground"> + <LinearLayout android:id="@+id/select_artist_folder" android:orientation="horizontal" @@ -30,14 +32,21 @@ android:layout_height="wrap_content" android:layout_marginLeft="10dip" android:layout_marginTop="6dip" - android:textAppearance="?android:attr/textAppearanceLarge"/> + android:textAppearance="?android:attr/textAppearanceLarge" + android:textColor="?attr/colorAccent"/> <TextView android:id="@+id/select_artist_folder_2" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginLeft="10dip" - android:textAppearance="?android:attr/textAppearanceSmall"/> + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="?android:textColorSecondary"/> </LinearLayout> </LinearLayout> + + <View + android:layout_width="fill_parent" + android:layout_height="1px" + android:background="?attr/colorPrimary"/> </LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/settings_activity.xml b/app/src/main/res/layout/settings_activity.xml new file mode 100644 index 00000000..c77528b2 --- /dev/null +++ b/app/src/main/res/layout/settings_activity.xml @@ -0,0 +1,21 @@ +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="vertical"> + + <android.support.v7.widget.Toolbar + android:id="@+id/main_toolbar" + android:layout_height="?attr/actionBarSize" + android:layout_width="match_parent" + android:background="?attr/colorPrimary" + android:elevation="4dp" + app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" + app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> + + <FrameLayout + android:id="@+id/fragment_container" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_weight="1"/> +</LinearLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/shuffle_dialog.xml b/app/src/main/res/layout/shuffle_dialog.xml index 295f57cb..63778ed7 100644 --- a/app/src/main/res/layout/shuffle_dialog.xml +++ b/app/src/main/res/layout/shuffle_dialog.xml @@ -14,7 +14,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/shuffle.startYear" /> + android:text="@string/shuffle.startYear" + android:textColor="?android:textColorPrimary"/> <EditText android:id="@+id/start_year" android:inputType="number" @@ -36,7 +37,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/shuffle.endYear" /> + android:text="@string/shuffle.endYear" + android:textColor="?android:textColorPrimary"/> <EditText android:id="@+id/end_year" android:inputType="number" @@ -66,7 +68,8 @@ android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginLeft="4dp" - android:hint="@string/shuffle.genre"/> + android:hint="@string/shuffle.genre" + android:textColor="?android:textColorPrimary"/> <Button android:id="@+id/genre_combo" diff --git a/app/src/main/res/layout/song_list_item.xml b/app/src/main/res/layout/song_list_item.xml index 86f77869..429dc142 100644 --- a/app/src/main/res/layout/song_list_item.xml +++ b/app/src/main/res/layout/song_list_item.xml @@ -3,15 +3,8 @@ android:id="@id/drag_handle" android:orientation="horizontal" android:layout_width="fill_parent" - android:layout_height="?android:attr/listPreferredItemHeight"> - - <CheckedTextView - android:id="@+id/song_check" - android:layout_width="wrap_content" - android:layout_height="fill_parent" - android:gravity="center_vertical" - android:checkMark="?android:attr/listChoiceIndicatorMultiple" - android:paddingLeft="3dip"/> + android:layout_height="?android:attr/listPreferredItemHeight" + android:background="?attr/selectableItemBackground"> <LinearLayout android:orientation="vertical" android:layout_width="0dip" @@ -25,24 +18,24 @@ android:layout_gravity="center_vertical"> <TextView - android:id="@+id/song_title" - android:layout_width="0dip" - android:layout_height="wrap_content" - android:layout_weight="1" - android:layout_gravity="left|center_vertical" - android:textAppearance="?android:attr/textAppearanceMedium" - android:singleLine="true" - android:ellipsize="marquee" - android:drawablePadding="6dip" - android:paddingLeft="6dip" - android:paddingRight="6dip"/> + android:id="@+id/song_title" + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_weight="1" + android:layout_gravity="left|center_vertical" + android:textAppearance="?android:attr/textAppearanceMedium" + android:singleLine="true" + android:ellipsize="marquee" + android:drawablePadding="6dip" + android:paddingLeft="6dip" + android:paddingRight="6dip" + android:textColor="?android:textColorPrimary"/> <ImageButton android:id="@+id/song_bookmark" android:layout_width="24dp" android:layout_height="24dp" android:layout_gravity="right|center_vertical" - android:src="@drawable/ic_menu_bookmark_selected" android:background="@null" android:focusable="false" android:scaleType="fitCenter" @@ -50,10 +43,10 @@ <ImageButton android:id="@+id/song_star" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_width="@dimen/Star.Small" + android:layout_height="@dimen/Star.Small" + android:scaleType="fitCenter" android:layout_gravity="right|center_vertical" - android:src="@drawable/ic_stat_star" android:background="@null" android:focusable="false" android:visibility="gone"/> @@ -91,7 +84,8 @@ android:textAppearance="?android:attr/textAppearanceSmall" android:singleLine="true" android:ellipsize="middle" - android:paddingLeft="6dip"/> + android:paddingLeft="6dip" + android:textColor="?android:textColorSecondary"/> <RatingBar android:id="@+id/song_rating" @@ -111,13 +105,14 @@ android:textAppearance="?android:attr/textAppearanceSmall" android:singleLine="true" android:paddingLeft="3dip" - android:paddingRight="4dip"/> + android:paddingRight="4dip" + android:textColor="?android:textColorSecondary"/> </LinearLayout> </LinearLayout> <ImageView - android:id="@+id/artist_more" + android:id="@+id/more_button" android:src="?attr/download_none" android:layout_width="wrap_content" android:layout_height="fill_parent" diff --git a/app/src/main/res/layout/start_timer.xml b/app/src/main/res/layout/start_timer.xml index 9736a31d..59bd60e3 100644 --- a/app/src/main/res/layout/start_timer.xml +++ b/app/src/main/res/layout/start_timer.xml @@ -11,7 +11,8 @@ android:layout_marginLeft="8dp" android:textSize="20dp" android:paddingRight="10px" - android:layout_gravity="center"/> + android:layout_gravity="center" + android:textColor="?android:textColorPrimary"/> <SeekBar android:id="@+id/timer_length_bar" diff --git a/app/src/main/res/layout/sync_dialog.xml b/app/src/main/res/layout/sync_dialog.xml index 5133b753..fc657186 100644 --- a/app/src/main/res/layout/sync_dialog.xml +++ b/app/src/main/res/layout/sync_dialog.xml @@ -8,5 +8,6 @@ android:layout_height="wrap_content" android:layout_margin="5dp" android:checked="false" - android:text="@string/offline.sync_dialog_default"/> + android:text="@string/offline.sync_dialog_default" + android:textColor="?android:textColorPrimary"/> </FrameLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/tab_progress.xml b/app/src/main/res/layout/tab_progress.xml index f6d326ca..7423777f 100644 --- a/app/src/main/res/layout/tab_progress.xml +++ b/app/src/main/res/layout/tab_progress.xml @@ -26,6 +26,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" - android:textAppearance="?android:attr/textAppearanceMedium"/> + android:textAppearance="?android:attr/textAppearanceMedium" + android:textColor="?android:textColorPrimary"/> </LinearLayout> </FrameLayout>
\ No newline at end of file diff --git a/app/src/main/res/layout/unscrollable_grid_view.xml b/app/src/main/res/layout/unscrollable_grid_view.xml deleted file mode 100644 index 96bea5ce..00000000 --- a/app/src/main/res/layout/unscrollable_grid_view.xml +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<github.daneren2005.dsub.view.UnscrollableGridView xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/gridview" - android:layout_width="fill_parent" - android:layout_height="wrap_content" - android:numColumns="@integer/Grid.Columns" - android:horizontalSpacing="10dp" - android:verticalSpacing="10dp" - android:gravity="center" - android:padding="20px" - android:stretchMode="columnWidth"/>
\ No newline at end of file diff --git a/app/src/main/res/layout/update_playlist.xml b/app/src/main/res/layout/update_playlist.xml index 7354ef5c..cc7e5ee6 100644 --- a/app/src/main/res/layout/update_playlist.xml +++ b/app/src/main/res/layout/update_playlist.xml @@ -22,7 +22,8 @@ android:layout_height="wrap_content" android:layout_weight="1" android:layout_marginLeft="4dp" - android:hint="@string/common.name" /> + android:hint="@string/common.name" + android:textColor="?android:textColorPrimary"/> </LinearLayout> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" @@ -36,7 +37,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/common.comment" /> + android:text="@string/common.comment" + android:textColor="?android:textColorPrimary"/> <EditText android:id="@+id/get_playlist_comment" android:inputType="text" @@ -58,7 +60,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/common.public" /> + android:text="@string/common.public" + android:textColor="?android:textColorPrimary"/> <CheckBox android:id="@+id/get_playlist_public" android:layout_width="fill_parent" diff --git a/app/src/main/res/layout/update_share.xml b/app/src/main/res/layout/update_share.xml index 92b7137b..ef44e304 100644 --- a/app/src/main/res/layout/update_share.xml +++ b/app/src/main/res/layout/update_share.xml @@ -14,7 +14,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/common.name" /> + android:text="@string/common.name" + android:textColor="?android:textColorPrimary"/> <EditText android:id="@+id/get_share_name" android:inputType="text" @@ -36,7 +37,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/share.expiration" /> + android:text="@string/share.expiration" + android:textColor="?android:textColorPrimary"/> <DatePicker android:id="@+id/get_share_expire" android:layout_width="fill_parent" @@ -57,7 +59,8 @@ android:layout_height="wrap_content" android:layout_marginLeft="4dp" android:textSize="20dp" - android:text="@string/share.no_expiration" /> + android:text="@string/share.no_expiration" + android:textColor="?android:textColorPrimary"/> <CheckBox android:id="@+id/get_share_no_expire" android:layout_width="fill_parent" diff --git a/app/src/main/res/layout/user_header.xml b/app/src/main/res/layout/user_header.xml index 0b303afe..c8186372 100644 --- a/app/src/main/res/layout/user_header.xml +++ b/app/src/main/res/layout/user_header.xml @@ -34,7 +34,8 @@ android:marqueeRepeatLimit="marquee_forever" android:scrollHorizontally="true" android:focusable="true" - android:focusableInTouchMode="true"> + android:focusableInTouchMode="true" + android:textColor="?android:textColorPrimary"> <requestFocus android:focusable="true" android:focusableInTouchMode="true" @@ -49,9 +50,16 @@ android:textAppearance="?android:attr/textAppearanceMedium" android:singleLine="true" android:ellipsize="end" - android:autoLink="email"/> + android:autoLink="email" + android:textColor="?android:textColorSecondary"/> </LinearLayout> + + <View + android:layout_width="fill_parent" + android:layout_height="1px" + android:background="?attr/colorPrimary" + android:layout_alignParentBottom="true"/> </RelativeLayout> diff --git a/app/src/main/res/layout/user_list_item.xml b/app/src/main/res/layout/user_list_item.xml index dc2bdab9..c2e708c8 100644 --- a/app/src/main/res/layout/user_list_item.xml +++ b/app/src/main/res/layout/user_list_item.xml @@ -3,7 +3,7 @@ android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:background="@android:color/transparent"> + android:background="?attr/selectableItemBackground"> <github.daneren2005.dsub.view.RecyclingImageView android:id="@+id/item_avatar" @@ -22,14 +22,15 @@ android:paddingLeft="12dip" android:paddingRight="6dip" android:minHeight="50dip" - android:background="@android:color/transparent"/> + android:background="@android:color/transparent" + android:textColor="?android:textColorPrimary"/> <ImageButton android:id="@+id/item_star" - android:layout_width="wrap_content" - android:layout_height="wrap_content" + android:layout_width="@dimen/Star.Small" + android:layout_height="@dimen/Star.Small" + android:scaleType="fitCenter" android:layout_gravity="right|center_vertical" - android:src="@drawable/ic_stat_star" android:background="@android:color/transparent" android:focusable="false" android:visibility="gone"/> diff --git a/app/src/main/res/menu/abstract_top_menu.xml b/app/src/main/res/menu/abstract_top_menu.xml index 22499ae9..7c8d414d 100644 --- a/app/src/main/res/menu/abstract_top_menu.xml +++ b/app/src/main/res/menu/abstract_top_menu.xml @@ -2,7 +2,7 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:compat="http://schemas.android.com/apk/res-auto"> <item - android:id="@+id/menu_search" + android:id="@+id/menu_global_search" android:icon="?attr/search" android:title="@string/menu.search" compat:showAsAction="always|withText"/> diff --git a/app/src/main/res/menu/drawer_navigation.xml b/app/src/main/res/menu/drawer_navigation.xml new file mode 100644 index 00000000..bd309455 --- /dev/null +++ b/app/src/main/res/menu/drawer_navigation.xml @@ -0,0 +1,54 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <group android:checkableBehavior="single"> + <item + android:id="@+id/drawer_home" + android:icon="?attr/drawerHome" + android:title="@string/button_bar.home"/> + <item + android:id="@+id/drawer_library" + android:icon="?attr/drawerLibrary" + android:title="@string/button_bar.browse"/> + <item + android:id="@+id/drawer_playlists" + android:icon="?attr/drawerPlaylists" + android:title="@string/button_bar.playlists"/> + <item + android:id="@+id/drawer_podcasts" + android:icon="?attr/drawerPodcasts" + android:title="@string/button_bar.podcasts"/> + <item + android:id="@+id/drawer_bookmarks" + android:icon="?attr/drawerBookmarks" + android:title="@string/button_bar.bookmarks"/> + <item + android:id="@+id/drawer_shares" + android:icon="?attr/drawerShares" + android:title="@string/button_bar.shares"/> + <item + android:id="@+id/drawer_chat" + android:icon="?attr/drawerChat" + android:title="@string/button_bar.chat"/> + <item + android:id="@+id/drawer_admin" + android:icon="?attr/drawerAdmin" + android:title="@string/button_bar.admin"/> + <item + android:id="@+id/drawer_downloading" + android:icon="?attr/drawerDownloading" + android:title="@string/button_bar.downloading" + android:visible="false"/> + </group> + + <group + android:id="@+id/drawer_bottom" + android:checkableBehavior="single"> + + <item android:id="@+id/drawer_offline" + android:title="@string/button_bar.offline"/> + + <item + android:id="@+id/drawer_settings" + android:title="@string/menu.settings"/> + </group> +</menu>
\ No newline at end of file diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml index 549c5fb6..0970c8ce 100644 --- a/app/src/main/res/menu/main.xml +++ b/app/src/main/res/menu/main.xml @@ -2,13 +2,13 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:compat="http://schemas.android.com/apk/res-auto"> <item - android:id="@+id/menu_search" + android:id="@+id/menu_global_search" android:icon="?attr/search" android:title="@string/menu.search" compat:showAsAction="always|withText"/> <item - android:id="@+id/menu_shuffle" + android:id="@+id/menu_global_shuffle" android:icon="?attr/shuffle" android:title="@string/menu.shuffle" compat:showAsAction="always|withText"/> diff --git a/app/src/main/res/menu/multiselect_media.xml b/app/src/main/res/menu/multiselect_media.xml new file mode 100644 index 00000000..75865a14 --- /dev/null +++ b/app/src/main/res/menu/multiselect_media.xml @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:compat="http://schemas.android.com/apk/res-auto"> + <item + android:id="@+id/menu_play_now" + android:icon="?attr/actionbar_start" + android:title="@string/menu.play" + compat:showAsAction="always|withText"/> + + <item + android:id="@+id/menu_shuffle" + android:icon="?attr/shuffle" + android:title="@string/menu.shuffle" + compat:showAsAction="ifRoom|withText"/> + + <item + android:id="@+id/menu_download" + android:title="@string/common.download"/> + + <item + android:id="@+id/menu_cache" + android:title="@string/common.pin"/> + + <item + android:id="@+id/menu_delete" + android:title="@string/menu.delete_cache"/> + + <item + android:id="@+id/menu_add_playlist" + android:title="@string/menu.add_playlist"/> + + <item + android:id="@+id/menu_remove_playlist" + android:title="@string/menu.remove_playlist"/> + + <group android:id="@+id/hide_play_next"> + <item + android:id="@+id/menu_play_next" + android:title="@string/common.play_next"/> + </group> + + <group android:id="@+id/hide_play_last"> + <item + android:id="@+id/menu_play_last" + android:title="@string/menu.play_last"/> + </group> +</menu> diff --git a/app/src/main/res/menu/multiselect_media_offline.xml b/app/src/main/res/menu/multiselect_media_offline.xml new file mode 100644 index 00000000..5587c106 --- /dev/null +++ b/app/src/main/res/menu/multiselect_media_offline.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:compat="http://schemas.android.com/apk/res-auto"> + <item + android:id="@+id/menu_play_now" + android:icon="?attr/actionbar_start" + android:title="@string/menu.play" + compat:showAsAction="always|withText"/> + + <item + android:id="@+id/menu_shuffle" + android:icon="?attr/shuffle" + android:title="@string/menu.shuffle" + compat:showAsAction="ifRoom|withText"/> + + <item + android:id="@+id/menu_delete" + android:title="@string/menu.delete_cache"/> + + <group android:id="@+id/hide_play_next"> + <item + android:id="@+id/menu_play_next" + android:title="@string/common.play_next"/> + </group> + + <group android:id="@+id/hide_play_last"> + <item + android:id="@+id/menu_play_last" + android:title="@string/menu.play_last"/> + </group> +</menu> diff --git a/app/src/main/res/menu/nowplaying_context.xml b/app/src/main/res/menu/nowplaying_context.xml index c9347353..845a98c8 100644 --- a/app/src/main/res/menu/nowplaying_context.xml +++ b/app/src/main/res/menu/nowplaying_context.xml @@ -19,10 +19,6 @@ android:title="@string/download.menu_lyrics"/> <item - android:id="@+id/menu_remove" - android:title="@string/download.menu_remove"/> - - <item android:id="@+id/menu_delete" android:title="@string/menu.delete_cache"/> diff --git a/app/src/main/res/menu/nowplaying_context_offline.xml b/app/src/main/res/menu/nowplaying_context_offline.xml index 24b23a8d..9ce63d79 100644 --- a/app/src/main/res/menu/nowplaying_context_offline.xml +++ b/app/src/main/res/menu/nowplaying_context_offline.xml @@ -15,10 +15,6 @@ android:title="@string/download.menu_show_album"/> <item - android:id="@+id/menu_remove" - android:title="@string/download.menu_remove"/> - - <item android:id="@+id/menu_delete" android:title="@string/menu.delete_cache"/> diff --git a/app/src/main/res/menu/search.xml b/app/src/main/res/menu/search.xml index cab9c4f6..e9377d68 100644 --- a/app/src/main/res/menu/search.xml +++ b/app/src/main/res/menu/search.xml @@ -2,7 +2,7 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:compat="http://schemas.android.com/apk/res-auto"> <item - android:id="@+id/menu_search" + android:id="@+id/menu_global_search" android:icon="?attr/search" android:title="@string/menu.search" compat:showAsAction="ifRoom|withText"/> diff --git a/app/src/main/res/menu/select_album.xml b/app/src/main/res/menu/select_album.xml index 3d2228e8..c94a4a3f 100644 --- a/app/src/main/res/menu/select_album.xml +++ b/app/src/main/res/menu/select_album.xml @@ -3,7 +3,7 @@ xmlns:compat="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/menu_play_now" - android:icon="?media_button_start" + android:icon="?actionbar_start" android:title="@string/menu.play" compat:showAsAction="always|withText"/> diff --git a/app/src/main/res/menu/select_album_context.xml b/app/src/main/res/menu/select_album_context.xml index 5b2529e7..388fd1f5 100644 --- a/app/src/main/res/menu/select_album_context.xml +++ b/app/src/main/res/menu/select_album_context.xml @@ -1,48 +1,10 @@ <?xml version="1.0" encoding="utf-8"?> -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:compat="http://schemas.android.com/apk/res-auto"> - +<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/album_menu_info" android:title="@string/common.info"/> - <item - android:id="@+id/album_menu_play_now" - android:title="@string/common.play_now" - /> - - <item - android:id="@+id/album_menu_play_shuffled" - android:title="@string/common.play_shuffled" - /> - - <group android:id="@+id/hide_play_next"> - <item - android:id="@+id/album_menu_play_next" - android:title="@string/common.play_next"/> - </group> - - <group android:id="@+id/hide_play_last"> - <item - android:id="@+id/album_menu_play_last" - android:title="@string/common.play_last"/> - </group> - - <item - android:id="@+id/album_menu_download" - android:title="@string/common.download" - /> - - <item - android:id="@+id/album_menu_pin" - android:title="@string/common.pin" - /> - - <item - android:id="@+id/album_menu_delete" - android:title="@string/menu.delete_cache"/> - <item android:id="@+id/album_menu_show_artist" android:title="@string/menu.show_artist"/> diff --git a/app/src/main/res/menu/select_album_context_offline.xml b/app/src/main/res/menu/select_album_context_offline.xml index a1805f5b..60858d91 100644 --- a/app/src/main/res/menu/select_album_context_offline.xml +++ b/app/src/main/res/menu/select_album_context_offline.xml @@ -1,31 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:compat="http://schemas.android.com/apk/res-auto"> - <item - android:id="@+id/album_menu_play_now" - android:title="@string/common.play_now" - /> - - <item - android:id="@+id/album_menu_play_shuffled" - android:title="@string/common.play_shuffled" - /> - - <group android:id="@+id/hide_play_next"> - <item - android:id="@+id/album_menu_play_next" - android:title="@string/common.play_next"/> - </group> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> - <group android:id="@+id/hide_play_last"> - <item - android:id="@+id/album_menu_play_last" - android:title="@string/common.play_last"/> - </group> - - <item - android:id="@+id/album_menu_delete" - android:title="@string/menu.delete_cache"/> + <item + android:id="@+id/album_menu_info" + android:title="@string/common.info"/> <item android:id="@+id/album_menu_star" diff --git a/app/src/main/res/menu/select_album_list.xml b/app/src/main/res/menu/select_album_list.xml index a9196d1c..17148a51 100644 --- a/app/src/main/res/menu/select_album_list.xml +++ b/app/src/main/res/menu/select_album_list.xml @@ -3,7 +3,7 @@ xmlns:compat="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/menu_play_now" - android:icon="?media_button_start" + android:icon="?actionbar_start" android:title="@string/menu.play" compat:showAsAction="always|withText"/> diff --git a/app/src/main/res/menu/select_artist.xml b/app/src/main/res/menu/select_artist.xml index 603f0a3b..66ba37ba 100644 --- a/app/src/main/res/menu/select_artist.xml +++ b/app/src/main/res/menu/select_artist.xml @@ -2,13 +2,13 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:compat="http://schemas.android.com/apk/res-auto"> <item - android:id="@+id/menu_shuffle" + android:id="@+id/menu_global_shuffle" android:icon="?attr/shuffle" android:title="@string/menu.shuffle" compat:showAsAction="always|withText"/> <item - android:id="@+id/menu_search" + android:id="@+id/menu_global_search" android:icon="?attr/search" android:title="@string/menu.search" compat:showAsAction="ifRoom|withText"/> diff --git a/app/src/main/res/menu/select_artist_context.xml b/app/src/main/res/menu/select_artist_context.xml index debc07c6..40f912db 100644 --- a/app/src/main/res/menu/select_artist_context.xml +++ b/app/src/main/res/menu/select_artist_context.xml @@ -1,44 +1,20 @@ <?xml version="1.0" encoding="utf-8"?> -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:compat="http://schemas.android.com/apk/res-auto"> - - <item - android:id="@+id/artist_menu_play_now" - android:title="@string/common.play_now" - /> - - <item - android:id="@+id/artist_menu_play_shuffled" - android:title="@string/common.play_shuffled" - /> - - <group android:id="@+id/hide_play_next"> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <group android:id="@+id/server_1_10"> <item - android:id="@+id/artist_menu_play_next" - android:title="@string/common.play_next"/> - </group> + android:id="@+id/artist_menu_play_now" + android:title="@string/common.play_now"/> - <group android:id="@+id/hide_play_last"> <item - android:id="@+id/artist_menu_play_last" - android:title="@string/common.play_last"/> - </group> - - <item - android:id="@+id/artist_menu_download" - android:title="@string/common.download" - /> + android:id="@+id/artist_menu_play_shuffled" + android:title="@string/common.play_shuffled"/> - <item - android:id="@+id/artist_menu_pin" - android:title="@string/common.pin" - /> - - <item - android:id="@+id/artist_menu_delete" - android:title="@string/menu.delete_cache"/> + <group android:id="@+id/hide_play_last"> + <item + android:id="@+id/artist_menu_play_last" + android:title="@string/common.play_last"/> + </group> - <group android:id="@+id/server_1_10"> <group android:id="@+id/hide_star"> <item android:id="@+id/artist_menu_star" diff --git a/app/src/main/res/menu/select_artist_context_offline.xml b/app/src/main/res/menu/select_artist_context_offline.xml index 17ee97e0..2dc78ab8 100644 --- a/app/src/main/res/menu/select_artist_context_offline.xml +++ b/app/src/main/res/menu/select_artist_context_offline.xml @@ -1,30 +1,16 @@ <?xml version="1.0" encoding="utf-8"?> -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:compat="http://schemas.android.com/apk/res-auto"> +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:id="@+id/artist_menu_play_now" + android:title="@string/common.play_now"/> - <item - android:id="@+id/artist_menu_play_now" - android:title="@string/common.play_now" - /> - - <item - android:id="@+id/artist_menu_play_shuffled" - android:title="@string/common.play_shuffled" - /> - - <group android:id="@+id/hide_play_next"> - <item - android:id="@+id/artist_menu_play_next" - android:title="@string/common.play_next"/> - </group> + <item + android:id="@+id/artist_menu_play_shuffled" + android:title="@string/common.play_shuffled"/> <group android:id="@+id/hide_play_last"> <item android:id="@+id/artist_menu_play_last" android:title="@string/common.play_last"/> </group> - - <item - android:id="@+id/artist_menu_delete" - android:title="@string/menu.delete_cache"/> -</menu> +</menu>
\ No newline at end of file diff --git a/app/src/main/res/menu/select_bookmark_context.xml b/app/src/main/res/menu/select_bookmark_context.xml index 2b1b83fd..aaa3e3e8 100644 --- a/app/src/main/res/menu/select_bookmark_context.xml +++ b/app/src/main/res/menu/select_bookmark_context.xml @@ -6,6 +6,12 @@ android:id="@+id/bookmark_menu_info" android:title="@string/common.info"/> + <group android:id="@+id/hide_play_last"> + <item + android:id="@+id/song_menu_play_last" + android:title="@string/common.play_last"/> + </group> + <item android:id="@+id/song_menu_show_album" android:title="@string/download.menu_show_album"/> @@ -15,18 +21,6 @@ android:title="@string/menu.show_artist"/> <item - android:id="@+id/song_menu_download" - android:title="@string/common.download"/> - - <item - android:id="@+id/song_menu_pin" - android:title="@string/common.pin"/> - - <item - android:id="@+id/song_menu_delete" - android:title="@string/menu.delete_cache"/> - - <item android:id="@+id/bookmark_menu_delete" android:title="@string/bookmark.delete"/> </menu> diff --git a/app/src/main/res/menu/select_playlist_context.xml b/app/src/main/res/menu/select_playlist_context.xml index 47033d9c..4941e94b 100644 --- a/app/src/main/res/menu/select_playlist_context.xml +++ b/app/src/main/res/menu/select_playlist_context.xml @@ -7,21 +7,6 @@ android:title="@string/common.info" /> - <item - android:id="@+id/playlist_menu_play_now" - android:title="@string/common.play_now" - /> - - <item - android:id="@+id/playlist_menu_play_shuffled" - android:title="@string/common.play_shuffled" - /> - - <item - android:id="@+id/playlist_menu_download" - android:title="@string/common.download" - /> - <item android:id="@+id/playlist_menu_sync" android:title="@string/menu.keep_synced"/> diff --git a/app/src/main/res/menu/select_playlist_context_offline.xml b/app/src/main/res/menu/select_playlist_context_offline.xml index d63aec17..6745d850 100644 --- a/app/src/main/res/menu/select_playlist_context_offline.xml +++ b/app/src/main/res/menu/select_playlist_context_offline.xml @@ -1,13 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> -<menu xmlns:android="http://schemas.android.com/apk/res/android" - xmlns:compat="http://schemas.android.com/apk/res-auto"> - <item - android:id="@+id/playlist_menu_play_now" - android:title="@string/common.play_now" +<menu xmlns:android="http://schemas.android.com/apk/res/android"> + <item + android:id="@+id/playlist_info" + android:title="@string/common.info" /> - - <item - android:id="@+id/playlist_menu_play_shuffled" - android:title="@string/common.play_shuffled" - /> </menu>
\ No newline at end of file diff --git a/app/src/main/res/menu/select_podcast_episode_context.xml b/app/src/main/res/menu/select_podcast_episode_context.xml index bacccda3..d535cc7e 100644 --- a/app/src/main/res/menu/select_podcast_episode_context.xml +++ b/app/src/main/res/menu/select_podcast_episode_context.xml @@ -7,32 +7,12 @@ android:title="@string/common.info" /> - <item - android:id="@+id/song_menu_play_now" - android:title="@string/common.play_now" - /> - - <group android:id="@+id/hide_play_next"> - <item - android:id="@+id/song_menu_play_next" - android:title="@string/common.play_next"/> - </group> - <group android:id="@+id/hide_play_last"> <item android:id="@+id/song_menu_play_last" android:title="@string/common.play_last"/> </group> - - <item - android:id="@+id/song_menu_download" - android:title="@string/common.download" - /> - - <item - android:id="@+id/song_menu_delete" - android:title="@string/menu.delete_cache"/> - + <group android:id="@+id/server_1.9"> <item android:id="@+id/bookmark_menu_delete" diff --git a/app/src/main/res/menu/select_podcast_episode_context_offline.xml b/app/src/main/res/menu/select_podcast_episode_context_offline.xml index 587d01f7..a34d7f08 100644 --- a/app/src/main/res/menu/select_podcast_episode_context_offline.xml +++ b/app/src/main/res/menu/select_podcast_episode_context_offline.xml @@ -6,25 +6,10 @@ android:id="@+id/song_menu_info" android:title="@string/common.info" /> - - <item - android:id="@+id/song_menu_play_now" - android:title="@string/common.play_now" - /> - - <group android:id="@+id/hide_play_next"> - <item - android:id="@+id/song_menu_play_next" - android:title="@string/common.play_next"/> - </group> <group android:id="@+id/hide_play_last"> <item android:id="@+id/song_menu_play_last" android:title="@string/common.play_last"/> </group> - - <item - android:id="@+id/song_menu_delete" - android:title="@string/menu.delete_cache"/> </menu> diff --git a/app/src/main/res/menu/select_podcasts.xml b/app/src/main/res/menu/select_podcasts.xml index f30429ce..41ad62fa 100644 --- a/app/src/main/res/menu/select_podcasts.xml +++ b/app/src/main/res/menu/select_podcasts.xml @@ -2,7 +2,7 @@ <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:compat="http://schemas.android.com/apk/res-auto"> <item - android:id="@+id/menu_search" + android:id="@+id/menu_global_search" android:icon="?attr/search" android:title="@string/menu.search" compat:showAsAction="always|withText"/> diff --git a/app/src/main/res/menu/select_song.xml b/app/src/main/res/menu/select_song.xml index fc4494cb..5718866a 100644 --- a/app/src/main/res/menu/select_song.xml +++ b/app/src/main/res/menu/select_song.xml @@ -3,7 +3,7 @@ xmlns:compat="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/menu_play_now" - android:icon="?attr/media_button_start" + android:icon="?attr/actionbar_start" android:title="@string/menu.play" compat:showAsAction="always|withText"/> @@ -32,14 +32,6 @@ <item android:id="@+id/menu_delete" android:title="@string/menu.delete_cache"/> - - <item - android:id="@+id/menu_add_playlist" - android:title="@string/menu.add_playlist"/> - - <item - android:id="@+id/menu_remove_playlist" - android:title="@string/menu.remove_playlist"/> <group android:id="@+id/hide_play_next"> <item diff --git a/app/src/main/res/menu/select_song_context.xml b/app/src/main/res/menu/select_song_context.xml index d8fc211c..b1e3c979 100644 --- a/app/src/main/res/menu/select_song_context.xml +++ b/app/src/main/res/menu/select_song_context.xml @@ -7,36 +7,11 @@ android:title="@string/common.info" /> - <item - android:id="@+id/song_menu_play_now" - android:title="@string/common.play_now" - /> - - <group android:id="@+id/hide_play_next"> - <item - android:id="@+id/song_menu_play_next" - android:title="@string/common.play_next"/> - </group> - <group android:id="@+id/hide_play_last"> <item android:id="@+id/song_menu_play_last" android:title="@string/common.play_last"/> </group> - - <item - android:id="@+id/song_menu_download" - android:title="@string/common.download" - /> - - <item - android:id="@+id/song_menu_pin" - android:title="@string/common.pin" - /> - - <item - android:id="@+id/song_menu_delete" - android:title="@string/menu.delete_cache"/> <group android:id="@+id/server_1.8"> <item diff --git a/app/src/main/res/menu/select_song_context_offline.xml b/app/src/main/res/menu/select_song_context_offline.xml index 49445876..1e697f30 100644 --- a/app/src/main/res/menu/select_song_context_offline.xml +++ b/app/src/main/res/menu/select_song_context_offline.xml @@ -6,27 +6,12 @@ android:id="@+id/song_menu_info" android:title="@string/common.info" /> - - <item - android:id="@+id/song_menu_play_now" - android:title="@string/common.play_now" - /> - - <group android:id="@+id/hide_play_next"> - <item - android:id="@+id/song_menu_play_next" - android:title="@string/common.play_next"/> - </group> <group android:id="@+id/hide_play_last"> <item android:id="@+id/song_menu_play_last" android:title="@string/common.play_last"/> </group> - - <item - android:id="@+id/song_menu_delete" - android:title="@string/menu.delete_cache"/> <item android:id="@+id/song_menu_star" diff --git a/app/src/main/res/menu/select_song_offline.xml b/app/src/main/res/menu/select_song_offline.xml index c45405fb..7a4a5407 100644 --- a/app/src/main/res/menu/select_song_offline.xml +++ b/app/src/main/res/menu/select_song_offline.xml @@ -3,7 +3,7 @@ xmlns:compat="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/menu_play_now" - android:icon="?attr/media_button_start" + android:icon="?attr/actionbar_start" android:title="@string/menu.play" compat:showAsAction="always|withText"/> diff --git a/app/src/main/res/menu/similar_artists.xml b/app/src/main/res/menu/similar_artists.xml index 771555b6..f6c30fb2 100644 --- a/app/src/main/res/menu/similar_artists.xml +++ b/app/src/main/res/menu/similar_artists.xml @@ -4,7 +4,7 @@ <item android:id="@+id/menu_play_now" - android:icon="?media_button_start" + android:icon="?actionbar_start" android:title="@string/menu.play" compat:showAsAction="always|withText"/> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 25f1b57c..45b89df9 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -42,13 +42,7 @@ <string name="main.welcome_text">Willkommen zu DSub! Die App ist aktuell für den Subsonic-Demo-Server konfiguriert. Nachdem Sie Ihren eigenen Server aufgesetzt haben (verfügbar unter <b>subsonic.org</b>) könne Sie diesen unter <b>Einstellungen</b> konfigurieren.</string> <string name="main.about_title">Über DSub</string> - <string name="main.about_text">Autor: Scott Jackson - \nEmail: dsub.android@gmail.com - \nVersion: %1$s - \nLokal gespeicherte Titel: %2$s - \nGenutzter Speicher: %3$s von %4$s - \nVerfügbarer Speicher: %5$s von %6$s</string> - <string name="main.faq_title">FAQ</string> + <string name="main.faq_title">FAQ</string> <string name="main.faq_text"> <![CDATA[ <font color="red">Cache vs Permanenter Cache</font>: @@ -142,8 +136,7 @@ <string name="select_album.select">Alle auswählen</string> <string name="select_album.n_selected">%d Lieder ausgewählt.</string> - <string name="select_album.n_unselected">%d Lieder deselektiert.</string> - <string name="select_album.more">Mehr</string> + <string name="select_album.more">Mehr</string> <string name="select_album.offline">Offline</string> <string name="select_album.searching">Suche...</string> <string name="select_album.no_sdcard">Fehler: Keine SD-Karte verfügbar.</string> @@ -190,8 +183,7 @@ <string name="download.playerstate_playing_shuffle">Playing shuffle</string> <string name="download.menu_show_album">Zeige Album</string> <string name="download.menu_lyrics">Liedtext</string> - <string name="download.menu_remove">Entferne aus Warteschlange</string> - <string name="download.menu_remove_all">Alle entfernen</string> + <string name="download.menu_remove_all">Alle entfernen</string> <string name="download.menu_screen_on">Bildschirm an</string> <string name="download.menu_shuffle">Mischen</string> <string name="download.menu_toggle">Umschalten</string> @@ -214,7 +206,6 @@ <string name="download.jukebox_not_authorized">Fernbedienung ist nicht erlaubt. Bitte aktivieren Sie den Jukebox-Modus unter <b>Nutzer > Einstellungen</b> auf Ihrem Subsonic-Server.</string> <string name="download.timer_length">Timer:</string> <string name="download.start_timer">Starte Timer</string> - <string name="download.stop_timer">Stoppe Timer</string> <string name="download.need_download">Video muss zuerst heruntergeladen werden</string> <string name="download.no_streaming_player">Stream kann nicht wiedergegeben werden.</string> <string name="download.playing_out_of">Wiedergabe: %1$d/%2$d</string> @@ -577,6 +568,74 @@ <item quantity="one">Noch ein Tag bis zum Ablauf des Testzeitraums.</item> <item quantity="other">%d Tage bis zum Ablauf des Testzeitraums.</item> </plurals> + <string name="details.album">Album</string> + <string name="details.artist">Künstler</string> + <string name="details.author">Autor</string> + <string name="details.available_space">Verfügbarer Platz</string> + <string name="details.bookmark_position">Lesezeichenposition</string> + <string name="details.comments">Kommentar</string> + <string name="details.created">Erstellt</string> + <string name="details.description">Beschreibung</string> + <string name="details.email">Email</string> + <string name="details.error">Fehlermeldung</string> + <string name="details.length">Länge</string> + <string name="details.of">%1$s von %2$s</string> + <string name="details.owner">Besitzer</string> + <string name="details.public">Öffentlich</string> + <string name="details.podcast">Podcast</string> + <string name="details.size">Größe</string> + <string name="details.status">Status</string> + <string name="details.title">Titel</string> + <string name="download.stop_time_remaining">Stoppe in %1$s</string> + <string name="playlist.shared">Geteilte Wiedergabelisten</string> + <string name="settings.max_bitrate_112">112 Kbps</string> + <string name="settings.max_bitrate_128">128 Kbps</string> + <string name="settings.max_bitrate_160">160 Kbps</string> + <string name="settings.max_bitrate_192">192 Kbps</string> + <string name="settings.max_bitrate_256">256 Kbps</string> + <string name="settings.max_bitrate_32">32 Kbps</string> + <string name="settings.max_bitrate_320">320 Kbps</string> + <string name="settings.max_bitrate_64">64 Kbps</string> + <string name="settings.max_bitrate_80">80 Kbps</string> + <string name="settings.max_bitrate_96">96 Kbps</string> + <string name="settings.max_video_bitrate_1000">1000 Kbps</string> + <string name="settings.max_video_bitrate_1500">1500 Kbps</string> + <string name="settings.max_video_bitrate_200">200 Kbps</string> + <string name="settings.max_video_bitrate_2000">2000 Kbps</string> + <string name="settings.max_video_bitrate_300">300 Kbps</string> + <string name="settings.max_video_bitrate_3000">3000 Kbps</string> + <string name="settings.max_video_bitrate_400">400 Kbps</string> + <string name="settings.max_video_bitrate_500">500 Kbps</string> + <string name="settings.max_video_bitrate_5000">5000 Kbps</string> + <string name="settings.max_video_bitrate_700">700 Kbps</string> + <string name="widget.4x1">DSub (4x1)</string> + <string name="widget.4x2">DSub (4x2)</string> + <string name="widget.4x3">DSub (4x3)</string> + <string name="widget.4x4">DSub (4x4)</string> + <string name="util.bytes_format.megabyte">0.00 MB</string> + <string name="util.bytes_format.kilobyte">0 KB</string> + <string name="util.bytes_format.gigabyte">0.00 GB</string> + <string name="util.bytes_format.byte">0 B</string> + <string name="common.close">Schliessen</string> + <string name="details.cached_format">Format im Cache</string> + <string name="details.genre">Genre</string> + <string name="details.cached_bitrate">Bitrate im Cache</string> + <string name="details.files_cached">Dateien im Cache</string> + <string name="details.files_permanent">Dateien im permanenten Cache</string> + <string name="details.rating">Bewertung</string> + <string name="details.server_bitrate">Originale Bitrate</string> + <string name="details.server_format">Originales Format</string> + <string name="details.song_count">Titelanzahl</string> + <string name="details.title.playlist">Details der Wiedergabeliste</string> + <string name="details.title.album">Albumdetails</string> + <string name="details.title.podcast">Podcastdetails</string> + <string name="details.title.song">Mediumdetails</string> + <string name="details.used_space">Genutzter Platz</string> + <string name="details.url">URL</string> + <string name="details.track">Medium</string> + <string name="details.year">Jahr</string> + <string name="details.version">Version</string> + <string name="playlist.mine">Meine Wiedergabelisten</string> <string name="settings.keep_played_count_none">Alle abgespielten Lieder entfernen</string> <string name="settings.keep_played_count_one">Das letzte abgespielte Lied behalten</string> <string name="settings.keep_played_count_three">3 abgespielte Lieder behalten</string> diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index cd255e13..f56e939e 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -41,13 +41,7 @@ <string name="main.welcome_title">Bienvenido!</string> <string name="main.welcome_text">Bienvenido a DSub! Ahora la aplicación está configurada para usar el servidor de demostración de Subsonic. Cuando configures tu servidor personal (disponible en <b>subsonic.org</b>), accede a <b>Preferencias</b> y cambia la configuración para conectarte.</string> <string name="main.about_title">Acerca de DSub</string> - <string name="main.about_text">Autor: Scott Jackson - \nEmail: dsub.android@gmail.com - \nVersión: %1$s - \nArchivos en caché: %2$s - \nEspacio usado: %3$s of %4$s - \nEspacio disponible: %5$s of %6$s</string> - <string name="main.select_server">Seleccionar servidor</string> + <string name="main.select_server">Seleccionar servidor</string> <string name="main.shuffle">Reproducción aleatoria</string> <string name="main.offline">Modo Offline</string> <string name="main.online">Modo Online</string> @@ -130,8 +124,7 @@ <string name="select_album.select">Seleccionar todo</string> <string name="select_album.n_selected">Seleccionadas %d canciones</string> - <string name="select_album.n_unselected">%d canciones deseleccionadas</string> - <string name="select_album.more">Más</string> + <string name="select_album.more">Más</string> <string name="select_album.offline">Offline</string> <string name="select_album.searching">Buscando...</string> <string name="select_album.no_sdcard">Error: No hay tarjeta SD disponible</string> @@ -176,8 +169,7 @@ <string name="download.playerstate_playing_shuffle">Reproduciendo en aleatorio</string> <string name="download.menu_show_album">Mostrar disco</string> <string name="download.menu_lyrics">Letras</string> - <string name="download.menu_remove">Eliminar de la cola</string> - <string name="download.menu_remove_all">Borrar todo</string> + <string name="download.menu_remove_all">Borrar todo</string> <string name="download.menu_screen_on">Pantalla encendida</string> <string name="download.menu_shuffle">Aleatorio</string> <string name="download.menu_toggle">Cambiar</string> @@ -199,7 +191,6 @@ <string name="download.jukebox_not_authorized">Control remoto no permitido. Por favor, active el modo jukebox en <b>Users > Settings</b> en su servidor Subsonic.</string> <string name="download.timer_length">Temporizador</string> <string name="download.start_timer">Iniciar temporizador</string> - <string name="download.stop_timer">Detener temporizador</string> <string name="download.need_download">El vídeo ha de ser descargado antes</string> <string name="download.no_streaming_player">Ningún reproductor puede reproducir este stream</string> <string name="download.playing_out_of">%1$d/%2$d</string> diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 759e3fd8..4674ca32 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -41,12 +41,6 @@ <string name="main.welcome_title">Bienvenue !</string> <string name="main.welcome_text">Bienvenue dans DSub ! L\'application est actuellement configurée pour se connecter au serveur de démo Subsonic (<b>demo.subsonic.org</b>). Vous pouvez configurer votre propre serveur dans les paramètres. Choisir <b>Paramètres</b> et mettre à jour la configuration pour vous y connecter.</string> <string name="main.about_title">A propos de DSub</string> - <string name="main.about_text">Auteur : Scott Jackson - \nEmail : dsub.android@gmail.com - \nVersion : %1$s - \nFichiers en cache : %2$s - \nEspace utilisé : %3$s de %4$s - \nEspace dispo. : %5$s de %6$s</string> <string name="main.faq_title">FAQ</string> <string name="main.faq_text"> <![CDATA[ @@ -129,8 +123,7 @@ <string name="select_album.select">Tout sélectionner</string> <string name="select_album.n_selected">%d pistes sélectionnées.</string> - <string name="select_album.n_unselected">%d pistes désélectionnées.</string> - <string name="select_album.more">Plus</string> + <string name="select_album.more">Plus</string> <string name="select_album.offline">Déconnecté</string> <string name="select_album.searching">Recherche en cours...</string> <string name="select_album.no_sdcard">Erreur : Aucune carte SD card disponible.</string> @@ -175,8 +168,7 @@ <string name="download.playerstate_playing_shuffle">Lecture au hasard</string> <string name="download.menu_show_album">Afficher l\'album</string> <string name="download.menu_lyrics">Paroles</string> - <string name="download.menu_remove">Enlever de la queue</string> - <string name="download.menu_remove_all">Enlever tout</string> + <string name="download.menu_remove_all">Enlever tout</string> <string name="download.menu_screen_on">Ecran actif</string> <string name="download.menu_shuffle">Hasard</string> <string name="download.menu_toggle">Basculer</string> @@ -199,7 +191,6 @@ <string name="download.jukebox_not_authorized">Mode télécommande non autorisée. Activer le mode jukebox.<b>Users > Settings</b> on your Subsonic server.</string> <string name="download.timer_length">Minuteur :</string> <string name="download.start_timer">Démarrer le minuteur</string> - <string name="download.stop_timer">Arrêter le minuteur</string> <string name="download.need_download">La vidéo doit d\'abord être téléchargée</string> <string name="download.no_streaming_player">Aucun lecteur ne peut afficher ce flux</string> <string name="download.playing_out_of">Lecture : %1$d/%2$d</string> diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index 6222989a..0809e8ba 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -7,14 +7,14 @@ <string name="common.cancel">Mégse</string> <string name="common.play_now">Lejátszás</string> <string name="common.play_shuffled">Lejátszás kevert sorrendben</string> - <string name="common.play_next">Sorbaállítás következőnek</string> - <string name="common.play_last">Sorbaállítás utolsónak</string> + <string name="common.play_next">Sorba állítás következőnek</string> + <string name="common.play_last">Sorba állítás utolsónak</string> <string name="common.download">Letöltés gyorsítótárba</string> <string name="common.pin">Letöltés tárolásra (megőrzés)</string> <string name="common.delete">Törlés</string> <string name="common.star">Csillagozás</string> <string name="common.unstar">Csillagozás ki</string> - <string name="common.info">Részletek</string> + <string name="common.info">Részletezés</string> <string name="common.name">Név</string> <string name="common.comment">Megjegyzés</string> <string name="common.public">Nyilvános</string> @@ -25,6 +25,7 @@ <string name="common.confirm_message_cache">cache</string> <string name="common.empty">Nem található!</string> <string name="common.warning">Figyelem!</string> + <string name="common.close">Bezár</string> <string name="button_bar.home">Főoldal</string> <string name="button_bar.browse">Médiatár</string> @@ -39,15 +40,9 @@ <string name="button_bar.downloading">Letöltések</string> <string name="main.welcome_title">Üdvözlet!</string> - <string name="main.welcome_text">Üdvözli a DSub! Az alkalmazás még nincs beállítva. Miután konfigurálta saját kiszolgálóját + <string name="main.welcome_text">Üdvözli a DSub! Az alkalmazás jelenleg egy Subsonic demo kiszolgálóhoz van beállítva. Miután konfigurálta saját kiszolgálóját (elérhető: <b>subsonic.org</b>), húzza balról jobbra az oldalsávot, lépjen be a <b>Beállítások</b> menüpontba és adja meg a kapcsolódási adatokat!</string> <string name="main.about_title">DSub információk</string> - <string name="main.about_text">Fejlesztő: Scott Jackson - \nEmail: dsub.android@gmail.com - \nVerzió: %1$s - \nGyorsítótárazott fájlok: %2$s - \nFelhasznált tároló: %3$s/%4$s - \nFelhasználható tároló: %5$s/%6$s</string> <string name="main.faq_title">GYIK</string> <string name="main.faq_text"> <![CDATA[ @@ -66,11 +61,11 @@ <string name="main.settings">Beállítások</string> <string name="main.albums_title">Albumok</string> <string name="main.albums_per_folder">Mappánként</string> - <string name="main.albums_newest">Utoljára hozzáadottak</string> - <string name="main.albums_recent">Utoljára lejátszottak</string> - <string name="main.albums_frequent">Legtöbbször lejátszottak</string> - <string name="main.albums_highest">Legjobbra értékeltek</string> - <string name="main.albums_starred">Csillagozottak</string> + <string name="main.albums_newest">Utoljára hozzáadott</string> + <string name="main.albums_recent">Utoljára lejátszott</string> + <string name="main.albums_frequent">Legtöbbször lejátszott</string> + <string name="main.albums_highest">Legjobbra értékelt</string> + <string name="main.albums_starred">Csillagozott</string> <string name="main.albums_random">Véletlenszerű kiválasztás</string> <string name="main.albums_genres">Műfajok</string> <string name="main.albums_year">Évtizedek</string> @@ -79,12 +74,14 @@ <string name="main.songs_genres">@string/main.albums_genres</string> <string name="main.back_confirm">Nyomja meg még egyszer a kilépéshez!</string> <string name="main.scan_complete">A médiatár frissítése befejeződött a kiszolgálón!</string> + <string name="main.artist">Előadó</string> + <string name="main.title">Cím</string> <string name="menu.search">Keresés</string> <string name="menu.shuffle">Lejátszás kevert sorrendben</string> <string name="menu.refresh">Frissítés</string> <string name="menu.play">Lejátszás</string> - <string name="menu.play_last">Sorbaállítás utolsónak</string> + <string name="menu.play_last">Sorba állítás utolsónak</string> <string name="menu.exit">Kilépés</string> <string name="menu.settings">Beállítások</string> <string name="menu.help">Súgó</string> @@ -102,9 +99,9 @@ <string name="menu.show_all">Összes média megjelenítése</string> <string name="menu.show_artist">Ugrás az előadóhoz</string> <string name="menu.share">Megosztás</string> - <string name="menu.delete_cache">Gyorsítótár törlése</string> + <string name="menu.delete_cache">Törlés a gyorsítótárból</string> <string name="menu.cast">Továbbítás eszközhöz</string> - <string name="menu.faq">FAQ</string> + <string name="menu.faq">GYIK</string> <string name="menu.add_user">Felhasználó hozzáadása</string> <string name="menu.rescan">Médiatár frissítése a kiszolgálón</string> <string name="menu.rate">Értékelés</string> @@ -133,14 +130,14 @@ <string name="search.more">Továbbiak</string> <string name="progress.wait">Kérem várjon...</string> + <string name="progress.artist_info">Az előadó életrajzának betöltése</string> <string name="music_library.label">Médiatár</string> <string name="music_library.label_offline">Kapcsolat nélküli médiák</string> <string name="select_album.select">Összes jelölése be/ki</string> <string name="select_album.n_selected">%d dal kijelölve.</string> - <string name="select_album.n_unselected">%d dal visszavonva.</string> - <string name="select_album.more">Továbbiak</string> + <string name="select_album.more">Továbbiak</string> <string name="select_album.offline">Offline</string> <string name="select_album.searching">Keresés...</string> <string name="select_album.no_sdcard">Hiba: SD kártya nem áll rendelkezésre!</string> @@ -182,12 +179,12 @@ <string name="download.empty">A várólista üres!</string> <string name="download.shuffle_loading">Kevert sorrendű lista betöltése...</string> <string name="download.playerstate_downloading">Letöltés - \"%s\"</string> + <string name="download.playerstate_mobile_disabled">Várakozás a Wi-Fi hálózatra a letöltéshez</string> <string name="download.playerstate_buffering">Pufferelés</string> <string name="download.playerstate_playing_shuffle">Sorrend keverése</string> <string name="download.menu_show_album">Ugrás az albumhoz</string> <string name="download.menu_lyrics">Dalszöveg</string> - <string name="download.menu_remove">Eltávolítás a várólistáról</string> - <string name="download.menu_remove_all">Összes eltávolítása</string> + <string name="download.menu_remove_all">Összes eltávolítása</string> <string name="download.menu_screen_on">Kijelző be</string> <string name="download.menu_shuffle">Sorrend keverése</string> <string name="download.menu_toggle">Váltás</string> @@ -232,7 +229,9 @@ <string name="starring_content_starred">\"%s\" csillagozás be</string> <string name="starring_content_unstarred">\"%s\" csillagozás ki</string> <string name="starring_content_error">Nem sikerült frissíteni \"%s\", próbálja később!</string> - + + <string name="playlist.mine">Saját lejátszási listák</string> + <string name="playlist.shared">Megosztott lejátszási listák</string> <string name="playlist_error">Nem sikerült elérni a lejátszási lista adatait!</string> <string name="updated_playlist">%1$s dal hozzáadva: \"%2$s\"</string> <string name="updated_playlist_error">Nem sikerült frissíteni \"%s\", próbálja később!</string> @@ -242,12 +241,7 @@ <string name="bookmark.delete_title">Könyvjelző törlése</string> <string name="bookmark.deleted">\"%s\" könyvjelző törölve</string> <string name="bookmark.deleted_error">\"%s\" könyvjelző törlése sikertelen!</string> - <string name="bookmark.details_title">Könyvjelző részletei</string> - <string name="bookmark.details">Dal: %1$s - \nPozíció: %2$s - \nLétrehozva: %3$s - \nUtolsó módosítás: %4$s - \nMegjegyzés: %5$s</string> + <string name="bookmark.details_title">Könyvjelző részletezése</string> <string name="bookmark.resume_title">Folytatja a lejátszást?</string> <string name="bookmark.resume">\"%1$s\" folytatása innen: \"%2$s\"</string> <string name="bookmark.action_resume">Folytatás</string> @@ -310,6 +304,8 @@ <string name="settings.track_summary">Dalsorszám megjelenítése a dal címe előtt, ha létezik.</string> <string name="settings.custom_sort">Egyéni rendezés</string> <string name="settings.custom_sort_summary">A kiszolgáló alapértelmezett rendezésének felülbírálása, rendezés a lemez sorszáma és a kiadás éve alapján.</string> + <string name="settings.open_to_library">Médiatár megnyitása</string> + <string name="settings.open_to_library_summary">A Médiatár megnyitása a Főoldal helyett.</string> <string name="settings.network_title">Hálózat</string> <string name="settings.max_bitrate_wifi">Max. audió bitráta - Wi-Fi</string> <string name="settings.max_bitrate_mobile">Max. audió bitráta - Mobilhálózat</string> @@ -375,6 +371,11 @@ <string name="settings.temp_loss_pause_lower">Megállítás, kérésre alacsonyabb hangerő</string> <string name="settings.temp_loss_lower">Alacsonyabb hangerő</string> <string name="settings.temp_loss_nothing">Ne csináljon semmit</string> + <string name="settings.keep_played_count_title">Lejátszottak megtartása</string> + <string name="settings.keep_played_count_none">Összes lejátszott eltávolítása</string> + <string name="settings.keep_played_count_one">Utoljára lejátszott megtartása</string> + <string name="settings.keep_played_count_two">2 lejátszott megtartása</string> + <string name="settings.keep_played_count_three">3 lejátszott megtartása</string> <string name="settings.disconnect_pause_title">Megállítás kapcsolatbontás esetén</string> <string name="settings.disconnect_pause_both">Megállítás minden esetben</string> <string name="settings.disconnect_pause_neither">Ne csináljon semmit</string> @@ -422,8 +423,8 @@ <string name="settings.sync_notification">Szinkronizálási értesítések</string> <string name="settings.sync_notification_summary">Értesítés megjelenítése, ha új média került szinkronizálásra.</string> <string name="settings.menu_options.title">Opcionális menübeállítások</string> - <string name="settings.menu_options.play_next_summary">Sorbaállítás következőnek opció megjelenítése a menüben.</string> - <string name="settings.menu_options.play_last_summary">Sorbaállítás utolsónak opció megjelenítése a menüben.</string> + <string name="settings.menu_options.play_next_summary">Sorba állítás következőnek opció megjelenítése a menüben.</string> + <string name="settings.menu_options.play_last_summary">Sorba állítás utolsónak opció megjelenítése a menüben.</string> <string name="settings.menu_options.star_summary">Csillagozás opció megjelenítése a menüben.</string> <string name="settings.menu_options.shared_summary">Megosztás opció megjelenítése a menüben.</string> <string name="settings.menu_options.rate_summary">Értékelés opció megjelenítése a menüben.</string> @@ -453,6 +454,8 @@ <string name="settings.casting_proxy_summary">Streamelés az eszközön (mint egy proxyn) keresztül. Ez megoldást hozhat néhány esetben, pl. saját aláírású tanúsítvány használatakor.</string> <string name="settings.rename_duplicates">Duplikált dalok átnevezése</string> <string name="settings.rename_duplicates_summary">Duplikált dalok átnevezése az eredeti fájlnévre, így megkülönböztethetővé válnak.</string> + <string name="settings.start_on_headphones">Lejátszó elindítása</string> + <string name="settings.start_on_headphones_summary">Lejátszó elindítása fülhallgató csatlakoztatásakor. Ez a funkció olyan szolgáltatás használatát igényli, ami a Dsub elindítása nélkül tudja kontrollálni a fülhallgató csatlakoztatási eseményeket.</string> <string name="shuffle.title">Sorrend keverése</string> <string name="shuffle.startYear">Kezdő év:</string> @@ -581,6 +584,46 @@ <string name="tasker.edit_server_offline">Offline kapcsoló: </string> <string name="tasker.edit_do_nothing">Ne csináljon semmit</string> + <string name="details.title.song">Dal információi</string> + <string name="details.title.album">Album információi</string> + <string name="details.title.podcast">Podcast információi</string> + <string name="details.title.playlist">Lejátszási lista információi</string> + <string name="details.podcast">Podcast</string> + <string name="details.status">Státusz</string> + <string name="details.artist">Előadó</string> + <string name="details.album">Album</string> + <string name="details.track">Dal</string> + <string name="details.genre">Műfaj</string> + <string name="details.year">Év</string> + <string name="details.server_format">Kiszolgáló formátuma</string> + <string name="details.server_bitrate">Kiszolgáló bitrátája</string> + <string name="details.cached_format">Gyorsítótárazott formátuma</string> + <string name="details.cached_bitrate">Gyorsítótárazott bitrátája</string> + <string name="details.size">Méret</string> + <string name="details.length">Hossz</string> + <string name="details.bookmark_position">Könyvjelző pozíciója</string> + <string name="details.rating">Értékelés</string> + <string name="details.description">Leírás</string> + <string name="details.owner">Tulajdonos</string> + <string name="details.comments">Megjegyzések</string> + <string name="details.song_count">Dalsorszám</string> + <string name="details.public">Nyilvános</string> + <string name="details.created">Létrehozva</string> + <string name="details.title">Cím</string> + <string name="details.url">URL</string> + <string name="details.error">Hibaüzenet</string> + <string name="details.author">Szerző</string> + <string name="details.email">Email</string> + <string name="details.version">Verzió</string> + <string name="details.files_cached">Gyorsítótárazott fájlok</string> + <string name="details.files_permanent">Megőrzött fájlok</string> + <string name="details.used_space">Felhasznált tároló</string> + <string name="details.available_space">Rendelkezésre álló hely</string> + <string name="details.of">%1$s/%2$s</string> + <string name="details.song">Dal</string> + <string name="details.position">Pozíció</string> + <string name="details.updated">Frissítve</string> + <plurals name="select_album_n_songs"> <item quantity="zero">Nincsenek dalok</item> <item quantity="one">1 dal</item> diff --git a/app/src/main/res/values-large/dimens.xml b/app/src/main/res/values-large/dimens.xml index b08dda86..dfe7ff84 100644 --- a/app/src/main/res/values-large/dimens.xml +++ b/app/src/main/res/values-large/dimens.xml @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <dimen name="Button">64dip</dimen> + <dimen name="Button.Large">74dip</dimen> <dimen name="Button.Small">54dip</dimen> <dimen name="AlbumArt.Small">96dip</dimen> <dimen name="AlbumArt.Header">210dip</dimen> diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index cfae3ea0..ffbb0485 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -32,12 +32,6 @@ <string name="main.welcome_text">Добро пожаловать в DSub! Это приложение настроено на работу с демо сервером Subsonic. После настройки Вашего персонального сервера (доступен на <b>subsonic.org</b>), пожалуйста, перейдите в <b>Настройки</b> и измените параметры для подключения.</string> <string name="main.about_title">О программе DSub</string> - <string name="main.about_text">Автор: Scott Jackson - \nEmail: dsub.android@gmail.com - \nВерсия: %1$s - \nFiles Cached: %2$s - \nИспользовано места: %3$s из %4$s - \nДоступно места: %5$s из %6$s</string> <string name="main.select_server">Выбрать сервер</string> <string name="main.shuffle">Случайное воспроизведение</string> <string name="main.offline">Отключиться</string> @@ -89,7 +83,6 @@ <string name="select_album.select">Выбрать все</string> <string name="select_album.n_selected">%d композиций выбрано.</string> - <string name="select_album.n_unselected">Выбор снят с %d композиций.</string> <string name="select_album.more">Еще</string> <string name="select_album.offline">Оффлайн</string> <string name="select_album.searching">Выполняется поиск...</string> @@ -108,7 +101,6 @@ <string name="download.playerstate_playing_shuffle">Воспроизводится случайно</string> <string name="download.menu_show_album">Показать альбом</string> <string name="download.menu_lyrics">Текст</string> - <string name="download.menu_remove">Убрать из очереди</string> <string name="download.menu_remove_all">Очистить</string> <string name="download.menu_screen_on">Включить подсветку</string> <string name="download.menu_shuffle">Перемешать</string> @@ -131,8 +123,7 @@ <string name="download.jukebox_not_authorized">Удаленное управление запрещено. Пожалуйста, активируйте режим jukebox в разделе <b>Настройки > Проигрыватели</b> на вашем сервере Subsonic.</string> <string name="download.timer_length">Длительность</string> <string name="download.start_timer">Запустить таймер</string> - <string name="download.stop_timer">Остановить таймер</string> - <string name="download.need_download">Необходимо сначала скачать видео</string> + <string name="download.need_download">Необходимо сначала скачать видео</string> <string name="download.no_streaming_player">Нет плеера для воспроизведения потока</string> <string name="starring_content_starred">\"%s\" добавлено в закладки</string> diff --git a/app/src/main/res/values-v11/colors.xml b/app/src/main/res/values-v11/colors.xml deleted file mode 100644 index f5a422bb..00000000 --- a/app/src/main/res/values-v11/colors.xml +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - <color name="notificationArtist">#bababa</color> - <color name="notificationTitle">#dddddd</color> -</resources> diff --git a/app/src/main/res/values-v11/styles.xml b/app/src/main/res/values-v11/styles.xml deleted file mode 100644 index 9a7cb2b2..00000000 --- a/app/src/main/res/values-v11/styles.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - <style name="BasicButton"> - <item name="android:background">?android:selectableItemBackground</item> - </style> -</resources>
\ No newline at end of file diff --git a/app/src/main/res/values-v16/themes.xml b/app/src/main/res/values-v16/themes.xml deleted file mode 100644 index 013ac0aa..00000000 --- a/app/src/main/res/values-v16/themes.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - <style name="DSub.TextViewStyle" parent="android:Widget.TextView"> - <item name="android:fontFamily">sans-serif-light</item> - </style> - - <style name="DSub.TextViewStyle.Bold" parent="android:Widget.TextView"> - <item name="android:fontFamily">sans-serif</item> - <item name="android:textStyle">bold</item> - </style> - - <style name="DSub.ButtonStyle" parent="android:Widget.Holo.Button"> - <item name="android:fontFamily">sans-serif-light</item> - </style> -</resources>
\ No newline at end of file diff --git a/app/src/main/res/values-v21/themes.xml b/app/src/main/res/values-v21/themes.xml new file mode 100644 index 00000000..acd117b5 --- /dev/null +++ b/app/src/main/res/values-v21/themes.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="Theme.DSub.Light" parent="Theme.DSub.Light.Base"> + <item name="android:windowTranslucentStatus">true</item> + </style> + + <style name="Theme.DSub.Dark" parent="Theme.DSub.Dark.Base"> + <item name="android:windowTranslucentStatus">true</item> + </style> +</resources>
\ No newline at end of file diff --git a/app/src/main/res/values-v22/styles.xml b/app/src/main/res/values-v22/styles.xml new file mode 100644 index 00000000..f85d2f23 --- /dev/null +++ b/app/src/main/res/values-v22/styles.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + <style name="NotificationText.Title" parent="@android:style/TextAppearance.Material.Notification.Title"></style> + <style name="NotificationText.Content" parent="@android:style/TextAppearance.Material.Notification"></style> + + <style name="NotificationButton.Expanded" parent="@style/NotificationButton.ExpandedBase"> + <item name="android:padding">2dip</item> + </style> + + <style name="NotificationLayoutDivider"> + <item name="android:divider">@drawable/notification_divider</item> + </style> + <style name="NotificationDivider"> + <item name="android:background">@drawable/notification_divider</item> + </style> +</resources>
\ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index c103fb15..a7dd932d 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -1,18 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> <resources> - <string-array name="drawerItems"> - <item>@string/button_bar.home</item> - <item>@string/button_bar.browse</item> - <item>@string/button_bar.playlists</item> - <item>@string/button_bar.podcasts</item> - <item>@string/button_bar.bookmarks</item> - <item>@string/button_bar.shares</item> - <item>@string/button_bar.chat</item> - <item>@string/button_bar.admin</item> - <item>@string/button_bar.downloading</item> - <item>@string/menu.settings</item> - </string-array> - <string-array name="drawerItemsDescriptions"> <item>Home</item> <item>Artist</item> @@ -46,32 +33,6 @@ <item>Chat</item> </string-array> - <array name="drawerItemIconsLight"> - <item>@drawable/main_offline_light</item> - <item>@drawable/ic_menu_library_light</item> - <item>@drawable/ic_menu_playlist_light</item> - <item>@drawable/ic_menu_podcast_light</item> - <item>@drawable/ic_menu_bookmark_light</item> - <item>@drawable/ic_menu_share_light</item> - <item>@drawable/ic_menu_chat_light</item> - <item>@drawable/ic_menu_admin_light</item> - <item>@drawable/ic_menu_download_light</item> - <item>@drawable/ic_menu_settings_light</item> - </array> - - <array name="drawerItemIconsDark"> - <item>@drawable/main_offline_dark</item> - <item>@drawable/ic_menu_library_dark</item> - <item>@drawable/ic_menu_playlist_dark</item> - <item>@drawable/ic_menu_podcast_dark</item> - <item>@drawable/ic_menu_bookmark_dark</item> - <item>@drawable/ic_menu_share_dark</item> - <item>@drawable/ic_menu_chat_dark</item> - <item>@drawable/ic_menu_admin_dark</item> - <item>@drawable/ic_menu_download_dark</item> - <item>@drawable/ic_menu_settings_dark</item> - </array> - <string-array name="themeValues"> <item>light</item> <item>dark</item> diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 9667117c..2b9b7f50 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -5,12 +5,20 @@ <attr name="media_button_forward" format="reference"/> <attr name="media_button_pause" format="reference"/> <attr name="media_button_repeat_off" format="reference"/> + <attr name="media_button_repeat_single" format="reference"/> + <attr name="media_button_repeat_all" format="reference"/> <attr name="media_button_start" format="reference"/> <attr name="media_button_stop" format="reference"/> + <attr name="actionbar_backward" format="reference"/> + <attr name="actionbar_forward" format="reference"/> + <attr name="actionbar_pause" format="reference"/> + <attr name="actionbar_start" format="reference"/> + <attr name="actionbar_stop" format="reference"/> <attr name="chat_send" format="reference"/> <attr name="add" format="reference"/> <attr name="download_none" format="reference"/> <attr name="shuffle" format="reference"/> + <attr name="shuffle_button" format="reference"/> <attr name="refresh" format="reference"/> <attr name="search" format="reference"/> <attr name="remove" format="reference"/> @@ -26,7 +34,21 @@ <attr name="rating_bad" format="reference"/> <attr name="rating_good" format="reference"/> <attr name="radio" format="reference"/> + <attr name="star_outline" format="reference"/> <attr name="drawerItemsIcons" format="reference"/> + <attr name="drawerHome" format="reference"/> + <attr name="drawerLibrary" format="reference"/> + <attr name="drawerPlaylists" format="reference"/> + <attr name="drawerPodcasts" format="reference"/> + <attr name="drawerBookmarks" format="reference"/> + <attr name="drawerShares" format="reference"/> + <attr name="drawerChat" format="reference"/> + <attr name="drawerAdmin" format="reference"/> + <attr name="drawerDownloading" format="reference"/> + <attr name="drawerSettings" format="reference"/> + <attr name="actionbarTitleStyle" format="reference"/> + <attr name="actionbarSubtitleStyle" format="reference"/> + <attr name="actionbarPopupStyle" format="reference"/> <declare-styleable name="SeekBarPreference"> <attr name="min" format="integer"/> diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index b1422ad6..772d0abf 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,17 +1,18 @@ <?xml version="1.0" encoding="utf-8"?> <resources> - <color name="lightBackground">#F1F0E6</color> - <color name="dividerColor">#FF33B5E5</color> <color name="appwidget_text">#FFFFFF</color> - <color name="notificationArtist">#434343</color> - <color name="notificationTitle">#000000</color> - <color name="background_holo_light">#ff33b5e5</color> <color name="overlayColor">#80000000</color> - <color name="ics_opaque">#8033b5e5</color> - <color name="cyan">#ff0099cc</color> <color name="holo_blue_light">#ff33b5e5</color> <color name="holo_orange_light">#ffffbb33</color> <color name="holo_green_light">#ff99cc00</color> <color name="holo_red_light">#ffff4444</color> + + <color name="lightPrimary">#2196f3</color> + <color name="lightPrimaryDark">#1e88e5</color> + <color name="lightAccent">#448aff</color> + + <color name="holoPrimary">#009688</color> + <color name="holoPrimaryDark">#00897b</color> + <color name="holoAccent">#64ffda</color> </resources>
\ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index be3e843d..b002ac9f 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -1,7 +1,9 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <dimen name="Button">54dip</dimen> + <dimen name="Button.Large">64dip</dimen> <dimen name="Button.Small">46dip</dimen> <dimen name="AlbumArt.Small">78dip</dimen> <dimen name="AlbumArt.Header">120dip</dimen> + <dimen name="Star.Small">20dp</dimen> </resources>
\ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3d67ec37..fc61a0f0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -25,6 +25,7 @@ <string name="common.confirm_message_cache">cache</string> <string name="common.empty">No data</string> <string name="common.warning">Warning</string> + <string name="common.close">Close</string> <string name="button_bar.home">Home</string> <string name="button_bar.browse">Library</string> @@ -37,17 +38,12 @@ <string name="button_bar.chat">Chat</string> <string name="button_bar.admin">Admin</string> <string name="button_bar.downloading">Downloading</string> + <string name="button_bar.offline">Offline</string> <string name="main.welcome_title">Welcome!</string> <string name="main.welcome_text">Welcome to DSub! The app is currently configured to use the Subsonic demo server. After you\'ve set up your personal server (available from <b>subsonic.org</b>), please go to <b>Settings</b> and change the configuration to connect to it.</string> <string name="main.about_title">About DSub</string> - <string name="main.about_text">Author: Scott Jackson - \nEmail: dsub.android@gmail.com - \nVersion: %1$s - \nFiles Cached: %2$s - \nUsed Space: %3$s of %4$s - \nAvailable Space: %5$s of %6$s</string> <string name="main.faq_title">FAQ</string> <string name="main.faq_text"> <![CDATA[ @@ -79,6 +75,8 @@ <string name="main.songs_genres">@string/main.albums_genres</string> <string name="main.back_confirm">Press back again to exit</string> <string name="main.scan_complete">Completed scan of Server</string> + <string name="main.artist">Artist</string> + <string name="main.title">Title</string> <string name="menu.search">Search</string> <string name="menu.shuffle">Shuffle</string> @@ -139,9 +137,8 @@ <string name="music_library.label_offline">Offline media</string> <string name="select_album.select">Select all</string> - <string name="select_album.n_selected">%d tracks selected.</string> - <string name="select_album.n_unselected">%d tracks unselected.</string> - <string name="select_album.more">More</string> + <string name="select_album.n_selected">%d selected.</string> + <string name="select_album.more">More</string> <string name="select_album.offline">Offline</string> <string name="select_album.searching">Searching...</string> <string name="select_album.no_sdcard">Error: No SD card available.</string> @@ -188,8 +185,7 @@ <string name="download.playerstate_playing_shuffle">Playing shuffle</string> <string name="download.menu_show_album">Show Album</string> <string name="download.menu_lyrics">Lyrics</string> - <string name="download.menu_remove">Remove from queue</string> - <string name="download.menu_remove_all">Remove all</string> + <string name="download.menu_remove_all">Remove all</string> <string name="download.menu_screen_on">Screen on</string> <string name="download.menu_shuffle">Shuffle</string> <string name="download.menu_toggle">Toggle</string> @@ -212,7 +208,7 @@ <string name="download.jukebox_not_authorized">Remote control is not allowed. Please enable jukebox mode in <b>Users > Settings</b> on your Subsonic server.</string> <string name="download.timer_length">Timer:</string> <string name="download.start_timer">Start Timer</string> - <string name="download.stop_timer">Stop Timer</string> + <string name="download.stop_time_remaining">Stop in %1$s</string> <string name="download.need_download">Video needs to be downloaded first</string> <string name="download.no_streaming_player">No player can play this stream</string> <string name="download.playing_out_of">Playing: %1$d/%2$d</string> @@ -234,7 +230,9 @@ <string name="starring_content_starred">Starred \"%s\"</string> <string name="starring_content_unstarred">Unstarred \"%s\"</string> <string name="starring_content_error">Failed to update \"%s\", please try later.</string> - + + <string name="playlist.mine">My Playlists</string> + <string name="playlist.shared">Shared Playlists</string> <string name="playlist_error">Failed to grab list of playlists</string> <string name="updated_playlist">Added %1$s songs to \"%2$s\"</string> <string name="updated_playlist_error">Failed to update \"%s\", please try later.</string> @@ -245,11 +243,6 @@ <string name="bookmark.deleted">Deleted the bookmark for \"%s\"</string> <string name="bookmark.deleted_error">Failed to delete the bookmark for \"%s\"</string> <string name="bookmark.details_title">Bookmark Details</string> - <string name="bookmark.details">Song: %1$s - \nPosition: %2$s - \nCreated: %3$s - \nLast Updated: %4$s - \nComment: %5$s</string> <string name="bookmark.resume_title">Resume playing?</string> <string name="bookmark.resume">Resume playing \'%1$s\' from %2$s</string> <string name="bookmark.action_resume">Resume</string> @@ -592,6 +585,46 @@ <string name="tasker.edit_server_offline">Toggle offline: </string> <string name="tasker.edit_do_nothing">Do Nothing</string> + <string name="details.title.song">Song Details</string> + <string name="details.title.album">Album Details</string> + <string name="details.title.podcast">Podcast Details</string> + <string name="details.title.playlist">Playlist Details</string> + <string name="details.podcast">Podcast</string> + <string name="details.status">Status</string> + <string name="details.artist">Artist</string> + <string name="details.album">Album</string> + <string name="details.track">Track</string> + <string name="details.genre">Genre</string> + <string name="details.year">Year</string> + <string name="details.server_format">Server Format</string> + <string name="details.server_bitrate">Server Bitrate</string> + <string name="details.cached_format">Cached Format</string> + <string name="details.cached_bitrate">Cached Bitrate</string> + <string name="details.size">Size</string> + <string name="details.length">Length</string> + <string name="details.bookmark_position">Bookmark Position</string> + <string name="details.rating">Rating</string> + <string name="details.description">Description</string> + <string name="details.owner">Owner</string> + <string name="details.comments">Comments</string> + <string name="details.song_count">Song Count</string> + <string name="details.public">Public</string> + <string name="details.created">Created</string> + <string name="details.title">Title</string> + <string name="details.url">URL</string> + <string name="details.error">Error Message</string> + <string name="details.author">Author</string> + <string name="details.email">Email</string> + <string name="details.version">Version</string> + <string name="details.files_cached">Files Cached</string> + <string name="details.files_permanent">Permanent Cached</string> + <string name="details.used_space">Used Space</string> + <string name="details.available_space">Available Space</string> + <string name="details.of">%1$s of %2$s</string> + <string name="details.song">Song</string> + <string name="details.position">Position</string> + <string name="details.updated">Updated</string> + <plurals name="select_album_n_songs"> <item quantity="zero">No songs</item> <item quantity="one">One song</item> diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 43271afd..94db6bca 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -1,7 +1,38 @@ <?xml version="1.0" encoding="utf-8"?> <resources> <style name="BasicButton"> - <item name="android:background">@drawable/abc_item_background_holo_light</item> + <item name="android:background">?attr/selectableItemBackgroundBorderless</item> + </style> + <style name="NotificationButton"> + <item name="android:background">?android:selectableItemBackground</item> + <item name="android:layout_width">46dip</item> + <item name="android:layout_height">fill_parent</item> + <item name="android:layout_gravity">center</item> + <item name="android:scaleType">fitCenter</item> + <item name="android:padding">2dip</item> + </style> + + <style name="NotificationButton.ExpandedBase"> + <item name="android:background">?android:selectableItemBackground</item> + <item name="android:layout_width">0dp</item> + <item name="android:layout_height">fill_parent</item> + <item name="android:layout_weight">1</item> + <item name="android:layout_gravity">center</item> + <item name="android:scaleType">fitCenter</item> + </style> + + <style name="NotificationButton.Expanded" parent="@style/NotificationButton.ExpandedBase"> + <item name="android:padding">10dip</item> + </style> + + <style name="NotificationText.Title" parent="@android:style/TextAppearance.StatusBar.EventContent.Title"></style> + <style name="NotificationText.Content" parent="@android:style/TextAppearance.StatusBar.EventContent"></style> + + <style name="NotificationLayoutDivider"> + <item name="android:divider">?android:listDivider</item> + </style> + <style name="NotificationDivider"> + <item name="android:background">?android:dividerHorizontal</item> </style> <style name="MoreButton" parent="BasicButton"> @@ -10,7 +41,6 @@ <style name="PlaybackControl" parent="@style/BasicButton"> <item name="android:scaleType">fitCenter</item> - <item name="android:padding">6dip</item> <item name="android:layout_marginLeft">4dip</item> <item name="android:layout_marginRight">4dip</item> <item name="android:layout_width">@dimen/Button</item> @@ -19,19 +49,25 @@ </style> <style name="PlaybackControl.Small" parent="@style/PlaybackControl"> - <item name="android:padding">4dip</item> <item name="android:layout_width">@dimen/Button.Small</item> <item name="android:layout_height">@dimen/Button.Small</item> </style> - - <style name="MenuBarButton" parent="@style/BasicButton"> - <item name="android:layout_width">0dip</item> - <item name="android:layout_height">45dip</item> - <item name="android:layout_weight">1</item> - <item name="android:textSize">14sp</item> - <item name="android:textStyle">bold</item> - <item name="android:textColor">?android:textColorPrimary</item> - </style> + + <style name="PlaybackControl.Large" parent="@style/PlaybackControl"> + <item name="android:layout_width">@dimen/Button.Large</item> + <item name="android:layout_height">@dimen/Button.Large</item> + </style> + + <style name="PlaybackControl.Match" parent="@style/PlaybackControl"> + <item name="android:layout_height">match_parent</item> + <item name="android:layout_width">wrap_content</item> + <item name="android:scaleType">fitCenter</item> + </style> + + <style name="PlaybackControl.BottomBar" parent="@style/PlaybackControl.Match"> + <item name="android:layout_width">0dp</item> + <item name="android:layout_weight">1</item> + </style> <style name="DownloadActionButton" parent="@style/BasicButton"> <item name="android:layout_width">wrap_content</item> @@ -52,44 +88,4 @@ <item name="android:paddingRight">16dip</item> <item name="android:paddingLeft">16dip</item> </style> - - <style name="DragDropListView"> - <item name="drag_enabled">true</item> - <item name="collapsed_height">1dp</item> - <item name="drag_scroll_start">1.0</item> - <item name="max_drag_scroll_speed">2.0</item> - <item name="float_alpha">0.6</item> - <item name="slide_shuffle_speed">0.3</item> - <item name="track_drag_sort">false</item> - <item name="use_default_controller">true</item> - <item name="drag_handle_id">@id/drag_handle</item> - <item name="sort_enabled">true</item> - <item name="remove_enabled">false</item> - <item name="remove_mode">flingRemove</item> - <item name="drag_start_mode">onLongPress</item> - <item name="float_background_color">@android:color/transparent</item> - </style> - - <style name="MainAlbumButton"> - <item name="android:drawablePadding">6dip</item> - <item name="android:layout_width">fill_parent</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:textAppearance">?android:attr/textAppearanceMedium</item> - <item name="android:gravity">center_vertical</item> - <item name="android:paddingLeft">6dip</item> - <item name="android:paddingRight">6dip</item> - <item name="android:minHeight">46dip</item> - </style> - - <style name="MainAlbumButtonLabel"> - <item name="android:layout_width">fill_parent</item> - <item name="android:layout_height">wrap_content</item> - <item name="android:textAppearance">?android:attr/textAppearanceSmall</item> - <item name="android:textColor">@color/cyan</item> - <item name="android:gravity">center_vertical</item> - <item name="android:paddingLeft">6dp</item> - <item name="android:textAllCaps">true</item> - <item name="android:textStyle">bold</item> - <item name="android:textSize">16sp</item> - </style> </resources>
\ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 78a2c34d..357ecdec 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,54 +1,82 @@ <?xml version="1.0" encoding="utf-8"?> <resources> - <style name="Theme.DSub.Light" parent="@style/Theme.AppCompat.Light"> - <item name="actionBarStyle">@style/Widget.DSub.ActionBarStyle.Light</item> - <item name="android:actionBarStyle">@style/Widget.DSub.ActionBarStyle.Light</item> + <style name="Theme.DSub.Light.Base" parent="@style/Theme.AppCompat.Light.DarkActionBar"> <item name="offline_icon">@drawable/main_offline_light</item> <item name="media_button_backward">@drawable/media_backward_light</item> <item name="media_button_forward">@drawable/media_forward_light</item> <item name="media_button_pause">@drawable/media_pause_light</item> <item name="media_button_repeat_off">@drawable/media_repeat_off_light</item> + <item name="media_button_repeat_single">@drawable/media_repeat_single_light</item> + <item name="media_button_repeat_all">@drawable/media_repeat_all_light</item> <item name="media_button_start">@drawable/media_start_light</item> <item name="media_button_stop">@drawable/media_stop_light</item> + <item name="actionbar_backward">@drawable/media_backward_dark</item> + <item name="actionbar_forward">@drawable/media_forward_dark</item> + <item name="actionbar_pause">@drawable/media_pause_dark</item> + <item name="actionbar_start">@drawable/media_start_dark</item> + <item name="actionbar_stop">@drawable/media_stop_dark</item> <item name="chat_send">@drawable/ic_menu_chat_send_light</item> - <item name="add">@drawable/ic_action_add_light</item> + <item name="add">@drawable/ic_action_add_dark</item> <item name="download_none">@drawable/download_none_light</item> - <item name="shuffle">@drawable/ic_menu_shuffle_light</item> - <item name="refresh">@drawable/ic_menu_refresh_light</item> - <item name="search">@drawable/ic_menu_search_light</item> - <item name="remove">@drawable/ic_menu_remove_light</item> - <item name="save">@drawable/ic_menu_save_light</item> + <item name="shuffle">@drawable/ic_menu_shuffle_dark</item> + <item name="shuffle_button">@drawable/ic_menu_shuffle_light</item> + <item name="refresh">@drawable/ic_menu_refresh_dark</item> + <item name="search">@drawable/ic_menu_search_dark</item> + <item name="remove">@drawable/ic_menu_remove_dark</item> + <item name="save">@drawable/ic_menu_save_dark</item> <item name="volume">@drawable/ic_action_volume_light</item> <item name="toggle_list">@drawable/action_toggle_list_light</item> <item name="select_server">@drawable/main_select_server_light</item> <item name="downloading">@drawable/downloading_light</item> <item name="bookmark">@drawable/ic_menu_bookmark_light</item> <item name="share">@drawable/ic_menu_share_light</item> - <item name="add_person">@drawable/ic_menu_add_person_light</item> - <item name="password">@drawable/ic_menu_password_light</item> + <item name="add_person">@drawable/ic_menu_add_person_dark</item> + <item name="password">@drawable/ic_menu_password_dark</item> <item name="rating_bad">@drawable/ic_action_rating_bad_light</item> <item name="rating_good">@drawable/ic_action_rating_good_light</item> - <item name="radio">@drawable/ic_menu_radio_light</item> - <item name="drawerItemsIcons">@array/drawerItemIconsLight</item> - <item name="android:textViewStyle">@style/DSub.TextViewStyle</item> - <item name="android:buttonStyle">@style/DSub.ButtonStyle.Light</item> + <item name="radio">@drawable/ic_menu_radio_dark</item> + <item name="star_outline">@drawable/ic_toggle_star_outline_light</item> + <item name="drawerHome">@drawable/main_offline_light</item> + <item name="drawerLibrary">@drawable/ic_menu_library_light</item> + <item name="drawerPlaylists">@drawable/ic_menu_playlist_light</item> + <item name="drawerPodcasts">@drawable/ic_menu_podcast_light</item> + <item name="drawerBookmarks">@drawable/ic_menu_bookmark_light</item> + <item name="drawerShares">@drawable/ic_menu_share_light</item> + <item name="drawerChat">@drawable/ic_menu_chat_light</item> + <item name="drawerAdmin">@drawable/ic_menu_admin_light</item> + <item name="drawerDownloading">@drawable/ic_menu_download_light</item> + <item name="drawerSettings">@drawable/ic_menu_settings_light</item> <item name="drawerArrowStyle">@style/DSub.DrawerArrow</item> - <item name="colorAccent">@color/cyan</item> + <item name="colorPrimary">@color/lightPrimary</item> + <item name="colorPrimaryDark">@color/lightPrimaryDark</item> + <item name="colorAccent">@color/lightAccent</item> + <item name="actionbarTitleStyle">@style/TextAppearance.AppCompat.Widget.ActionBar.Title.Inverse</item> + <item name="actionbarSubtitleStyle">@style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle.Inverse</item> + <item name="actionbarPopupStyle">@style/ThemeOverlay.AppCompat.Light</item> + <item name="android:spinnerItemStyle">@style/DarkSpinnerItem</item> + <item name="windowActionModeOverlay">true</item> + <item name="actionModeBackground">?attr/colorPrimary</item> </style> - <style name="Theme.DSub.Dark" parent="@style/Theme.AppCompat"> - <item name="actionBarStyle">@style/Widget.DSub.ActionBarStyle.Dark</item> - <item name="android:actionBarStyle">@style/Widget.DSub.ActionBarStyle.Dark</item> + <style name="Theme.DSub.Dark.Base" parent="@style/Theme.AppCompat"> <item name="offline_icon">@drawable/main_offline_dark</item> <item name="media_button_backward">@drawable/media_backward_dark</item> <item name="media_button_forward">@drawable/media_forward_dark</item> <item name="media_button_pause">@drawable/media_pause_dark</item> - <item name="media_button_repeat_off">@drawable/media_repeat_off</item> + <item name="media_button_repeat_off">@drawable/media_repeat_off_dark</item> + <item name="media_button_repeat_single">@drawable/media_repeat_single_dark</item> + <item name="media_button_repeat_all">@drawable/media_repeat_all_dark</item> <item name="media_button_start">@drawable/media_start_dark</item> <item name="media_button_stop">@drawable/media_stop_dark</item> + <item name="actionbar_backward">@drawable/media_backward_dark</item> + <item name="actionbar_forward">@drawable/media_forward_dark</item> + <item name="actionbar_pause">@drawable/media_pause_dark</item> + <item name="actionbar_start">@drawable/media_start_dark</item> + <item name="actionbar_stop">@drawable/media_stop_dark</item> <item name="chat_send">@drawable/ic_menu_chat_send_dark</item> <item name="add">@drawable/ic_action_add_dark</item> <item name="download_none">@drawable/download_none_dark</item> <item name="shuffle">@drawable/ic_menu_shuffle_dark</item> + <item name="shuffle_button">@drawable/ic_menu_shuffle_dark</item> <item name="refresh">@drawable/ic_menu_refresh_dark</item> <item name="search">@drawable/ic_menu_search_dark</item> <item name="remove">@drawable/ic_menu_remove_dark</item> @@ -64,46 +92,63 @@ <item name="rating_bad">@drawable/ic_action_rating_bad_dark</item> <item name="rating_good">@drawable/ic_action_rating_good_dark</item> <item name="radio">@drawable/ic_menu_radio_dark</item> - <item name="drawerItemsIcons">@array/drawerItemIconsDark</item> - <item name="android:textViewStyle">@style/DSub.TextViewStyle</item> - <item name="android:buttonStyle">@style/DSub.ButtonStyle.Dark</item> + <item name="star_outline">@drawable/ic_toggle_star_outline_dark</item> + <item name="drawerHome">@drawable/main_offline_dark</item> + <item name="drawerLibrary">@drawable/ic_menu_library_dark</item> + <item name="drawerPlaylists">@drawable/ic_menu_playlist_dark</item> + <item name="drawerPodcasts">@drawable/ic_menu_podcast_dark</item> + <item name="drawerBookmarks">@drawable/ic_menu_bookmark_dark</item> + <item name="drawerShares">@drawable/ic_menu_share_dark</item> + <item name="drawerChat">@drawable/ic_menu_chat_dark</item> + <item name="drawerAdmin">@drawable/ic_menu_admin_dark</item> + <item name="drawerDownloading">@drawable/ic_menu_download_dark</item> + <item name="drawerSettings">@drawable/ic_menu_settings_dark</item> <item name="drawerArrowStyle">@style/DSub.DrawerArrow</item> - <item name="colorAccent">@color/cyan</item> + <item name="colorPrimary">@color/lightPrimary</item> + <item name="colorPrimaryDark">@color/lightPrimaryDark</item> + <item name="colorAccent">@color/lightAccent</item> + <item name="actionbarTitleStyle">@style/TextAppearance.AppCompat.Widget.ActionBar.Title</item> + <item name="actionbarSubtitleStyle">@style/TextAppearance.AppCompat.Widget.ActionBar.Subtitle</item> + <item name="actionbarPopupStyle">@style/ThemeOverlay.AppCompat.Dark</item> + <item name="windowActionModeOverlay">true</item> + <item name="actionModeBackground">?attr/colorPrimary</item> + </style> + <style name="Theme.DSub.Light" parent="Theme.DSub.Light.Base"> + </style> + <style name="Theme.DSub.Dark" parent="Theme.DSub.Dark.Base"> </style> <style name="Theme.DSub.Black" parent="Theme.DSub.Dark"> <item name="android:windowBackground">@android:color/black</item> </style> <style name="Theme.DSub.Holo" parent="Theme.DSub.Dark"> <item name="android:windowBackground">@drawable/background</item> - </style> - - <style name="Widget.DSub.ActionBarStyle.Light" parent="Widget.AppCompat.Light.ActionBar.Solid"> - <item name="background">@android:color/transparent</item> - <item name="android:background">@android:color/transparent</item> - <item name="backgroundStacked">@android:color/transparent</item> - <item name="android:backgroundStacked">@android:color/transparent</item> + <item name="colorPrimary">@color/holoPrimary</item> + <item name="colorPrimaryDark">@color/holoPrimaryDark</item> + <item name="colorAccent">@color/holoAccent</item> </style> - <style name="Widget.DSub.ActionBarStyle.Dark" parent="Widget.AppCompat.ActionBar.Solid"> - <item name="background">@android:color/transparent</item> - <item name="android:background">@android:color/transparent</item> - <item name="backgroundStacked">@android:color/transparent</item> - <item name="android:backgroundStacked">@android:color/transparent</item> + <style name="Theme.DSub.Light.No_Actionbar" parent="Theme.DSub.Light"> + <item name="windowActionBar">false</item> + <item name="windowNoTitle">true</item> </style> - - <style name="DSub.TextViewStyle" parent="android:Widget.TextView"> + <style name="Theme.DSub.Black.No_Actionbar" parent="Theme.DSub.Black"> + <item name="windowActionBar">false</item> + <item name="windowNoTitle">true</item> </style> - - <style name="DSub.TextViewStyle.Bold" parent="android:Widget.TextView"> - <item name="android:textStyle">bold</item> + <style name="Theme.DSub.Dark.No_Actionbar" parent="Theme.DSub.Dark"> + <item name="windowActionBar">false</item> + <item name="windowNoTitle">true</item> </style> - - <style name="DSub.ButtonStyle.Dark" parent="android:Widget.Holo.Button"> - </style> - <style name="DSub.ButtonStyle.Light" parent="android:Widget.Holo.Light.Button"> + <style name="Theme.DSub.Holo.No_Actionbar" parent="Theme.DSub.Holo"> + <item name="windowActionBar">false</item> + <item name="windowNoTitle">true</item> </style> <style name="DSub.DrawerArrow" parent="Widget.AppCompat.DrawerArrowToggle"> <item name="spinBars">true</item> </style> + + <style name="DarkSpinnerItem" parent="Widget.AppCompat.TextView.SpinnerItem"> + <item name="android:textColor">?android:attr/textColorPrimaryInverse</item> + </style> </resources> diff --git a/app/src/main/res/xml/changelog.xml b/app/src/main/res/xml/changelog.xml index 572c1d5b..77239b1a 100644 --- a/app/src/main/res/xml/changelog.xml +++ b/app/src/main/res/xml/changelog.xml @@ -1,5 +1,36 @@ <?xml version="1.0" encoding="utf-8"?> <changelog> + <release version="5.0 Beta 2" versioncode="154" releasedate="8/21/2015"> + <change>Toggle offline from Drawer</change> + <change>Put some context items back</change> + <change>Fast scrollings returns</change> + <change>Updated more icons</change> + <change>Updated notification on Lolipop</change> + <change>Fix podcast multiselect</change> + <change>Misc bug fixes</change> + </release> + <release version="5.0 Beta 1" versioncode="153" releasedate="7/31/2015"> + <change>Moderate Material Update</change> + <change>Rewrote everything to use RecyclerView</change> + <change>Swiped up playing bar</change> + <change>Swiped to remove from current playing list</change> + <change>Colored status bar</change> + <change>Updated drawer</change> + <change>Select server from drawer</change> + <change>Playlists with album art</change> + <change>Separate sections for mine vs shared playlists</change> + <change>Paired down context menus</change> + <change>Long select to multiselect songs/albums</change> + <change>Updated search to look like the rest of the app</change> + <change>Some stuff colored based on theme (more to follow)</change> + <change>Better looking detail dialogs</change> + <change>Performance enhancements from changing to event driven instead of polling</change> + <change>Sleep time remaining</change> + <change>Add Permanent Cached song count to About dialog</change> + <change>Option to keep 0, 1, 2, or 3 past songs in list</change> + <change>Updated icon</change> + <change>Removed support for Android 2.3</change> + </release> <release version="4.9.7" versioncode="152" releasedate="5/8/2015"> <change>Lazy load artist bio information</change> <change>Keep previous search in bar when searching again</change> diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml index b23825bf..078ccbeb 100644 --- a/app/src/main/res/xml/settings.xml +++ b/app/src/main/res/xml/settings.xml @@ -42,7 +42,7 @@ android:title="@string/settings.track_title" android:summary="@string/settings.track_summary" android:key="displayTrack" - android:defaultValue="false"/> + android:defaultValue="true"/> <CheckBoxPreference android:title="@string/settings.hide_widget_title" @@ -365,7 +365,7 @@ android:title="@string/settings.play_now_after" android:summary="@string/settings.play_now_after_summary" android:key="playNowAfter" - android:defaultValue="false"/> + android:defaultValue="true"/> </PreferenceCategory> <PreferenceCategory @@ -374,7 +374,7 @@ <ListPreference android:title="@string/settings.video_player" android:key="videoPlayer" - android:defaultValue="raw" + android:defaultValue="hls" android:entryValues="@array/videoPlayerValues" android:entries="@array/videoPlayerNames"/> </PreferenceCategory> |