From 2a0cc4d889431fd17954e0cf84a4485dbbfc3d24 Mon Sep 17 00:00:00 2001 From: William Brawner Date: Sat, 18 May 2024 22:13:39 -0600 Subject: [PATCH] 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 --- app/.gitignore | 1 - app/build.gradle.kts | 19 +---- app/google-services.json | 78 ------------------- .../simplemarkdown/utility/ErrorHandler.kt | 23 ------ .../wbrawner/simplemarkdown/MainActivity.kt | 6 ++ .../simplemarkdown/MarkdownApplication.kt | 2 + .../simplemarkdown/ui/SettingsScreen.kt | 20 +++++ .../simplemarkdown/utility/ErrorHandler.kt | 6 -- .../utility/PreferenceHelper.kt | 2 +- app/src/main/res/values/strings.xml | 2 - .../utility/CrashlyticsErrorHandler.kt | 32 -------- build.gradle.kts | 4 + core/.gitignore | 2 + {app => core}/acra.properties.sample | 0 core/build.gradle.kts | 66 ++++++++++++++++ core/consumer-rules.pro | 0 core/proguard-rules.pro | 21 +++++ core/src/main/AndroidManifest.xml | 4 + .../simplemarkdown/core/ErrorReporterTree.kt | 37 +++++++++ free/.gitignore | 1 + free/build.gradle.kts | 63 +++++++++++++++ free/consumer-rules.pro | 0 free/proguard-rules.pro | 21 +++++ free/src/main/AndroidManifest.xml | 4 + .../simplemarkdown/utility/ReviewHelper.kt | 0 .../utility/SupportLinkProvider.kt | 1 + non-free/.gitignore | 1 + non-free/build.gradle.kts | 65 ++++++++++++++++ non-free/consumer-rules.pro | 0 non-free/proguard-rules.pro | 21 +++++ non-free/src/main/AndroidManifest.xml | 4 + .../simplemarkdown/utility/ReviewHelper.kt | 12 ++- .../utility/SupportLinkProvider.kt | 2 + non-free/src/main/res/values/strings.xml | 6 ++ settings.gradle.kts | 2 +- 35 files changed, 360 insertions(+), 168 deletions(-) delete mode 100644 app/google-services.json delete mode 100644 app/src/free/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt delete mode 100644 app/src/main/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt delete mode 100644 app/src/play/java/com/wbrawner/simplemarkdown/utility/CrashlyticsErrorHandler.kt create mode 100644 core/.gitignore rename {app => core}/acra.properties.sample (100%) create mode 100644 core/build.gradle.kts create mode 100644 core/consumer-rules.pro create mode 100644 core/proguard-rules.pro create mode 100644 core/src/main/AndroidManifest.xml create mode 100644 core/src/main/java/com/wbrawner/simplemarkdown/core/ErrorReporterTree.kt create mode 100644 free/.gitignore create mode 100644 free/build.gradle.kts create mode 100644 free/consumer-rules.pro create mode 100644 free/proguard-rules.pro create mode 100644 free/src/main/AndroidManifest.xml rename {app/src/free => free/src/main}/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt (100%) rename {app/src/free => free/src/main}/java/com/wbrawner/simplemarkdown/utility/SupportLinkProvider.kt (68%) create mode 100644 non-free/.gitignore create mode 100644 non-free/build.gradle.kts create mode 100644 non-free/consumer-rules.pro create mode 100644 non-free/proguard-rules.pro create mode 100644 non-free/src/main/AndroidManifest.xml rename {app/src/play => non-free/src/main}/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt (91%) rename {app/src/play => non-free/src/main}/java/com/wbrawner/simplemarkdown/utility/SupportLinkProvider.kt (97%) create mode 100644 non-free/src/main/res/values/strings.xml diff --git a/app/.gitignore b/app/.gitignore index 88a8265..78c9600 100644 --- a/app/.gitignore +++ b/app/.gitignore @@ -2,4 +2,3 @@ *.apk *.aab /release -acra.properties diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 689489c..1acc3a1 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -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) diff --git a/app/google-services.json b/app/google-services.json deleted file mode 100644 index 169bd73..0000000 --- a/app/google-services.json +++ /dev/null @@ -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" -} \ No newline at end of file diff --git a/app/src/free/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt b/app/src/free/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt deleted file mode 100644 index abd3cd0..0000000 --- a/app/src/free/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt +++ /dev/null @@ -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") - } - } - } -} diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/MainActivity.kt b/app/src/main/java/com/wbrawner/simplemarkdown/MainActivity.kt index f1ea8f6..873f940 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/MainActivity.kt +++ b/app/src/main/java/com/wbrawner/simplemarkdown/MainActivity.kt @@ -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(Preference.ERROR_REPORTS_ENABLED) + .collectAsState() + LaunchedEffect(errorReporterPreference) { + ACRA.errorReporter.setEnabled(errorReporterPreference) + } val windowSizeClass = calculateWindowSizeClass(this) SimpleMarkdownTheme { val navController = rememberNavController() diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/MarkdownApplication.kt b/app/src/main/java/com/wbrawner/simplemarkdown/MarkdownApplication.kt index 6b0b887..7aa1ef4 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/MarkdownApplication.kt +++ b/app/src/main/java/com/wbrawner/simplemarkdown/MarkdownApplication.kt @@ -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) diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/ui/SettingsScreen.kt b/app/src/main/java/com/wbrawner/simplemarkdown/ui/SettingsScreen.kt index a519c9b..e612a91 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/ui/SettingsScreen.kt +++ b/app/src/main/java/com/wbrawner/simplemarkdown/ui/SettingsScreen.kt @@ -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 + ) + } + } + } } } } diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt b/app/src/main/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt deleted file mode 100644 index a961b4b..0000000 --- a/app/src/main/java/com/wbrawner/simplemarkdown/utility/ErrorHandler.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.wbrawner.simplemarkdown.utility - -interface ErrorHandler { - fun enable(enable: Boolean) - fun reportException(t: Throwable, message: String? = null) -} diff --git a/app/src/main/java/com/wbrawner/simplemarkdown/utility/PreferenceHelper.kt b/app/src/main/java/com/wbrawner/simplemarkdown/utility/PreferenceHelper.kt index e50bc10..bae6b30 100644 --- a/app/src/main/java/com/wbrawner/simplemarkdown/utility/PreferenceHelper.kt +++ b/app/src/main/java/com/wbrawner/simplemarkdown/utility/PreferenceHelper.kt @@ -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) } \ 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 32767f3..603f757 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -72,9 +72,7 @@ SimpleMarkdown is and always will be completely free and open source! View SimpleMarkdown on GitHub Support SimpleMarkdown - %1$s – %2$s Rate SimpleMarkdown - Thank you so much for your support! Heart @string/pref_value_light diff --git a/app/src/play/java/com/wbrawner/simplemarkdown/utility/CrashlyticsErrorHandler.kt b/app/src/play/java/com/wbrawner/simplemarkdown/utility/CrashlyticsErrorHandler.kt deleted file mode 100644 index bf4c065..0000000 --- a/app/src/play/java/com/wbrawner/simplemarkdown/utility/CrashlyticsErrorHandler.kt +++ /dev/null @@ -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() - } -} diff --git a/build.gradle.kts b/build.gradle.kts index be1bd56..79ae3be 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,6 +13,10 @@ buildscript { } } +plugins { + id("com.autonomousapps.dependency-analysis") version "1.31.0" +} + allprojects { repositories { google() diff --git a/core/.gitignore b/core/.gitignore new file mode 100644 index 0000000..4e2ad02 --- /dev/null +++ b/core/.gitignore @@ -0,0 +1,2 @@ +/build +/acra.properties diff --git a/app/acra.properties.sample b/core/acra.properties.sample similarity index 100% rename from app/acra.properties.sample rename to core/acra.properties.sample diff --git a/core/build.gradle.kts b/core/build.gradle.kts new file mode 100644 index 0000000..fd8033f --- /dev/null +++ b/core/build.gradle.kts @@ -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") +} \ No newline at end of file diff --git a/core/consumer-rules.pro b/core/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/core/proguard-rules.pro b/core/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/core/proguard-rules.pro @@ -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 \ No newline at end of file diff --git a/core/src/main/AndroidManifest.xml b/core/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a5918e6 --- /dev/null +++ b/core/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/core/src/main/java/com/wbrawner/simplemarkdown/core/ErrorReporterTree.kt b/core/src/main/java/com/wbrawner/simplemarkdown/core/ErrorReporterTree.kt new file mode 100644 index 0000000..10a7c7f --- /dev/null +++ b/core/src/main/java/com/wbrawner/simplemarkdown/core/ErrorReporterTree.kt @@ -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 + } + } +} \ No newline at end of file diff --git a/free/.gitignore b/free/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/free/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/free/build.gradle.kts b/free/build.gradle.kts new file mode 100644 index 0000000..561fac2 --- /dev/null +++ b/free/build.gradle.kts @@ -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") +} \ No newline at end of file diff --git a/free/consumer-rules.pro b/free/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/free/proguard-rules.pro b/free/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/free/proguard-rules.pro @@ -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 \ No newline at end of file diff --git a/free/src/main/AndroidManifest.xml b/free/src/main/AndroidManifest.xml new file mode 100644 index 0000000..a5918e6 --- /dev/null +++ b/free/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/free/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt b/free/src/main/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt similarity index 100% rename from app/src/free/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt rename to free/src/main/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt diff --git a/app/src/free/java/com/wbrawner/simplemarkdown/utility/SupportLinkProvider.kt b/free/src/main/java/com/wbrawner/simplemarkdown/utility/SupportLinkProvider.kt similarity index 68% rename from app/src/free/java/com/wbrawner/simplemarkdown/utility/SupportLinkProvider.kt rename to free/src/main/java/com/wbrawner/simplemarkdown/utility/SupportLinkProvider.kt index d39f9be..59ac1f0 100644 --- a/app/src/free/java/com/wbrawner/simplemarkdown/utility/SupportLinkProvider.kt +++ b/free/src/main/java/com/wbrawner/simplemarkdown/utility/SupportLinkProvider.kt @@ -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() {} \ No newline at end of file diff --git a/non-free/.gitignore b/non-free/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/non-free/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/non-free/build.gradle.kts b/non-free/build.gradle.kts new file mode 100644 index 0000000..06764c3 --- /dev/null +++ b/non-free/build.gradle.kts @@ -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") +} \ No newline at end of file diff --git a/non-free/consumer-rules.pro b/non-free/consumer-rules.pro new file mode 100644 index 0000000..e69de29 diff --git a/non-free/proguard-rules.pro b/non-free/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/non-free/proguard-rules.pro @@ -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 \ No newline at end of file diff --git a/non-free/src/main/AndroidManifest.xml b/non-free/src/main/AndroidManifest.xml new file mode 100644 index 0000000..51706e6 --- /dev/null +++ b/non-free/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/app/src/play/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt b/non-free/src/main/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt similarity index 91% rename from app/src/play/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt rename to non-free/src/main/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt index eea5807..37d98ea 100644 --- a/app/src/play/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt +++ b/non-free/src/main/java/com/wbrawner/simplemarkdown/utility/ReviewHelper.kt @@ -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 diff --git a/app/src/play/java/com/wbrawner/simplemarkdown/utility/SupportLinkProvider.kt b/non-free/src/main/java/com/wbrawner/simplemarkdown/utility/SupportLinkProvider.kt similarity index 97% rename from app/src/play/java/com/wbrawner/simplemarkdown/utility/SupportLinkProvider.kt rename to non-free/src/main/java/com/wbrawner/simplemarkdown/utility/SupportLinkProvider.kt index 768d19d..d748668 100644 --- a/app/src/play/java/com/wbrawner/simplemarkdown/utility/SupportLinkProvider.kt +++ b/non-free/src/main/java/com/wbrawner/simplemarkdown/utility/SupportLinkProvider.kt @@ -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 = diff --git a/non-free/src/main/res/values/strings.xml b/non-free/src/main/res/values/strings.xml new file mode 100644 index 0000000..809bb7e --- /dev/null +++ b/non-free/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ + + + %1$s – %2$s + Thank you so much for your support! + Heart + \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index 15a801b..66b7f51 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1 +1 @@ -include(":app") +include(":app", ":core", ":free", "non-free")