diff --git a/app/build.gradle b/app/build.gradle index 4506cf0e..20814305 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -75,7 +75,6 @@ ext { dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) - testCompile 'junit:junit:4.12' compile "com.android.support:support-compat:$supportLibVersion" compile "com.android.support:support-core-utils:$supportLibVersion" @@ -94,19 +93,18 @@ dependencies { compile "com.android.support:preference-v7:$supportLibVersion" compile "com.android.support:preference-v14:$supportLibVersion" - compile 'com.crashlytics.sdk.android:crashlytics:2.6.7' +// compile 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.10.6' + // TODO: go back to master branch as soon as possible + compile 'com.crashlytics.sdk.android:crashlytics:2.6.7' compile 'com.github.kabouzeid:app-theme-helper:1.3.7' compile 'com.github.kabouzeid:RecyclerView-FastScroll:1.0.16-kmod' compile 'com.github.kabouzeid:SeekArc:1.2-kmod' compile 'com.github.kabouzeid:AndroidSlidingUpPanel:3.3.0-kmod3' - compile 'com.afollestad.material-dialogs:core:0.9.4.5' compile 'com.afollestad.material-dialogs:commons:0.9.4.5' compile 'com.afollestad:material-cab:0.1.12' - -// compile 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.10.6' - compile 'com.github.h6ah4i:android-advancedrecyclerview:feature~support_libraries_v26-SNAPSHOT' // TODO: go back to master branch as soon as possible + compile 'com.github.h6ah4i:android-advancedrecyclerview:feature~support_libraries_v26-SNAPSHOT' compile 'com.github.ksoichiro:android-observablescrollview:1.6.0' compile 'com.squareup.retrofit2:retrofit:2.3.0' compile 'com.squareup.retrofit2:converter-gson:2.3.0' @@ -117,7 +115,8 @@ dependencies { compile 'com.heinrichreimersoftware:material-intro:1.6.2' compile 'me.zhanghai.android.materialprogressbar:library:1.4.1' compile 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:2.1.5' - compile 'com.jakewharton:butterknife:8.6.0' + compile 'com.android.support.constraint:constraint-layout:+' + testCompile 'junit:junit:4.12' annotationProcessor 'com.jakewharton:butterknife-compiler:8.6.0' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d0c73348..d2f06caf 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ - + @@ -21,7 +21,6 @@ android:supportsRtl="true" android:theme="@style/Theme.Phonograph.Light" tools:ignore="UnusedAttribute"> - @@ -146,9 +145,9 @@ - + - + @@ -195,14 +194,15 @@ android:exported="false" android:label="@string/app_widget_card_name"> - + + android:resource="@xml/app_widget_card_info" /> + - + \ No newline at end of file diff --git a/app/src/main/java/com/kabouzeid/gramophone/App.java b/app/src/main/java/com/kabouzeid/gramophone/App.java index 27ffae41..106b59da 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/App.java +++ b/app/src/main/java/com/kabouzeid/gramophone/App.java @@ -49,7 +49,7 @@ public class App extends Application { @Override public void onPurchaseHistoryRestored() { - Toast.makeText(App.this, R.string.restored_previous_purchases_please_restart, Toast.LENGTH_LONG).show(); + Toast.makeText(App.this, R.string.restored_previous_purchase_please_restart, Toast.LENGTH_LONG).show(); } @Override @@ -63,7 +63,7 @@ public class App extends Application { } public static boolean isProVersion() { - return BuildConfig.DEBUG || app.billingProcessor.isPurchased(PRO_VERSION_PRODUCT_ID); + return app.billingProcessor.isPurchased(PRO_VERSION_PRODUCT_ID); } @Override diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/BuyDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/BuyDialog.java deleted file mode 100644 index 982e4366..00000000 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/BuyDialog.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.kabouzeid.gramophone.dialogs; - -import android.app.Dialog; -import android.content.Intent; -import android.os.AsyncTask; -import android.os.Build; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.app.DialogFragment; -import android.util.Log; -import android.widget.Toast; - -import com.afollestad.materialdialogs.DialogAction; -import com.afollestad.materialdialogs.MaterialDialog; -import com.afollestad.materialdialogs.internal.MDButton; -import com.anjlab.android.iab.v3.BillingProcessor; -import com.anjlab.android.iab.v3.SkuDetails; -import com.anjlab.android.iab.v3.TransactionDetails; -import com.kabouzeid.gramophone.App; -import com.kabouzeid.gramophone.BuildConfig; -import com.kabouzeid.gramophone.R; - -import java.lang.ref.WeakReference; - -/** - * @author Karim Abou Zeid (kabouzeid) - */ -public class BuyDialog extends DialogFragment implements BillingProcessor.IBillingHandler { - public static final String TAG = BuyDialog.class.getSimpleName(); - - private BillingProcessor billingProcessor; - - private AsyncTask skuDetailsLoadAsyncTask; - - public static BuyDialog create() { - return new BuyDialog(); - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - billingProcessor = new BillingProcessor(getContext(), App.GOOGLE_PLAY_LICENSE_KEY, this); - return new MaterialDialog.Builder(getContext()) - .title(R.string.buy_pro) - .content("Unlock all features, such as:\n• Folder view\n• All theme colors\n• Black theme\n• Sleep timer") - .positiveText(R.string.buy) - .onPositive(new MaterialDialog.SingleButtonCallback() { - @Override - public void onClick(@NonNull MaterialDialog materialDialog, @NonNull DialogAction dialogAction) { - billingProcessor.purchase(getActivity(), App.PRO_VERSION_PRODUCT_ID); - } - }) - .build(); - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (!billingProcessor.handleActivityResult(requestCode, resultCode, data)) { - super.onActivityResult(requestCode, resultCode, data); - } - } - - @Override - public void onProductPurchased(String productId, TransactionDetails details) { - loadSkuDetails(); - Toast.makeText(getContext(), R.string.thank_you, Toast.LENGTH_SHORT).show(); - } - - @Override - public void onPurchaseHistoryRestored() { - loadSkuDetails(); - Toast.makeText(getContext(), R.string.restored_previous_purchases_please_restart, Toast.LENGTH_LONG).show(); - } - - @Override - public void onBillingError(int errorCode, Throwable error) { - Log.e(TAG, "Billing error: code = " + errorCode, error); - } - - @Override - public void onBillingInitialized() { - loadSkuDetails(); - } - - @Override - public void onDestroy() { - if (billingProcessor != null) { - billingProcessor.release(); - } - if (skuDetailsLoadAsyncTask != null) { - skuDetailsLoadAsyncTask.cancel(true); - } - super.onDestroy(); - } - - private void loadSkuDetails() { - if (skuDetailsLoadAsyncTask != null) { - skuDetailsLoadAsyncTask.cancel(false); - } - skuDetailsLoadAsyncTask = new SkuDetailsLoadAsyncTask(this).execute(); - } - - private static class SkuDetailsLoadAsyncTask extends AsyncTask { - private final WeakReference donationDialogWeakReference; - - public SkuDetailsLoadAsyncTask(BuyDialog donationsDialog) { - this.donationDialogWeakReference = new WeakReference<>(donationsDialog); - } - - @Override - protected SkuDetails doInBackground(Void... params) { - BuyDialog dialog = donationDialogWeakReference.get(); - if (dialog != null) { - return dialog.billingProcessor.getPurchaseListingDetails(App.PRO_VERSION_PRODUCT_ID); - } - cancel(false); - return null; - } - - @Override - protected void onPostExecute(SkuDetails skuDetails) { - super.onPostExecute(skuDetails); - BuyDialog dialog = donationDialogWeakReference.get(); - if (dialog == null) return; - - if (skuDetails == null) { - if (!BuildConfig.DEBUG) dialog.dismiss(); - return; - } - - MDButton positiveButton = ((MaterialDialog) dialog.getDialog()).getActionButton(DialogAction.POSITIVE); - positiveButton.setText(String.format("%s %s", dialog.getString(R.string.buy), skuDetails.priceText)); - } - } -} diff --git a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java index 747146d3..19ea79aa 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java +++ b/app/src/main/java/com/kabouzeid/gramophone/dialogs/SleepTimerDialog.java @@ -21,6 +21,7 @@ import com.afollestad.materialdialogs.internal.ThemeSingleton; import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.service.MusicService; +import com.kabouzeid.gramophone.ui.activities.PurchaseActivity; import com.kabouzeid.gramophone.util.MusicUtil; import com.kabouzeid.gramophone.util.PreferenceUtil; import com.triggertrap.seekarc.SeekArc; @@ -62,8 +63,7 @@ public class SleepTimerDialog extends DialogFragment { } if (!App.isProVersion()) { Toast.makeText(getActivity(), getString(R.string.sleep_timer_is_a_pro_feature), Toast.LENGTH_LONG).show(); - BuyDialog.create().show(getFragmentManager(), "BUY_DIALOG"); - dismiss(); + startActivity(new Intent(getContext(), PurchaseActivity.class)); return; } 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 2959a62f..0c1e4f43 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 @@ -30,7 +30,6 @@ import com.kabouzeid.appthemehelper.util.ATHUtil; import com.kabouzeid.appthemehelper.util.NavigationViewUtil; import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; -import com.kabouzeid.gramophone.dialogs.BuyDialog; import com.kabouzeid.gramophone.dialogs.ChangelogDialog; import com.kabouzeid.gramophone.glide.SongGlideRequest; import com.kabouzeid.gramophone.helper.MusicPlayerRemote; @@ -57,6 +56,7 @@ public class MainActivity extends AbsSlidingMusicPanelActivity { public static final String TAG = MainActivity.class.getSimpleName(); public static final int APP_INTRO_REQUEST = 100; + public static final int PURCHASE_REQUEST = 101; private static final int LIBRARY = 0; private static final int FOLDERS = 1; @@ -112,7 +112,7 @@ public class MainActivity extends AbsSlidingMusicPanelActivity { private void setMusicChooser(int key) { if (!App.isProVersion() && key == FOLDERS) { Toast.makeText(this, R.string.folder_view_is_a_pro_feature, Toast.LENGTH_LONG).show(); - BuyDialog.create().show(getSupportFragmentManager(), "BUY_DIALOG"); + startActivityForResult(new Intent(this, PurchaseActivity.class), PURCHASE_REQUEST); key = LIBRARY; } @@ -146,6 +146,12 @@ public class MainActivity extends AbsSlidingMusicPanelActivity { if (!hasPermissions()) { requestPermissions(); } + } else if (requestCode == PURCHASE_REQUEST) { + if (resultCode == RESULT_OK) { + if (App.isProVersion()) { + setUpPro(); + } + } } } @@ -169,7 +175,7 @@ public class MainActivity extends AbsSlidingMusicPanelActivity { NavigationViewUtil.setItemTextColors(navigationView, ThemeStore.textColorPrimary(this), accentColor); if (App.isProVersion()) { - navigationView.getMenu().removeGroup(R.id.navigation_drawer_menu_category_buy_pro); + setUpPro(); } navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override @@ -196,7 +202,7 @@ public class MainActivity extends AbsSlidingMusicPanelActivity { new Handler().postDelayed(new Runnable() { @Override public void run() { - BuyDialog.create().show(getSupportFragmentManager(), "BUY_DIALOG"); + startActivityForResult(new Intent(MainActivity.this, PurchaseActivity.class), PURCHASE_REQUEST); } }, 200); break; @@ -222,6 +228,10 @@ public class MainActivity extends AbsSlidingMusicPanelActivity { }); } + private void setUpPro() { + navigationView.getMenu().removeGroup(R.id.navigation_drawer_menu_category_buy_pro); + } + private void setUpDrawerLayout() { setUpNavigationView(); } diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PurchaseActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PurchaseActivity.java new file mode 100644 index 00000000..e244a84f --- /dev/null +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/PurchaseActivity.java @@ -0,0 +1,172 @@ +package com.kabouzeid.gramophone.ui.activities; + +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.Toast; + +import com.anjlab.android.iab.v3.BillingProcessor; +import com.anjlab.android.iab.v3.TransactionDetails; +import com.kabouzeid.appthemehelper.color.MaterialColor; +import com.kabouzeid.gramophone.App; +import com.kabouzeid.gramophone.R; +import com.kabouzeid.gramophone.ui.activities.base.AbsBaseActivity; + +import java.lang.ref.WeakReference; + +import butterknife.BindView; +import butterknife.ButterKnife; + +public class PurchaseActivity extends AbsBaseActivity implements BillingProcessor.IBillingHandler { + + public static final String TAG = PurchaseActivity.class.getSimpleName(); + + private static final int ACTIVITY_COLOR = MaterialColor.Green._500.getAsColor(); + + @BindView(R.id.toolbar) + Toolbar toolbar; + @BindView(R.id.restore_button) + Button restoreButton; + @BindView(R.id.purchase_button) + Button purchaseButton; + + private BillingProcessor billingProcessor; + private AsyncTask restorePurchaseAsyncTask; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_purchase); + setDrawUnderStatusbar(true); + ButterKnife.bind(this); + + setStatusbarColor(ACTIVITY_COLOR); + setNavigationbarColor(ACTIVITY_COLOR); + setTaskDescriptionColor(ACTIVITY_COLOR); + + setSupportActionBar(toolbar); + //noinspection ConstantConditions + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setTitle(getString(R.string.purchase) + " Phonograph Pro"); + + restoreButton.setEnabled(false); + purchaseButton.setEnabled(false); + + restoreButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (restorePurchaseAsyncTask == null || restorePurchaseAsyncTask.getStatus() != AsyncTask.Status.RUNNING) { + restorePurchase(); + } + } + }); + + purchaseButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + billingProcessor.purchase(PurchaseActivity.this, App.PRO_VERSION_PRODUCT_ID); + } + }); + + billingProcessor = new BillingProcessor(this, App.GOOGLE_PLAY_LICENSE_KEY, this); + + + } + + private void restorePurchase() { + if (restorePurchaseAsyncTask != null) { + restorePurchaseAsyncTask.cancel(false); + } + restorePurchaseAsyncTask = new RestorePurchaseAsyncTask(this).execute(); + } + + @Override + public void onProductPurchased(@NonNull String productId, @Nullable TransactionDetails details) { + Toast.makeText(this, R.string.thank_you, Toast.LENGTH_SHORT).show(); + setResult(RESULT_OK); + } + + @Override + public void onPurchaseHistoryRestored() { + if (App.isProVersion()) { + Toast.makeText(this, R.string.restored_previous_purchase_please_restart, Toast.LENGTH_LONG).show(); + setResult(RESULT_OK); + } else { + Toast.makeText(this, R.string.no_purchase_found, Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void onBillingError(int errorCode, @Nullable Throwable error) { + Log.e(TAG, "Billing error: code = " + errorCode, error); + } + + @Override + public void onBillingInitialized() { + restoreButton.setEnabled(true); + purchaseButton.setEnabled(true); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + if (!billingProcessor.handleActivityResult(requestCode, resultCode, data)) { + super.onActivityResult(requestCode, resultCode, data); + } + } + + @Override + public void onDestroy() { + if (billingProcessor != null) { + billingProcessor.release(); + } + super.onDestroy(); + } + + private static class RestorePurchaseAsyncTask extends AsyncTask { + private final WeakReference buyActivityWeakReference; + + public RestorePurchaseAsyncTask(PurchaseActivity purchaseActivity) { + this.buyActivityWeakReference = new WeakReference<>(purchaseActivity); + } + + @Override + protected void onPreExecute() { + super.onPreExecute(); + PurchaseActivity purchaseActivity = buyActivityWeakReference.get(); + if (purchaseActivity != null) { + Toast.makeText(purchaseActivity, R.string.restoring_purchase, Toast.LENGTH_SHORT).show(); + } else { + cancel(false); + } + } + + @Override + protected Boolean doInBackground(Void... params) { + PurchaseActivity purchaseActivity = buyActivityWeakReference.get(); + if (purchaseActivity != null) { + return purchaseActivity.billingProcessor.loadOwnedPurchasesFromGoogle(); + } + cancel(false); + return null; + } + + @Override + protected void onPostExecute(Boolean b) { + super.onPostExecute(b); + PurchaseActivity purchaseActivity = buyActivityWeakReference.get(); + if (purchaseActivity == null || b == null) return; + + if (b) { + purchaseActivity.onPurchaseHistoryRestored(); + } else { + Toast.makeText(purchaseActivity, R.string.could_not_restore_purchase, Toast.LENGTH_SHORT).show(); + } + } + } +} diff --git a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SettingsActivity.java b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SettingsActivity.java index ddb231cb..54467994 100644 --- a/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SettingsActivity.java +++ b/app/src/main/java/com/kabouzeid/gramophone/ui/activities/SettingsActivity.java @@ -28,12 +28,9 @@ import com.kabouzeid.appthemehelper.util.ColorUtil; import com.kabouzeid.gramophone.App; import com.kabouzeid.gramophone.R; import com.kabouzeid.gramophone.appshortcuts.DynamicShortcutManager; -import com.kabouzeid.gramophone.dialogs.BuyDialog; -import com.kabouzeid.gramophone.helper.MusicPlayerRemote; import com.kabouzeid.gramophone.misc.NonProAllowedColors; import com.kabouzeid.gramophone.preferences.NowPlayingScreenPreference; import com.kabouzeid.gramophone.preferences.NowPlayingScreenPreferenceDialog; -import com.kabouzeid.gramophone.service.MusicService; import com.kabouzeid.gramophone.ui.activities.base.AbsBaseActivity; import com.kabouzeid.gramophone.util.NavigationUtil; import com.kabouzeid.gramophone.util.PreferenceUtil; @@ -82,7 +79,7 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia if (Arrays.binarySearch(NonProAllowedColors.PRIMARY_COLORS, selectedColor) < 0) { // color wasn't found Toast.makeText(this, R.string.only_the_first_5_colors_available, Toast.LENGTH_LONG).show(); - BuyDialog.create().show(getSupportFragmentManager(), "BUY_DIALOG"); + startActivity(new Intent(this, PurchaseActivity.class)); return; } } @@ -96,7 +93,7 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia if (Arrays.binarySearch(NonProAllowedColors.ACCENT_COLORS, selectedColor) < 0) { // color wasn't found Toast.makeText(this, R.string.only_the_first_5_colors_available, Toast.LENGTH_LONG).show(); - BuyDialog.create().show(getSupportFragmentManager(), "BUY_DIALOG"); + startActivity(new Intent(this, PurchaseActivity.class)); return; } } @@ -202,7 +199,7 @@ public class SettingsActivity extends AbsBaseActivity implements ColorChooserDia String themeName = (String) o; if (themeName.equals("black") && !App.isProVersion()) { Toast.makeText(getActivity(), R.string.black_theme_is_a_pro_feature, Toast.LENGTH_LONG).show(); - BuyDialog.create().show(getFragmentManager(), "BUY_DIALOG"); + startActivity(new Intent(getContext(), PurchaseActivity.class)); return false; } diff --git a/app/src/main/res/drawable/promo_banner.png b/app/src/main/res/drawable/promo_banner.png new file mode 100644 index 00000000..c0208b48 Binary files /dev/null and b/app/src/main/res/drawable/promo_banner.png differ diff --git a/app/src/main/res/drawable/promo_banner16.png b/app/src/main/res/drawable/promo_banner16.png new file mode 100644 index 00000000..354c7467 Binary files /dev/null and b/app/src/main/res/drawable/promo_banner16.png differ diff --git a/app/src/main/res/layout-w640dp/activity_about_content.xml b/app/src/main/res/layout-w640dp/activity_about_content.xml deleted file mode 100644 index 3a522330..00000000 --- a/app/src/main/res/layout-w640dp/activity_about_content.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_purchase.xml b/app/src/main/res/layout/activity_purchase.xml new file mode 100644 index 00000000..43a0d19a --- /dev/null +++ b/app/src/main/res/layout/activity_purchase.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_purchase_content.xml b/app/src/main/res/layout/activity_purchase_content.xml new file mode 100644 index 00000000..dbc0af4b --- /dev/null +++ b/app/src/main/res/layout/activity_purchase_content.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + +