Split free & play code into separate gradle modules
This will hopefully enable me to use the gradle build health plugin, and still be compliant with F-Droid's policies. A consequence of this is that I had to go back to ACRA for error reporting, since I couldn't find a way to keep Firebase's gradle plugins on a library module instead of the main app module
This commit is contained in:
parent
de9956cbf7
commit
2a0cc4d889
35 changed files with 360 additions and 168 deletions
1
app/.gitignore
vendored
1
app/.gitignore
vendored
|
@ -2,4 +2,3 @@
|
|||
*.apk
|
||||
*.aab
|
||||
/release
|
||||
acra.properties
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import java.io.FileInputStream
|
||||
import java.io.FileNotFoundException
|
||||
import java.util.Locale
|
||||
import java.util.Properties
|
||||
|
||||
plugins {
|
||||
|
@ -111,6 +110,8 @@ play {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
"freeImplementation"(project(":free"))
|
||||
"playImplementation"(project(":non-free"))
|
||||
implementation("androidx.compose.material3:material3-window-size-class-android:1.2.0")
|
||||
val navigationVersion = "2.7.2"
|
||||
implementation("androidx.navigation:navigation-fragment-ktx:$navigationVersion")
|
||||
|
@ -134,7 +135,6 @@ dependencies {
|
|||
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
|
||||
implementation("com.google.android.material:material:1.9.0")
|
||||
implementation("androidx.legacy:legacy-support-v13:1.0.0")
|
||||
implementation("com.jakewharton.timber:timber:5.0.1")
|
||||
implementation("androidx.core:core-ktx:1.12.0")
|
||||
implementation("androidx.browser:browser:1.6.0")
|
||||
val commonMarkVersion = "0.22.0"
|
||||
|
@ -169,21 +169,6 @@ dependencies {
|
|||
implementation("eu.crydee:syllable-counter:4.0.2")
|
||||
}
|
||||
|
||||
android.productFlavors.forEach { flavor ->
|
||||
if (gradle.startParameter.taskRequests.toString().lowercase(Locale.getDefault()).contains(flavor.name)
|
||||
&& flavor.name == "play"
|
||||
) {
|
||||
apply(plugin = "com.google.gms.google-services")
|
||||
apply(plugin = "com.google.firebase.crashlytics")
|
||||
|
||||
dependencies {
|
||||
implementation("com.android.billingclient:billing:6.0.1")
|
||||
implementation("com.google.android.play:core-ktx:1.8.1")
|
||||
implementation("com.google.firebase:firebase-crashlytics:18.4.1")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fladle {
|
||||
variant.set("playDebug")
|
||||
useOrchestrator.set(true)
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
{
|
||||
"project_info": {
|
||||
"project_number": "318641233555",
|
||||
"firebase_url": "https://simplemarkdown.firebaseio.com",
|
||||
"project_id": "simplemarkdown",
|
||||
"storage_bucket": "simplemarkdown.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:318641233555:android:09d865cad87e3b5f",
|
||||
"android_client_info": {
|
||||
"package_name": "com.wbrawner.simplemarkdown"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "318641233555-83n2k1mqhokf0b7lhccqiva9pspgripq.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.wbrawner.simplemarkdown",
|
||||
"certificate_hash": "710e37c230689bc259fc6e2e032e2f56956f8d33"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "318641233555-a5rm2cqqf66jc9j5nmg3ttepdt2iaeno.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyBDMcXg-10NsXLDKJRtj5WnXoHrwg3m9Os"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "318641233555-a5rm2cqqf66jc9j5nmg3ttepdt2iaeno.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"admob_app_id": "ca-app-pub-3319579963502409~4576405307"
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:318641233555:android:5dfb62206717437e",
|
||||
"android_client_info": {
|
||||
"package_name": "com.wbrawner.simplemarkdown.samsung"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "318641233555-a5rm2cqqf66jc9j5nmg3ttepdt2iaeno.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyBDMcXg-10NsXLDKJRtj5WnXoHrwg3m9Os"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "318641233555-a5rm2cqqf66jc9j5nmg3ttepdt2iaeno.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package com.wbrawner.simplemarkdown.utility
|
||||
|
||||
import timber.log.Timber
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class errorHandlerImpl {
|
||||
operator fun getValue(thisRef: Any, property: KProperty<*>): ErrorHandler {
|
||||
return implementation
|
||||
}
|
||||
|
||||
companion object {
|
||||
// Default no-op error handler for debugging
|
||||
val implementation: ErrorHandler = object : ErrorHandler {
|
||||
override fun enable(enable: Boolean) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
override fun reportException(t: Throwable, message: String?) {
|
||||
Timber.e(t, "Caught non-fatal exception. Message: $message")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -41,6 +41,7 @@ import com.wbrawner.simplemarkdown.ui.SettingsScreen
|
|||
import com.wbrawner.simplemarkdown.ui.SupportScreen
|
||||
import com.wbrawner.simplemarkdown.ui.theme.SimpleMarkdownTheme
|
||||
import com.wbrawner.simplemarkdown.utility.Preference
|
||||
import org.acra.ACRA
|
||||
|
||||
class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsResultCallback {
|
||||
private val viewModel: MarkdownViewModel by viewModels {
|
||||
|
@ -84,6 +85,11 @@ class MainActivity : AppCompatActivity(), ActivityCompat.OnRequestPermissionsRes
|
|||
}
|
||||
AppCompatDelegate.setDefaultNightMode(darkMode)
|
||||
}
|
||||
val errorReporterPreference by preferenceHelper.observe<Boolean>(Preference.ERROR_REPORTS_ENABLED)
|
||||
.collectAsState()
|
||||
LaunchedEffect(errorReporterPreference) {
|
||||
ACRA.errorReporter.setEnabled(errorReporterPreference)
|
||||
}
|
||||
val windowSizeClass = calculateWindowSizeClass(this)
|
||||
SimpleMarkdownTheme {
|
||||
val navController = rememberNavController()
|
||||
|
|
|
@ -2,6 +2,7 @@ package com.wbrawner.simplemarkdown
|
|||
|
||||
import android.app.Application
|
||||
import android.os.StrictMode
|
||||
import com.wbrawner.simplemarkdown.core.ErrorReporterTree
|
||||
import com.wbrawner.simplemarkdown.utility.AndroidFileHelper
|
||||
import com.wbrawner.simplemarkdown.utility.AndroidPreferenceHelper
|
||||
import com.wbrawner.simplemarkdown.utility.FileHelper
|
||||
|
@ -34,6 +35,7 @@ class MarkdownApplication : Application() {
|
|||
}
|
||||
}
|
||||
}
|
||||
Timber.plant(ErrorReporterTree.create(this))
|
||||
super.onCreate()
|
||||
ReviewHelper.init(this)
|
||||
fileHelper = AndroidFileHelper(this)
|
||||
|
|
|
@ -29,6 +29,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import com.wbrawner.simplemarkdown.BuildConfig
|
||||
import com.wbrawner.simplemarkdown.ui.theme.SimpleMarkdownTheme
|
||||
import com.wbrawner.simplemarkdown.utility.Preference
|
||||
import com.wbrawner.simplemarkdown.utility.PreferenceHelper
|
||||
|
@ -79,6 +80,25 @@ fun SettingsScreen(navController: NavController, preferenceHelper: PreferenceHel
|
|||
preference = Preference.READABILITY_ENABLED,
|
||||
preferenceHelper = preferenceHelper
|
||||
)
|
||||
if (BuildConfig.DEBUG) {
|
||||
Row(modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable {
|
||||
error("Forced crash")
|
||||
}
|
||||
.padding(16.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically) {
|
||||
Column(verticalArrangement = Arrangement.Center) {
|
||||
Text(text = "Force a crash", style = MaterialTheme.typography.bodyLarge)
|
||||
Text(
|
||||
text = "Purposefully crash the app for testing purposes",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
package com.wbrawner.simplemarkdown.utility
|
||||
|
||||
interface ErrorHandler {
|
||||
fun enable(enable: Boolean)
|
||||
fun reportException(t: Throwable, message: String? = null)
|
||||
}
|
|
@ -62,6 +62,6 @@ enum class Preference(val key: String, val default: Any?) {
|
|||
AUTOSAVE_URI("autosave.uri", null),
|
||||
CUSTOM_CSS("pref.custom_css", null),
|
||||
DARK_MODE("darkMode", "Auto"),
|
||||
ERROR_REPORTS_ENABLED("crashlytics.enable", true),
|
||||
ERROR_REPORTS_ENABLED("acra.enable", true),
|
||||
READABILITY_ENABLED("readability.enable", false)
|
||||
}
|
|
@ -72,9 +72,7 @@
|
|||
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>
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
package com.wbrawner.simplemarkdown.utility
|
||||
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.wbrawner.simplemarkdown.BuildConfig
|
||||
import timber.log.Timber
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
class CrashlyticsErrorHandler : ErrorHandler {
|
||||
private val crashlytics = FirebaseCrashlytics.getInstance()
|
||||
|
||||
override fun enable(enable: Boolean) {
|
||||
crashlytics.setCrashlyticsCollectionEnabled(enable)
|
||||
}
|
||||
|
||||
override fun reportException(t: Throwable, message: String?) {
|
||||
@Suppress("ConstantConditionIf")
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.e(t, "Caught exception: $message")
|
||||
}
|
||||
crashlytics.recordException(t)
|
||||
}
|
||||
}
|
||||
|
||||
class errorHandlerImpl {
|
||||
operator fun getValue(thisRef: Any, property: KProperty<*>): ErrorHandler {
|
||||
return impl
|
||||
}
|
||||
|
||||
companion object {
|
||||
val impl = CrashlyticsErrorHandler()
|
||||
}
|
||||
}
|
|
@ -13,6 +13,10 @@ buildscript {
|
|||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("com.autonomousapps.dependency-analysis") version "1.31.0"
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
google()
|
||||
|
|
2
core/.gitignore
vendored
Normal file
2
core/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
/build
|
||||
/acra.properties
|
66
core/build.gradle.kts
Normal file
66
core/build.gradle.kts
Normal file
|
@ -0,0 +1,66 @@
|
|||
import java.io.FileInputStream
|
||||
import java.io.FileNotFoundException
|
||||
import java.util.Properties
|
||||
|
||||
plugins {
|
||||
id("com.android.library")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
}
|
||||
|
||||
val acraProperties = Properties()
|
||||
try {
|
||||
val acraPropertiesFile = project.file("acra.properties")
|
||||
acraProperties.load(FileInputStream(acraPropertiesFile))
|
||||
} catch (ignored: FileNotFoundException) {
|
||||
logger.warn("Unable to load ACRA properties. Error reporting won't be available")
|
||||
acraProperties["url"] = ""
|
||||
acraProperties["user"] = ""
|
||||
acraProperties["pass"] = ""
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.wbrawner.simplemarkdown.core"
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 23
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
buildConfigField("String", "ACRA_URL", "\"${acraProperties["url"]}\"")
|
||||
buildConfigField("String", "ACRA_USER", "\"${acraProperties["user"]}\"")
|
||||
buildConfigField("String", "ACRA_PASS", "\"${acraProperties["pass"]}\"")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
val acraVersion = "5.11.3"
|
||||
api("ch.acra:acra-core:$acraVersion")
|
||||
implementation("ch.acra:acra-http:$acraVersion")
|
||||
implementation("ch.acra:acra-limiter:$acraVersion")
|
||||
implementation("ch.acra:acra-advanced-scheduler:$acraVersion")
|
||||
api("com.jakewharton.timber:timber:5.0.1")
|
||||
implementation("androidx.core:core-ktx:1.13.1")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("com.google.android.material:material:1.12.0")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||
}
|
0
core/consumer-rules.pro
Normal file
0
core/consumer-rules.pro
Normal file
21
core/proguard-rules.pro
vendored
Normal file
21
core/proguard-rules.pro
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
4
core/src/main/AndroidManifest.xml
Normal file
4
core/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</manifest>
|
|
@ -0,0 +1,37 @@
|
|||
package com.wbrawner.simplemarkdown.core
|
||||
|
||||
import android.app.Application
|
||||
import android.util.Log
|
||||
import org.acra.ACRA
|
||||
import org.acra.config.httpSender
|
||||
import org.acra.data.StringFormat
|
||||
import org.acra.ktx.initAcra
|
||||
import org.acra.ktx.sendSilentlyWithAcra
|
||||
import org.acra.sender.HttpSender
|
||||
import timber.log.Timber
|
||||
|
||||
class ErrorReporterTree private constructor(): Timber.Tree() {
|
||||
override fun log(priority: Int, tag: String?, message: String, t: Throwable?) {
|
||||
if (priority != Log.ERROR) return
|
||||
t?.sendSilentlyWithAcra()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(application: Application): ErrorReporterTree {
|
||||
application.createErrorReporterTree()
|
||||
return ErrorReporterTree()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Application.createErrorReporterTree() {
|
||||
initAcra {
|
||||
reportFormat = StringFormat.JSON
|
||||
httpSender {
|
||||
uri = "${BuildConfig.ACRA_URL}/report" /*best guess, you may need to adjust this*/
|
||||
basicAuthLogin = BuildConfig.ACRA_USER
|
||||
basicAuthPassword = BuildConfig.ACRA_PASS
|
||||
httpMethod = HttpSender.Method.POST
|
||||
}
|
||||
}
|
||||
}
|
1
free/.gitignore
vendored
Normal file
1
free/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/build
|
63
free/build.gradle.kts
Normal file
63
free/build.gradle.kts
Normal file
|
@ -0,0 +1,63 @@
|
|||
plugins {
|
||||
id("com.android.library")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.wbrawner.simplemarkdown.free"
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 23
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.5.3"
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(project(":core"))
|
||||
implementation("androidx.core:core-ktx:1.13.1")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("com.google.android.material:material:1.12.0")
|
||||
implementation("com.jakewharton.timber:timber:5.0.1")
|
||||
val composeBom = platform("androidx.compose:compose-bom:2023.08.00")
|
||||
implementation(composeBom)
|
||||
androidTestImplementation(composeBom)
|
||||
implementation("androidx.compose.runtime:runtime")
|
||||
implementation("androidx.compose.ui:ui")
|
||||
implementation("androidx.activity:activity-compose")
|
||||
implementation("androidx.compose.foundation:foundation")
|
||||
implementation("androidx.compose.foundation:foundation-layout")
|
||||
implementation("androidx.compose.material:material")
|
||||
implementation("androidx.compose.runtime:runtime-livedata")
|
||||
implementation("androidx.compose.ui:ui-tooling")
|
||||
implementation("androidx.compose.material3:material3")
|
||||
implementation("androidx.compose.material:material-icons-extended")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||
}
|
0
free/consumer-rules.pro
Normal file
0
free/consumer-rules.pro
Normal file
21
free/proguard-rules.pro
vendored
Normal file
21
free/proguard-rules.pro
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
4
free/src/main/AndroidManifest.xml
Normal file
4
free/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
</manifest>
|
|
@ -2,5 +2,6 @@ package com.wbrawner.simplemarkdown.utility
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
|
||||
// TODO: Link out to liberapay, GH Sponsors, PayPal, etc
|
||||
@Composable
|
||||
fun SupportLinks() {}
|
1
non-free/.gitignore
vendored
Normal file
1
non-free/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/build
|
65
non-free/build.gradle.kts
Normal file
65
non-free/build.gradle.kts
Normal file
|
@ -0,0 +1,65 @@
|
|||
plugins {
|
||||
id("com.android.library")
|
||||
id("org.jetbrains.kotlin.android")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.wbrawner.simplemarkdown"
|
||||
compileSdk = 34
|
||||
|
||||
defaultConfig {
|
||||
minSdk = 23
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
proguardFiles(
|
||||
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||
"proguard-rules.pro"
|
||||
)
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
buildFeatures {
|
||||
compose = true
|
||||
}
|
||||
composeOptions {
|
||||
kotlinCompilerExtensionVersion = "1.5.3"
|
||||
}
|
||||
kotlinOptions {
|
||||
jvmTarget = "1.8"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api(project(":core"))
|
||||
implementation("androidx.core:core-ktx:1.13.1")
|
||||
implementation("androidx.appcompat:appcompat:1.6.1")
|
||||
implementation("androidx.preference:preference-ktx:1.2.1")
|
||||
implementation("com.android.billingclient:billing:6.0.1")
|
||||
implementation("com.google.android.play:core-ktx:1.8.1")
|
||||
implementation("com.jakewharton.timber:timber:5.0.1")
|
||||
val composeBom = platform("androidx.compose:compose-bom:2023.08.00")
|
||||
implementation(composeBom)
|
||||
androidTestImplementation(composeBom)
|
||||
implementation("androidx.compose.runtime:runtime")
|
||||
implementation("androidx.compose.ui:ui")
|
||||
implementation("androidx.activity:activity-compose")
|
||||
implementation("androidx.compose.foundation:foundation")
|
||||
implementation("androidx.compose.foundation:foundation-layout")
|
||||
implementation("androidx.compose.material:material")
|
||||
implementation("androidx.compose.runtime:runtime-livedata")
|
||||
implementation("androidx.compose.ui:ui-tooling")
|
||||
implementation("androidx.compose.material3:material3")
|
||||
implementation("androidx.compose.material:material-icons-extended")
|
||||
testImplementation("junit:junit:4.13.2")
|
||||
androidTestImplementation("androidx.test.ext:junit:1.1.5")
|
||||
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
|
||||
}
|
0
non-free/consumer-rules.pro
Normal file
0
non-free/consumer-rules.pro
Normal file
21
non-free/proguard-rules.pro
vendored
Normal file
21
non-free/proguard-rules.pro
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
# Add project specific ProGuard rules here.
|
||||
# You can control the set of applied configuration files using the
|
||||
# proguardFiles setting in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
||||
|
||||
# Uncomment this to preserve the line number information for
|
||||
# debugging stack traces.
|
||||
#-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
# If you keep the line number information, uncomment this to
|
||||
# hide the original source file name.
|
||||
#-renamesourcefileattribute SourceFile
|
4
non-free/src/main/AndroidManifest.xml
Normal file
4
non-free/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="com.android.vending.BILLING" />
|
||||
</manifest>
|
|
@ -9,7 +9,6 @@ import androidx.core.content.edit
|
|||
import androidx.preference.PreferenceManager
|
||||
import com.google.android.play.core.review.ReviewManager
|
||||
import com.google.android.play.core.review.ReviewManagerFactory
|
||||
import com.wbrawner.simplemarkdown.MainActivity
|
||||
import timber.log.Timber
|
||||
|
||||
private const val KEY_TIME_IN_APP = "timeInApp"
|
||||
|
@ -41,13 +40,12 @@ object ReviewHelper : Application.ActivityLifecycleCallbacks {
|
|||
fun init(
|
||||
application: Application,
|
||||
sharedPreferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(application),
|
||||
reviewManager: ReviewManager = ReviewManagerFactory.create(application),
|
||||
timber: Timber.Tree = Timber.asTree()
|
||||
) {
|
||||
this.application = application
|
||||
this.sharedPreferences = sharedPreferences
|
||||
this.reviewManager = reviewManager
|
||||
this.timber = timber
|
||||
reviewManager = ReviewManagerFactory.create(application)
|
||||
ReviewHelper.application = application
|
||||
ReviewHelper.sharedPreferences = sharedPreferences
|
||||
ReviewHelper.timber = timber
|
||||
if (sharedPreferences.getLong(KEY_TIME_IN_APP, 0L) == -1L) {
|
||||
// We've already prompted the user for the review so let's not be annoying about it
|
||||
timber.i("User already prompted for review, not configuring ReviewHelper")
|
||||
|
@ -64,7 +62,7 @@ object ReviewHelper : Application.ActivityLifecycleCallbacks {
|
|||
if (activityCount++ == 0) {
|
||||
activeTime = SystemClock.elapsedRealtime()
|
||||
}
|
||||
if (activity !is MainActivity || sharedPreferences.getLong(KEY_TIME_IN_APP, 0L) < TIME_TO_PROMPT) {
|
||||
if (sharedPreferences.getLong(KEY_TIME_IN_APP, 0L) < TIME_TO_PROMPT) {
|
||||
// Not ready to prompt just yet
|
||||
timber.v("Not ready to prompt user for review yet")
|
||||
return
|
|
@ -22,6 +22,7 @@ import com.android.billingclient.api.ConsumeParams
|
|||
import com.android.billingclient.api.ProductDetails
|
||||
import com.android.billingclient.api.QueryProductDetailsParams
|
||||
import com.wbrawner.simplemarkdown.R
|
||||
import timber.log.Timber
|
||||
|
||||
@Composable
|
||||
fun SupportLinks() {
|
||||
|
@ -68,6 +69,7 @@ fun SupportLinks() {
|
|||
.build()
|
||||
billingClient?.queryProductDetailsAsync(productDetailsQuery) { result, productDetails ->
|
||||
if (result.responseCode != BillingClient.BillingResponseCode.OK || productDetails.isEmpty()) {
|
||||
Timber.w("Failed to load product details: ${result.debugMessage}")
|
||||
return@queryProductDetailsAsync
|
||||
}
|
||||
products =
|
6
non-free/src/main/res/values/strings.xml
Normal file
6
non-free/src/main/res/values/strings.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="support_button_purchase">%1$s – %2$s</string>
|
||||
<string name="support_thank_you">Thank you so much for your support!</string>
|
||||
<string name="description_heart">Heart</string>
|
||||
</resources>
|
|
@ -1 +1 @@
|
|||
include(":app")
|
||||
include(":app", ":core", ":free", "non-free")
|
||||
|
|
Loading…
Reference in a new issue