Add support page

This commit is contained in:
Billy Brawner 2019-11-07 10:16:44 -06:00 committed by William Brawner
parent 5d61ccc4fb
commit 070d580044
9 changed files with 206 additions and 33 deletions

View file

@ -17,7 +17,6 @@ try {
keystoreProperties['storePassword'] = ""
}
android {
configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.1'
@ -101,6 +100,7 @@ dependencies {
implementation 'com.android.billingclient:billing:1.2'
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
implementation "androidx.core:core-ktx:1.1.0"
implementation 'androidx.browser:browser:1.0.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
def coroutines_version = "1.3.0-RC2"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version"
@ -136,10 +136,10 @@ task jacocoTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) {
def kotlinDebugTree = fileTree(dir: "$project.buildDir/tmp/kotlin-classes/debug", excludes: fileFilter)
def mainSrc = "$project.projectDir/src/main/java"
sourceDirectories = files([mainSrc])
classDirectories = files([javaDebugTree, kotlinDebugTree])
executionData = fileTree(dir: project.buildDir, includes: [
sourceDirectories.setFrom(files([mainSrc]))
classDirectories.setFrom(files([javaDebugTree, kotlinDebugTree]))
executionData.setFrom(fileTree(dir: project.buildDir, includes: [
'jacoco/testDebugUnitTest.exec',
'outputs/code-coverage/connected/*coverage.ec'
])
]))
}

View file

@ -18,10 +18,6 @@
android:theme="@style/AppTheme"
tools:ignore="AllowBackup"
tools:targetApi="n">
<meta-data
android:name="com.google.android.gms.ads.APPLICATION_ID"
android:value="@string/admob_app_id" />
<activity
android:name=".view.activity.SplashActivity"
android:theme="@style/AppTheme.Splash"
@ -68,6 +64,8 @@
android:value=".view.activity.MainActivity" />
</activity>
<activity android:name=".view.activity.SupportActivity" />
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="false" />

View file

@ -1,21 +1,61 @@
package com.wbrawner.simplemarkdown.view.activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.browser.customtabs.CustomTabsIntent
import com.android.billingclient.api.*
import java.util.*
import com.google.android.material.button.MaterialButton
import com.wbrawner.simplemarkdown.R
import kotlinx.android.synthetic.main.activity_support.*
class SupportActivity : AppCompatActivity(), BillingClientStateListener, PurchasesUpdatedListener {
private lateinit var billingClient: BillingClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_support)
setSupportActionBar(toolbar)
setTitle(R.string.support_title)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
billingClient = BillingClient.newBuilder(applicationContext)
.setListener(this)
.build()
billingClient.startConnection(this)
githubButton.setOnClickListener {
CustomTabsIntent.Builder()
.addDefaultShareMenuItem()
.build()
.launchUrl(this@SupportActivity, Uri.parse("https://github.com/wbrawner/SimpleMarkdown"))
}
rateButton.setOnClickListener {
val playStoreIntent = Intent(Intent.ACTION_VIEW)
.apply {
data = Uri.parse("market://details?id=${packageName}")
addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY or
Intent.FLAG_ACTIVITY_NEW_DOCUMENT or
Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
}
try {
startActivity(playStoreIntent)
} catch (ignored: ActivityNotFoundException) {
playStoreIntent.data = Uri.parse("https://play.google.com/store/apps/details?id=${packageName}")
startActivity(playStoreIntent)
}
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
finish()
return true
}
return super.onOptionsItemSelected(item)
}
override fun onBillingSetupFinished(responseCode: Int) {
@ -23,36 +63,47 @@ class SupportActivity : AppCompatActivity(), BillingClientStateListener, Purchas
return
}
// The billing client is ready. You can query purchases here.
val skuList = ArrayList<String>()
skuList.add("support_the_developer")
val params = SkuDetailsParams.newBuilder()
params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP)
billingClient.querySkuDetailsAsync(params.build()) { responseCode1, skuDetailsList ->
val skuDetails = SkuDetailsParams.newBuilder()
.setSkusList(listOf("support_the_developer", "tip_coffee", "tip_beer"))
.setType(BillingClient.SkuType.INAPP)
.build()
billingClient.querySkuDetailsAsync(skuDetails) { skuDetailsResponseCode, skuDetailsList ->
// Process the result.
if (responseCode1 != BillingClient.BillingResponse.OK || skuDetailsList == null) {
if (skuDetailsResponseCode != BillingClient.BillingResponse.OK || skuDetailsList.isNullOrEmpty()) {
return@querySkuDetailsAsync
}
val skuDetails = skuDetailsList!!.get(0)
val sku = skuDetails.getSku()
val price = skuDetails.getPrice()
Log.d("SimpleMarkdown",
"Got product with sku: " + sku + " and price: " + price + " " + skuDetails.getPriceCurrencyCode())
val flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build()
val responseCode2 = billingClient.launchBillingFlow(this, flowParams)
skuDetailsList.sortedBy { it.priceAmountMicros }.forEach { skuDetails ->
val supportButton = MaterialButton(this@SupportActivity)
supportButton.text = getString(
R.string.support_button_purchase,
skuDetails.title,
skuDetails.price
)
supportButton.setOnClickListener {
val flowParams = BillingFlowParams.newBuilder()
.setSkuDetails(skuDetails)
.build()
billingClient.launchBillingFlow(this, flowParams)
}
supportButtons.addView(supportButton)
}
}
}
override fun onBillingServiceDisconnected() {
// TODO: Set a flag and just try again later
billingClient.startConnection(this)
}
override fun onPurchasesUpdated(responseCode: Int, purchases: List<Purchase>?) {
purchases?.forEach { purchase ->
billingClient.consumeAsync(purchase.purchaseToken) { _, _ ->
Toast.makeText(
this@SupportActivity,
getString(R.string.support_thank_you),
Toast.LENGTH_SHORT
).show()
}
}
}
}

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z" />
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="@color/colorOnBackground"
android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z" />
</vector>

