aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2017-06-30 20:32:33 -0700
committerAllan Wang <me@allanwang.ca>2017-06-30 20:32:33 -0700
commit1811531d6934f4eadfca70b30afa2dac76400bef (patch)
tree7b9a3fec0a840f602ee2be371c9c224211c4b426 /app
parent8760cb29b8a37d15a1dcba018054d4010b90df21 (diff)
downloadfrost-1811531d6934f4eadfca70b30afa2dac76400bef.tar.gz
frost-1811531d6934f4eadfca70b30afa2dac76400bef.tar.bz2
frost-1811531d6934f4eadfca70b30afa2dac76400bef.zip
Test more billing
Diffstat (limited to 'app')
-rw-r--r--app/build.gradle6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt82
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt15
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt23
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt10
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt63
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt50
-rw-r--r--app/src/main/res/layout/item_about_links.xml33
-rw-r--r--app/src/main/res/values/ids.xml1
-rw-r--r--app/src/main/res/values/strings.xml2
-rw-r--r--app/src/main/res/values/strings_preferences2
11 files changed, 235 insertions, 52 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 9b8446ff..f72c9096 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -53,8 +53,8 @@ android {
resValue "string", "frost_web", "Frost Web Test"
}
release {
- minifyEnabled true
- shrinkResources true
+ minifyEnabled false
+ shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
resValue "string", "app_name", "Frost"
resValue "string", "frost_web", "Frost Web"
@@ -121,6 +121,8 @@ dependencies {
compile "com.jude:swipebackhelper:${SWIPE_BACK}"
+ compile 'com.android.billingclient:billing:dp-1'
+
compile("com.crashlytics.sdk.android:crashlytics:${CRASHLYTICS}@aar") {
transitive = true;
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt
index 67ce8f7c..b9bb52d8 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt
@@ -1,14 +1,25 @@
package com.pitchedapps.frost
+import android.graphics.Color
+import android.support.constraint.ConstraintLayout
+import android.support.v7.widget.RecyclerView
+import android.view.View
+import android.widget.ImageView
import ca.allanwang.kau.about.AboutActivityBase
import ca.allanwang.kau.adapters.FastItemThemedAdapter
-import ca.allanwang.kau.iitems.CardIItem
-import ca.allanwang.kau.logging.KL
-import ca.allanwang.kau.utils.isColorVisibleOn
-import ca.allanwang.kau.utils.withMinAlpha
+import ca.allanwang.kau.adapters.ThemableIItem
+import ca.allanwang.kau.adapters.ThemableIItemDelegate
+import ca.allanwang.kau.iitems.LibraryIItem
+import ca.allanwang.kau.utils.*
+import ca.allanwang.kau.views.createSimpleRippleDrawable
import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.entity.Library
+import com.mikepenz.aboutlibraries.entity.License
+import com.mikepenz.community_material_typeface_library.CommunityMaterial
import com.mikepenz.fastadapter.IItem
+import com.mikepenz.fastadapter.items.AbstractItem
+import com.mikepenz.google_material_typeface_library.GoogleMaterial
+import com.mikepenz.iconics.typeface.IIcon
import com.pitchedapps.frost.utils.Prefs
@@ -51,8 +62,65 @@ class AboutActivity : AboutActivityBase(R.string::class.java, configBuilder = {
}
override fun postInflateMainPage(adapter: FastItemThemedAdapter<IItem<*, *>>) {
- adapter.add(CardIItem {
- descRes = R.string.frost_description
- })
+ /**
+ * Frost may not be a library but we're conveying the same info
+ */
+ val frost = Library().apply {
+ libraryName = string(R.string.app_name)
+ author = "Pitched Apps"
+ libraryWebsite = "https://github.com/AllanWang/Frost-for-Facebook"
+ isOpenSource = true
+ libraryDescription = string(R.string.frost_description)
+ libraryVersion = BuildConfig.VERSION_NAME
+ license = License().apply {
+ licenseName = "GNU GPL v3"
+ licenseWebsite = "https://www.gnu.org/licenses/gpl-3.0.en.html"
+ }
+ }
+ adapter.add(LibraryIItem(frost)).add(AboutLinks())
+
+ }
+
+ class AboutLinks : AbstractItem<AboutLinks, AboutLinks.ViewHolder>(), ThemableIItem by ThemableIItemDelegate() {
+ override fun getViewHolder(v: View): ViewHolder = ViewHolder(v)
+
+ override fun getType(): Int = R.id.item_about_links
+
+ override fun getLayoutRes(): Int = R.layout.item_about_links
+
+ override fun bindView(holder: ViewHolder, payloads: MutableList<Any>?) {
+ super.bindView(holder, payloads)
+ with(holder) {
+ bindIconColor(rate, github)
+ bindBackgroundColor(container)
+ }
+ }
+
+ fun theme(vararg images: ImageView) {
+ val ripple = createSimpleRippleDrawable(accentColor!!, Color.TRANSPARENT)
+ images.forEach {
+ it.background = ripple
+ it.drawable.setTint(textColor!!)
+ }
+ }
+
+ class ViewHolder(v: View) : RecyclerView.ViewHolder(v) {
+
+ val container: ConstraintLayout by bindView(R.id.about_icons_container)
+ val rate: ImageView by bindView(R.id.about_rate)
+ val github: ImageView by bindView(R.id.about_github)
+
+ init {
+ val c = itemView.context
+ setup(rate, GoogleMaterial.Icon.gmd_star, { c.startPlayStoreLink(R.string.play_store_package_id) })
+ setup(github, CommunityMaterial.Icon.cmd_github_circle, { c.startLink("https://github.com/AllanWang/Frost-for-Facebook") })
+ }
+
+ fun setup(image: ImageView, icon: IIcon, onClick: () -> Unit) {
+ image.setImageDrawable(icon.toDrawable(itemView.context, 32))
+ image.setOnClickListener({ onClick() })
+ }
+
+ }
}
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
index a221859f..4dce7d4a 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
@@ -12,8 +12,8 @@ import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
import com.mikepenz.materialdrawer.util.DrawerImageLoader
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.utils.CrashReportingTree
-import com.pitchedapps.frost.utils.iab.IAB
import com.pitchedapps.frost.utils.Prefs
+import com.pitchedapps.frost.utils.iab.IAB
import com.raizlabs.android.dbflow.config.FlowConfig
import com.raizlabs.android.dbflow.config.FlowManager
import io.fabric.sdk.android.Fabric
@@ -36,11 +36,7 @@ class FrostApp : Application() {
override fun onCreate() {
FlowManager.init(FlowConfig.Builder(this).build())
Prefs.initialize(this, "${BuildConfig.APPLICATION_ID}.prefs")
- FbCookie()
- if (Prefs.installDate == -1L) Prefs.installDate = System.currentTimeMillis()
- if (Prefs.identifier == -1) Prefs.identifier = Random().nextInt(Int.MAX_VALUE)
- Prefs.lastLaunch = System.currentTimeMillis()
-// if (LeakCanary.isInAnalyzerProcess(this)) return
+ // if (LeakCanary.isInAnalyzerProcess(this)) return
// refWatcher = LeakCanary.install(this)
if (BuildConfig.DEBUG) {
Timber.plant(DebugTree())
@@ -50,10 +46,15 @@ class FrostApp : Application() {
Crashlytics.setUserIdentifier(Prefs.frostId)
Timber.plant(CrashReportingTree())
}
+ FbCookie()
+ if (Prefs.installDate == -1L) Prefs.installDate = System.currentTimeMillis()
+ if (Prefs.identifier == -1) Prefs.identifier = Random().nextInt(Int.MAX_VALUE)
+ Prefs.lastLaunch = System.currentTimeMillis()
+
+
super.onCreate()
- IAB.setupAsync(this)
//Drawer profile loading logic
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String) {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
index dcb68696..9094c58e 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
@@ -1,7 +1,11 @@
package com.pitchedapps.frost
+import android.app.AlarmManager
+import android.app.PendingIntent
+import android.content.Context
import android.content.Intent
import android.graphics.drawable.ColorDrawable
+import android.os.Build
import android.os.Bundle
import android.support.annotation.StringRes
import android.support.design.widget.*
@@ -39,6 +43,7 @@ import com.pitchedapps.frost.facebook.FbTab
import com.pitchedapps.frost.facebook.PROFILE_PICTURE_URL
import com.pitchedapps.frost.fragments.WebFragment
import com.pitchedapps.frost.utils.*
+import com.pitchedapps.frost.utils.iab.IAB
import com.pitchedapps.frost.views.BadgedIcon
import com.pitchedapps.frost.web.FrostWebViewSearch
import io.reactivex.android.schedulers.AndroidSchedulers
@@ -84,6 +89,7 @@ class MainActivity : BaseActivity(), FrostWebViewSearch.SearchContract {
const val REQUEST_REFRESH = 80808
const val REQUEST_NAV = 10101
const val REQUEST_SEARCH = 70707
+ const val REQUEST_RESTART_APPLICATION = 60606
}
override fun onCreate(savedInstanceState: Bundle?) {
@@ -365,6 +371,18 @@ class MainActivity : BaseActivity(), FrostWebViewSearch.SearchContract {
REQUEST_REFRESH -> webFragmentObservable.onNext(FRAGMENT_REFRESH)
REQUEST_NAV -> frostNavigationBar()
REQUEST_SEARCH -> invalidateOptionsMenu()
+ REQUEST_RESTART_APPLICATION -> { //completely restart application
+ val intent = packageManager.getLaunchIntentForPackage(packageName)
+ intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
+ val pending = PendingIntent.getActivity(this, 666, intent, PendingIntent.FLAG_CANCEL_CURRENT)
+ val alarm = getSystemService(Context.ALARM_SERVICE) as AlarmManager
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
+ alarm.setExactAndAllowWhileIdle(AlarmManager.RTC, System.currentTimeMillis() + 100, pending)
+ else
+ alarm.setExact(AlarmManager.RTC, System.currentTimeMillis() + 100, pending)
+ finish()
+ System.exit(0)
+ }
}
}
}
@@ -374,6 +392,11 @@ class MainActivity : BaseActivity(), FrostWebViewSearch.SearchContract {
FbCookie.switchBackUser { }
}
+ override fun onStart() {
+ super.onStart()
+ IAB.setupAsync(this)
+ }
+
override fun onBackPressed() {
if (searchView?.onBackPressed() ?: false) return
if (currentFragment.onBackPressed()) return
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt
index 054b3669..fcb22320 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt
@@ -22,4 +22,14 @@ fun SettingsActivity.getExperimentalPrefs(): KPrefAdapterBuilder.() -> Unit = {
checkbox(R.string.verbose_logging, { Prefs.verboseLogging }, { Prefs.verboseLogging = it }) {
descRes = R.string.verbose_logging_desc
}
+
+ plainText(R.string.restart_frost) {
+ descRes = R.string.restart_frost_desc
+ onClick = {
+ _, _, _ ->
+ setResult(MainActivity.REQUEST_RESTART_APPLICATION)
+ finish()
+ true
+ }
+ }
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt
index 19b9b6f7..0fd10c5b 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt
@@ -16,17 +16,20 @@ object IAB {
var helper: IabHelper? = null
- fun setupAsync(context: Context) {
- if (!context.isFromGooglePlay) return
+ fun setupAsync(activity: Activity) {
if (helper == null) {
+ L.d("IAB setup async")
+ if (!activity.isFromGooglePlay && !BuildConfig.DEBUG) return L.d("IAB not from google play")
try {
- helper = IabHelper(context.applicationContext, PUBLIC_BILLING_KEY)
+ helper = IabHelper(activity.applicationContext, PUBLIC_BILLING_KEY)
helper!!.startSetup {
result ->
+ L.d("IAB result ${result.message}")
if (!result.isSuccess) L.eThrow("IAB Setup error: $result")
}
} catch (e: Exception) {
L.e(e, "IAB error")
+ activity.playStoreNoLongerPro()
}
}
}
@@ -35,7 +38,7 @@ object IAB {
private const val FROST_PRO = "frost_pro"
val IS_FROST_PRO: Boolean
- get() = (BuildConfig.DEBUG && Prefs.debugPro) || (IAB.helper?.queryInventory()?.getSkuDetails(FROST_PRO) != null)
+ get() = (BuildConfig.DEBUG && Prefs.debugPro) || Prefs.previouslyPro
private fun Context.checkFromPlay(): Boolean {
val isPlay = isFromGooglePlay || BuildConfig.DEBUG
@@ -52,44 +55,32 @@ private fun Context.checkFromPlay(): Boolean {
fun Activity.openPlayProPurchase(code: Int) = openPlayPurchase(FROST_PRO, code)
fun Activity.openPlayPurchase(key: String, code: Int) {
+ L.d("Open play purchase $key $code")
if (!checkFromPlay()) return
frostAnswersCustom("PLAY_PURCHASE") {
putCustomAttribute("Key", key)
}
- IAB.helper?.flagEndAsync() ?: playStoreErrorDialog()
- IAB.helper?.queryInventoryAsync {
+ L.d("IAB flag end async")
+ IAB.helper?.flagEndAsync() ?: return playStoreGenericError("Null flag end async")
+ L.d("IAB query inv async")
+ IAB.helper!!.queryInventoryAsync {
res, inv ->
- if (res.isFailure) {
- L.e("IAB error: ${res.message}")
- playStoreErrorDialog()
- } else if (inv == null) {
- playStoreErrorDialog("Empty inventory")
- } else {
- val donation = inv.getSkuDetails(key)
- if (donation != null) {
- IAB.helper?.launchPurchaseFlow(this@openPlayPurchase, donation.sku, code) {
- result, _ ->
- if (result.isSuccess) materialDialogThemed {
- title(R.string.play_thank_you)
- content(R.string.play_purchased_pro)
- positiveText(R.string.kau_ok)
- } else playStoreErrorDialog("Result: ${result.message}")
- frostAnswers {
- logPurchase(PurchaseEvent()
- .putItemId(key)
- .putSuccess(result.isSuccess))
- }
- } ?: playStoreErrorDialog("Launch Purchase Flow")
+ if (res.isFailure) return@queryInventoryAsync playStoreGenericError("Query res error")
+ if (inv == null) return@queryInventoryAsync playStoreGenericError("Empty inventory")
+ L.d("IAB: inventory ${inv.allOwnedSkus}")
+ val donation = inv.getSkuDetails(key) ?: return@queryInventoryAsync playStoreGenericError("Donation null")
+ IAB.helper!!.launchPurchaseFlow(this@openPlayPurchase, donation.sku, code) {
+ result, _ ->
+ if (result.isSuccess) materialDialogThemed {
+ title(R.string.play_thank_you)
+ content(R.string.play_purchased_pro)
+ positiveText(R.string.kau_ok)
+ } else playStoreGenericError("Result: ${result.message}")
+ frostAnswers {
+ logPurchase(PurchaseEvent()
+ .putItemId(key)
+ .putSuccess(result.isSuccess))
}
}
}
-}
-
-private fun Context.playStoreErrorDialog(s: String = "Play Store Error") {
- materialDialogThemed {
- title(R.string.uh_oh)
- content(R.string.play_store_billing_error)
- positiveText(R.string.kau_ok)
- }
- L.e(Throwable(s), "Play Store Error")
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt
new file mode 100644
index 00000000..e855138f
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt
@@ -0,0 +1,50 @@
+package com.pitchedapps.frost.utils.iab
+
+import android.app.Activity
+import ca.allanwang.kau.utils.restart
+import ca.allanwang.kau.utils.startPlayStoreLink
+import com.pitchedapps.frost.R
+import com.pitchedapps.frost.utils.L
+import com.pitchedapps.frost.utils.Prefs
+import com.pitchedapps.frost.utils.materialDialogThemed
+
+/**
+ * Created by Allan Wang on 2017-06-30.
+ */
+private fun playStoreLog(text: String) {
+ L.e(Throwable(text), "Play Store Exception")
+}
+
+fun Activity.playStoreNoLongerPro() {
+ if (!Prefs.previouslyPro) return //never pro to begin with
+ Prefs.previouslyPro = false
+ playStoreLog("No Longer Pro")
+ materialDialogThemed {
+ title(R.string.uh_oh)
+ content(R.string.play_store_not_pro)
+ positiveText(R.string.reload)
+ dismissListener {
+ this@playStoreNoLongerPro.restart()
+ }
+ }
+}
+
+fun Activity.playStoreNotAvailable() {
+ playStoreLog("Store not available")
+ materialDialogThemed {
+ title(R.string.uh_oh)
+ content(R.string.play_store_not_found)
+ positiveText(R.string.kau_ok)
+ neutralText(R.string.kau_play_store)
+ onNeutral { _, _ -> startPlayStoreLink(R.string.play_store_package_id) }
+ }
+}
+
+fun Activity.playStoreGenericError(text: String = "Store generic error") {
+ playStoreLog("IAB: $text")
+ materialDialogThemed {
+ title(R.string.uh_oh)
+ content(R.string.play_store_billing_error)
+ positiveText(R.string.kau_ok)
+ }
+} \ No newline at end of file
diff --git a/app/src/main/res/layout/item_about_links.xml b/app/src/main/res/layout/item_about_links.xml
new file mode 100644
index 00000000..db831835
--- /dev/null
+++ b/app/src/main/res/layout/item_about_links.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/about_icons_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:clickable="false"
+ android:padding="@dimen/kau_spacing_normal">
+
+ <ImageView
+ android:id="@+id/about_rate"
+ android:layout_width="@dimen/kau_avatar_bounds"
+ android:layout_height="@dimen/kau_avatar_bounds"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:scaleType="center"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@+id/about_github"
+ app:layout_constraintHorizontal_chainStyle="spread_inside"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+
+ <ImageView
+ android:id="@id/about_github"
+ android:layout_width="@dimen/kau_avatar_bounds"
+ android:layout_height="@dimen/kau_avatar_bounds"
+ android:background="?android:attr/selectableItemBackgroundBorderless"
+ android:scaleType="center"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/about_rate"
+ app:layout_constraintTop_toTopOf="parent" />
+
+</android.support.constraint.ConstraintLayout> \ No newline at end of file
diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml
index 9ce1b4e3..a0bb0a87 100644
--- a/app/src/main/res/values/ids.xml
+++ b/app/src/main/res/values/ids.xml
@@ -2,4 +2,5 @@
<resources>
<item name="item_account" type="id" />
<item name="item_keyword" type="id" />
+ <item name="item_about_links" type="id" />
</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 5e4fe3ba..ec7a6cf6 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -49,6 +49,8 @@
<string name="pro_features">Pro Features</string>
<string name="custom_pro">Custom [Pro]</string>
<string name="uh_oh">Uh Oh</string>
+ <string name="reload">Reload</string>
+ <string name="play_store_not_pro">It seems like you are a pro user, but we couldn\'t find your purchasing info. If this error persists, please try clearing the Play Store cache and reinstalling the app.</string>
<string name="play_store_not_found">This is a pro feature, but this app doesn\'t seem to be installed from the Play Store. Please reinstall if this is an issue.</string>
<string name="play_store_billing_error">Something went wrong. Please try again later.</string>
<string name="play_thank_you">Thank you!</string>
diff --git a/app/src/main/res/values/strings_preferences b/app/src/main/res/values/strings_preferences
index afa41943..1c20b810 100644
--- a/app/src/main/res/values/strings_preferences
+++ b/app/src/main/res/values/strings_preferences
@@ -54,5 +54,7 @@
<string name="search_desc">Enable the search bar instead of a search overlay</string>
<string name="verbose_logging">Verbose Logging</string>
<string name="verbose_logging_desc">Enable verbose logging to help with crash reports. Logging will only be sent once an error is encountered, so repeat the issue to notify the dev.</string>
+ <string name="restart_frost">Restart Frost</string>
+ <string name="restart_frost_desc">Crashlytics will only submit logs when a crash occurs or if errors are found and the app is restarted. Clicking here will restart the app and flush whatever issues are currently found.</string>
</resources> \ No newline at end of file