diff --git a/app/build.gradle b/app/build.gradle index 793a76f1..19896c91 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -132,5 +132,6 @@ dependencies { compile 'org.solovyev.android.views:linear-layout-manager:0.5@aar' //noinspection GradleDynamicVersion compile 'com.anjlab.android.iab.v3:library:1.0.+' - compile('de.psdev.licensesdialog:licensesdialog:1.8.0') + compile 'de.psdev.licensesdialog:licensesdialog:1.8.0' + compile 'com.github.kabouzeid:AppIntro:3.3.0k' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 972cc9d9..def6e912 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -139,6 +139,10 @@ + + diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/IntroActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/IntroActivity.java new file mode 100644 index 00000000..b78643a8 --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/IntroActivity.java @@ -0,0 +1,37 @@ +package com.kabouzeid.gramophone.ui.activities; + +import android.Manifest; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Bundle; +import android.support.v4.content.ContextCompat; + +import com.github.paolorotolo.appintro.AppIntro; +import com.github.paolorotolo.appintro.AppIntroFragment; +import com.kabouzeid.gramophone.R; +import com.kabouzeid.gramophone.util.ColorUtil; + +/** + * @author Karim Abou Zeid (kabouzeid) + */ +public class IntroActivity extends AppIntro { + @Override + public void init(Bundle savedInstanceState) { + int color = ContextCompat.getColor(this, R.color.blue_grey_700); + setStatusBarColor(ColorUtil.shiftColorDown(color)); + + addSlide(AppIntroFragment.newInstance(getString(R.string.app_name), "Welcome to Phonograph, a beautiful and lightweight music player for Android. ", R.drawable.icon_web, color)); + if (!hasExternalStoragePermission()) { + addSlide(AppIntroFragment.newInstance("Storage", "The storage permission is required for Phonograph to read your music library.", R.drawable.ic_folder_web, color)); + askForPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1); + } + addSlide(AppIntroFragment.newInstance(getString(R.string.label_current_playing_queue), "You can swipe the card in the now playing screen up to reveal to full playing queue.", R.drawable.intro_swipe_up, color)); + } + + private boolean hasExternalStoragePermission() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + return checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED && checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED; + } + return true; + } +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java index 30bc464d..f8eeafb7 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/MainActivity.java @@ -114,6 +114,17 @@ public class MainActivity extends AbsSlidingMusicPanelActivity setStatusBarThemeColor(); checkChangelog(); + + PreferenceUtil.getInstance(this).incrementAppOpenCount(); + + new Thread(new Runnable() { + @Override + public void run() { + if (PreferenceUtil.getInstance(MainActivity.this).getAppOpenCount() == 1) { + startActivity(new Intent(MainActivity.this, IntroActivity.class)); + } + } + }).start(); } @Override diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsBaseActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsBaseActivity.java index 313fa262..450ccb1f 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsBaseActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/base/AbsBaseActivity.java @@ -8,9 +8,11 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; +import android.support.design.widget.Snackbar; import android.view.KeyEvent; -import android.widget.Toast; +import android.view.View; +import com.afollestad.materialdialogs.internal.ThemeSingleton; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.interfaces.KabViewsDisableAble; @@ -28,7 +30,7 @@ public abstract class AbsBaseActivity extends AbsThemeActivity implements KabVie protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setVolumeControlStream(AudioManager.STREAM_MUSIC); - checkExternalStoragePermissions(); + hasExternalStoragePermission = hasExternalStoragePermission(); } @Override @@ -36,13 +38,17 @@ public abstract class AbsBaseActivity extends AbsThemeActivity implements KabVie super.onResume(); enableViews(); - // the handler is necessary to avoid "java.lang.RuntimeException: Performing pause of activity that is not resumed" - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - recreateIfPermissionsChanged(); - } - }, 200); + if (!hasExternalStoragePermission()) { + requestPermissions(); + } else if (didPermissionsChanged()) { + // the handler is necessary to avoid "java.lang.RuntimeException: Performing pause of activity that is not resumed" + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + recreate(); + } + }, 200); + } } @Override @@ -83,22 +89,13 @@ public abstract class AbsBaseActivity extends AbsThemeActivity implements KabVie return areViewsEnabled; } - protected void recreateIfPermissionsChanged() { - if (didPermissionsChanged()) { - recreate(); - } - } - private boolean didPermissionsChanged() { return hasExternalStoragePermission != hasExternalStoragePermission(); } - private void checkExternalStoragePermissions() { - hasExternalStoragePermission = hasExternalStoragePermission(); - if (!hasExternalStoragePermission) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_EXTERNAL_STORAGE_PERMISSION); - } + private void requestPermissions() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_EXTERNAL_STORAGE_PERMISSION); } } @@ -117,7 +114,17 @@ public abstract class AbsBaseActivity extends AbsThemeActivity implements KabVie return; } } - Toast.makeText(this, getResources().getString(R.string.permission_to_access_external_storage_denied), Toast.LENGTH_SHORT).show(); + Snackbar.make(getWindow().getDecorView(), R.string.permission_to_access_external_storage_denied, Snackbar.LENGTH_INDEFINITE) + .setAction(getString(R.string.action_settings), onGoToPermissionSettingsClickListener) + .setActionTextColor(ThemeSingleton.get().positiveColor) + .show(); } } + + private View.OnClickListener onGoToPermissionSettingsClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + //TODO + } + }; } diff --git a/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtil.java b/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtil.java index d6e9bd03..9f302d27 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtil.java +++ b/app/src/main/java/com/kabouzeid/gramophone/util/PreferenceUtil.java @@ -62,6 +62,8 @@ public final class PreferenceUtil { public static final String LAST_CHANGELOG_VERSION = "last_changelog_version"; + public static final String APP_OPEN_COUNT = "app_open_count"; + private static PreferenceUtil sInstance; private final SharedPreferences mPreferences; @@ -361,4 +363,12 @@ public final class PreferenceUtil { public final int getLastChangelogVersion() { return mPreferences.getInt(LAST_CHANGELOG_VERSION, -1); } + + public void incrementAppOpenCount() { + mPreferences.edit().putInt(APP_OPEN_COUNT, getAppOpenCount() + 1).apply(); + } + + public final int getAppOpenCount() { + return mPreferences.getInt(APP_OPEN_COUNT, 0); + } } diff --git a/app/src/main/res/drawable-xxxhdpi/ic_folder_web.png b/app/src/main/res/drawable-xxxhdpi/ic_folder_web.png new file mode 100644 index 00000000..ba79cecc Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_folder_web.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/icon_web.png b/app/src/main/res/drawable-xxxhdpi/icon_web.png new file mode 100644 index 00000000..5f9e782e Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/icon_web.png differ diff --git a/app/src/main/res/drawable-xxxhdpi/intro_swipe_up.png b/app/src/main/res/drawable-xxxhdpi/intro_swipe_up.png new file mode 100644 index 00000000..d9e2c11c Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/intro_swipe_up.png differ diff --git a/app/src/main/res/raw/notices.xml b/app/src/main/res/raw/notices.xml index 696ac003..0fd0a273 100644 --- a/app/src/main/res/raw/notices.xml +++ b/app/src/main/res/raw/notices.xml @@ -88,6 +88,12 @@ Copyright 2014 AnjLab Apache Software License 2.0 + + AppIntro + https://github.com/PaoloRotolo/AppIntro + Copyright {2015} {Paolo Rotolo} + Apache Software License 2.0 + Material Dialogs https://github.com/afollestad/material-dialogs diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 5be53518..6178831a 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -8,6 +8,8 @@ #424242 #E0E0E0 + #455A64 + #FFFFFF \ 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 32452ff3..9ef9cf3a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,6 +9,7 @@ Share "Settings" About + Show intro Clear playlist Playing queue Add to favorites @@ -212,4 +213,5 @@ Loading products… Up next Now playing layout + Intro diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 382b3953..dd509116 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip