Added new IntroActivity.

This commit is contained in:
Karim Abou Zeid 2016-02-21 18:20:35 +01:00
commit f4680fdb44
11 changed files with 293 additions and 107 deletions

View file

@ -140,8 +140,8 @@ dependencies {
//noinspection GradleDynamicVersion //noinspection GradleDynamicVersion
compile 'com.anjlab.android.iab.v3:library:1.0.+' 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'
compile 'com.github.bumptech.glide:glide:3.7.0' compile 'com.github.bumptech.glide:glide:3.7.0'
compile 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar' compile 'com.github.bumptech.glide:okhttp3-integration:1.4.0@aar'
compile 'com.github.kabouzeid:RecyclerView-FastScroll:v1.6-kmod' compile 'com.github.kabouzeid:RecyclerView-FastScroll:v1.6-kmod'
compile 'com.heinrichreimersoftware:material-intro:1.0'
} }

View file

@ -149,7 +149,8 @@
android:label="@string/action_about" /> android:label="@string/action_about" />
<activity <activity
android:name=".ui.activities.IntroActivity" android:theme="@style/Theme.Intro"
android:name=".ui.activities.intro.AppIntroActivity"
android:label="@string/intro_label" /> android:label="@string/intro_label" />
</application> </application>

View file

@ -2,6 +2,7 @@ package com.kabouzeid.gramophone.dialogs;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Dialog; import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
@ -56,13 +57,8 @@ public class ChangelogDialog extends DialogFragment {
.showListener(new DialogInterface.OnShowListener() { .showListener(new DialogInterface.OnShowListener() {
@Override @Override
public void onShow(DialogInterface dialog) { public void onShow(DialogInterface dialog) {
try { if (getActivity() != null)
PackageInfo pInfo = getActivity().getPackageManager().getPackageInfo(getActivity().getPackageName(), 0); setChangelogRead(getActivity());
int currentVersion = pInfo.versionCode;
PreferenceUtil.getInstance(getActivity()).setLastChangeLogVersion(currentVersion);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
} }
}) })
.build(); .build();
@ -93,6 +89,16 @@ public class ChangelogDialog extends DialogFragment {
return dialog; return dialog;
} }
public static void setChangelogRead(@NonNull Context context) {
try {
PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
int currentVersion = pInfo.versionCode;
PreferenceUtil.getInstance(context).setLastChangeLogVersion(currentVersion);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
private static String colorToHex(int color) { private static String colorToHex(int color) {
return Integer.toHexString(color).substring(2); return Integer.toHexString(color).substring(2);
} }

View file

@ -23,6 +23,7 @@ import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.dialogs.ChangelogDialog; import com.kabouzeid.gramophone.dialogs.ChangelogDialog;
import com.kabouzeid.gramophone.dialogs.DonationDialog; import com.kabouzeid.gramophone.dialogs.DonationDialog;
import com.kabouzeid.gramophone.ui.activities.base.AbsBaseActivity; import com.kabouzeid.gramophone.ui.activities.base.AbsBaseActivity;
import com.kabouzeid.gramophone.ui.activities.intro.AppIntroActivity;
import butterknife.Bind; import butterknife.Bind;
import butterknife.ButterKnife; import butterknife.ButterKnife;
@ -224,7 +225,7 @@ public class AboutActivity extends AbsBaseActivity implements View.OnClickListen
} else if (v == licenses) { } else if (v == licenses) {
showLicenseDialog(); showLicenseDialog();
} else if (v == intro) { } else if (v == intro) {
startActivity(new Intent(this, IntroActivity.class)); startActivity(new Intent(this, AppIntroActivity.class));
} else if (v == addToGooglePlusCircles) { } else if (v == addToGooglePlusCircles) {
openUrl(GOOGLE_PLUS); openUrl(GOOGLE_PLUS);
} else if (v == followOnTwitter) { } else if (v == followOnTwitter) {

View file

@ -1,81 +0,0 @@
package com.kabouzeid.gramophone.ui.activities;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.content.ContextCompat;
import android.widget.Toast;
import com.github.paolorotolo.appintro.AppIntro;
import com.github.paolorotolo.appintro.AppIntroFragment;
import com.kabouzeid.appthemehelper.ATH;
import com.kabouzeid.appthemehelper.util.ColorUtil;
import com.kabouzeid.gramophone.R;
import com.kabouzeid.gramophone.util.PreferenceUtil;
/**
* @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);
ATH.setStatusbarColor(this, ColorUtil.darkenColor(color));
ATH.setTaskDescriptionColor(this, color);
showSkipButton(false);
setDoneText(getString(R.string.action_done).toUpperCase());
setGrantText(getString(R.string.action_grant).toUpperCase());
addSlide(AppIntroFragment.newInstance(getString(R.string.app_name), getString(R.string.welcome_to_phonograph), R.drawable.icon_web, color));
if (!hasExternalStoragePermission()) {
addSlide(AppIntroFragment.newInstance(getString(R.string.label_storage), getString(R.string.storage_permission_explaination), 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_playing_queue), getString(R.string.open_playing_queue_instruction), R.drawable.tutorial_queue_swipe_up, color));
addSlide(AppIntroFragment.newInstance(getString(R.string.label_playing_queue), getString(R.string.rearrange_playing_queue_instruction), R.drawable.tutorial_rearrange_queue, 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;
}
boolean doubleBackToExitPressedOnce = false;
@Override
public void onBackPressed() {
if (doubleBackToExitPressedOnce) {
onSkipPressed();
return;
}
doubleBackToExitPressedOnce = true;
Toast.makeText(this, R.string.press_back_again_to_exit_intro, Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
doubleBackToExitPressedOnce = false;
}
}, 2000);
}
@Override
public void onSkipPressed() {
super.onSkipPressed();
PreferenceUtil.getInstance(this).setIntroShown();
}
@Override
public void onDonePressed() {
super.onDonePressed();
PreferenceUtil.getInstance(this).setIntroShown();
}
}

View file

@ -56,6 +56,7 @@ import com.kabouzeid.gramophone.loader.SongLoader;
import com.kabouzeid.gramophone.model.Song; import com.kabouzeid.gramophone.model.Song;
import com.kabouzeid.gramophone.service.MusicService; import com.kabouzeid.gramophone.service.MusicService;
import com.kabouzeid.gramophone.ui.activities.base.AbsSlidingMusicPanelActivity; import com.kabouzeid.gramophone.ui.activities.base.AbsSlidingMusicPanelActivity;
import com.kabouzeid.gramophone.ui.activities.intro.AppIntroActivity;
import com.kabouzeid.gramophone.ui.fragments.mainactivityfragments.AbsMainActivityFragment; import com.kabouzeid.gramophone.ui.fragments.mainactivityfragments.AbsMainActivityFragment;
import com.kabouzeid.gramophone.ui.fragments.mainactivityfragments.AbsMainActivityRecyclerViewCustomGridSizeFragment; import com.kabouzeid.gramophone.ui.fragments.mainactivityfragments.AbsMainActivityRecyclerViewCustomGridSizeFragment;
import com.kabouzeid.gramophone.util.NavigationUtil; import com.kabouzeid.gramophone.util.NavigationUtil;
@ -94,7 +95,7 @@ public class MainActivity extends AbsSlidingMusicPanelActivity
private PagerAdapter pagerAdapter; private PagerAdapter pagerAdapter;
private MaterialCab cab; private MaterialCab cab;
private boolean introActivityHandlingPermissions; private boolean blockRequestPermissions;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -116,17 +117,18 @@ public class MainActivity extends AbsSlidingMusicPanelActivity
setUpToolbar(); setUpToolbar();
setUpViewPager(); setUpViewPager();
checkChangelog();
if (!PreferenceUtil.getInstance(this).introShown()) { if (!PreferenceUtil.getInstance(this).introShown()) {
// let the app intro handle getting the permissions first PreferenceUtil.getInstance(this).setIntroShown();
introActivityHandlingPermissions = true; ChangelogDialog.setChangelogRead(this);
blockRequestPermissions = true;
new Handler().postDelayed(new Runnable() { new Handler().postDelayed(new Runnable() {
@Override @Override
public void run() { public void run() {
startActivityForResult(new Intent(MainActivity.this, IntroActivity.class), APP_INTRO_REQUEST); startActivityForResult(new Intent(MainActivity.this, AppIntroActivity.class), APP_INTRO_REQUEST);
} }
}, 200); }, 200);
} else {
checkShowChangelog();
} }
} }
@ -134,16 +136,16 @@ public class MainActivity extends AbsSlidingMusicPanelActivity
protected void onActivityResult(int requestCode, int resultCode, Intent data) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
if (requestCode == APP_INTRO_REQUEST) { if (requestCode == APP_INTRO_REQUEST) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { blockRequestPermissions = false;
// app intro is done, recreate to refresh permissions if (!hasPermissions()) {
onPermissionsChanged(); requestPermissions();
} }
} }
} }
@Override @Override
protected void requestPermissions() { protected void requestPermissions() {
if (!introActivityHandlingPermissions) super.requestPermissions(); if (!blockRequestPermissions) super.requestPermissions();
} }
@Override @Override
@ -574,7 +576,7 @@ public class MainActivity extends AbsSlidingMusicPanelActivity
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
} }
private void checkChangelog() { private void checkShowChangelog() {
try { try {
PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0); PackageInfo pInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
int currentVersion = pInfo.versionCode; int currentVersion = pInfo.versionCode;

View file

@ -58,16 +58,20 @@ public abstract class AbsBaseActivity extends AbsThemeActivity implements KabVie
if (hasPermissions() != createdWithPermissionsGranted) { if (hasPermissions() != createdWithPermissionsGranted) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// the handler is necessary to avoid "java.lang.RuntimeException: Performing pause of activity that is not resumed"
onPermissionsChanged(); onPermissionsChanged();
} }
} }
} }
protected void onPermissionsChanged() { protected void onPermissionsChanged() {
postRecreate();
}
@Override
public void postRecreate() {
if (!recreating) { if (!recreating) {
recreating = true; recreating = true;
postRecreate(); super.postRecreate();
} }
} }
@ -86,7 +90,7 @@ public abstract class AbsBaseActivity extends AbsThemeActivity implements KabVie
/** /**
* Should be overwritten and re enable all {@link android.view.View} to ensure they are accessible again * Should be overwritten and re enable all {@link android.view.View} to ensure they are accessible again
* <p> * <p/>
* This is necessary because of a bug with the shared element transition * This is necessary because of a bug with the shared element transition
*/ */
@Override @Override
@ -96,7 +100,7 @@ public abstract class AbsBaseActivity extends AbsThemeActivity implements KabVie
/** /**
* Should be overwritten and disable all views that start a new activity on click to prevent opening an activity multiple times * Should be overwritten and disable all views that start a new activity on click to prevent opening an activity multiple times
* <p> * <p/>
* This is necessary because of a bug with the shared element transition * This is necessary because of a bug with the shared element transition
*/ */
@Override @Override

View file

@ -0,0 +1,60 @@
package com.kabouzeid.gramophone.ui.activities.intro;
import android.Manifest;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import com.kabouzeid.gramophone.R;
/**
* @author Karim Abou Zeid (kabouzeid)
*/
public class AppIntroActivity extends com.heinrichreimersoftware.materialintro.app.IntroActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
setFullscreen(false);
super.onCreate(savedInstanceState);
addSlide(new PhonographSimpleSlide.Builder()
.title(R.string.app_name)
.description(R.string.welcome_to_phonograph)
.image(R.drawable.icon_web)
.background(R.color.md_blue_grey_500)
.backgroundDark(R.color.md_blue_grey_600)
.build());
addSlide(new PhonographSimpleSlide.Builder()
.title(R.string.label_playing_queue)
.description(R.string.open_playing_queue_instruction)
.image(R.drawable.tutorial_queue_swipe_up)
.background(R.color.md_purple_500)
.backgroundDark(R.color.md_purple_600)
.build());
addSlide(new PhonographSimpleSlide.Builder()
.title(R.string.label_playing_queue)
.description(R.string.rearrange_playing_queue_instruction)
.image(R.drawable.tutorial_rearrange_queue)
.background(R.color.md_deep_purple_500)
.backgroundDark(R.color.md_deep_purple_600)
.build());
if (!hasExternalStoragePermission()) {
addSlide(new PhonographSimpleSlide.Builder()
.title(R.string.label_storage)
.description(R.string.storage_permission_explaination)
.image(R.drawable.ic_folder_web)
.background(R.color.md_indigo_500)
.backgroundDark(R.color.md_indigo_600)
.build());
}
}
private boolean hasExternalStoragePermission() {
//noinspection SimplifiableIfStatement
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;
}
}

View file

@ -0,0 +1,151 @@
package com.kabouzeid.gramophone.ui.activities.intro;
import android.os.Bundle;
import android.support.annotation.ColorRes;
import android.support.annotation.DrawableRes;
import android.support.annotation.StringRes;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.ColorUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.heinrichreimersoftware.materialintro.slide.Slide;
import com.kabouzeid.gramophone.R;
public class PhonographSimpleSlide extends Slide {
private final Fragment fragment;
@ColorRes
private final int background;
@ColorRes
private final int backgroundDark;
private PhonographSimpleSlide(Builder builder) {
fragment = Fragment.newInstance(builder.title, builder.description, builder.image, builder.background);
background = builder.background;
backgroundDark = builder.backgroundDark;
}
@Override
public Fragment getFragment() {
return fragment;
}
@Override
public int getBackground() {
return background;
}
@Override
public int getBackgroundDark() {
return backgroundDark;
}
public static class Builder {
@ColorRes
private int background = 0;
@ColorRes
private int backgroundDark = 0;
@StringRes
private int title = 0;
@StringRes
private int description = 0;
@DrawableRes
private int image = 0;
public Builder background(int background) {
this.background = background;
return this;
}
public Builder backgroundDark(int backgroundDark) {
this.backgroundDark = backgroundDark;
return this;
}
public Builder title(int title) {
this.title = title;
return this;
}
public Builder description(int description) {
this.description = description;
return this;
}
public Builder image(int image) {
this.image = image;
return this;
}
public PhonographSimpleSlide build() {
if (background == 0 || title == 0)
throw new IllegalArgumentException("You must set at least a title and background.");
return new PhonographSimpleSlide(this);
}
}
public static class Fragment extends android.support.v4.app.Fragment {
private static final String ARGUMENT_TITLE_RES =
"com.kabouzeid.gramophone.SimpleFragment.ARGUMENT_TITLE_RES";
private static final String ARGUMENT_DESCRIPTION_RES =
"com.kabouzeid.gramophone.SimpleFragment.ARGUMENT_DESCRIPTION_RES";
private static final String ARGUMENT_IMAGE_RES =
"com.kabouzeid.gramophone.SimpleFragment.ARGUMENT_IMAGE_RES";
private static final String ARGUMENT_BACKGROUND_RES =
"com.kabouzeid.gramophone.SimpleFragment.ARGUMENT_BACKGROUND_RES";
public static Fragment newInstance(@StringRes int title, @StringRes int description, @DrawableRes int image, @ColorRes int background) {
Fragment fragment = new Fragment();
Bundle arguments = new Bundle();
arguments.putInt(ARGUMENT_TITLE_RES, title);
arguments.putInt(ARGUMENT_DESCRIPTION_RES, description);
arguments.putInt(ARGUMENT_IMAGE_RES, image);
arguments.putInt(ARGUMENT_BACKGROUND_RES, background);
fragment.setArguments(arguments);
return fragment;
}
public Fragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View fragment = inflater.inflate(R.layout.fragment_intro_slide, container, false);
TextView title = (TextView) fragment.findViewById(R.id.mi_title);
TextView description = (TextView) fragment.findViewById(R.id.mi_description);
ImageView image = (ImageView) fragment.findViewById(R.id.mi_image);
Bundle arguments = getArguments();
title.setText(arguments.getInt(ARGUMENT_TITLE_RES));
description.setText(arguments.getInt(ARGUMENT_DESCRIPTION_RES));
image.setImageResource(arguments.getInt(ARGUMENT_IMAGE_RES));
int background = ContextCompat.getColor(getContext(),
arguments.getInt(ARGUMENT_BACKGROUND_RES));
if (ColorUtils.calculateLuminance(background) > 0.4) {
//Use dark text color
title.setTextColor(ContextCompat.getColor(getContext(),
R.color.mi_text_color_primary_light));
description.setTextColor(ContextCompat.getColor(getContext(),
R.color.mi_text_color_secondary_light));
} else {
//Use light text color
title.setTextColor(ContextCompat.getColor(getContext(),
R.color.mi_text_color_primary_dark));
description.setTextColor(ContextCompat.getColor(getContext(),
R.color.mi_text_color_secondary_dark));
}
return fragment;
}
}
}

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical"
android:padding="@dimen/mi_baseline">
<TextView
android:id="@id/mi_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/mi_baseline"
android:fontFamily="sans-serif-light"
android:gravity="center"
android:textAppearance="@style/TextAppearance.AppCompat.Display1"
tools:ignore="UnusedAttribute"
tools:text="Lorem ipsum" />
<TextView
android:id="@id/mi_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/mi_baseline"
android:gravity="center"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
tools:text="Lorem ipsum dolor sit amet, consectetur, adipisci velit, …" />
<ImageView
android:id="@id/mi_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/mi_baseline"
android:gravity="center"
tools:ignore="ContentDescription"
android:paddingBottom="@dimen/mi_pager_margin_bottom"
tools:src="@drawable/tutorial_queue_swipe_up" />
</LinearLayout>

View file

@ -231,7 +231,7 @@
<string name="label_storage">Storage</string> <string name="label_storage">Storage</string>
<string name="open_playing_queue_instruction">Swipe the card in the now playing screen up to reveal the full playing queue.</string> <string name="open_playing_queue_instruction">Swipe the card in the now playing screen up to reveal the full playing queue.</string>
<string name="rearrange_playing_queue_instruction">Rearrange the playing queue by dragging a song from its track number.</string> <string name="rearrange_playing_queue_instruction">Rearrange the playing queue by dragging a song from its track number.</string>
<string name="storage_permission_explaination">The storage permission is required for Phonograph to read your music library.</string> <string name="storage_permission_explaination">Phonograph will now ask you to grant the storage permission. The permission is required in order to read your music library.</string>
<string name="library">Library</string> <string name="library">Library</string>
<string name="folders">Folders</string> <string name="folders">Folders</string>
<string name="saved_playlist_to">Saved playlist to %s.</string> <string name="saved_playlist_to">Saved playlist to %s.</string>