Merge branch 'support-simplemarkdown' into 'master'

Support SimpleMarkdown

See merge request billybrawner/SimpleMarkdown!5
This commit is contained in:
Billy Brawner 2019-11-07 23:29:02 +00:00
commit e7fe9918cf
23 changed files with 431 additions and 121 deletions

View file

@ -17,7 +17,6 @@ try {
keystoreProperties['storePassword'] = ""
}
android {
configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.1'
@ -88,27 +87,25 @@ dependencies {
androidTestUtil "androidx.test:orchestrator:$android_test"
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
implementation 'androidx.appcompat:appcompat:1.1.0-rc01'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.preference:preference:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.google.android.material:material:1.0.0'
implementation 'com.google.android.material:material:1.1.0-beta01'
implementation 'androidx.legacy:legacy-support-v13:1.0.0'
implementation 'com.commonsware.cwac:anddown:0.3.0'
implementation 'com.google.dagger:dagger:2.22.1'
annotationProcessor 'com.google.dagger:dagger-compiler:2.22.1'
kapt 'com.google.dagger:dagger-android-processor:2.22.1'
kapt 'com.google.dagger:dagger-compiler:2.22.1'
implementation 'com.google.firebase:firebase-core:17.1.0'
implementation 'com.google.firebase:firebase-core:17.2.1'
implementation 'com.android.billingclient:billing:1.2'
implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1'
implementation "androidx.core:core-ktx:1.0.2"
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"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
def lifecycle_version = "2.0.0"
def lifecycle_version = "2.1.0"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version"
kapt "androidx.lifecycle:lifecycle-compiler:$lifecycle_version"
kapt "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
implementation 'eu.crydee:syllable-counter:4.0.2'
}
@ -136,10 +133,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

@ -2,12 +2,17 @@ package com.wbrawner.simplemarkdown
import android.app.Application
import android.os.StrictMode
import com.wbrawner.simplemarkdown.utility.CrashlyticsErrorHandler
import com.wbrawner.simplemarkdown.utility.ErrorHandler
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModelFactory
class MarkdownApplication : Application() {
val viewModelFactory: MarkdownViewModelFactory by lazy {
MarkdownViewModelFactory()
}
val errorHandler: ErrorHandler by lazy {
CrashlyticsErrorHandler()
}
override fun onCreate() {
if (BuildConfig.DEBUG) {

View file

@ -1,14 +1,15 @@
package com.wbrawner.simplemarkdown.utility
import android.content.Context
import android.util.Log
import com.crashlytics.android.Crashlytics
import io.fabric.sdk.android.BuildConfig
import com.wbrawner.simplemarkdown.BuildConfig
import io.fabric.sdk.android.Fabric
import java.util.concurrent.atomic.AtomicBoolean
interface ErrorHandler {
fun init(context: Context)
fun reportException(t: Throwable)
fun reportException(t: Throwable, message: String? = null)
}
class CrashlyticsErrorHandler : ErrorHandler {
@ -20,8 +21,13 @@ class CrashlyticsErrorHandler : ErrorHandler {
}
}
override fun reportException(t: Throwable) {
if (!isInitialized.get() || BuildConfig.DEBUG) return
override fun reportException(t: Throwable, message: String?) {
@Suppress("ConstantConditionIf")
if (BuildConfig.DEBUG) {
Log.e("CrashlyticsErrorHandler", "Caught exception: $message", t)
return
}
if (!isInitialized.get()) return
Crashlytics.logException(t)
}
}

View file

@ -8,7 +8,6 @@ import android.content.res.Configuration
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.preference.PreferenceManager
import android.view.Menu
import android.view.MenuItem
import android.view.View
@ -20,25 +19,19 @@ import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.preference.PreferenceManager
import com.wbrawner.simplemarkdown.MarkdownApplication
import com.wbrawner.simplemarkdown.R
import com.wbrawner.simplemarkdown.utility.ErrorHandler
import com.wbrawner.simplemarkdown.utility.getName
import com.wbrawner.simplemarkdown.utility.readAssetToString
import com.wbrawner.simplemarkdown.utility.toHtml
import com.wbrawner.simplemarkdown.view.adapter.EditPagerAdapter
import com.wbrawner.simplemarkdown.view.fragment.MainMenuFragment
import com.wbrawner.simplemarkdown.viewmodel.MarkdownViewModel
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.*
import java.io.File
import java.io.FileInputStream
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsResultCallback, CoroutineScope {
@Inject
lateinit var errorHandler: ErrorHandler
private var shouldAutoSave = true
override val coroutineContext: CoroutineContext = Dispatchers.Main
private lateinit var viewModel: MarkdownViewModel
@ -47,6 +40,8 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_menu_black_24dp)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
window.decorView.apply {
systemUiVisibility = (
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
@ -89,7 +84,7 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes
// The user has left the app, with autosave enabled, and we don't already have a
// Uri for them or for some reason we were unable to save to the original Uri. In
// this case, we need to just save to internal file storage so that we can recover
val fileUri = Uri.fromFile(File(filesDir, viewModel.fileName.value))
val fileUri = Uri.fromFile(File(filesDir, viewModel.fileName.value!!))
if (viewModel.save(this@MainActivity, fileUri)) {
fileUri
} else {
@ -118,6 +113,13 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
MainMenuFragment()
.apply {
errorHandler = (application as MarkdownApplication).errorHandler
}
.show(supportFragmentManager, null)
}
R.id.action_save -> {
launch {
if (!viewModel.save(this@MainActivity)) {
@ -149,50 +151,10 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes
item.isChecked = !item.isChecked
pager!!.setSwipeLocked(item.isChecked)
}
R.id.action_help -> showInfoActivity(R.id.action_help)
R.id.action_settings -> {
val settingsIntent = Intent(this@MainActivity, SettingsActivity::class.java)
startActivityForResult(settingsIntent, REQUEST_DARK_MODE)
}
R.id.action_libraries -> showInfoActivity(R.id.action_libraries)
R.id.action_privacy -> showInfoActivity(R.id.action_privacy)
}
return super.onOptionsItemSelected(item)
}
private fun showInfoActivity(action: Int) {
val infoIntent = Intent(this@MainActivity, MarkdownInfoActivity::class.java)
var fileName = ""
var title = ""
when (action) {
R.id.action_help -> {
fileName = "Cheatsheet.md"
title = getString(R.string.action_help)
}
R.id.action_libraries -> {
fileName = "Libraries.md"
title = getString(R.string.action_libraries)
}
R.id.action_privacy -> {
fileName = "Privacy Policy.md"
title = getString(R.string.action_privacy)
}
}
infoIntent.putExtra("title", title)
launch {
try {
val html = assets?.readAssetToString(fileName)
?.toHtml()
?: throw RuntimeException("Unable to open stream to $fileName")
infoIntent.putExtra("html", html)
startActivity(infoIntent)
} catch (e: Exception) {
errorHandler.reportException(e)
Toast.makeText(this@MainActivity, R.string.file_load_error, Toast.LENGTH_SHORT).show()
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
@ -244,7 +206,6 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes
viewModel.save(this@MainActivity, data.data)
}
}
REQUEST_DARK_MODE -> recreate()
}
super.onActivityResult(requestCode, resultCode, data)
}

View file

@ -1,21 +1,69 @@
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.view.View
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)
window.decorView.apply {
systemUiVisibility = (
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
)
}
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 +71,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,100 @@
package com.wbrawner.simplemarkdown.view.fragment
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.wbrawner.simplemarkdown.R
import com.wbrawner.simplemarkdown.utility.ErrorHandler
import com.wbrawner.simplemarkdown.utility.readAssetToString
import com.wbrawner.simplemarkdown.utility.toHtml
import com.wbrawner.simplemarkdown.view.activity.MainActivity
import com.wbrawner.simplemarkdown.view.activity.MarkdownInfoActivity
import com.wbrawner.simplemarkdown.view.activity.SettingsActivity
import com.wbrawner.simplemarkdown.view.activity.SupportActivity
import kotlinx.android.synthetic.main.fragment_menu_main.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlin.coroutines.CoroutineContext
class MainMenuFragment : BottomSheetDialogFragment(), CoroutineScope {
override val coroutineContext: CoroutineContext = Dispatchers.Main
lateinit var errorHandler: ErrorHandler
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.fragment_menu_main, container, false)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mainMenuNavigationView.setNavigationItemSelectedListener {
when (it.itemId) {
R.id.action_help -> showInfoActivity(context, R.id.action_help)
R.id.action_settings -> {
val settingsIntent = Intent(context, SettingsActivity::class.java)
startActivityForResult(settingsIntent, MainActivity.REQUEST_DARK_MODE)
}
R.id.action_libraries -> showInfoActivity(context, R.id.action_libraries)
R.id.action_privacy -> showInfoActivity(context, R.id.action_privacy)
R.id.action_support -> Intent(context, SupportActivity::class.java)
.apply {
startActivity(this)
dialog?.dismiss()
}
}
true
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == MainActivity.REQUEST_DARK_MODE) {
activity?.recreate()
dialog?.dismiss()
return
}
super.onActivityResult(requestCode, resultCode, data)
}
private fun showInfoActivity(context: Context?, action: Int) {
val infoIntent = Intent(context, MarkdownInfoActivity::class.java)
var fileName = ""
var title = ""
when (action) {
R.id.action_help -> {
fileName = "Cheatsheet.md"
title = getString(R.string.action_help)
}
R.id.action_libraries -> {
fileName = "Libraries.md"
title = getString(R.string.action_libraries)
}
R.id.action_privacy -> {
fileName = "Privacy Policy.md"
title = getString(R.string.action_privacy)
}
}
infoIntent.putExtra("title", title)
launch {
// TODO: Refactor this to have the info activity load the markdown instead of doing
// it here
try {
val html = context?.assets?.readAssetToString(fileName)
?.toHtml()
?: throw RuntimeException("Unable to open stream to $fileName")
infoIntent.putExtra("html", html)
startActivity(infoIntent, null)
} catch (e: Exception) {
errorHandler.reportException(e)
Toast.makeText(context, R.string.file_load_error, Toast.LENGTH_SHORT).show()
}
dialog?.dismiss()
}
}
}

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,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z" />
</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="#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="#FF000000"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,19h-2v-2h2v2zM15.07,11.25l-0.9,0.92C13.45,12.9 13,13.5 13,15h-2v-0.5c0,-1.1 0.45,-2.1 1.17,-2.83l1.24,-1.26c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2L8,9c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,0.88 -0.36,1.68 -0.93,2.25z" />
</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="#FF000000"
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM13,17h-2v-6h2v6zM13,9h-2L11,7h2v2z" />
</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,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M19.1,12.9a2.8,2.8 0,0 0,0.1 -0.9,2.8 2.8,0 0,0 -0.1,-0.9l2.1,-1.6a0.7,0.7 0,0 0,0.1 -0.6L19.4,5.5a0.7,0.7 0,0 0,-0.6 -0.2l-2.4,1a6.5,6.5 0,0 0,-1.6 -0.9l-0.4,-2.6a0.5,0.5 0,0 0,-0.5 -0.4H10.1a0.5,0.5 0,0 0,-0.5 0.4L9.3,5.4a5.6,5.6 0,0 0,-1.7 0.9l-2.4,-1a0.4,0.4 0,0 0,-0.5 0.2l-2,3.4c-0.1,0.2 0,0.4 0.2,0.6l2,1.6a2.8,2.8 0,0 0,-0.1 0.9,2.8 2.8,0 0,0 0.1,0.9L2.8,14.5a0.7,0.7 0,0 0,-0.1 0.6l1.9,3.4a0.7,0.7 0,0 0,0.6 0.2l2.4,-1a6.5,6.5 0,0 0,1.6 0.9l0.4,2.6a0.5,0.5 0,0 0,0.5 0.4h3.8a0.5,0.5 0,0 0,0.5 -0.4l0.3,-2.6a5.6,5.6 0,0 0,1.7 -0.9l2.4,1a0.4,0.4 0,0 0,0.5 -0.2l2,-3.4c0.1,-0.2 0,-0.4 -0.2,-0.6ZM12,15.6A3.6,3.6 0,1 1,15.6 12,3.6 3.6,0 0,1 12,15.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="0dp"
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

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.navigation.NavigationView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/mainMenuNavigationView"
app:menu="@menu/menu_main" />

View file

@ -25,20 +25,4 @@
android:checkable="true"
android:title="@string/action_lock_swipe"
app:showAsAction="never" />
<item
android:id="@+id/action_settings"
android:title="@string/action_settings"
app:showAsAction="never" />
<item
android:id="@+id/action_help"
android:title="@string/action_help"
app:showAsAction="never" />
<item
android:id="@+id/action_libraries"
android:title="@string/action_libraries"
app:showAsAction="never" />
<item
android:id="@+id/action_privacy"
android:title="@string/action_privacy"
app:showAsAction="never" />
</menu>

View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<group android:id="@+id/mainGroup">
<item
android:id="@+id/action_settings"
android:title="@string/action_settings"
android:icon="@drawable/ic_settings_black_24dp"
app:showAsAction="never" />
<item
android:id="@+id/action_support"
android:title="@string/support_title"
android:icon="@drawable/ic_favorite_black_24dp"
app:showAsAction="never" />
</group>
<group android:id="@+id/addtionalInfoGroup">
<item
android:id="@+id/action_help"
android:title="@string/action_help"
android:icon="@drawable/ic_help_black_24dp"
app:showAsAction="never" />
<item
android:id="@+id/action_libraries"
android:title="@string/action_libraries"
android:icon="@drawable/ic_info_black_24dp"
app:showAsAction="never" />
<item
android:id="@+id/action_privacy"
android:title="@string/action_privacy"
android:icon="@drawable/ic_eye_black_24dp"
app:showAsAction="never" />
</group>
</menu>

View file

@ -1,6 +1,6 @@
<resources>
<style name="AppTheme" parent="Theme.AppCompat.NoActionBar">
<style name="AppTheme" parent="Theme.MaterialComponents.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>

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

@ -1,7 +1,7 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>

View file

@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = '1.3.31'
ext.kotlin_version = '1.3.50'
repositories {
jcenter()
google()
@ -10,9 +10,9 @@ buildscript {
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.4.2'
classpath 'com.google.gms:google-services:4.2.0'
classpath 'io.fabric.tools:gradle:1.26.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"
}
}

View file

@ -1,6 +1,6 @@
#Fri May 17 18:03:51 MST 2019
#Wed Nov 06 17:12:14 CST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip