From 028b66863caad602ff709a48488266d53eb6fa58 Mon Sep 17 00:00:00 2001 From: Arcao Date: Sun, 7 Apr 2024 00:15:41 +0200 Subject: [PATCH 1/7] Migrate to Kotlin DSL, TOML and update dependencies --- .idea/codeStyles/Project.xml | 2 - .idea/compiler.xml | 2 +- .idea/kotlinc.xml | 3 + .idea/misc.xml | 2 +- app/build.gradle | 173 ----------- app/build.gradle.kts | 211 +++++++++++++ app/src/main/AndroidManifest.xml | 7 +- .../authentication/LoginViewModel.kt | 4 +- .../base/constants/AppConstants.kt | 11 +- .../fragment/AbstractPreferenceFragment.kt | 2 +- .../base/util/KoinTimberLogger.kt | 3 +- .../ImportBookmarkActivity.kt | 8 +- .../fragment/BookmarkFragment.kt | 10 +- .../fragment/BookmarkListFragment.kt | 4 +- .../GeocacheCodesInputDialogFragment.kt | 23 +- .../live_map/LiveMapService.kt | 2 +- .../util/LiveMapNotificationManager.kt | 58 +--- .../settings/SettingsActivity.kt | 2 +- .../fragment/AdvancedPreferenceFragment.kt | 20 +- .../fragment/DownloadingPreferenceFragment.kt | 2 +- .../fragment/FilterPreferenceFragment.kt | 2 +- .../DifficultyFilterPreferenceFragment.kt | 2 +- .../filter/TerrainFilterPreferenceFragment.kt | 2 +- .../settings/widget/SliderPreference.kt | 2 +- .../locus/api/mapper/GeocacheConverter.kt | 7 +- build.gradle | 114 ------- build.gradle.kts | 34 +++ geocaching-api/build.gradle | 86 ------ geocaching-api/build.gradle.kts | 105 +++++++ ...chingOAuth2AccessTokenJsonExtractorTest.kt | 10 +- ...GeocachingAuthenticationInterceptorTest.kt | 10 +- gradle.properties | 3 +- gradle/libs.versions.toml | 132 ++++++++ gradle/wrapper/gradle-wrapper.jar | Bin 54329 -> 60756 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 286 +++++++++++------- gradlew.bat | 55 ++-- ktlint.gradle | 30 -- settings.gradle | 3 - settings.gradle.kts | 47 +++ versions.gradle | 63 ---- 41 files changed, 836 insertions(+), 708 deletions(-) delete mode 100644 app/build.gradle create mode 100644 app/build.gradle.kts delete mode 100644 build.gradle create mode 100644 build.gradle.kts delete mode 100644 geocaching-api/build.gradle create mode 100644 geocaching-api/build.gradle.kts create mode 100644 gradle/libs.versions.toml delete mode 100644 ktlint.gradle delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts delete mode 100644 versions.gradle diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 0c3bb70d..d36cd686 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -30,8 +30,6 @@ - - + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index a0911980..00000000 --- a/app/build.gradle +++ /dev/null @@ -1,173 +0,0 @@ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-parcelize' -apply plugin: 'kotlin-kapt' -apply plugin: 'com.google.firebase.crashlytics' -apply plugin: 'de.mannodermaus.android-junit5' - -dependencies { - // Android Support - implementation "androidx.appcompat:appcompat:$appcompat_version" - implementation "androidx.recyclerview:recyclerview:$recycler_view_version" - implementation "androidx.cardview:cardview:$card_view_version" - implementation "com.google.android.material:material:$material_version" - implementation "androidx.constraintlayout:constraintlayout:$constraint_layout_version" - implementation "androidx.preference:preference-ktx:$preference_version" - - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_extension_version" - - implementation "androidx.core:core-ktx:$core_version" - implementation "androidx.collection:collection-ktx:$collection_version" - implementation "androidx.browser:browser:$browser_version" - implementation "androidx.fragment:fragment-ktx:$fragment_version" - implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" - implementation "androidx.paging:paging-runtime-ktx:$paging_version" - - coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:$desugar_jdk_libs_version" - - // kotlin - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" - - // koin - implementation "io.insert-koin:koin-android:$koin_version" - - // Geocaching API - api project(":geocaching-api") - - // Locus API - implementation "com.asamm:locus-api-android:$locus_api_version" - - // Logging API - implementation "com.arcao:slf4j-timber:$slf4jtimber_version" - implementation "com.jakewharton.timber:timber:$timber_version" - - // Material dialogs - implementation "com.afollestad.material-dialogs:core:$material_dialogs_version" - implementation "com.afollestad.material-dialogs:input:$material_dialogs_version" - - // Crashlytics & Firebase - implementation platform("com.google.firebase:firebase-bom:$firebase_bom_version") - implementation 'com.google.firebase:firebase-crashlytics-ktx' - implementation 'com.google.firebase:firebase-analytics-ktx' - - // Networking - implementation "com.squareup.okhttp3:okhttp:$okhttp_version" -} - -android { - namespace 'com.arcao.geocaching4locus' - - compileSdkVersion rootProject.compile_sdk_version - - defaultConfig { - applicationId 'com.arcao.geocaching4locus' - archivesBaseName = parent.name - - minSdkVersion rootProject.min_sdk_version - targetSdkVersion rootProject.target_sdk_version - - versionName rootProject.version_name - versionCode hasProperty('devBuild') ? 1 : gitVersionCode() - - multiDexEnabled true - - aaptOptions { - cruncherEnabled = false - } - - buildConfigField 'String', 'GIT_SHA', 'null' - buildConfigField 'String', 'BUILD_TIME', 'null' - buildConfigField 'String', 'GEOCACHING_API_KEY', "\"${geocachingApiKey}\"" - buildConfigField 'String', 'GEOCACHING_API_SECRET', "\"${geocachingApiSecret}\"" - buildConfigField 'boolean', 'GEOCACHING_API_STAGING', "${geocachingApiStaging}" - - buildConfigField 'String', 'TEST_USER', 'null' - buildConfigField 'String', 'TEST_PASSWORD', 'null' - resConfigs 'en', 'cs', 'de', 'es', 'fr', 'nl', 'no', 'pl', 'sk' - - } - - compileOptions { - encoding 'UTF-8' - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - coreLibraryDesugaringEnabled true - } - - kotlinOptions { - freeCompilerArgs += [ - "-opt-in=kotlin.RequiresOptIn", - "-Xjvm-default=all-compatibility" - ] - jvmTarget = JavaVersion.VERSION_1_8 - } - - buildFeatures { - dataBinding = true - } - - signingConfigs { - release { - keyAlias = 'geocaching4locus' - } - } - - buildTypes { - debug { - ext.alwaysUpdateBuildId = false - versionNameSuffix '-dev' - crunchPngs false - - firebaseCrashlytics { - mappingFileUploadEnabled false - } - } - release { - versionNameSuffix '' - - buildConfigField 'String', 'GIT_SHA', '"' + gitSha() + '"' - buildConfigField 'String', 'BUILD_TIME', '"' + gitTimestamp() + '"' - - signingConfig signingConfigs.release - minifyEnabled false - // App crash on VerifyError on Android 4.2, 4.3; https://issuetracker.google.com/issues/134304597 - shrinkResources false - crunchPngs false - - proguardFile getDefaultProguardFile('proguard-android-optimize.txt') - proguardFiles fileTree(dir: 'proguard-rules', include: '*.pro').getFiles().toArray() - } - } - packagingOptions { - resources { - excludes += [ - 'META-INF/DEPENDENCIES', - 'META-INF/LICENSE', - 'META-INF/atomicfu.kotlin_module', - 'org/apache/http/version.properties', - 'templates/release-notes.vm', - 'log4j.xml' - ] - } - } - - lint { - abortOnError false - } -} - -if (project.hasProperty('storeFile') && - project.hasProperty('storePassword') && - project.hasProperty('keyPassword')) { - android.signingConfigs.release.storeFile = file(storeFile) - android.signingConfigs.release.storePassword = storePassword - android.signingConfigs.release.keyPassword = keyPassword -} else { - android.buildTypes.release.signingConfig = android.signingConfigs.debug -} - -apply plugin: 'com.google.gms.google-services' diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 00000000..210031a7 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,211 @@ +import java.io.ByteArrayOutputStream + +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + id("kotlin-kapt") + id("kotlin-parcelize") + alias(libs.plugins.firebase.crashlytics) + alias(libs.plugins.android.junit5) + alias(libs.plugins.google.services) +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +fun String.runCommand(currentWorkingDir: File = file("./")): String { + val byteOut = ByteArrayOutputStream() + project.exec { + workingDir = currentWorkingDir + commandLine = this@runCommand.split("\\s".toRegex()) + standardOutput = byteOut + } + return String(byteOut.toByteArray()).trim() +} + +fun gitSha() = "git rev-parse --short HEAD".runCommand(rootDir).trim() +fun gitTimestamp() = "git log -n 1 --format=%aI".runCommand(rootDir).trim() +fun gitVersionCode() = "git rev-list --count HEAD".runCommand(rootDir).trim().toInt() + +dependencies { + // Android Support + implementation(libs.androidx.appcompat) + implementation(libs.androidx.recyclerview) + implementation(libs.androidx.cardview) + implementation(libs.google.material) + implementation(libs.androidx.constraintlayout) + implementation(libs.androidx.preference.ktx) + + implementation(libs.androidx.lifecycle.viewmodel.ktx) + implementation(libs.androidx.lifecycle.livedata.ktx) + implementation(libs.androidx.lifecycle.extensions) + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.collection.ktx) + implementation(libs.androidx.browser) + implementation(libs.androidx.fragment.ktx) + implementation(libs.androidx.paging.runtime.ktx) + + // Java 8 libraries for older devices + coreLibraryDesugaring(libs.desugar.jdk.libs) + + // kotlin + implementation(libs.kotlin.stdlib) + implementation(libs.kotlinx.coroutines.core) + implementation(libs.kotlinx.coroutines.android) + + // koin + implementation(libs.koin.android) + + // Geocaching API + api(project(":geocaching-api")) + + // Locus API + implementation(libs.locus.android) + + // Logging API + implementation(libs.logging.slf4j.timber) + implementation(libs.logging.timber) + + // Material dialogs + implementation(libs.material.dialogs.core) + implementation(libs.material.dialogs.input) + + // Crashlytics & Firebase - Use Bill Of Materials to get working artifact combination + implementation(platform(libs.firebase.bom)) + implementation(libs.firebase.crashlytics) + implementation(libs.firebase.analytics) + + // Networking + implementation(libs.okhttp) +} + +android { + namespace = "com.arcao.geocaching4locus" + compileSdk = libs.versions.targetSdk.get().toInt() + + defaultConfig { + applicationId = "com.arcao.geocaching4locus" + + minSdk = libs.versions.minSdk.get().toInt() + targetSdk = libs.versions.targetSdk.get().toInt() + + versionName = libs.versions.app.get() + + multiDexEnabled = true + + // set Geocaching API staging key and secret if production key and secret is not set + // Note: Staging server is slow and not for production use!!!! + val geocachingApiKey = + properties["geocachingApiKey"] ?: "9C7552E1-3C04-4D04-A395-230D8931E494" + val geocachingApiSecret = + properties["geocachingApiSecret"] ?: "DA7CC147-7B5B-4423-BCB4-D0C03E2BF685" + val geocachingApiStaging = properties["geocachingApiStaging"] != "false" + + buildConfigField("String", "GIT_SHA", "null") + buildConfigField("String", "BUILD_TIME", "null") + buildConfigField("String", "GEOCACHING_API_KEY", "\"${geocachingApiKey}\"") + buildConfigField("String", "GEOCACHING_API_SECRET", "\"${geocachingApiSecret}\"") + buildConfigField("boolean", "GEOCACHING_API_STAGING", "${geocachingApiStaging}") + + buildConfigField("String", "TEST_USER", "null") + buildConfigField("String", "TEST_PASSWORD", "null") + resourceConfigurations += setOf("en", "cs", "de", "es", "fr", "nl", "no", "pl", "sk") + + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + *fileTree(mapOf("dir" to "proguard-rules", "include" to "*.pro")).files.toTypedArray() + ) + } + + compileOptions { + // Flag to enable support for the new language APIs + isCoreLibraryDesugaringEnabled = true + + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlin { + jvmToolchain(17) + } + + kotlinOptions { + freeCompilerArgs += listOf("-Xjvm-default=all", "-opt-in=kotlin.RequiresOptIn") + } + + buildFeatures { + buildConfig = true + dataBinding = true + } + + signingConfigs { + create("release") { + keyAlias = "geocaching4locus" + } + } + + buildTypes { + debug { + versionNameSuffix = "-dev" + isCrunchPngs = false + +// firebaseCrashlytics { +// mappingFileUploadEnabled = false +// } + } + release { + versionNameSuffix = "" + + buildConfigField("String", "GIT_SHA", "\"" + gitSha() + "\"") + buildConfigField("String", "BUILD_TIME", "\"" + gitTimestamp() + "\"") + + isMinifyEnabled = true + signingConfig = signingConfigs.getByName("release") + + isShrinkResources = true + isCrunchPngs = false + } + } + packaging { + resources { + excludes += listOf( + "META-INF/DEPENDENCIES", + "META-INF/LICENSE", + "META-INF/atomicfu.kotlin_module", + "org/apache/http/version.properties", + "templates/release-notes.vm", + "log4j.xml" + ) + } + } +} + +androidComponents { + onVariants { variant -> + val buildName = variant.buildType ?: "release" + variant.outputs.forEach { output -> + if (buildName == "debug") { + output.versionCode.set(1) + } else { + output.versionCode.set(gitVersionCode()) + } + } + } +} + +if (project.hasProperty("storeFile") && + project.hasProperty("storePassword") && + project.hasProperty("keyPassword") +) { + android.signingConfigs.getByName("release").storeFile = file(properties["storeFile"] as String) + android.signingConfigs.getByName("release").storePassword = + properties["storePassword"] as String + android.signingConfigs.getByName("release").keyPassword = properties["keyPassword"] as String +} else { + android.buildTypes.getByName("release").signingConfig = + android.signingConfigs.getByName("debug") +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2580c5ac..a3c20ffa 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ + @@ -377,13 +378,13 @@ + + + - - - diff --git a/app/src/main/java/com/arcao/geocaching4locus/authentication/LoginViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/authentication/LoginViewModel.kt index a302c011..1108c1cd 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/authentication/LoginViewModel.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/authentication/LoginViewModel.kt @@ -2,7 +2,7 @@ package com.arcao.geocaching4locus.authentication import android.content.Intent import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.Transformations +import androidx.lifecycle.map import com.arcao.geocaching4locus.App import com.arcao.geocaching4locus.authentication.usecase.CreateAccountUseCase import com.arcao.geocaching4locus.authentication.usecase.RetrieveAuthorizationUrlUseCase @@ -31,7 +31,7 @@ class LoginViewModel( private var job: Job? = null val code = MutableLiveData("") - val continueButtonEnabled = Transformations.map(code, String::isNotBlank) + val continueButtonEnabled = code.map(String::isNotBlank) val formVisible = MutableLiveData(true) var fromIntent = false private set diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/constants/AppConstants.kt b/app/src/main/java/com/arcao/geocaching4locus/base/constants/AppConstants.kt index 68d92847..edeb88ba 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/base/constants/AppConstants.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/base/constants/AppConstants.kt @@ -9,11 +9,12 @@ import locus.api.android.objects.VersionCode object AppConstants { const val OAUTH_CALLBACK_URL = "https://geocaching4locus.eu/oauth" - val USERS_GUIDE_URI = Uri.parse("https://geocaching4locus.eu/users-guide/")!! - val WEBSITE_URI = Uri.parse("https://geocaching4locus.eu/")!! - val FACEBOOK_URI = Uri.parse("https://www.facebook.com/Geocaching4Locus")!! - val GEOCACHING_URI = Uri.parse("http://geocaching.com/")!! - val POWER_SAVE_INFO_URI = Uri.parse("https://geocaching4locus.eu/redirect/power-save-issue")!! + val USERS_GUIDE_URI: Uri = Uri.parse("https://geocaching4locus.eu/users-guide/") + val WEBSITE_URI: Uri = Uri.parse("https://geocaching4locus.eu/") + val FACEBOOK_URI: Uri = Uri.parse("https://www.facebook.com/Geocaching4Locus") + val GEOCACHING_URI: Uri = Uri.parse("http://geocaching.com/") + val POWER_SAVE_INFO_URI: Uri = + Uri.parse("https://geocaching4locus.eu/redirect/power-save-issue") // Saved in Base64 because Google Play doesn't allow donation via Paypal. // This will prevent it to autodetect by robot. diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/fragment/AbstractPreferenceFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/base/fragment/AbstractPreferenceFragment.kt index dda4392f..735f02dc 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/base/fragment/AbstractPreferenceFragment.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/base/fragment/AbstractPreferenceFragment.kt @@ -28,7 +28,7 @@ abstract class AbstractPreferenceFragment : PreferenceFragmentCompat(), setPreferencesFromResource(preferenceResource, rootKey) } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { // empty } diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/util/KoinTimberLogger.kt b/app/src/main/java/com/arcao/geocaching4locus/base/util/KoinTimberLogger.kt index d3e0a3af..0597d975 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/base/util/KoinTimberLogger.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/base/util/KoinTimberLogger.kt @@ -6,11 +6,12 @@ import org.koin.core.logger.MESSAGE import timber.log.Timber class KoinTimberLogger : Logger() { - override fun log(level: Level, msg: MESSAGE) { + override fun display(level: Level, msg: MESSAGE) { when (level) { Level.DEBUG -> Timber.d(msg) Level.INFO -> Timber.i(msg) Level.ERROR -> Timber.e(msg) + Level.WARNING -> Timber.w(msg) Level.NONE -> { // log nothing } diff --git a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/ImportBookmarkActivity.kt b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/ImportBookmarkActivity.kt index e8057aec..f90f0022 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/ImportBookmarkActivity.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/ImportBookmarkActivity.kt @@ -41,23 +41,25 @@ class ImportBookmarkActivity : AbstractActionBarActivity() { setDisplayHomeAsUpEnabled(true) } - @Suppress("IMPLICIT_CAST_TO_ANY") viewModel.action.withObserve(this) { action -> when (action) { ImportBookmarkAction.LocusMapNotInstalled -> { showLocusMissingError() } + ImportBookmarkAction.ShowList -> { supportFragmentManager.commit { replace(R.id.fragment, BookmarkListFragment.newInstance()) } } + is ImportBookmarkAction.ChooseBookmark -> { supportFragmentManager.commit { replace(R.id.fragment, BookmarkFragment.newInstance(action.geocacheList)) addToBackStack(null) } } + ImportBookmarkAction.PremiumMembershipRequired -> { startActivity( ErrorActivity.IntentBuilder(this).message(R.string.error_premium_feature) @@ -65,6 +67,7 @@ class ImportBookmarkActivity : AbstractActionBarActivity() { ) finish() } + is ImportBookmarkAction.SignIn -> loginActivity.launch(null) }.exhaustive } @@ -84,9 +87,10 @@ class ImportBookmarkActivity : AbstractActionBarActivity() { override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) { android.R.id.home -> { - onBackPressed() + onBackPressedDispatcher.onBackPressed() true } + else -> super.onOptionsItemSelected(item) } diff --git a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkFragment.kt index 2b43704d..c9074cd0 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkFragment.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkFragment.kt @@ -29,7 +29,7 @@ import com.arcao.geocaching4locus.import_bookmarks.ImportBookmarkViewModel import com.arcao.geocaching4locus.import_bookmarks.adapter.BookmarkGeocachesAdapter import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch -import org.koin.androidx.viewmodel.ext.android.sharedViewModel +import org.koin.androidx.viewmodel.ext.android.activityViewModel import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.parameter.parametersOf @@ -40,7 +40,7 @@ class BookmarkFragment : BaseBookmarkFragment() { private val viewModel by viewModel { parametersOf(bookmarkList) } - private val activityViewModel by sharedViewModel() + private val activityViewModel by activityViewModel() private val adapter = BookmarkGeocachesAdapter() private val toolbar get() = (activity as? AppCompatActivity)?.supportActionBar @@ -55,10 +55,12 @@ class BookmarkFragment : BaseBookmarkFragment() { adapter.selectAll() true } + R.id.deselectAll -> { adapter.selectNone() true } + else -> false } } @@ -133,7 +135,6 @@ class BookmarkFragment : BaseBookmarkFragment() { adapter.tracker.onSaveInstanceState(outState) } - @Suppress("IMPLICIT_CAST_TO_ANY") fun handleAction(action: BookmarkAction) { when (action) { is BookmarkAction.Error -> { @@ -149,6 +150,7 @@ class BookmarkFragment : BaseBookmarkFragment() { finish() } } + is BookmarkAction.Finish -> { startActivity(action.intent) requireActivity().apply { @@ -156,12 +158,14 @@ class BookmarkFragment : BaseBookmarkFragment() { finish() } } + BookmarkAction.Cancel -> { requireActivity().apply { setResult(Activity.RESULT_CANCELED) finish() } } + is BookmarkAction.LoadingError -> { startActivity(action.intent) requireActivity().apply { diff --git a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkListFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkListFragment.kt index 4edb3e77..ef69a530 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkListFragment.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkListFragment.kt @@ -25,12 +25,12 @@ import com.arcao.geocaching4locus.import_bookmarks.adapter.BookmarkListAdapter import com.arcao.geocaching4locus.import_bookmarks.widget.decorator.MarginItemDecoration import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch -import org.koin.androidx.viewmodel.ext.android.sharedViewModel +import org.koin.androidx.viewmodel.ext.android.activityViewModel import org.koin.androidx.viewmodel.ext.android.viewModel class BookmarkListFragment : BaseBookmarkFragment() { private val viewModel by viewModel() - private val activityViewModel by sharedViewModel() + private val activityViewModel by activityViewModel() private val toolbar get() = (activity as? AppCompatActivity)?.supportActionBar private val adapter = BookmarkListAdapter { bookmarkList, importAll -> diff --git a/app/src/main/java/com/arcao/geocaching4locus/importgc/fragment/GeocacheCodesInputDialogFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/importgc/fragment/GeocacheCodesInputDialogFragment.kt index f647869a..df6caa7d 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/importgc/fragment/GeocacheCodesInputDialogFragment.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/importgc/fragment/GeocacheCodesInputDialogFragment.kt @@ -7,8 +7,6 @@ import android.text.Editable import android.text.TextWatcher import android.view.WindowManager import android.widget.EditText -import androidx.annotation.NonNull -import androidx.annotation.Nullable import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.WhichButton import com.afollestad.materialdialogs.actions.getActionButton @@ -19,10 +17,10 @@ import com.arcao.geocaching4locus.base.fragment.AbstractDialogFragment import com.arcao.geocaching4locus.base.util.runIfIs import com.arcao.geocaching4locus.importgc.ImportGeocacheCodeViewModel import com.google.android.material.textfield.TextInputLayout -import org.koin.androidx.viewmodel.ext.android.sharedViewModel +import org.koin.androidx.viewmodel.ext.android.activityViewModel class GeocacheCodesInputDialogFragment : AbstractDialogFragment() { - val model by sharedViewModel() + val model by activityViewModel() private lateinit var editTextView: EditText lateinit var textInputLayout: TextInputLayout @@ -40,7 +38,7 @@ class GeocacheCodesInputDialogFragment : AbstractDialogFragment() { } } - private fun fireOnInputFinished(@Nullable input: Array?) { + private fun fireOnInputFinished(input: Array?) { activity.runIfIs(DialogListener::class) { onInputFinished(input ?: emptyArray()) } @@ -51,12 +49,9 @@ class GeocacheCodesInputDialogFragment : AbstractDialogFragment() { super.onCancel(dialog) } - @NonNull override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - val dialog = MaterialDialog(requireContext()) - .title(R.string.title_import_from_gc) - .customView(R.layout.dialog_gc_number_input) - .noAutoDismiss() + val dialog = MaterialDialog(requireContext()).title(R.string.title_import_from_gc) + .customView(R.layout.dialog_gc_number_input).noAutoDismiss() .positiveButton(R.string.button_ok) { dialog -> try { val geocacheCodes = model.parseGeocacheCodes(editTextView.text) @@ -65,16 +60,16 @@ class GeocacheCodesInputDialogFragment : AbstractDialogFragment() { } catch (e: Exception) { textInputLayout.error = getText(R.string.error_gc_code_invalid) } - } - .negativeButton(R.string.button_cancel) { dialog -> + }.negativeButton(R.string.button_cancel) { dialog -> fireOnInputFinished(null) dialog.dismiss() } dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE) - textInputLayout = - dialog.getCustomView() as? TextInputLayout ?: throw IllegalStateException("Custom view is null") + textInputLayout = dialog.getCustomView() as? TextInputLayout ?: throw IllegalStateException( + "Custom view is null" + ) val positiveButton = dialog.getActionButton(WhichButton.POSITIVE) diff --git a/app/src/main/java/com/arcao/geocaching4locus/live_map/LiveMapService.kt b/app/src/main/java/com/arcao/geocaching4locus/live_map/LiveMapService.kt index f95d5e98..4651cb7c 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/live_map/LiveMapService.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/live_map/LiveMapService.kt @@ -47,7 +47,7 @@ class LiveMapService : LifecycleService() { private fun cancelTasks() { viewModel.cancelTasks() ServiceUtil.releaseAllWakeLocks(ComponentName(this, LiveMapService::class.java)) - stopForeground(true) + stopForeground(STOP_FOREGROUND_REMOVE) } override fun onDestroy() { diff --git a/app/src/main/java/com/arcao/geocaching4locus/live_map/util/LiveMapNotificationManager.kt b/app/src/main/java/com/arcao/geocaching4locus/live_map/util/LiveMapNotificationManager.kt index 438908c3..1a0aaabc 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/live_map/util/LiveMapNotificationManager.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/live_map/util/LiveMapNotificationManager.kt @@ -7,12 +7,10 @@ import android.app.PendingIntent import android.content.Context import android.content.Intent import android.content.SharedPreferences -import android.os.Build import android.os.Handler import android.os.Looper import android.os.SystemClock import android.widget.Toast -import androidx.annotation.RequiresApi import androidx.annotation.StringRes import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat @@ -88,12 +86,9 @@ class LiveMapNotificationManager( } init { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - createChannel() - } + createChannel() } - @RequiresApi(Build.VERSION_CODES.O) private fun createChannel() { val channelDescription = context.getText(R.string.menu_live_map) @@ -139,6 +134,7 @@ class LiveMapNotificationManager( } return true } + else -> { if (!isLiveMapEnabled && !defaultPreferenceManager.showLiveMapDisabledNotification) { return false @@ -176,25 +172,14 @@ class LiveMapNotificationManager( nb.priority = NotificationCompat.PRIORITY_DEFAULT nb.setSmallIcon(R.drawable.ic_stat_live_map_downloading_anim) - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { - nb.setContentText( - context.getText( - R.string.notify_live_map_message_downloading, - current, - count, - current * 100 / count - ) - ) - } else { - nb.setContentTitle( - context.getText( - R.string.notify_live_map_message_downloading, - current, - count, - current * 100 / count - ) + nb.setContentTitle( + context.getText( + R.string.notify_live_map_message_downloading, + current, + count, + current * 100 / count ) - } + ) } notificationManager.notify(AppConstants.NOTIFICATION_ID_LIVEMAP, nb.build()) @@ -268,13 +253,8 @@ class LiveMapNotificationManager( pendingIntent ) - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { - nb.setContentTitle(context.getText(R.string.notify_live_map)) - nb.setContentText(state) - } else { - nb.setSubText(context.getText(R.string.menu_live_map)) - nb.setContentTitle(state) - } + nb.setSubText(context.getText(R.string.menu_live_map)) + nb.setContentTitle(state) return nb } @@ -282,22 +262,14 @@ class LiveMapNotificationManager( private fun createPendingActivityIntent(intent: Intent) = PendingIntent.getActivity( context, 0, intent, - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE - } else { - PendingIntent.FLAG_UPDATE_CURRENT - } + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) private fun createPendingBroadcastIntent(action: String) = PendingIntent.getBroadcast( context, 0, Intent(action, null, context, LiveMapBroadcastReceiver::class.java), - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - PendingIntent.FLAG_IMMUTABLE - } else { - 0 - } + PendingIntent.FLAG_IMMUTABLE ) private fun showError(@StringRes message: Int) { @@ -339,10 +311,10 @@ class LiveMapNotificationManager( } } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { if (PrefConstants.LIVE_MAP == key) { for (listener in stateChangeListeners) { - listener.onLiveMapStateChange(sharedPreferences.getBoolean(key, false)) + listener.onLiveMapStateChange(preferences.getBoolean(key, false)) } } } diff --git a/app/src/main/java/com/arcao/geocaching4locus/settings/SettingsActivity.kt b/app/src/main/java/com/arcao/geocaching4locus/settings/SettingsActivity.kt index 7aaed440..9aae19e1 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/settings/SettingsActivity.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/settings/SettingsActivity.kt @@ -53,7 +53,7 @@ class SettingsActivity : AbstractActionBarActivity(), when (item.itemId) { // Respond to the action bar's Up/Home button android.R.id.home -> { - onBackPressed() + onBackPressedDispatcher.onBackPressed() return true } } diff --git a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/AdvancedPreferenceFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/AdvancedPreferenceFragment.kt index 0ffb2899..b03b75af 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/AdvancedPreferenceFragment.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/AdvancedPreferenceFragment.kt @@ -15,19 +15,27 @@ class AdvancedPreferenceFragment : AbstractPreferenceFragment() { override val preferenceResource: Int get() = R.xml.preference_category_advanced - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { super.onSharedPreferenceChanged(sharedPreferences, key) when (key) { IMPERIAL_UNITS -> { - val imperialUnits = sharedPreferences.getBoolean(IMPERIAL_UNITS, false) + val imperialUnits = preferences.getBoolean(IMPERIAL_UNITS, false) - val defaultValue = if (imperialUnits) DISTANCE_MILES_DEFAULT else DISTANCE_KM_DEFAULT + val defaultValue = if (imperialUnits) { + DISTANCE_MILES_DEFAULT + } else { + DISTANCE_KM_DEFAULT + } - var distance = sharedPreferences.getParsedFloat(FILTER_DISTANCE, defaultValue) - distance = if (imperialUnits) distance / MILES_PER_KILOMETER else distance * MILES_PER_KILOMETER + var distance = preferences.getParsedFloat(FILTER_DISTANCE, defaultValue) + distance = if (imperialUnits) { + distance / MILES_PER_KILOMETER + } else { + distance * MILES_PER_KILOMETER + } - sharedPreferences.edit { + preferences.edit { putString(FILTER_DISTANCE, distance.toString()) } } diff --git a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/DownloadingPreferenceFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/DownloadingPreferenceFragment.kt index 18c99b41..cbe1b91e 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/DownloadingPreferenceFragment.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/DownloadingPreferenceFragment.kt @@ -73,7 +73,7 @@ class DownloadingPreferenceFragment : AbstractPreferenceFragment() { } } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { super.onSharedPreferenceChanged(sharedPreferences, key) when (key) { diff --git a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/FilterPreferenceFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/FilterPreferenceFragment.kt index 2ee78da8..131bedcb 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/FilterPreferenceFragment.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/FilterPreferenceFragment.kt @@ -48,7 +48,7 @@ class FilterPreferenceFragment : AbstractPreferenceFragment() { prepareDistancePreference() } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { super.onSharedPreferenceChanged(sharedPreferences, key) when (key) { diff --git a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/DifficultyFilterPreferenceFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/DifficultyFilterPreferenceFragment.kt index 0e67a511..92046c9f 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/DifficultyFilterPreferenceFragment.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/DifficultyFilterPreferenceFragment.kt @@ -42,7 +42,7 @@ class DifficultyFilterPreferenceFragment : AbstractPreferenceFragment() { } } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { super.onSharedPreferenceChanged(sharedPreferences, key) when (key) { diff --git a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/TerrainFilterPreferenceFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/TerrainFilterPreferenceFragment.kt index df513698..6be5cef0 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/TerrainFilterPreferenceFragment.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/TerrainFilterPreferenceFragment.kt @@ -42,7 +42,7 @@ class TerrainFilterPreferenceFragment : AbstractPreferenceFragment() { } } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { super.onSharedPreferenceChanged(sharedPreferences, key) when (key) { diff --git a/app/src/main/java/com/arcao/geocaching4locus/settings/widget/SliderPreference.kt b/app/src/main/java/com/arcao/geocaching4locus/settings/widget/SliderPreference.kt index 4c9a5773..9a8a8fed 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/settings/widget/SliderPreference.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/settings/widget/SliderPreference.kt @@ -14,7 +14,7 @@ import com.arcao.geocaching4locus.R class SliderPreference @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = R.attr.dialogPreferenceStyle + defStyleAttr: Int = androidx.preference.R.attr.dialogPreferenceStyle ) : DialogPreference(context, attrs, defStyleAttr), PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback { private var value: Int = 0 diff --git a/app/src/main/java/locus/api/mapper/GeocacheConverter.kt b/app/src/main/java/locus/api/mapper/GeocacheConverter.kt index 808d2bda..8164ccf5 100644 --- a/app/src/main/java/locus/api/mapper/GeocacheConverter.kt +++ b/app/src/main/java/locus/api/mapper/GeocacheConverter.kt @@ -1,8 +1,6 @@ package locus.api.mapper import android.content.Context -import androidx.annotation.NonNull -import androidx.annotation.Nullable import com.arcao.geocaching4locus.R import com.arcao.geocaching4locus.data.api.model.AdditionalWaypoint import com.arcao.geocaching4locus.data.api.model.Geocache @@ -70,7 +68,7 @@ class GeocacheConverter( cache.containsHtml ?: false ) encodedHints = cache.hints.orEmpty() - notes = cache.userData?.note.orEmpty() + notesExternal = cache.userData?.note.orEmpty() favoritePoints = cache.favoritePoints ?: 0 images = mutableListOf().apply { @@ -176,8 +174,7 @@ class GeocacheConverter( ) } - @Nullable - private fun getWaypointsFromNote(@NonNull geocache: Geocache): Collection? { + private fun getWaypointsFromNote(geocache: Geocache): Collection? { var note = geocache.userData?.note ?: return null if (note.isBlank()) diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 37c11341..00000000 --- a/build.gradle +++ /dev/null @@ -1,114 +0,0 @@ -// Top-level build file where you can add configuration options common to all sub-projects/modules. - -buildscript { - apply from: 'versions.gradle' - - ext.isTravis = 'true' == System.getenv('TRAVIS') - ext.preDexEnabled = 'true' == System.getProperty('pre-dex', 'true') - - ext.gitSha = { - return 'git rev-parse --short HEAD'.execute([], rootDir).text.trim() - } - - ext.gitTimestamp = { - return 'git log -n 1 --format=%aI'.execute([], rootDir).text.trim() - } - - ext.gitVersionCode = { - return 'git rev-list --count HEAD'.execute([], rootDir).text.trim().toInteger() - } - - // set Geocaching API staging key and secret if production key and secret is not set - // Note: Staging server is slow and not for production use!!!! - if (!project.hasProperty('geocachingApiKey')) { - ext.geocachingApiKey = '9C7552E1-3C04-4D04-A395-230D8931E494' - } - if (!project.hasProperty('geocachingApiSecret')) { - ext.geocachingApiSecret = 'DA7CC147-7B5B-4423-BCB4-D0C03E2BF685' - } - if (!project.hasProperty('geocachingApiStaging')) { - ext.geocachingApiStaging = true - } - - repositories { - google { - content { - includeGroupByRegex("com\\.android") - includeGroupByRegex("com\\.android\\..*") - includeGroupByRegex("com\\.google\\..*") - includeGroupByRegex("androidx\\..*") - includeGroupByRegex("android\\.arch\\..*") - } - } - maven { - url 'https://maven.fabric.io/public' - content { - includeGroupByRegex("com\\.crashlytics\\..*") - includeGroupByRegex("io\\.fabric\\..*") - } - } - mavenCentral() - gradlePluginPortal() - } - - dependencies { - classpath "com.android.tools.build:gradle:$android_plugin_version" - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "com.github.ben-manes:gradle-versions-plugin:$versions_plugin_version" - classpath "com.google.gms:google-services:$google_services_plugin_version" - classpath "com.google.firebase:firebase-crashlytics-gradle:$firebase_crashlytics_plugin_version" - classpath "de.mannodermaus.gradle.plugins:android-junit5:$junit5_plugin_version" - classpath "io.insert-koin:koin-gradle-plugin:$koin_version" - } -} - -def isNonStable = { String version -> - def stableKeyword = ['RELEASE', 'FINAL', 'GA'].any { it -> version.toUpperCase().contains(it) } - def regex = /^[0-9,.v-]+(-r)?$/ - return !stableKeyword && !(version ==~ regex) -} - -allprojects { - apply plugin: 'com.github.ben-manes.versions' - apply from: "$rootDir/ktlint.gradle" - - repositories { - google { - content { - includeGroupByRegex("com\\.android") - includeGroupByRegex("com\\.android\\..*") - includeGroupByRegex("com\\.google\\..*") - includeGroupByRegex("androidx\\..*") - includeGroupByRegex("android\\.arch\\..*") - } - } - maven { - url 'https://maven.fabric.io/public' - content { - includeGroupByRegex("com\\.crashlytics\\..*") - includeGroupByRegex("io\\.fabric\\..*") - } - } - // for Locus API - maven { - url "https://dl.bintray.com/asammsoft/maven/" - content { - includeGroupByRegex("com\\.asamm\\..*") - } - } - - mavenCentral() - } - - // dependencyUpdates: suggest only released artifacts - dependencyUpdates { - // disallow release candidates as upgradable versions from stable versions - rejectVersionIf { - isNonStable(it.candidate.version) && !isNonStable(it.currentVersion) - } - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..b53fbc53 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,34 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask + +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.versions) apply false + alias(libs.plugins.google.services) apply false + alias(libs.plugins.firebase.crashlytics) apply false + alias(libs.plugins.android.junit5) apply false + alias(libs.plugins.ksp) apply false +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory.asFile.get()) +} + +allprojects { + apply(plugin = "com.github.ben-manes.versions") + + fun isNonStable(version: String): Boolean { + val stableKeyword = + listOf("RELEASE", "FINAL", "GA").any { version.uppercase().contains(it) } + val regex = "^[0-9,.v-]+(-r)?$".toRegex() + val isStable = stableKeyword || regex.matches(version) + return isStable.not() + } + + tasks.withType { + rejectVersionIf { + isNonStable(candidate.version) && !isNonStable(currentVersion) + } + } +} diff --git a/geocaching-api/build.gradle b/geocaching-api/build.gradle deleted file mode 100644 index 70c85e2d..00000000 --- a/geocaching-api/build.gradle +++ /dev/null @@ -1,86 +0,0 @@ -apply plugin: 'com.android.library' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-parcelize' -apply plugin: 'de.mannodermaus.android-junit5' -apply plugin: 'kotlin-kapt' - -android { - compileSdkVersion rootProject.compile_sdk_version - - defaultConfig { - testInstrumentationRunnerArguments runnerBuilder: 'de.mannodermaus.junit5.AndroidJUnit5Builder' - minSdkVersion rootProject.min_sdk_version - targetSdkVersion rootProject.target_sdk_version - - multiDexEnabled true - - buildConfigField 'String', 'GEOCACHING_API_KEY', "\"${geocachingApiKey}\"" - buildConfigField 'String', 'GEOCACHING_API_SECRET', "\"${geocachingApiSecret}\"" - buildConfigField 'boolean', 'GEOCACHING_API_STAGING', "${geocachingApiStaging}" - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - consumerProguardFiles 'consumer-rules.pro' - } - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - coreLibraryDesugaringEnabled true - } - - kotlinOptions { - freeCompilerArgs += [ - "-opt-in=kotlin.RequiresOptIn", - "-Xjvm-default=all-compatibility" - ] - jvmTarget = JavaVersion.VERSION_1_8 - } - - testOptions { - junitPlatform { - // Configuration goes here! - } - } - packagingOptions { - jniLibs { - excludes += ['META-INF/LICENSE*'] - } - resources { - excludes += ['META-INF/LICENSE*'] - } - } - - namespace 'com.arcao.geocaching4locus.geocaching_api' -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" - - api "com.github.scribejava:scribejava-core:$scribejava_version" - api "com.github.scribejava:scribejava-httpclient-okhttp:$scribejava_version" - implementation "com.jakewharton.timber:timber:$timber_version" - - coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:$desugar_jdk_libs_version" - - // koin - implementation "io.insert-koin:koin-android:$koin_version" - - implementation "com.squareup.moshi:moshi:$moshi_version" - kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshi_version" - - implementation "com.squareup.retrofit2:converter-moshi:$retrofit_version" - - implementation "com.squareup.okhttp3:okhttp:$okhttp_version" - implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version" - - testImplementation "org.junit.jupiter:junit-jupiter-api:$junit_version" - testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit_version" - testImplementation "io.mockk:mockk:$mockk_version" - testImplementation "com.squareup.okhttp3:mockwebserver:$okhttp_version" - - androidTestImplementation "androidx.test:runner:$test_runner_version" - androidTestImplementation "de.mannodermaus.junit5:android-test-core:$android_test_junit" - androidTestRuntimeOnly "de.mannodermaus.junit5:android-test-runner:$android_test_junit" -} diff --git a/geocaching-api/build.gradle.kts b/geocaching-api/build.gradle.kts new file mode 100644 index 00000000..6e523f9b --- /dev/null +++ b/geocaching-api/build.gradle.kts @@ -0,0 +1,105 @@ +plugins { + alias(libs.plugins.kotlin.android) + id("com.android.library") + id("kotlin-parcelize") + alias(libs.plugins.ksp) + alias(libs.plugins.android.junit5) +} + +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } +} + +android { + namespace = "com.arcao.geocaching4locus.geocaching_api" + compileSdk = libs.versions.targetSdk.get().toInt() + + defaultConfig { + testInstrumentationRunnerArguments += mapOf("runnerBuilder" to "de.mannodermaus.junit5.AndroidJUnit5Builder") + minSdk = libs.versions.minSdk.get().toInt() + + multiDexEnabled = true + + // set Geocaching API staging key and secret if production key and secret is not set + // Note: Staging server is slow and not for production use!!!! + val geocachingApiKey = + properties["geocachingApiKey"] ?: "9C7552E1-3C04-4D04-A395-230D8931E494" + val geocachingApiSecret = + properties["geocachingApiSecret"] ?: "DA7CC147-7B5B-4423-BCB4-D0C03E2BF685" + val geocachingApiStaging = properties["geocachingApiStaging"] != "false" + + buildConfigField("String", "GEOCACHING_API_KEY", "\"${geocachingApiKey}\"") + buildConfigField("String", "GEOCACHING_API_SECRET", "\"${geocachingApiSecret}\"") + buildConfigField("boolean", "GEOCACHING_API_STAGING", "${geocachingApiStaging}") + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + compileOptions { + // Flag to enable support for the new language APIs + isCoreLibraryDesugaringEnabled = true + + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } + + kotlin { + jvmToolchain(17) + } + + kotlinOptions { + freeCompilerArgs += listOf("-Xjvm-default=all", "-opt-in=kotlin.RequiresOptIn") + } + + buildFeatures { + buildConfig = true + } + + testOptions { + junitPlatform { + // Configuration goes here! + } + } + packaging { + resources { + excludes += listOf("META-INF/LICENSE*") + } + } +} + +dependencies { + // kotlin + implementation(libs.kotlin.stdlib) + implementation(libs.kotlinx.coroutines.core) + + api(libs.scribejava.core) + api(libs.scribejava.okhttp) + implementation(libs.logging.timber) + + // Java 8 libraries for older devices + coreLibraryDesugaring(libs.desugar.jdk.libs) + + // koin + implementation(libs.koin.android) + + implementation(libs.moshi.core) + ksp(libs.moshi.kotlin.codegen) + + implementation(libs.retrofit) + implementation(libs.retrofit.converter.moshi) + + implementation(libs.okhttp) + implementation(libs.okhttp.logging.interceptor) + + testImplementation(libs.junit.jupiter.api) + testRuntimeOnly(libs.junit.jupiter.engine) + testImplementation(libs.mockk) + testImplementation(libs.okhttp.mockwebserver) + + androidTestImplementation(libs.androidx.test.runner) + androidTestImplementation(libs.junit.android.test.core) + androidTestRuntimeOnly(libs.junit.android.test.runner) +} diff --git a/geocaching-api/src/test/java/com/arcao/geocaching4locus/data/account/oauth/GeocachingOAuth2AccessTokenJsonExtractorTest.kt b/geocaching-api/src/test/java/com/arcao/geocaching4locus/data/account/oauth/GeocachingOAuth2AccessTokenJsonExtractorTest.kt index 242b5e03..c8fa3a68 100644 --- a/geocaching-api/src/test/java/com/arcao/geocaching4locus/data/account/oauth/GeocachingOAuth2AccessTokenJsonExtractorTest.kt +++ b/geocaching-api/src/test/java/com/arcao/geocaching4locus/data/account/oauth/GeocachingOAuth2AccessTokenJsonExtractorTest.kt @@ -1,6 +1,7 @@ package com.arcao.geocaching4locus.data.account.oauth import com.github.scribejava.core.model.OAuth2AccessTokenErrorResponse +import com.github.scribejava.core.model.Response import com.github.scribejava.core.oauth2.OAuth2Error import org.intellij.lang.annotations.Language import org.junit.jupiter.api.Assertions @@ -15,7 +16,14 @@ internal class GeocachingOAuth2AccessTokenJsonExtractorTest { "{\"statusCode\":\"BadRequest\",\"errorMessage\":\"invalid_grant\",\"errors\":[{\"message\":\"invalid_grant\",\"detail\":\"the provided code is invalid, used, expired, or revoked\"}]}" val exception = Assertions.assertThrows(OAuth2AccessTokenErrorResponse::class.java) { - GeocachingOAuth2AccessTokenJsonExtractor.generateError(errorJson) + GeocachingOAuth2AccessTokenJsonExtractor.generateError( + Response( + 400, + "Bad Request", + emptyMap(), + errorJson + ) + ) } // expected diff --git a/geocaching-api/src/test/java/com/arcao/geocaching4locus/data/api/internal/okhttp/interceptor/GeocachingAuthenticationInterceptorTest.kt b/geocaching-api/src/test/java/com/arcao/geocaching4locus/data/api/internal/okhttp/interceptor/GeocachingAuthenticationInterceptorTest.kt index a0cdbd30..ff6840cd 100644 --- a/geocaching-api/src/test/java/com/arcao/geocaching4locus/data/api/internal/okhttp/interceptor/GeocachingAuthenticationInterceptorTest.kt +++ b/geocaching-api/src/test/java/com/arcao/geocaching4locus/data/api/internal/okhttp/interceptor/GeocachingAuthenticationInterceptorTest.kt @@ -4,7 +4,6 @@ import com.arcao.geocaching4locus.data.account.AccountManager import com.arcao.geocaching4locus.data.account.GeocachingAccount import com.arcao.geocaching4locus.data.api.endpoint.GeocachingApiEndpoint import com.arcao.geocaching4locus.data.api.model.User -import io.mockk.Called import io.mockk.Ordering import io.mockk.coEvery import io.mockk.coVerify @@ -69,6 +68,7 @@ internal object GeocachingAuthenticationInterceptorTest { } } + @Suppress("DeferredResultUnused") @Test fun verifyRefreshTokenNotCalled() { // given @@ -79,9 +79,9 @@ internal object GeocachingAuthenticationInterceptorTest { // expected verify(timeout = 5000) { chain.proceed(any()) } - coVerify(timeout = 5000) { - account.refreshToken() wasNot Called - endpoint.userAsync() wasNot Called + coVerify(timeout = 5000, exactly = 0) { + account.refreshToken() + endpoint.userAsync() } } @@ -97,6 +97,6 @@ internal object GeocachingAuthenticationInterceptorTest { verify { chain.proceed(match { it.header("authorization") == "bearer accessToken1234" }) } - coVerify { account.refreshToken() wasNot Called } + coVerify(exactly = 0) { account.refreshToken() } } } diff --git a/gradle.properties b/gradle.properties index 45a83197..c5d10aee 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,5 +9,6 @@ kotlin.incremental=true kapt.incremental.apt=true # near instant builds when there are few changes kapt.include.compile.classpath=false -android.databinding.incremental=true android.lifecycleProcessor.incremental=true +android.nonTransitiveRClass=true +android.nonFinalResIds=false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 00000000..5f0b31f8 --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,132 @@ +[versions] +app = "3.0.9" +minSdk = "26" +targetSdk = "34" + +# build plugins +plugin-android = "8.3.1" +plugin-firebase-crashlytics = "2.9.9" +plugin-google_services = "4.4.1" +plugin-android-junit5 = "1.8.2.1" +plugin-versions = "0.45.0" +plugin-ksp = "1.9.23-1.0.20" + +# android +androidx-appcompat = "1.6.1" +androidx-card_view = "1.0.0" +androidx-collection = "1.4.0" +androidx-constraint_layout = "2.1.4" +androidx-core = "1.12.0" +androidx-browser = "1.8.0" +androidx-fragment = "1.6.2" +androidx-lifecycle-core = "2.7.0" +androidx-lifecycle-extensions = "2.2.0" +google-material = "1.11.0" +androidx-paging = "3.2.1" +androidx-preference = "1.2.1" +androidx-recycler_view = "1.3.2" +android-desugar_jdk_libs = "2.0.4" + +# google +firebase-bom = "32.8.0" + +# kotlin +kotlin-coroutines = "1.7.1" +kotlin-bom = "1.9.23" + +# networking +moshi = "1.14.0" +okhttp = "4.11.0" +retrofit = "2.9.0" + +# testing +junit-android-test = "1.3.0" +junit-jupiter = "5.9.2" +mockk = "1.13.4" +androidx-test-runner = "1.5.2" + +# logging +slf4j-timber = "3.1" +timber = "5.0.1" + +# support +koin = "3.4.3" +scribejava = "8.3.3" +material_dialogs = "3.3.0" + +locus_api = "0.9.50" + +[libraries] +androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" } +androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "androidx-recycler_view" } +androidx-cardview = { module = "androidx.cardview:cardview", version.ref = "androidx-card_view" } +androidx-constraintlayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "androidx-constraint_layout" } +androidx-preference-ktx = { module = "androidx.preference:preference-ktx", version.ref = "androidx-preference" } +androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "androidx-lifecycle-core" } +androidx-lifecycle-livedata-ktx = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "androidx-lifecycle-core" } +androidx-lifecycle-extensions = { module = "androidx.lifecycle:lifecycle-extensions", version.ref = "androidx-lifecycle-extensions" } +androidx-core-ktx = { module = "androidx.core:core-ktx", version.ref = "androidx-core" } +androidx-collection-ktx = { module = "androidx.collection:collection-ktx", version.ref = "androidx-collection" } +androidx-browser = { module = "androidx.browser:browser", version.ref = "androidx-browser" } +androidx-fragment-ktx = { module = "androidx.fragment:fragment-ktx", version.ref = "androidx-fragment" } +androidx-paging-runtime-ktx = { module = "androidx.paging:paging-runtime-ktx", version.ref = "androidx-paging" } +desugar-jdk-libs = { module = "com.android.tools:desugar_jdk_libs", version.ref = "android-desugar_jdk_libs" } +google-material = { module = "com.google.android.material:material", version.ref = "google-material" } + +# kotlin +kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin-bom" } +kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlin-coroutines" } +kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlin-coroutines" } + +# koin +koin-android = { module = "io.insert-koin:koin-android", version.ref = "koin" } + +# Locus API +locus-android = { module = "com.asamm:locus-api-android", version.ref = "locus_api" } + +# Logging API +logging-slf4j-timber = { module = "com.arcao:slf4j-timber", version.ref = "slf4j-timber" } +logging-timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" } + +# Material dialogs +material-dialogs-core = { module = "com.afollestad.material-dialogs:core", version.ref = "material_dialogs" } +material-dialogs-input = { module = "com.afollestad.material-dialogs:input", version.ref = "material_dialogs" } + +# Crashlytics & Firebase +firebase-bom = { module = "com.google.firebase:firebase-bom", version.ref = "firebase-bom" } +firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics-ktx" } +firebase-analytics = { module = "com.google.firebase:firebase-analytics-ktx" } + +# OkHTTP +okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" } +okhttp-mockwebserver = { module = "com.squareup.okhttp3:mockwebserver", version.ref = "okhttp" } +okhttp-logging_interceptor = { module = "com.squareup.okhttp3:logging-interceptor", version.ref = "okhttp" } + +# Retrofit +retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" } +retrofit-converter-moshi = { module = "com.squareup.retrofit2:converter-moshi", version.ref = "retrofit" } + +# moshi +moshi-core = { module = "com.squareup.moshi:moshi", version.ref = "moshi" } +moshi-kotlin-codegen = { module = "com.squareup.moshi:moshi-kotlin-codegen", version.ref = "moshi" } + +# scribe java +scribejava-core = { module = "com.github.scribejava:scribejava-core", version.ref = "scribejava" } +scribejava-okhttp = { module = "com.github.scribejava:scribejava-httpclient-okhttp", version.ref = "scribejava" } + +# testing +junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit-jupiter" } +junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit-jupiter" } +junit-android-test-core = { module = "de.mannodermaus.junit5:android-test-core", version.ref = "junit-android-test" } +junit-android-test-runner = { module = "de.mannodermaus.junit5:android-test-runner", version.ref = "junit-android-test" } +mockk = { module = "io.mockk:mockk", version.ref = "mockk" } +androidx-test-runner = { module = "androidx.test:runner", version.ref = "androidx-test-runner" } + +[plugins] +android-application = { id = "com.android.application", version.ref = "plugin-android" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin-bom" } +versions = { id = "com.github.ben-manes.versions", version.ref = "plugin-versions" } +google-services = { id = "com.google.gms.google-services", version.ref = "plugin-google_services" } +firebase-crashlytics = { id = "com.google.firebase.crashlytics", version.ref = "plugin-firebase-crashlytics" } +android-junit5 = { id = "de.mannodermaus.android-junit5", version.ref = "plugin-android-junit5" } +ksp = { id = "com.google.devtools.ksp", version.ref = "plugin-ksp" } \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a5fe1cb94b9ee5ce57e6113458225bcba12d83e3..249e5832f090a2944b7473328c07c9755baa3196 100644 GIT binary patch literal 60756 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

<5G2M1WZP5 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 \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG=`dirname "$PRG"`"/$link" - fi +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac done -SAVED="`pwd`" -cd "`dirname \"$PRG\"`/" >/dev/null -APP_HOME="`pwd -P`" -cd "$SAVED" >/dev/null + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit APP_NAME="Gradle" -APP_BASE_NAME=`basename "$0"` +APP_BASE_NAME=${0##*/} # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS="" +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD="maximum" +MAX_FD=maximum warn () { echo "$*" -} +} >&2 die () { echo echo "$*" echo exit 1 -} +} >&2 # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false -case "`uname`" in - CYGWIN* ) - cygwin=true - ;; - Darwin* ) - darwin=true - ;; - MINGW* ) - msys=true - ;; - NONSTOP* ) - nonstop=true - ;; +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACMD=$JAVA_HOME/jre/sh/java else - JAVACMD="$JAVA_HOME/bin/java" + JAVACMD=$JAVA_HOME/bin/java fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME @@ -81,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else - JAVACMD="java" + JAVACMD=java which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the @@ -89,84 +140,101 @@ location of your Java installation." fi # Increase the maximum file descriptors if we can. -if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then - MAX_FD_LIMIT=`ulimit -H -n` - if [ $? -eq 0 ] ; then - if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then - MAX_FD="$MAX_FD_LIMIT" - fi - ulimit -n $MAX_FD - if [ $? -ne 0 ] ; then - warn "Could not set maximum file descriptor limit: $MAX_FD" - fi - else - warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" - fi +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac fi -# For Darwin, add options to specify how the application appears in the dock -if $darwin; then - GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" -fi +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) -# For Cygwin, switch paths to Windows format before running java -if $cygwin ; then - APP_HOME=`cygpath --path --mixed "$APP_HOME"` - CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - JAVACMD=`cygpath --unix "$JAVACMD"` - - # We build the pattern for arguments to be converted via cygpath - ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` - SEP="" - for dir in $ROOTDIRSRAW ; do - ROOTDIRS="$ROOTDIRS$SEP$dir" - SEP="|" - done - OURCYGPATTERN="(^($ROOTDIRS))" - # Add a user-defined pattern to the cygpath arguments - if [ "$GRADLE_CYGPATTERN" != "" ] ; then - OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" - fi # Now convert the arguments - kludge to limit ourselves to /bin/sh - i=0 - for arg in "$@" ; do - CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` - CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option - - if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition - eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` - else - eval `echo args$i`="\"$arg\"" + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) fi - i=$((i+1)) + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg done - case $i in - (0) set -- ;; - (1) set -- "$args0" ;; - (2) set -- "$args0" "$args1" ;; - (3) set -- "$args0" "$args1" "$args2" ;; - (4) set -- "$args0" "$args1" "$args2" "$args3" ;; - (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; - (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; - (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; - (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; - (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; - esac fi -# Escape application args -save () { - for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done - echo " " -} -APP_ARGS=$(save "$@") - -# Collect all arguments for the java command, following the shell quoting and substitution rules -eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" - -# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong -if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then - cd "$(dirname "$0")" +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" fi +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat index f9553162..f127cfd4 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,4 +1,20 @@ -@if "%DEBUG%" == "" @echo off +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -9,19 +25,22 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS= +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -35,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -45,38 +64,26 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/ktlint.gradle b/ktlint.gradle deleted file mode 100644 index 0ff47627..00000000 --- a/ktlint.gradle +++ /dev/null @@ -1,30 +0,0 @@ - -configurations { - ktlint -} - -dependencies { - ktlint "com.github.shyiko:ktlint:$ktlintVersion" -} - -task ktlint(type: JavaExec, group: "verification") { - description = "Check Kotlin code style." - classpath = configurations.ktlint - mainClass = "com.github.shyiko.ktlint.Main" - args "src/**/*.kt" -} - -task ktlintFormat(type: JavaExec, group: "formatting") { - description = "Fix Kotlin code style deviations." - classpath = configurations.ktlint - mainClass = "com.github.shyiko.ktlint.Main" - args "-F", "src/**/*.kt" -} - -task ktlintIde(type: JavaExec, group: "formatting") { - description = "Apply code style to IntelliJ Idea/Android Studio IDE" - classpath = configurations.ktlint - workingDir = project.rootDir - mainClass = "com.github.shyiko.ktlint.Main" - args "--apply-to-idea-project", "--android", "-y" -} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 7badb9ba..00000000 --- a/settings.gradle +++ /dev/null @@ -1,3 +0,0 @@ -rootProject.name = 'Geocaching4Locus' - -include ':app', ':geocaching-api' diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..b3554b42 --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,47 @@ +@file:Suppress("UnstableApiUsage") + +pluginManagement { + repositories { + gradlePluginPortal() + google { + content { + includeGroupByRegex("com\\.android") + includeGroupByRegex("com\\.android\\..*") + includeGroupByRegex("com\\.google\\..*") + includeGroupByRegex("androidx\\..*") + includeGroupByRegex("android\\.arch\\..*") + } + } + mavenCentral() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google { + content { + includeGroupByRegex("com\\.android") + includeGroupByRegex("com\\.android\\..*") + includeGroupByRegex("com\\.google\\..*") + includeGroupByRegex("androidx\\..*") + includeGroupByRegex("android\\.arch\\..*") + } + } + // for Locus API + maven { + url = uri("https://dl.bintray.com/asammsoft/maven/") + content { + includeGroupByRegex("com\\.asamm\\..*") + } + } + + mavenCentral() + maven { + url = uri("https://jitpack.io") + } + } +} + +rootProject.name = "Geocaching4Locus" +include(":app", ":geocaching-api") diff --git a/versions.gradle b/versions.gradle deleted file mode 100644 index d111c15e..00000000 --- a/versions.gradle +++ /dev/null @@ -1,63 +0,0 @@ -ext { - version_name = '3.0.9' - - min_sdk_version = 21 - compile_sdk_version = 32 - target_sdk_version = 32 - - // build plugins - android_plugin_version = '7.3.1' - firebase_crashlytics_plugin_version = '2.5.2' - google_services_plugin_version = '4.3.10' - junit5_plugin_version = '1.7.1.1' - versions_plugin_version = '0.28.0' - - // android - appcompat_version = '1.5.1' - card_view_version = '1.0.0' - collection_version = '1.2.0' - constraint_layout_version = '2.1.4' - core_version = '1.8.0' // 1.9.0 require compileSdkVersion 33 - browser_version = '1.4.0' - fragment_version = '1.5.3' - lifecycle_version = '2.5.1' - lifecycle_extension_version = '2.2.0' - material_version = '1.7.0' - multidex_version = '2.0.1' - paging_version = '3.1.1' - preference_version = '1.2.0' - recycler_view_version = '1.2.1' - desugar_jdk_libs_version = '1.1.8' - - // google - crashlytics_version = '2.10.1' - firebase_bom_version = '31.0.0' - - // kotlin - kotlin_coroutines_version = '1.6.4' - kotlin_version = '1.7.20' - - // networking - moshi_version = '1.14.0' - okhttp_version = '4.10.0' - retrofit_version = '2.9.0' - - // testing - android_test_junit = '1.3.0' - junit_version = '5.9.1' - ktlintVersion = '0.31.0' - mockk_version = '1.13.2' - test_runner_version = '1.4.0' - - // logging - slf4jtimber_version = '3.1' - timber_version = '5.0.1' - - // support - koin_version = '3.2.0' - scribejava_version = '8.3.2' - material_dialogs_version = '3.3.0' - three_ten_abp_version = '1.2.4' - - locus_api_version = '0.9.46' -} From 241bac911252adc36c7f15230a8318be07989d22 Mon Sep 17 00:00:00 2001 From: Arcao Date: Sun, 7 Apr 2024 00:50:13 +0200 Subject: [PATCH 2/7] Update .gitignore --- .gitignore | 64 ++++++++++++++++++++++-------------------------------- 1 file changed, 26 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index 1d3cf309..415d8bfa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,8 @@ -# Created by https://www.gitignore.io/api/android,crashlytics +# Created by https://www.toptal.com/developers/gitignore/api/android,crashlytics +# Edit at https://www.toptal.com/developers/gitignore?templates=android,crashlytics ### Android ### -# Built application files -*.apk -*.ap_ - -# Files for the ART/Dalvik VM -*.dex - -# Java class files -*.class - -# Generated files -bin/ -gen/ -out/ - # Gradle files .gradle/ build/ @@ -24,37 +10,39 @@ build/ # Local configuration file (sdk path, etc) local.properties -# Proguard folder generated by Eclipse -proguard/ - -# Log Files +# Log/OS Files *.log -# Android Studio Navigation editor temp files -.navigation/ - -# Android Studio captures folder +# Android Studio generated files and folders captures/ +.externalNativeBuild/ +.cxx/ +*.apk +output.json -# Intellij +# IntelliJ *.iml -.idea/workspace.xml -.idea/tasks.xml -.idea/gradle.xml -.idea/dictionaries -.idea/libraries +.idea/ +misc.xml +deploymentTargetDropDown.xml +render.experimental.xml + +# Keystore files +*.jks +*.keystore -# External native build folder generated in Android Studio 2.2 and later -.externalNativeBuild +# Google Services (e.g. APIs or Firebase) +google-services.json -# Freeline -freeline.py -freeline/ -freeline_project_description.json +# Android Profiling +*.hprof ### Android Patch ### gen-external-apklibs +# Replacement of .externalNativeBuild directories introduced +# with Android Studio 3.5. + ### Crashlytics ### #Crashlytics crashlytics-build.properties @@ -62,9 +50,9 @@ com_crashlytics_export_strings.xml crashlytics.properties fabric.properties - -# End of https://www.gitignore.io/api/android,crashlytics +# End of https://www.toptal.com/developers/gitignore/api/android,crashlytics .idea/caches /account.dat +/pkce.bin .idea/markdown-* From 156a3c87186ee37af6c0dd7460f2f381118b737e Mon Sep 17 00:00:00 2001 From: Arcao Date: Sun, 7 Apr 2024 00:50:45 +0200 Subject: [PATCH 3/7] Add PKCE for OAuth sign in --- .../util/PreferenceAccountManager.kt | 12 +++++++++- .../data/account/AccountManager.kt | 24 +++++++++++++++++-- .../data/account/FileAccountManager.kt | 15 +++++++++++- 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/arcao/geocaching4locus/authentication/util/PreferenceAccountManager.kt b/app/src/main/java/com/arcao/geocaching4locus/authentication/util/PreferenceAccountManager.kt index 82fb5eac..90baf76a 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/authentication/util/PreferenceAccountManager.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/authentication/util/PreferenceAccountManager.kt @@ -1,6 +1,7 @@ package com.arcao.geocaching4locus.authentication.util import android.content.Context +import android.util.Base64 import androidx.core.content.edit import com.arcao.geocaching4locus.base.constants.PrefConstants import com.arcao.geocaching4locus.data.account.AccountManager @@ -65,7 +66,16 @@ class PreferenceAccountManager(context: Context, oAuthService: OAuth20Service) : } } - @Suppress("DEPRECATION") + override fun savePkceRandom(randomBytes: ByteArray) { + prefs.edit { + putString("pkce", Base64.encodeToString(randomBytes, Base64.URL_SAFE or Base64.NO_WRAP)) + } + } + + override fun loadPkceRandom(): ByteArray = prefs.getString("pkce", null)?.let { + Base64.decode(it, Base64.URL_SAFE or Base64.NO_WRAP) + } ?: error("Unable to sign in, missing PKCE.") + private fun upgradeStorage() { val prefVersion = prefs.getInt(PrefConstants.PREF_VERSION, 0) if (prefVersion < 4) { diff --git a/geocaching-api/src/main/java/com/arcao/geocaching4locus/data/account/AccountManager.kt b/geocaching-api/src/main/java/com/arcao/geocaching4locus/data/account/AccountManager.kt index 8e06f944..1f66bc88 100644 --- a/geocaching-api/src/main/java/com/arcao/geocaching4locus/data/account/AccountManager.kt +++ b/geocaching-api/src/main/java/com/arcao/geocaching4locus/data/account/AccountManager.kt @@ -1,22 +1,34 @@ package com.arcao.geocaching4locus.data.account +import com.github.scribejava.core.oauth.AccessTokenRequestParams import com.github.scribejava.core.oauth.OAuth20Service +import com.github.scribejava.core.pkce.PKCEService import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext import java.time.Duration import java.time.Instant +import kotlin.random.Random abstract class AccountManager( private val oAuthService: OAuth20Service ) { + private val pkceService: PKCEService by lazy { + PKCEService.defaultInstance() + } + var account: GeocachingAccount? = null protected set val authorizationUrl: String get() { - return oAuthService.authorizationUrl + val randomBytes = Random.nextBytes(32) + savePkceRandom(randomBytes) + + return oAuthService.createAuthorizationUrlBuilder().pkce( + PKCEService.defaultInstance().generatePKCE(randomBytes) + ).build() } private val refreshAccountMutex = Mutex() @@ -28,9 +40,17 @@ abstract class AccountManager( this.account = account } + abstract fun savePkceRandom(randomBytes: ByteArray) + + abstract fun loadPkceRandom(): ByteArray + suspend fun createAccount(code: String): GeocachingAccount { val token = withContext(Dispatchers.IO) { - oAuthService.getAccessToken(code) + val pkce = pkceService.generatePKCE(loadPkceRandom()) + + oAuthService.getAccessToken( + AccessTokenRequestParams.create(code).pkceCodeVerifier(pkce.codeVerifier) + ) } val newAccount = GeocachingAccount( diff --git a/geocaching-api/src/main/java/com/arcao/geocaching4locus/data/account/FileAccountManager.kt b/geocaching-api/src/main/java/com/arcao/geocaching4locus/data/account/FileAccountManager.kt index 974ee4d7..48ae68a7 100644 --- a/geocaching-api/src/main/java/com/arcao/geocaching4locus/data/account/FileAccountManager.kt +++ b/geocaching-api/src/main/java/com/arcao/geocaching4locus/data/account/FileAccountManager.kt @@ -7,7 +7,8 @@ import java.time.Instant class FileAccountManager( oAuthService: OAuth20Service, - private val dataFile: File = File("account.dat") + private val dataFile: File = File("account.dat"), + private val pkceFile: File = File("pkce.bin") ) : AccountManager(oAuthService) { init { account = loadAccount() @@ -55,6 +56,18 @@ class FileAccountManager( ) } + override fun savePkceRandom(randomBytes: ByteArray) { + pkceFile.writeBytes(randomBytes) + } + + override fun loadPkceRandom(): ByteArray { + return pkceFile.readBytes().also { + check(it.isNotEmpty()) { + "Unable to sign in, missing PKCE." + } + } + } + private operator fun List.component6(): E? = this[5] private operator fun List.component7(): E? = this[6] From bac70c634ee91efc5f44bc232dec12862d1b9ddf Mon Sep 17 00:00:00 2001 From: Arcao Date: Sun, 7 Apr 2024 01:12:53 +0200 Subject: [PATCH 4/7] Add direct web redirect back to app while sign in --- app/src/main/AndroidManifest.xml | 73 ++++++++++---------------------- 1 file changed, 23 insertions(+), 50 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a3c20ffa..d8f1fce9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -174,22 +174,11 @@ - - - - + + + + + @@ -197,45 +186,17 @@ - - - - - - - - - + + + + + + @@ -261,6 +222,18 @@ android:host="oauth" android:scheme="com.arcao.geocaching4locus" /> + + + + + + + + + + + + Date: Sun, 7 Apr 2024 10:23:36 +0200 Subject: [PATCH 5/7] Fix proguard rules --- app/proguard-rules/proguard-scribejava.pro | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/proguard-rules/proguard-scribejava.pro b/app/proguard-rules/proguard-scribejava.pro index 8ac061a3..5b3b89cb 100644 --- a/app/proguard-rules/proguard-scribejava.pro +++ b/app/proguard-rules/proguard-scribejava.pro @@ -2,3 +2,5 @@ -dontwarn com.github.scribejava.core.services.DatatypeConverterEncoder -dontwarn org.apache.commons.codec.binary.** -dontwarn com.ning.http.client.** +-dontwarn jakarta.xml.bind.DatatypeConverter +-dontwarn javax.xml.bind.DatatypeConverter From 1ac47a367aeccc4e31c7fbb9d7c5270257855d83 Mon Sep 17 00:00:00 2001 From: Arcao Date: Sun, 7 Apr 2024 10:24:01 +0200 Subject: [PATCH 6/7] Update dependencies --- gradle/libs.versions.toml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5f0b31f8..ef6165eb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -31,18 +31,18 @@ android-desugar_jdk_libs = "2.0.4" firebase-bom = "32.8.0" # kotlin -kotlin-coroutines = "1.7.1" +kotlin-coroutines = "1.8.0" kotlin-bom = "1.9.23" # networking -moshi = "1.14.0" -okhttp = "4.11.0" -retrofit = "2.9.0" +moshi = "1.15.1" +okhttp = "4.12.0" +retrofit = "2.11.0" # testing -junit-android-test = "1.3.0" -junit-jupiter = "5.9.2" -mockk = "1.13.4" +junit-android-test = "1.4.0" +junit-jupiter = "5.10.2" +mockk = "1.13.10" androidx-test-runner = "1.5.2" # logging @@ -50,11 +50,11 @@ slf4j-timber = "3.1" timber = "5.0.1" # support -koin = "3.4.3" +koin = "3.5.4" scribejava = "8.3.3" material_dialogs = "3.3.0" -locus_api = "0.9.50" +locus_api = "0.9.52" [libraries] androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" } From a14c27315eb3519aa777a196408dfe552dc01589 Mon Sep 17 00:00:00 2001 From: Arcao Date: Sun, 7 Apr 2024 10:26:25 +0200 Subject: [PATCH 7/7] Change app version to 3.0.10 --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ef6165eb..31465eb3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,5 +1,5 @@ [versions] -app = "3.0.9" +app = "3.0.10" minSdk = "26" targetSdk = "34"