View file

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:fitsSystemWindows="true">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:padding="16dp"
app:layout_constraintBottom_toTopOf="@+id/bottomSheet"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/heartIcon"
android:layout_width="100dp"
android:layout_height="100dp"
android:src="@drawable/ic_favorite_black_24dp"
android:tint="@color/colorAccent"
android:contentDescription="@string/description_heart"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/supportInfoText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:text="@string/support_info"
android:textAlignment="center"
android:textColor="@color/colorOnBackground"
app:layout_constraintTop_toBottomOf="@+id/heartIcon" />
<com.google.android.material.button.MaterialButton
android:id="@+id/githubButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/colorBackgroundGitHub"
android:textColor="@color/colorWhite"
android:text="@string/action_view_github"
app:layout_constraintTop_toBottomOf="@+id/supportInfoText" />
<com.google.android.material.button.MaterialButton
android:id="@+id/rateButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/colorBackgroundPlayStore"
android:textColor="@color/colorWhite"
android:text="@string/action_rate"
app:layout_constraintTop_toBottomOf="@+id/githubButton" />
<LinearLayout
android:id="@+id/supportButtons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@+id/rateButton" />
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
<com.google.android.material.card.MaterialCardView
android:id="@+id/bottomSheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:translationY="16dp"
app:cardCornerRadius="16dp"
app:cardElevation="4dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_marginBottom="16dp"
android:background="@color/colorBackground" />
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -5,4 +5,7 @@
<color name="colorAccent">#d32f2f</color>
<color name="colorBackground">#FFFFFF</color>
<color name="colorOnBackground">#000000</color>
<color name="colorBackgroundGitHub">#24292e</color>
<color name="colorWhite">#FFFFFFFF</color>
<color name="colorBackgroundPlayStore">#689f38</color>
</resources>

View file

@ -2,8 +2,6 @@
<string name="app_name">Simple Markdown</string>
<string name="app_name_short">Markdown</string>
<string name="admob_app_id">ca-app-pub-3319579963502409~4576405307</string>
<string name="action_settings">Settings</string>
<string name="action_help">Help</string>
<string name="action_edit">Edit</string>
@ -65,6 +63,20 @@
<string name="prompt_save_changes">Would you like to save your changes?</string>
<string name="action_discard">Discard</string>
<string name="action_save_as">Save as…</string>
<string name="support_info">SimpleMarkdown is a personal project of mine that I develop and
maintain in my free time. I very much appreciate any and all forms of support, whether
that be assistance with designing the app or icons, adding translations for other
languages, contributing to the code, or giving me a tip. If you have any troubles with
SimpleMarkdown, please don\'t hesitate to get in touch, and if you haven\'t already,
please rate the app on the Play Store.\n\nAlso please keep in mind that the in-app
purchases for the tips won\'t unlock any additional functionality in the app.
SimpleMarkdown is and always will be completely free and open source!</string>
<string name="action_view_github">View SimpleMarkdown on GitHub</string>
<string name="support_title">Support SimpleMarkdown</string>
<string name="support_button_purchase">%1$s %2$s</string>
<string name="action_rate">Rate SimpleMarkdown</string>
<string name="support_thank_you">Thank you so much for your support!</string>
<string name="description_heart">Heart</string>
<string-array name="pref_entries_dark_mode">
<item>@string/pref_value_light</item>
<item>@string/pref_value_dark</item>

View file

@ -10,7 +10,7 @@ buildscript {
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.1'
classpath 'com.android.tools.build:gradle:3.5.2'
classpath 'com.google.gms:google-services:4.3.2'
classpath 'io.fabric.tools:gradle:1.31.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"