diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 75d474f1..0c3bb70d 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -30,15 +30,6 @@
-
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index 8144c3cf..f8617650 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -11,6 +11,6 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index bb02910f..46115fbf 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -46,5 +46,5 @@
-
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
deleted file mode 100644
index 7f68460d..00000000
--- a/.idea/runConfigurations.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 095cfd15..a0911980 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,8 +1,9 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
+apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
apply plugin: 'com.google.firebase.crashlytics'
+apply plugin: 'de.mannodermaus.android-junit5'
dependencies {
// Android Support
@@ -15,14 +16,13 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
- implementation "androidx.lifecycle:lifecycle-extensions:$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.multidex:multidex:$multidex_version"
implementation "androidx.paging:paging-runtime-ktx:$paging_version"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:$desugar_jdk_libs_version"
@@ -33,9 +33,7 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
// koin
- implementation "org.koin:koin-android:$koin_version"
- implementation "org.koin:koin-androidx-viewmodel:$koin_version"
- implementation "org.koin:koin-androidx-scope:$koin_version"
+ implementation "io.insert-koin:koin-android:$koin_version"
// Geocaching API
api project(":geocaching-api")
@@ -53,21 +51,17 @@ dependencies {
// Crashlytics & Firebase
implementation platform("com.google.firebase:firebase-bom:$firebase_bom_version")
- implementation 'com.google.firebase:firebase-core'
- implementation 'com.google.firebase:firebase-crashlytics'
- implementation 'com.google.firebase:firebase-analytics'
+ implementation 'com.google.firebase:firebase-crashlytics-ktx'
+ implementation 'com.google.firebase:firebase-analytics-ktx'
// Networking
implementation "com.squareup.okhttp3:okhttp:$okhttp_version"
}
android {
- compileSdkVersion rootProject.compile_sdk_version
+ namespace 'com.arcao.geocaching4locus'
- dexOptions {
- // Skip pre-dexing when running on Travis CI or when disabled via -Dpre-dex=false.
- preDexLibraries preDexEnabled && !isTravis
- }
+ compileSdkVersion rootProject.compile_sdk_version
defaultConfig {
applicationId 'com.arcao.geocaching4locus'
@@ -93,8 +87,8 @@ android {
buildConfigField 'String', 'TEST_USER', 'null'
buildConfigField 'String', 'TEST_PASSWORD', 'null'
-
resConfigs 'en', 'cs', 'de', 'es', 'fr', 'nl', 'no', 'pl', 'sk'
+
}
compileOptions {
@@ -106,8 +100,8 @@ android {
kotlinOptions {
freeCompilerArgs += [
- "-Xopt-in=kotlin.RequiresOptIn",
- "-Xjvm-default=compatibility"
+ "-opt-in=kotlin.RequiresOptIn",
+ "-Xjvm-default=all-compatibility"
]
jvmTarget = JavaVersion.VERSION_1_8
}
@@ -139,7 +133,8 @@ android {
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
+ minifyEnabled false
+ // App crash on VerifyError on Android 4.2, 4.3; https://issuetracker.google.com/issues/134304597
shrinkResources false
crunchPngs false
@@ -147,20 +142,22 @@ android {
proguardFiles fileTree(dir: 'proguard-rules', include: '*.pro').getFiles().toArray()
}
}
-
packagingOptions {
- exclude 'META-INF/DEPENDENCIES'
- exclude 'META-INF/LICENSE'
- exclude 'META-INF/atomicfu.kotlin_module'
- exclude 'org/apache/http/version.properties'
- exclude 'templates/release-notes.vm'
- exclude 'log4j.xml'
+ resources {
+ excludes += [
+ 'META-INF/DEPENDENCIES',
+ 'META-INF/LICENSE',
+ 'META-INF/atomicfu.kotlin_module',
+ 'org/apache/http/version.properties',
+ 'templates/release-notes.vm',
+ 'log4j.xml'
+ ]
+ }
}
- lintOptions { abortOnError false }
-}
-androidExtensions {
- experimental = true
+ lint {
+ abortOnError false
+ }
}
if (project.hasProperty('storeFile') &&
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index fa76d27d..2e7a1b2b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,7 +1,6 @@
@@ -38,11 +37,13 @@
android:name=".App"
android:allowBackup="true"
android:backupAgent=".base.util.backup.PreferencesBackupAgent"
+ android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/full_backup_scheme"
android:hardwareAccelerated="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
- android:largeHeap="true">
+ android:largeHeap="true"
+ tools:targetApi="s">
@@ -183,6 +184,12 @@
android:host="*.coord.info"
android:pathPrefix="/GC"
android:scheme="https" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/arcao/feedback/collector/ConfigurationCollector.kt b/app/src/main/java/com/arcao/feedback/collector/ConfigurationCollector.kt
index 02d56c91..bde37c3f 100644
--- a/app/src/main/java/com/arcao/feedback/collector/ConfigurationCollector.kt
+++ b/app/src/main/java/com/arcao/feedback/collector/ConfigurationCollector.kt
@@ -6,7 +6,6 @@ import android.util.SparseArray
import timber.log.Timber
import java.lang.reflect.Field
import java.lang.reflect.Modifier
-import java.util.Locale
class ConfigurationCollector(private val context: Context) : Collector() {
override val name: String
@@ -150,14 +149,17 @@ class ConfigurationCollector(private val context: Context) : Collector() {
* @throws IllegalAccessException if the supplied field is inaccessible.
*/
@Throws(IllegalAccessException::class)
- private fun getFieldValueName(conf: Configuration, f: Field): String? {
+ private fun getFieldValueName(conf: Configuration, f: Field): String {
when (val fieldName = f.name) {
FIELD_MCC, FIELD_MNC -> return f.getInt(conf).toString()
FIELD_UIMODE -> return activeFlags(VALUE_ARRAYS[PREFIX_UI_MODE]!!, f.getInt(conf))
- FIELD_SCREENLAYOUT -> return activeFlags(VALUE_ARRAYS[PREFIX_SCREENLAYOUT]!!, f.getInt(conf))
+ FIELD_SCREENLAYOUT -> return activeFlags(
+ VALUE_ARRAYS[PREFIX_SCREENLAYOUT]!!,
+ f.getInt(conf)
+ )
else -> {
val values =
- VALUE_ARRAYS[fieldName.toUpperCase(Locale.ROOT) + '_'] // Unknown field, return the raw int as String
+ VALUE_ARRAYS[fieldName.uppercase() + '_'] // Unknown field, return the raw int as String
?: return f.getInt(conf).toString()
return values.get(f.getInt(conf)) // Unknown value, return the raw int as String
diff --git a/app/src/main/java/com/arcao/feedback/collector/DisplayManagerCollector.kt b/app/src/main/java/com/arcao/feedback/collector/DisplayManagerCollector.kt
index aa5b7b70..0da7b6e7 100644
--- a/app/src/main/java/com/arcao/feedback/collector/DisplayManagerCollector.kt
+++ b/app/src/main/java/com/arcao/feedback/collector/DisplayManagerCollector.kt
@@ -4,12 +4,10 @@ import android.content.Context
import android.graphics.Point
import android.graphics.Rect
import android.hardware.display.DisplayManager
-import android.os.Build
import android.util.DisplayMetrics
import android.util.SparseArray
import android.view.Display
import android.view.Surface
-import android.view.WindowManager
import timber.log.Timber
class DisplayManagerCollector(private val context: Context) : Collector() {
@@ -20,20 +18,13 @@ class DisplayManagerCollector(private val context: Context) : Collector() {
var displays: Array? = null
val result = StringBuilder()
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
- // Before Android 4.2, there was a single display available from the
- // window manager
- val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
- displays = arrayOf(windowManager.defaultDisplay)
- } else {
- // Since Android 4.2, we can fetch multiple displays with the
- // DisplayManager.
- try {
- val displayManager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
- displays = displayManager.displays
- } catch (e: IllegalArgumentException) {
- Timber.e(e, "Error while collecting DisplayManager data")
- }
+ // Since Android 4.2, we can fetch multiple displays with the
+ // DisplayManager.
+ try {
+ val displayManager = context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
+ displays = displayManager.displays
+ } catch (e: IllegalArgumentException) {
+ Timber.e(e, "Error while collecting DisplayManager data")
}
displays?.forEach { display ->
@@ -102,6 +93,7 @@ class DisplayManagerCollector(private val context: Context) : Collector() {
try {
// since API v13
val size = Rect()
+ @Suppress("DEPRECATION")
display.getRectSize(size)
result.append(display.displayId).append(".rectSize=[").append(size.top).append(',').append(size.left)
.append(',').append(size.width()).append(',').append(size.height()).append(']').append('\n')
diff --git a/app/src/main/java/com/arcao/feedback/collector/LogCatCollector.kt b/app/src/main/java/com/arcao/feedback/collector/LogCatCollector.kt
index 2ea5c7ed..eb0cfc7c 100644
--- a/app/src/main/java/com/arcao/feedback/collector/LogCatCollector.kt
+++ b/app/src/main/java/com/arcao/feedback/collector/LogCatCollector.kt
@@ -9,6 +9,7 @@ class LogCatCollector : Collector() {
override val name: String
get() = "LOGCAT"
+ @Suppress("BlockingMethodInNonBlockingContext", "ControlFlowWithEmptyBody")
override suspend fun collect(): String = coroutineScope {
try {
val process = Runtime.getRuntime().exec(COMMAND_LINE)
diff --git a/app/src/main/java/com/arcao/feedback/collector/MemoryCollector.kt b/app/src/main/java/com/arcao/feedback/collector/MemoryCollector.kt
index 910ca5af..3d621bb5 100644
--- a/app/src/main/java/com/arcao/feedback/collector/MemoryCollector.kt
+++ b/app/src/main/java/com/arcao/feedback/collector/MemoryCollector.kt
@@ -8,6 +8,7 @@ class MemoryCollector : Collector() {
override val name: String
get() = "MEMORY"
+ @Suppress("BlockingMethodInNonBlockingContext")
override suspend fun collect(): String {
try {
val commandLine = arrayOf("dumpsys", "meminfo", Process.myPid().toString())
diff --git a/app/src/main/java/com/arcao/geocaching4locus/App.kt b/app/src/main/java/com/arcao/geocaching4locus/App.kt
index 31197558..4285851f 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/App.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/App.kt
@@ -3,14 +3,10 @@
package com.arcao.geocaching4locus
import android.app.Application
-import android.content.Context
-import android.os.Build
import android.webkit.CookieManager
-import android.webkit.CookieSyncManager
import androidx.annotation.WorkerThread
import androidx.core.content.edit
import androidx.core.content.pm.PackageInfoCompat
-import androidx.multidex.MultiDex
import androidx.preference.PreferenceManager
import com.arcao.feedback.feedbackModule
import com.arcao.geocaching4locus.authentication.util.isPremium
@@ -46,7 +42,7 @@ class App : Application() {
putString(PrefConstants.DEVICE_ID, value)
}
}
- value.orEmpty()
+ value
}
val version: String by lazy {
@@ -89,11 +85,6 @@ class App : Application() {
analyticsManager.setPremiumMember(accountManager.isPremium)
}
- override fun attachBaseContext(base: Context) {
- super.attachBaseContext(base)
- MultiDex.install(this)
- }
-
private fun prepareCrashlytics() {
// Set up Crashlytics, disabled for debug builds
if (BuildConfig.DEBUG) {
@@ -114,8 +105,8 @@ class App : Application() {
null
}
- crashlytics.setCustomKey(CrashlyticsConstants.LOCUS_VERSION, lv?.versionName ?: "")
- crashlytics.setCustomKey(CrashlyticsConstants.LOCUS_PACKAGE, lv?.packageName ?: "")
+ crashlytics.setCustomKey(CrashlyticsConstants.LOCUS_VERSION, lv?.versionName.orEmpty())
+ crashlytics.setCustomKey(CrashlyticsConstants.LOCUS_PACKAGE, lv?.packageName.orEmpty())
}
@WorkerThread
@@ -134,12 +125,7 @@ class App : Application() {
}
private fun flushCookie() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- CookieManager.getInstance().flush()
- } else {
- @Suppress("DEPRECATION")
- CookieSyncManager.createInstance(this).sync()
- }
+ CookieManager.getInstance().flush()
}
companion object {
diff --git a/app/src/main/java/com/arcao/geocaching4locus/AppModule.kt b/app/src/main/java/com/arcao/geocaching4locus/AppModule.kt
index c259dac0..fcd4d2c2 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/AppModule.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/AppModule.kt
@@ -1,6 +1,5 @@
package com.arcao.geocaching4locus
-import android.content.Intent
import com.arcao.geocaching4locus.authentication.LoginViewModel
import com.arcao.geocaching4locus.authentication.usecase.CreateAccountUseCase
import com.arcao.geocaching4locus.authentication.usecase.RetrieveAuthorizationUrlUseCase
@@ -27,7 +26,6 @@ import com.arcao.geocaching4locus.base.usecase.RemoveLocusMapPointsUseCase
import com.arcao.geocaching4locus.base.usecase.RequireLocationPermissionRequestUseCase
import com.arcao.geocaching4locus.base.usecase.SendPointsSilentToLocusMapUseCase
import com.arcao.geocaching4locus.base.usecase.WritePointToPackPointsFileUseCase
-import com.arcao.geocaching4locus.base.usecase.entity.GeocacheListEntity
import com.arcao.geocaching4locus.base.util.AnalyticsManager
import com.arcao.geocaching4locus.dashboard.DashboardViewModel
import com.arcao.geocaching4locus.data.account.AccountManager
@@ -36,8 +34,6 @@ import com.arcao.geocaching4locus.error.handler.ExceptionHandler
import com.arcao.geocaching4locus.import_bookmarks.ImportBookmarkViewModel
import com.arcao.geocaching4locus.import_bookmarks.fragment.BookmarkListViewModel
import com.arcao.geocaching4locus.import_bookmarks.fragment.BookmarkViewModel
-import com.arcao.geocaching4locus.import_bookmarks.paging.GeocacheUserListsDataSourceFactory
-import com.arcao.geocaching4locus.import_bookmarks.paging.ListGeocachesDataSourceFactory
import com.arcao.geocaching4locus.importgc.ImportGeocacheCodeViewModel
import com.arcao.geocaching4locus.importgc.ImportUrlViewModel
import com.arcao.geocaching4locus.live_map.LiveMapViewModel
@@ -104,9 +100,9 @@ internal val appModule = module {
// login
viewModel { LoginViewModel(get(), get(), get(), get(), get(), get(), get()) }
// dashboard
- viewModel { (calledFromLocusMap: Boolean) ->
+ viewModel { parameters ->
DashboardViewModel(
- calledFromLocusMap,
+ parameters.get(),
get(),
get(),
get(),
@@ -135,9 +131,9 @@ internal val appModule = module {
// import bookmarks
viewModel { ImportBookmarkViewModel(get(), get(), get()) }
viewModel { BookmarkListViewModel(get(), get(), get(), get(), get(), get(), get(), get()) }
- viewModel { (bl: GeocacheListEntity) ->
+ viewModel { parameters ->
BookmarkViewModel(
- bl,
+ parameters.get(),
get(),
get(),
get(),
@@ -149,14 +145,12 @@ internal val appModule = module {
get()
)
}
- factory { GeocacheUserListsDataSourceFactory(get(), get()) }
- factory { ListGeocachesDataSourceFactory(get(), get()) }
// live map
factory { LiveMapViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get()) }
// search nearest
- viewModel { (intent: Intent) ->
+ viewModel { parameters ->
SearchNearestViewModel(
- intent,
+ parameters.get(),
get(),
get(),
get(),
diff --git a/app/src/main/java/com/arcao/geocaching4locus/authentication/LoginActivity.kt b/app/src/main/java/com/arcao/geocaching4locus/authentication/LoginActivity.kt
index 61eb3a1b..9ae1146d 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/authentication/LoginActivity.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/authentication/LoginActivity.kt
@@ -9,6 +9,7 @@ import android.os.Bundle
import android.view.MenuItem
import android.view.View
import androidx.activity.addCallback
+import androidx.activity.result.contract.ActivityResultContract
import androidx.appcompat.widget.Toolbar
import androidx.browser.customtabs.CustomTabsIntent
import androidx.core.net.toUri
@@ -35,6 +36,7 @@ class LoginActivity : AbstractActionBarActivity() {
binding.vm = viewModel
setContentView(binding.root)
+
@Suppress("USELESS_CAST")
setSupportActionBar(binding.toolbar as Toolbar)
@@ -102,7 +104,7 @@ class LoginActivity : AbstractActionBarActivity() {
try {
CustomTabsIntent.Builder()
.setInstantAppsEnabled(true)
- .enableUrlBarHiding()
+ .setUrlBarHidingEnabled(true)
.build().launchUrl(this, url.toUri())
} catch (e: ActivityNotFoundException) {
showWebPage(url.toUri())
@@ -137,4 +139,13 @@ class LoginActivity : AbstractActionBarActivity() {
return intent
}
}
+
+ object Contract : ActivityResultContract() {
+ override fun createIntent(context: Context, input: Void?) =
+ Intent(context, LoginActivity::class.java)
+
+ override fun parseResult(resultCode: Int, intent: Intent?): Boolean {
+ return resultCode == Activity.RESULT_OK
+ }
+ }
}
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 52dcaaee..a302c011 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/authentication/LoginViewModel.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/authentication/LoginViewModel.kt
@@ -30,7 +30,7 @@ class LoginViewModel(
val action = Command()
private var job: Job? = null
- val code = MutableLiveData("")
+ val code = MutableLiveData("")
val continueButtonEnabled = Transformations.map(code, String::isNotBlank)
val formVisible = MutableLiveData(true)
var fromIntent = false
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 e555a2ef..82fb5eac 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,9 +1,7 @@
package com.arcao.geocaching4locus.authentication.util
-import android.app.Activity
import android.content.Context
import androidx.core.content.edit
-import com.arcao.geocaching4locus.authentication.LoginActivity
import com.arcao.geocaching4locus.base.constants.PrefConstants
import com.arcao.geocaching4locus.data.account.AccountManager
import com.arcao.geocaching4locus.data.account.GeocachingAccount
@@ -84,14 +82,6 @@ class PreferenceAccountManager(context: Context, oAuthService: OAuth20Service) :
}
}
-fun AccountManager.requestSignOn(activity: Activity, requestCode: Int): Boolean {
- if (account != null)
- return false
-
- activity.startActivityForResult(LoginActivity.createIntent(activity), requestCode)
- return true
-}
-
val AccountManager.isPremium: Boolean
get() = account?.isPremium() ?: false
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 6fa1b3a3..68d92847 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
@@ -1,12 +1,10 @@
package com.arcao.geocaching4locus.base.constants
import android.net.Uri
-import android.os.Build
import android.util.Base64
import com.arcao.geocaching4locus.data.api.model.GeocacheSize
import com.arcao.geocaching4locus.data.api.model.GeocacheType
-
-import locus.api.android.utils.LocusUtils
+import locus.api.android.objects.VersionCode
object AppConstants {
const val OAUTH_CALLBACK_URL = "https://geocaching4locus.eu/oauth"
@@ -27,16 +25,15 @@ object AppConstants {
)
)
- const val LOCUS_MIN_VERSION = "3.36.0"
- val LOCUS_MIN_VERSION_CODE: LocusUtils.VersionCode = LocusUtils.VersionCode.UPDATE_15
+ const val LOCUS_MIN_VERSION = "3.52.0"
+ val LOCUS_MIN_VERSION_CODE: VersionCode = VersionCode.UPDATE_17
+
+ const val INITIAL_REQUEST_SIZE = 30
- /* Adaptive downloading configuration */
- const val ADAPTIVE_DOWNLOADING_MIN_ITEMS = 10
- const val ADAPTIVE_DOWNLOADING_MAX_ITEMS = 100
- const val ADAPTIVE_DOWNLOADING_STEP = 20
- const val ADAPTIVE_DOWNLOADING_MIN_TIME_MS = 3500 // more than time required for 30 calls per minute
- const val ADAPTIVE_DOWNLOADING_MAX_TIME_MS = 10000
- const val ITEMS_PER_REQUEST = 30
+ const val SEARCH_MAX_REQUEST_SIZE = 100
+ const val LIVE_MAP_MAX_REQUEST_SIZE = SEARCH_MAX_REQUEST_SIZE
+ const val GEOCACHES_MAX_REQUEST_SIZE = 50
+ const val LIST_GEOCACHES_DOWNLOAD_MAX_ITEMS = 50
const val MINUTES_PER_HOUR = 60
@@ -63,8 +60,7 @@ object AppConstants {
const val DISTANCE_MIN_METERS = 100
const val DISTANCE_MAX_METERS = 50000
- val PREMIUM_CHARACTER =
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) String(Character.toChars(0x1F451)) else "(PM)"
+ val PREMIUM_CHARACTER = String(Character.toChars(0x1F451))
const val NOTIFICATION_ID_LIVEMAP = 1
@@ -100,7 +96,7 @@ object AppConstants {
GeocacheSize.NOT_CHOSEN,
GeocacheSize.MICRO,
GeocacheSize.SMALL,
- GeocacheSize.MEDIUM,
+ GeocacheSize.REGULAR,
GeocacheSize.LARGE,
GeocacheSize.VIRTUAL,
GeocacheSize.OTHER
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/fragment/AbstractDialogFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/base/fragment/AbstractDialogFragment.kt
index 5d2173e6..16b632e4 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/fragment/AbstractDialogFragment.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/fragment/AbstractDialogFragment.kt
@@ -1,6 +1,5 @@
package com.arcao.geocaching4locus.base.fragment
-import androidx.annotation.NonNull
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
@@ -16,7 +15,7 @@ abstract class AbstractDialogFragment : DialogFragment() {
// This is work around for the situation when method show is called after saving
// state even if you do all right. Especially when show is called after click on
// a button.
- override fun show(@NonNull transaction: FragmentTransaction, tag: String?): Int {
+ override fun show(transaction: FragmentTransaction, tag: String?): Int {
return try {
super.show(transaction, tag)
} catch (e: IllegalStateException) {
@@ -33,18 +32,6 @@ abstract class AbstractDialogFragment : DialogFragment() {
}
}
- // This is to work around what is apparently a bug. If you don't have it
- // here the dialog will be dismissed on rotation, so tell it not to dismiss.
- override fun onDestroyView() {
- dialog?.let { dialog ->
- if (retainInstance) {
- dialog.setDismissMessage(null)
- }
- }
-
- super.onDestroyView()
- }
-
override fun dismiss() {
try {
super.dismiss()
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 ffffcaeb..dda4392f 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
@@ -34,18 +34,18 @@ abstract class AbstractPreferenceFragment : PreferenceFragmentCompat(),
override fun onCreate(paramBundle: Bundle?) {
super.onCreate(paramBundle)
- preferences = PreferenceManager.getDefaultSharedPreferences(activity)
+ preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
}
override fun onResume() {
super.onResume()
- preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
+ preferenceScreen.sharedPreferences?.registerOnSharedPreferenceChangeListener(this)
preparePreference()
}
override fun onPause() {
super.onPause()
- preferenceScreen.sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
+ preferenceScreen.sharedPreferences?.unregisterOnSharedPreferenceChangeListener(this)
}
@CallSuper
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/fragment/SliderDialogFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/base/fragment/SliderDialogFragment.kt
index 0d417d21..9b65539b 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/fragment/SliderDialogFragment.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/fragment/SliderDialogFragment.kt
@@ -15,8 +15,6 @@ import android.view.View
import android.widget.EditText
import android.widget.SeekBar
import android.widget.TextView
-import androidx.annotation.NonNull
-import androidx.annotation.Nullable
import androidx.annotation.StringRes
import androidx.core.os.bundleOf
import com.afollestad.materialdialogs.MaterialDialog
@@ -62,7 +60,6 @@ class SliderDialogFragment : AbstractDialogFragment(), SeekBar.OnSeekBarChangeLi
listener?.onDialogClosed(this)
}
- @NonNull
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val arguments = requireArguments()
@@ -99,7 +96,7 @@ class SliderDialogFragment : AbstractDialogFragment(), SeekBar.OnSeekBarChangeLi
}
}
- override fun onSaveInstanceState(@NonNull outState: Bundle) {
+ override fun onSaveInstanceState(outState: Bundle) {
outState.putInt(PARAM_DEFAULT_VALUE, value)
super.onSaveInstanceState(outState)
}
@@ -167,13 +164,12 @@ class SliderDialogFragment : AbstractDialogFragment(), SeekBar.OnSeekBarChangeLi
seekBarView.progress = (value - minValue) / valueStep
}
- private class InputTextFilter internal constructor(
- internal val editTextView: EditText,
+ private class InputTextFilter(
+ val editTextView: EditText,
private val min: Int,
private val max: Int,
step: Int
) : NumberKeyListener() {
- @Nullable
private val availableValues: Array?
init {
@@ -195,19 +191,18 @@ class SliderDialogFragment : AbstractDialogFragment(), SeekBar.OnSeekBarChangeLi
return InputType.TYPE_CLASS_TEXT
}
- @NonNull
override fun getAcceptedChars(): CharArray {
return DIGIT_CHARACTERS
}
override fun filter(
- @NonNull source: CharSequence,
+ source: CharSequence,
start: Int,
end: Int,
dest: Spanned,
dstart: Int,
dend: Int
- ): CharSequence? {
+ ): CharSequence {
if (availableValues == null || availableValues.isEmpty()) {
var filtered: CharSequence? = super.filter(source, start, end, dest, dstart, dend)
if (filtered == null) {
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/paging/DataSourceState.kt b/app/src/main/java/com/arcao/geocaching4locus/base/paging/DataSourceState.kt
deleted file mode 100644
index b4556948..00000000
--- a/app/src/main/java/com/arcao/geocaching4locus/base/paging/DataSourceState.kt
+++ /dev/null
@@ -1,8 +0,0 @@
-package com.arcao.geocaching4locus.base.paging
-
-sealed class DataSourceState {
- object LoadingInitial : DataSourceState()
- object LoadingNext : DataSourceState()
- object Done : DataSourceState()
- class Error(val e: Exception) : DataSourceState()
-}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/paging/PagingExt.kt b/app/src/main/java/com/arcao/geocaching4locus/base/paging/PagingExt.kt
new file mode 100644
index 00000000..42ce49cc
--- /dev/null
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/paging/PagingExt.kt
@@ -0,0 +1,18 @@
+package com.arcao.geocaching4locus.base.paging
+
+import androidx.paging.CombinedLoadStates
+import androidx.paging.LoadState
+
+fun CombinedLoadStates.handleErrors(callback: (Throwable) -> Unit) {
+ val state = source.append as? LoadState.Error
+ ?: source.prepend as? LoadState.Error
+ ?: source.refresh as? LoadState.Error
+ ?: append as? LoadState.Error
+ ?: prepend as? LoadState.Error
+ ?: refresh as? LoadState.Error
+
+ if (state != null) {
+ callback(state.error)
+ }
+}
+
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/selection/SelectionTracker.kt b/app/src/main/java/com/arcao/geocaching4locus/base/selection/SelectionTracker.kt
index 7db36f06..5af79936 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/selection/SelectionTracker.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/selection/SelectionTracker.kt
@@ -5,7 +5,6 @@ import android.os.Parcelable
import android.util.SparseArray
import androidx.core.util.containsKey
import androidx.core.util.forEach
-import androidx.core.util.set
import androidx.core.util.valueIterator
import androidx.recyclerview.widget.RecyclerView
import java.util.concurrent.CopyOnWriteArraySet
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GeocachingApiLoginUseCase.kt b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GeocachingApiLoginUseCase.kt
index 3d5b7a11..2898032a 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GeocachingApiLoginUseCase.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GeocachingApiLoginUseCase.kt
@@ -2,6 +2,7 @@ package com.arcao.geocaching4locus.base.usecase
import androidx.annotation.WorkerThread
import com.arcao.geocaching4locus.authentication.util.isAccountUpdateRequired
+import com.arcao.geocaching4locus.authentication.util.restrictions
import com.arcao.geocaching4locus.base.AccountNotFoundException
import com.arcao.geocaching4locus.base.coroutine.CoroutinesDispatcherProvider
import com.arcao.geocaching4locus.data.account.AccountManager
@@ -20,7 +21,15 @@ class GeocachingApiLoginUseCase(
val account = accountManager.account ?: throw AccountNotFoundException("Account not found.")
if (account.isAccountUpdateRequired()) {
- account.updateUserInfo(repository.user())
+ val user = repository.user()
+
+ account.updateUserInfo(user)
+
+ // update restrictions
+ accountManager.restrictions().apply {
+ updateLimits(user)
+ applyRestrictions(user)
+ }
}
}
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetGpsLocationUseCase.kt b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetGpsLocationUseCase.kt
index 08028e52..a3b36623 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetGpsLocationUseCase.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetGpsLocationUseCase.kt
@@ -23,8 +23,11 @@ class GetGpsLocationUseCase(
@SuppressLint("MissingPermission")
suspend operator fun invoke() = withContext(dispatcherProvider.main) {
- suspendCancellableCoroutine { result ->
- if (!context.hasGpsLocationPermission || !locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
+ suspendCancellableCoroutine { result ->
+ if (!context.hasGpsLocationPermission || !locationManager.isProviderEnabled(
+ LocationManager.GPS_PROVIDER
+ )
+ ) {
result.resume(null)
return@suspendCancellableCoroutine
}
@@ -55,13 +58,14 @@ class GetGpsLocationUseCase(
result.resume(location)
}
- override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
+ @Deprecated("Deprecated in Java")
+ override fun onStatusChanged(provider: String, status: Int, extras: Bundle?) {
}
- override fun onProviderEnabled(provider: String?) {
+ override fun onProviderEnabled(provider: String) {
}
- override fun onProviderDisabled(provider: String?) {
+ override fun onProviderDisabled(provider: String) {
if (result.isCompleted) return
Timber.i("onProviderDisabled: $provider")
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetListGeocachesUseCase.kt b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetListGeocachesUseCase.kt
index 04d09e53..6267c86d 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetListGeocachesUseCase.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetListGeocachesUseCase.kt
@@ -55,10 +55,10 @@ class GetListGeocachesUseCase(
) = flow {
geocachingApiLogin()
- var count = AppConstants.ITEMS_PER_REQUEST
+ var count = AppConstants.INITIAL_REQUEST_SIZE
var current = 0
- var itemsPerRequest = AppConstants.ITEMS_PER_REQUEST
+ var itemsPerRequest = AppConstants.INITIAL_REQUEST_SIZE
while (current < count) {
val startTimeMillis = System.currentTimeMillis()
@@ -83,7 +83,11 @@ class GetListGeocachesUseCase(
emit(mapper.createLocusPoints(geocaches))
current += geocaches.size
- itemsPerRequest = DownloadingUtil.computeItemsPerRequest(itemsPerRequest, startTimeMillis)
+ itemsPerRequest = DownloadingUtil.computeRequestSize(
+ itemsPerRequest,
+ AppConstants.LIST_GEOCACHES_DOWNLOAD_MAX_ITEMS,
+ startTimeMillis
+ )
}
Timber.v("found geocaches: %d", current)
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetLiveMapPointsFromRectangleCoordinatesUseCase.kt b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetLiveMapPointsFromRectangleCoordinatesUseCase.kt
index eae5bed3..3cbddbe9 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetLiveMapPointsFromRectangleCoordinatesUseCase.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetLiveMapPointsFromRectangleCoordinatesUseCase.kt
@@ -38,7 +38,6 @@ class GetLiveMapPointsFromRectangleCoordinatesUseCase(
difficultyMax: Float = 5F,
terrainMin: Float = 1F,
terrainMax: Float = 5F,
- excludeIgnoreList: Boolean = true,
countHandler: (Int) -> Unit = {}
) = flow {
geocachingApiLogin()
@@ -82,8 +81,11 @@ class GetLiveMapPointsFromRectangleCoordinatesUseCase(
emit(mapper.createLocusPoints(geocaches))
current += geocaches.size
- itemsPerRequest =
- DownloadingUtil.computeItemsPerRequest(itemsPerRequest, startTimeMillis)
+ itemsPerRequest = DownloadingUtil.computeRequestSize(
+ itemsPerRequest,
+ AppConstants.LIVE_MAP_MAX_REQUEST_SIZE,
+ startTimeMillis
+ )
}
} finally {
try {
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetOldPointNewPointPairFromPointUseCase.kt b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetOldPointNewPointPairFromPointUseCase.kt
index 78cea97e..2cc7fd2c 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetOldPointNewPointPairFromPointUseCase.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetOldPointNewPointPairFromPointUseCase.kt
@@ -12,7 +12,7 @@ import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.yield
import locus.api.mapper.DataMapper
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
class GetOldPointNewPointPairFromPointUseCase(
private val repository: GeocachingApiRepository,
@@ -29,8 +29,8 @@ class GetOldPointNewPointPairFromPointUseCase(
) = flow {
geocachingApiLogin()
- flow.takeListVariable(AppConstants.ITEMS_PER_REQUEST) { points ->
- val requestedCacheIds = points.map { it.gcData.cacheID }.toTypedArray()
+ flow.takeListVariable(AppConstants.INITIAL_REQUEST_SIZE) { points ->
+ val requestedCacheIds = points.mapNotNull { it.gcData?.cacheID }.toTypedArray()
val startTimeMillis = System.currentTimeMillis()
@@ -47,12 +47,17 @@ class GetOldPointNewPointPairFromPointUseCase(
if (cachesToAdd.isNotEmpty()) {
val receivedPoints = mapper.createLocusPoints(cachesToAdd)
for (oldPoint in points) {
- val newPoint = receivedPoints.find { it.gcData.cacheID == oldPoint.gcData.cacheID }
+ val newPoint =
+ receivedPoints.find { it.gcData?.cacheID == oldPoint.gcData?.cacheID }
emit(Pair(oldPoint, newPoint))
}
}
- DownloadingUtil.computeItemsPerRequest(points.size, startTimeMillis)
+ DownloadingUtil.computeRequestSize(
+ points.size,
+ AppConstants.GEOCACHES_MAX_REQUEST_SIZE,
+ startTimeMillis
+ )
}
}.flowOn(dispatcherProvider.io)
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromCoordinatesUseCase.kt b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromCoordinatesUseCase.kt
index a84ec3e8..88ff4c53 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromCoordinatesUseCase.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromCoordinatesUseCase.kt
@@ -39,7 +39,6 @@ class GetPointsFromCoordinatesUseCase(
difficultyMax: Float = 5F,
terrainMin: Float = 1F,
terrainMax: Float = 5F,
- excludeIgnoreList: Boolean = true,
maxCount: Int = 50,
countHandler: (Int) -> Unit = {}
) = flow {
@@ -48,7 +47,7 @@ class GetPointsFromCoordinatesUseCase(
var count = maxCount
var current = 0
- var itemsPerRequest = AppConstants.ITEMS_PER_REQUEST
+ var itemsPerRequest = AppConstants.INITIAL_REQUEST_SIZE
while (current < count) {
val startTimeMillis = System.currentTimeMillis()
@@ -89,7 +88,11 @@ class GetPointsFromCoordinatesUseCase(
current += geocaches.size
itemsPerRequest =
- DownloadingUtil.computeItemsPerRequest(itemsPerRequest, startTimeMillis)
+ DownloadingUtil.computeRequestSize(
+ itemsPerRequest,
+ AppConstants.SEARCH_MAX_REQUEST_SIZE,
+ startTimeMillis
+ )
}
Timber.v("found geocaches: %d", current)
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromGeocacheCodesUseCase.kt b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromGeocacheCodesUseCase.kt
index 08674fa6..61457552 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromGeocacheCodesUseCase.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromGeocacheCodesUseCase.kt
@@ -35,7 +35,7 @@ class GetPointsFromGeocacheCodesUseCase(
val count = geocacheCodes.size
var current = 0
- var itemsPerRequest = AppConstants.ITEMS_PER_REQUEST
+ var itemsPerRequest = AppConstants.INITIAL_REQUEST_SIZE
while (current < count) {
val startTimeMillis = System.currentTimeMillis()
@@ -60,7 +60,11 @@ class GetPointsFromGeocacheCodesUseCase(
current += requestedCacheIds.size
- itemsPerRequest = DownloadingUtil.computeItemsPerRequest(itemsPerRequest, startTimeMillis)
+ itemsPerRequest = DownloadingUtil.computeRequestSize(
+ itemsPerRequest,
+ AppConstants.GEOCACHES_MAX_REQUEST_SIZE,
+ startTimeMillis
+ )
}
Timber.v("found geocaches: %d", current)
@@ -93,7 +97,11 @@ class GetPointsFromGeocacheCodesUseCase(
}
}
- private fun getRequestedGeocacheIds(cacheIds: Array, current: Int, cachesPerRequest: Int): Array {
+ private fun getRequestedGeocacheIds(
+ cacheIds: Array,
+ current: Int,
+ cachesPerRequest: Int
+ ): Array {
val count = min(cacheIds.size - current, cachesPerRequest)
return cacheIds.copyOfRange(current, current + count)
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromPointIndexesUseCase.kt b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromPointIndexesUseCase.kt
index 8d7909b2..e941042d 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromPointIndexesUseCase.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromPointIndexesUseCase.kt
@@ -9,7 +9,7 @@ import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import locus.api.manager.LocusMapManager
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
class GetPointsFromPointIndexesUseCase(
private val locusMapManager: LocusMapManager,
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromRectangleCoordinatesUseCase.kt b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromRectangleCoordinatesUseCase.kt
index 55269d32..3bf8c554 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromRectangleCoordinatesUseCase.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetPointsFromRectangleCoordinatesUseCase.kt
@@ -39,16 +39,15 @@ class GetPointsFromRectangleCoordinatesUseCase(
difficultyMax: Float = 5F,
terrainMin: Float = 1F,
terrainMax: Float = 5F,
- excludeIgnoreList: Boolean = true,
maxCount: Int = 50,
countHandler: (Int) -> Unit = {}
) = flow {
geocachingApiLogin()
- var count = AppConstants.ITEMS_PER_REQUEST
+ var count = maxCount
var current = 0
- var itemsPerRequest = AppConstants.ITEMS_PER_REQUEST
+ var itemsPerRequest = AppConstants.INITIAL_REQUEST_SIZE
while (current < count) {
val startTimeMillis = System.currentTimeMillis()
@@ -87,7 +86,11 @@ class GetPointsFromRectangleCoordinatesUseCase(
current += geocaches.size
itemsPerRequest =
- DownloadingUtil.computeItemsPerRequest(itemsPerRequest, startTimeMillis)
+ DownloadingUtil.computeRequestSize(
+ itemsPerRequest,
+ AppConstants.SEARCH_MAX_REQUEST_SIZE,
+ startTimeMillis
+ )
}
Timber.v("found geocaches: %d", current)
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetWifiLocationUseCase.kt b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetWifiLocationUseCase.kt
index 48cc20b8..2bb44b6a 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetWifiLocationUseCase.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/GetWifiLocationUseCase.kt
@@ -23,8 +23,11 @@ class GetWifiLocationUseCase(
@SuppressLint("MissingPermission")
suspend operator fun invoke() = withContext(dispatcherProvider.main) {
- suspendCancellableCoroutine { result ->
- if (!context.hasWifiLocationPermission || !locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
+ suspendCancellableCoroutine { result ->
+ if (!context.hasWifiLocationPermission || !locationManager.isProviderEnabled(
+ LocationManager.NETWORK_PROVIDER
+ )
+ ) {
result.resume(null)
return@suspendCancellableCoroutine
}
@@ -55,13 +58,14 @@ class GetWifiLocationUseCase(
result.resume(location)
}
- override fun onStatusChanged(provider: String?, status: Int, extras: Bundle?) {
+ @Deprecated("Deprecated in Java")
+ override fun onStatusChanged(provider: String, status: Int, extras: Bundle?) {
}
- override fun onProviderEnabled(provider: String?) {
+ override fun onProviderEnabled(provider: String) {
}
- override fun onProviderDisabled(provider: String?) {
+ override fun onProviderDisabled(provider: String) {
if (result.isCompleted) return
Timber.i("onProviderDisabled: $provider")
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/SendPointsSilentToLocusMapUseCase.kt b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/SendPointsSilentToLocusMapUseCase.kt
index a9433496..ba6cc440 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/SendPointsSilentToLocusMapUseCase.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/SendPointsSilentToLocusMapUseCase.kt
@@ -2,10 +2,9 @@ package com.arcao.geocaching4locus.base.usecase
import com.arcao.geocaching4locus.base.coroutine.CoroutinesDispatcherProvider
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.withContext
import locus.api.manager.LocusMapManager
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
class SendPointsSilentToLocusMapUseCase(
private val locusMapManager: LocusMapManager,
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/WritePointToPackPointsFileUseCase.kt b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/WritePointToPackPointsFileUseCase.kt
index b58f8c4a..2b003055 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/WritePointToPackPointsFileUseCase.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/WritePointToPackPointsFileUseCase.kt
@@ -2,11 +2,10 @@ package com.arcao.geocaching4locus.base.usecase
import com.arcao.geocaching4locus.base.coroutine.CoroutinesDispatcherProvider
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.withContext
import locus.api.android.objects.PackPoints
import locus.api.manager.LocusMapManager
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
import locus.api.utils.StoreableWriter
@Suppress("BlockingMethodInNonBlockingContext")
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/entity/GeocacheListEntity.kt b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/entity/GeocacheListEntity.kt
index eca32430..98291796 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/entity/GeocacheListEntity.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/entity/GeocacheListEntity.kt
@@ -2,7 +2,7 @@ package com.arcao.geocaching4locus.base.usecase.entity
import android.os.Parcelable
import com.arcao.geocaching4locus.data.api.model.enums.GeocacheListType
-import kotlinx.android.parcel.Parcelize
+import kotlinx.parcelize.Parcelize
@Parcelize
data class GeocacheListEntity(
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/entity/ListGeocacheEntity.kt b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/entity/ListGeocacheEntity.kt
index 6231ce46..7b73ba27 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/usecase/entity/ListGeocacheEntity.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/usecase/entity/ListGeocacheEntity.kt
@@ -2,8 +2,8 @@ package com.arcao.geocaching4locus.base.usecase.entity
import android.os.Parcelable
import com.arcao.geocaching4locus.data.api.util.ReferenceCode
-import kotlinx.android.parcel.IgnoredOnParcel
-import kotlinx.android.parcel.Parcelize
+import kotlinx.parcelize.IgnoredOnParcel
+import kotlinx.parcelize.Parcelize
@Parcelize
data class ListGeocacheEntity(
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/util/CoordinatesFormatter.kt b/app/src/main/java/com/arcao/geocaching4locus/base/util/CoordinatesFormatter.kt
index 679d2de5..5494ef0f 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/util/CoordinatesFormatter.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/util/CoordinatesFormatter.kt
@@ -54,7 +54,7 @@ object CoordinatesFormatter {
var direction = 1.0
try {
- ch = tmp[index].toUpperCase()
+ ch = tmp[index].uppercaseChar()
if (ch == 'S' || ch == 'W' || ch == '-') {
direction = -1.0
index++
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/util/DownloadingUtil.kt b/app/src/main/java/com/arcao/geocaching4locus/base/util/DownloadingUtil.kt
index e350e073..f83d30bf 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/util/DownloadingUtil.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/util/DownloadingUtil.kt
@@ -1,25 +1,36 @@
package com.arcao.geocaching4locus.base.util
-import com.arcao.geocaching4locus.base.constants.AppConstants
import kotlin.math.max
import kotlin.math.min
object DownloadingUtil {
- fun computeItemsPerRequest(currentItemsPerRequest: Int, startTimeMillis: Long): Int {
- var itemsPerRequest = currentItemsPerRequest
+ /* Adaptive downloading configuration */
+ const val MIN_REQUEST_SIZE = 10
+ const val REQUEST_SIZE_INCREMENT = 20
+ const val REQUEST_SIZE_DECREMENT = REQUEST_SIZE_INCREMENT
+ const val MIN_REQUEST_TIME_MS =
+ 3500 // more than time required for 30 calls per minute
+ const val MAX_REQUEST_TIME_MS = 10000
+
+ fun computeRequestSize(
+ currentRequestSize: Int,
+ maxRequestSize: Int,
+ startTimeMillis: Long
+ ): Int {
+ var requestSize = currentRequestSize
val requestDuration = System.currentTimeMillis() - startTimeMillis
- // keep the request time between ADAPTIVE_DOWNLOADING_MIN_TIME_MS and ADAPTIVE_DOWNLOADING_MAX_TIME_MS
- if (requestDuration < AppConstants.ADAPTIVE_DOWNLOADING_MIN_TIME_MS)
- itemsPerRequest += AppConstants.ADAPTIVE_DOWNLOADING_STEP
+ // keep the request time between MIN_REQUEST_TIME_MS and MAX_REQUEST_TIME_MS
+ if (requestDuration < MIN_REQUEST_TIME_MS)
+ requestSize += REQUEST_SIZE_INCREMENT
- if (requestDuration > AppConstants.ADAPTIVE_DOWNLOADING_MAX_TIME_MS)
- itemsPerRequest -= AppConstants.ADAPTIVE_DOWNLOADING_STEP
+ if (requestDuration > MAX_REQUEST_TIME_MS)
+ requestSize -= REQUEST_SIZE_DECREMENT
// keep the value in a range
- itemsPerRequest = max(itemsPerRequest, AppConstants.ADAPTIVE_DOWNLOADING_MIN_ITEMS)
- itemsPerRequest = min(itemsPerRequest, AppConstants.ADAPTIVE_DOWNLOADING_MAX_ITEMS)
+ requestSize = max(requestSize, MIN_REQUEST_SIZE)
+ requestSize = min(requestSize, maxRequestSize)
- return itemsPerRequest
+ return requestSize
}
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/util/FlowExtension.kt b/app/src/main/java/com/arcao/geocaching4locus/base/util/FlowExtension.kt
index 5c553a42..c93c5c4d 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/util/FlowExtension.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/util/FlowExtension.kt
@@ -1,7 +1,6 @@
package com.arcao.geocaching4locus.base.util
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.collect
suspend fun Flow.takeListVariable(initialCount: Int, action: suspend (List) -> Int) {
if (initialCount <= 0) {
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/util/IntentExtension.kt b/app/src/main/java/com/arcao/geocaching4locus/base/util/IntentExtension.kt
index ebc54143..35c2344e 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/util/IntentExtension.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/util/IntentExtension.kt
@@ -1,6 +1,7 @@
package com.arcao.geocaching4locus.base.util
import android.app.Activity
+import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
@@ -13,11 +14,11 @@ fun Activity.showWebPage(uri: Uri): Boolean {
.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY or Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
- return if (intent.resolveActivity(packageManager) != null) {
+ return try {
startActivity(intent)
true
- } else {
- Toast.makeText(this, "Web page cannot be opened. No application found to show web pages.", Toast.LENGTH_LONG)
+ } catch (e: ActivityNotFoundException) {
+ Toast.makeText(this, "Unable to open web page, no application found.", Toast.LENGTH_LONG)
.show()
false
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/util/LiveDataExtension.kt b/app/src/main/java/com/arcao/geocaching4locus/base/util/LiveDataExtension.kt
index e4428371..ad4066cf 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/util/LiveDataExtension.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/util/LiveDataExtension.kt
@@ -10,7 +10,7 @@ import java.util.concurrent.atomic.AtomicBoolean
@MainThread
inline fun LiveData.withObserve(owner: LifecycleOwner, crossinline block: (T) -> Unit) =
- observe(owner, Observer { block(it!!) })
+ observe(owner, { block(it!!) })
@MainThread
operator fun MutableLiveData.invoke() {
@@ -34,11 +34,11 @@ open class Command : MutableLiveData() {
Timber.e("${javaClass.simpleName}: Multiple observers registered but only one will be notified of changes.")
}
- super.observe(owner, Observer {
+ super.observe(owner) {
if (pending.compareAndSet(true, false)) {
observer.onChanged(it)
}
- })
+ }
}
@MainThread
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/util/LocusMapExtension.kt b/app/src/main/java/com/arcao/geocaching4locus/base/util/LocusMapExtension.kt
index 504c7ef5..dcb4dd20 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/util/LocusMapExtension.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/util/LocusMapExtension.kt
@@ -5,7 +5,7 @@ import androidx.fragment.app.FragmentActivity
import com.arcao.geocaching4locus.error.fragment.LocusTestingErrorDialogFragment
import locus.api.android.utils.IntentHelper
import locus.api.android.utils.LocusConst
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
fun FragmentActivity.showLocusMissingError() =
LocusTestingErrorDialogFragment.newInstance(this).show(supportFragmentManager)
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/util/PermissionUtil.kt b/app/src/main/java/com/arcao/geocaching4locus/base/util/PermissionUtil.kt
index 9923d791..d5d96acc 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/util/PermissionUtil.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/util/PermissionUtil.kt
@@ -3,9 +3,6 @@ package com.arcao.geocaching4locus.base.util
import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
-import androidx.annotation.NonNull
-import androidx.appcompat.app.AppCompatActivity
-import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
object PermissionUtil {
@@ -15,41 +12,17 @@ object PermissionUtil {
)
val PERMISSION_LOCATION_WIFI = arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION)
- fun verifyPermissions(@NonNull grantResults: IntArray): Boolean {
- for (result in grantResults) {
- if (result != PackageManager.PERMISSION_GRANTED) {
- return false
- }
- }
- return true
- }
-
fun hasPermission(context: Context, vararg permissions: String): Boolean {
for (permission in permissions) {
- if (ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_DENIED)
- return false
+ if (ContextCompat.checkSelfPermission(
+ context,
+ permission
+ ) == PackageManager.PERMISSION_DENIED
+ ) return false
}
return true
}
-
- fun requestGpsLocationPermission(activity: AppCompatActivity, requestCode: Int): Boolean {
- return if (activity.hasGpsLocationPermission) {
- true
- } else {
- ActivityCompat.requestPermissions(activity, PERMISSION_LOCATION_GPS, requestCode)
- false
- }
- }
-
- fun requestWifiLocationPermission(activity: AppCompatActivity, requestCode: Int): Boolean {
- return if (activity.hasGpsLocationPermission) {
- true
- } else {
- ActivityCompat.requestPermissions(activity, PERMISSION_LOCATION_WIFI, requestCode)
- false
- }
- }
}
val Context.hasGpsLocationPermission
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/util/ResourcesExtension.kt b/app/src/main/java/com/arcao/geocaching4locus/base/util/ResourcesExtension.kt
index 8f882409..e7341331 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/util/ResourcesExtension.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/util/ResourcesExtension.kt
@@ -23,7 +23,7 @@ fun Context.getMainLocale(): Locale {
return if (locales.isEmpty) {
Locale.getDefault()
} else {
- locales[0]
+ locales[0] ?: Locale.getDefault()
}
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/util/ServiceUtil.kt b/app/src/main/java/com/arcao/geocaching4locus/base/util/ServiceUtil.kt
index 49bf636a..38f2ce6b 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/base/util/ServiceUtil.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/base/util/ServiceUtil.kt
@@ -111,8 +111,8 @@ object ServiceUtil {
}
}
- private class WakeLockContainer internal constructor(
- internal val tag: String,
- internal val wakeLock: PowerManager.WakeLock
+ private class WakeLockContainer(
+ val tag: String,
+ val wakeLock: PowerManager.WakeLock
)
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/dashboard/DashboardActivity.kt b/app/src/main/java/com/arcao/geocaching4locus/dashboard/DashboardActivity.kt
index 8f57c4f1..90b1aae9 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/dashboard/DashboardActivity.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/dashboard/DashboardActivity.kt
@@ -1,21 +1,19 @@
package com.arcao.geocaching4locus.dashboard
-import android.app.Activity
-import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
+import androidx.activity.result.ActivityResultCallback
import androidx.appcompat.widget.Toolbar
import androidx.databinding.DataBindingUtil
import com.arcao.geocaching4locus.R
-import com.arcao.geocaching4locus.authentication.util.requestSignOn
+import com.arcao.geocaching4locus.authentication.LoginActivity
import com.arcao.geocaching4locus.base.AbstractActionBarActivity
import com.arcao.geocaching4locus.base.constants.AppConstants
import com.arcao.geocaching4locus.base.util.isCalledFromLocusMap
import com.arcao.geocaching4locus.base.util.showLocusMissingError
import com.arcao.geocaching4locus.base.util.showWebPage
import com.arcao.geocaching4locus.base.util.withObserve
-import com.arcao.geocaching4locus.data.account.AccountManager
import com.arcao.geocaching4locus.databinding.ActivityDashboardBinding
import com.arcao.geocaching4locus.download_rectangle.DownloadRectangleActivity
import com.arcao.geocaching4locus.import_bookmarks.ImportBookmarkActivity
@@ -23,7 +21,6 @@ import com.arcao.geocaching4locus.importgc.ImportGeocacheCodeActivity
import com.arcao.geocaching4locus.live_map.fragment.PowerSaveWarningDialogFragment
import com.arcao.geocaching4locus.search_nearest.SearchNearestActivity
import com.arcao.geocaching4locus.settings.SettingsActivity
-import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
@@ -34,10 +31,24 @@ class DashboardActivity : AbstractActionBarActivity(),
parametersOf(isCalledFromLocusMap())
}
- private val accountManager by inject()
-
private lateinit var binding: ActivityDashboardBinding
+ private val successCallback = ActivityResultCallback { success ->
+ if (success) finish()
+ }
+ private val searchNearestActivity =
+ registerForActivityResult(SearchNearestActivity.Contract, successCallback)
+ private val importGeocacheCodeActivity =
+ registerForActivityResult(ImportGeocacheCodeActivity.Contract, successCallback)
+ private val downloadRectangleActivity =
+ registerForActivityResult(DownloadRectangleActivity.Contract, successCallback)
+ private val importBookmarkActivity =
+ registerForActivityResult(ImportBookmarkActivity.Contract, successCallback)
+ private val settingsActivity = registerForActivityResult(SettingsActivity.Contract) {}
+ private val loginActivity = registerForActivityResult(LoginActivity.Contract) { success ->
+ if (success) viewModel.onClickLiveMap()
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -47,39 +58,26 @@ class DashboardActivity : AbstractActionBarActivity(),
viewModel.action.withObserve(this, ::handleAction)
+ @Suppress("USELESS_CAST")
setSupportActionBar(binding.toolbar as Toolbar)
supportActionBar?.title = title
}
- private fun handleAction(action: DashboardAction?) {
+ private fun handleAction(action: DashboardAction) {
when (action) {
- is DashboardAction.SearchNearest -> {
- startActivityForResult(
- Intent(this, SearchNearestActivity::class.java).apply {
- if (isCalledFromLocusMap()) putExtras(intent)
- }, 0
- )
- }
- is DashboardAction.ImportGcCode ->
- startActivityForResult(Intent(this, ImportGeocacheCodeActivity::class.java), 0)
- is DashboardAction.DownloadLiveMapGeocaches ->
- startActivityForResult(Intent(this, DownloadRectangleActivity::class.java), 0)
- is DashboardAction.ImportBookmarks ->
- startActivityForResult(Intent(this, ImportBookmarkActivity::class.java), 0)
- is DashboardAction.Preferences ->
- startActivity(SettingsActivity.createIntent(this))
- is DashboardAction.UsersGuide ->
- showWebPage(AppConstants.USERS_GUIDE_URI)
-
- is DashboardAction.LocusMapNotInstalled ->
- showLocusMissingError()
- is DashboardAction.SignIn ->
- accountManager.requestSignOn(this, REQUEST_SIGN_ON)
- is DashboardAction.WarnPowerSaveActive ->
- PowerSaveWarningDialogFragment.newInstance().show(supportFragmentManager)
-
- is DashboardAction.NavigationBack ->
- finish()
+ is DashboardAction.SearchNearest -> searchNearestActivity.launch(
+ if (isCalledFromLocusMap()) intent else null
+ )
+ is DashboardAction.ImportGcCode -> importGeocacheCodeActivity.launch(null)
+ is DashboardAction.DownloadLiveMapGeocaches -> downloadRectangleActivity.launch(null)
+ is DashboardAction.ImportBookmarks -> importBookmarkActivity.launch(null)
+ is DashboardAction.Preferences -> settingsActivity.launch(null)
+ is DashboardAction.UsersGuide -> showWebPage(AppConstants.USERS_GUIDE_URI)
+ is DashboardAction.LocusMapNotInstalled -> showLocusMissingError()
+ is DashboardAction.SignIn -> loginActivity.launch(null)
+ is DashboardAction.WarnPowerSaveActive -> PowerSaveWarningDialogFragment.newInstance()
+ .show(supportFragmentManager)
+ is DashboardAction.NavigationBack -> finish()
}
}
@@ -102,27 +100,7 @@ class DashboardActivity : AbstractActionBarActivity(),
}
}
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
-
- if (requestCode == REQUEST_SIGN_ON && resultCode == Activity.RESULT_OK) {
- viewModel.onClickLiveMap()
- } else if (resultCode == Activity.RESULT_OK) {
- finish()
- }
- }
-
- override fun onResume() {
- super.onResume()
-
- binding.vm = viewModel
- }
-
override fun onPowerSaveWarningConfirmed() {
viewModel.onPowerSaveWarningConfirmed()
}
-
- companion object {
- private const val REQUEST_SIGN_ON = 1
- }
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/dashboard/DashboardViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/dashboard/DashboardViewModel.kt
index 7c7cfe79..2455febc 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/dashboard/DashboardViewModel.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/dashboard/DashboardViewModel.kt
@@ -1,6 +1,6 @@
package com.arcao.geocaching4locus.dashboard
-import android.content.Context
+import android.app.Application
import androidx.annotation.UiThread
import androidx.lifecycle.MutableLiveData
import com.arcao.geocaching4locus.authentication.util.isPremium
@@ -16,7 +16,7 @@ import locus.api.manager.LocusMapManager
class DashboardViewModel(
private val calledFromLocusMap: Boolean,
- private val context: Context,
+ private val context: Application,
private val notificationManager: LiveMapNotificationManager,
private val accountManager: AccountManager,
private val locusMapManager: LocusMapManager,
diff --git a/app/src/main/java/com/arcao/geocaching4locus/dashboard/widget/DashboardButton.kt b/app/src/main/java/com/arcao/geocaching4locus/dashboard/widget/DashboardButton.kt
index f8293f37..121f634d 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/dashboard/widget/DashboardButton.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/dashboard/widget/DashboardButton.kt
@@ -4,9 +4,9 @@ import android.content.Context
import android.content.res.ColorStateList
import android.content.res.TypedArray
import android.util.AttributeSet
-import android.widget.ToggleButton
import androidx.annotation.StyleableRes
import androidx.appcompat.content.res.AppCompatResources
+import androidx.appcompat.widget.AppCompatToggleButton
import androidx.core.content.withStyledAttributes
import androidx.core.graphics.drawable.DrawableCompat
import com.arcao.geocaching4locus.R
@@ -15,7 +15,7 @@ class DashboardButton @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = R.attr.dashboardButtonStyle
-) : ToggleButton(
+) : AppCompatToggleButton(
context,
attrs,
defStyleAttr
@@ -45,7 +45,11 @@ class DashboardButton @JvmOverloads constructor(
private fun applyCompoundDrawableTint(a: TypedArray) {
// support for alpha attribute in ColorStateList
- getCompatColorStateList(context, a, R.styleable.DashboardButton_compoundDrawableTint)?.let { colorList ->
+ getCompatColorStateList(
+ context,
+ a,
+ R.styleable.DashboardButton_compoundDrawableTint
+ )?.let { colorList ->
val compoundDrawables = compoundDrawables
for (i in 0..3) {
if (compoundDrawables[i] == null)
@@ -54,7 +58,12 @@ class DashboardButton @JvmOverloads constructor(
compoundDrawables[i] = DrawableCompat.wrap(compoundDrawables[i])
DrawableCompat.setTintList(compoundDrawables[i], colorList)
}
- setCompoundDrawables(compoundDrawables[0], compoundDrawables[1], compoundDrawables[2], compoundDrawables[3])
+ setCompoundDrawables(
+ compoundDrawables[0],
+ compoundDrawables[1],
+ compoundDrawables[2],
+ compoundDrawables[3]
+ )
}
}
@@ -68,8 +77,15 @@ class DashboardButton @JvmOverloads constructor(
super.setChecked(checked)
}
- private fun getCompatColorStateList(context: Context, a: TypedArray, @StyleableRes index: Int): ColorStateList? {
+ private fun getCompatColorStateList(
+ context: Context,
+ a: TypedArray,
+ @StyleableRes index: Int
+ ): ColorStateList? {
val resourceId = a.getResourceId(index, 0)
- return if (resourceId == 0) null else AppCompatResources.getColorStateList(context, resourceId)
+ return if (resourceId == 0) null else AppCompatResources.getColorStateList(
+ context,
+ resourceId
+ )
}
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/download_rectangle/DownloadRectangleActivity.kt b/app/src/main/java/com/arcao/geocaching4locus/download_rectangle/DownloadRectangleActivity.kt
index b1577e90..55d45855 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/download_rectangle/DownloadRectangleActivity.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/download_rectangle/DownloadRectangleActivity.kt
@@ -1,22 +1,30 @@
package com.arcao.geocaching4locus.download_rectangle
import android.app.Activity
+import android.content.Context
import android.content.Intent
import android.os.Bundle
+import androidx.activity.result.contract.ActivityResultContract
import com.arcao.geocaching4locus.R
-import com.arcao.geocaching4locus.authentication.util.requestSignOn
+import com.arcao.geocaching4locus.authentication.LoginActivity
import com.arcao.geocaching4locus.base.AbstractActionBarActivity
import com.arcao.geocaching4locus.base.util.exhaustive
import com.arcao.geocaching4locus.base.util.showLocusMissingError
import com.arcao.geocaching4locus.base.util.withObserve
-import com.arcao.geocaching4locus.data.account.AccountManager
import com.arcao.geocaching4locus.error.ErrorActivity
-import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
class DownloadRectangleActivity : AbstractActionBarActivity() {
val viewModel by viewModel()
- private val accountManager by inject()
+
+ private val loginActivity = registerForActivityResult(LoginActivity.Contract) { success ->
+ if (success) {
+ viewModel.startDownload()
+ } else {
+ setResult(Activity.RESULT_CANCELED)
+ finish()
+ }
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -54,31 +62,23 @@ class DownloadRectangleActivity : AbstractActionBarActivity() {
setResult(Activity.RESULT_CANCELED)
finish()
}
- is DownloadRectangleAction.SignIn -> {
- accountManager.requestSignOn(this, REQUEST_SIGN_ON)
- }
+ is DownloadRectangleAction.SignIn -> loginActivity.launch(null)
DownloadRectangleAction.LastLiveMapDataInvalid -> {
- startActivity(ErrorActivity.IntentBuilder(this).message(R.string.error_live_map_geocaches_not_visible).build())
+ startActivity(
+ ErrorActivity.IntentBuilder(this)
+ .message(R.string.error_live_map_geocaches_not_visible).build()
+ )
finish()
}
}.exhaustive
}
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
+ object Contract : ActivityResultContract() {
+ override fun createIntent(context: Context, input: Void?) =
+ Intent(context, DownloadRectangleActivity::class.java)
- // restart update process after log in
- if (requestCode == REQUEST_SIGN_ON) {
- if (resultCode == Activity.RESULT_OK) {
- viewModel.startDownload()
- } else {
- setResult(Activity.RESULT_CANCELED)
- finish()
- }
+ override fun parseResult(resultCode: Int, intent: Intent?): Boolean {
+ return resultCode == Activity.RESULT_OK
}
}
-
- companion object {
- private const val REQUEST_SIGN_ON = 1
- }
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/download_rectangle/DownloadRectangleViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/download_rectangle/DownloadRectangleViewModel.kt
index d23da1ed..38fef206 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/download_rectangle/DownloadRectangleViewModel.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/download_rectangle/DownloadRectangleViewModel.kt
@@ -1,6 +1,6 @@
package com.arcao.geocaching4locus.download_rectangle
-import android.content.Context
+import android.app.Application
import com.arcao.geocaching4locus.R
import com.arcao.geocaching4locus.base.BaseViewModel
import com.arcao.geocaching4locus.base.constants.AppConstants
@@ -21,7 +21,7 @@ import locus.api.manager.LocusMapManager
import timber.log.Timber
class DownloadRectangleViewModel constructor(
- private val context: Context,
+ private val context: Application,
private val accountManager: AccountManager,
private val exceptionHandler: ExceptionHandler,
private val getPointsFromRectangleCoordinates: GetPointsFromRectangleCoordinatesUseCase,
@@ -74,7 +74,7 @@ class DownloadRectangleViewModel constructor(
center = true
)
- var count = AppConstants.ITEMS_PER_REQUEST
+ var count = AppConstants.INITIAL_REQUEST_SIZE
var receivedGeocaches = 0
try {
@@ -94,7 +94,6 @@ class DownloadRectangleViewModel constructor(
filterPreferenceManager.difficultyMax,
filterPreferenceManager.terrainMin,
filterPreferenceManager.terrainMax,
- filterPreferenceManager.excludeIgnoreList,
AppConstants.LIVEMAP_CACHES_COUNT
) { count = it }.map { list ->
receivedGeocaches += list.size
@@ -103,12 +102,14 @@ class DownloadRectangleViewModel constructor(
// apply additional downloading full geocache if required
if (filterPreferenceManager.simpleCacheData) {
list.forEach { point ->
- point.setExtraOnDisplay(
- context.packageName,
- UpdateActivity::class.java.name,
- UpdateActivity.PARAM_SIMPLE_CACHE_ID,
- point.gcData.cacheID
- )
+ point.gcData?.cacheID?.let { cacheId ->
+ point.setExtraOnDisplay(
+ context.packageName,
+ UpdateActivity::class.java.name,
+ UpdateActivity.PARAM_SIMPLE_CACHE_ID,
+ cacheId
+ )
+ }
}
}
list
diff --git a/app/src/main/java/com/arcao/geocaching4locus/error/handler/ExceptionHandler.kt b/app/src/main/java/com/arcao/geocaching4locus/error/handler/ExceptionHandler.kt
index 35bfd1ff..e4136aca 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/error/handler/ExceptionHandler.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/error/handler/ExceptionHandler.kt
@@ -80,7 +80,10 @@ class ExceptionHandler(private val context: Context, private val accountManager:
accountManager.deleteAccount()
return builder.message(R.string.error_no_account)
.positiveAction(
- SettingsActivity.createIntent(context, AccountsPreferenceFragment::class.java)
+ SettingsActivity.Contract.createIntent(
+ context,
+ AccountsPreferenceFragment::class.java
+ )
)
.positiveButtonText(R.string.button_ok)
.clearNegativeButtonText()
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 0c0e30f4..e8057aec 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
@@ -1,27 +1,34 @@
package com.arcao.geocaching4locus.import_bookmarks
import android.app.Activity
+import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
+import androidx.activity.result.contract.ActivityResultContract
import androidx.fragment.app.commit
import com.arcao.geocaching4locus.R
-import com.arcao.geocaching4locus.authentication.util.requestSignOn
+import com.arcao.geocaching4locus.authentication.LoginActivity
import com.arcao.geocaching4locus.base.AbstractActionBarActivity
import com.arcao.geocaching4locus.base.util.exhaustive
import com.arcao.geocaching4locus.base.util.showLocusMissingError
import com.arcao.geocaching4locus.base.util.withObserve
-import com.arcao.geocaching4locus.data.account.AccountManager
import com.arcao.geocaching4locus.error.ErrorActivity
import com.arcao.geocaching4locus.import_bookmarks.fragment.BaseBookmarkFragment
import com.arcao.geocaching4locus.import_bookmarks.fragment.BookmarkFragment
import com.arcao.geocaching4locus.import_bookmarks.fragment.BookmarkListFragment
-import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
class ImportBookmarkActivity : AbstractActionBarActivity() {
private val viewModel by viewModel()
- private val accountManager by inject()
+
+ private val loginActivity = registerForActivityResult(LoginActivity.Contract) { success ->
+ if (success) {
+ viewModel.init()
+ } else {
+ finish()
+ }
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -52,12 +59,13 @@ class ImportBookmarkActivity : AbstractActionBarActivity() {
}
}
ImportBookmarkAction.PremiumMembershipRequired -> {
- startActivity(ErrorActivity.IntentBuilder(this).message(R.string.error_premium_feature).build())
+ startActivity(
+ ErrorActivity.IntentBuilder(this).message(R.string.error_premium_feature)
+ .build()
+ )
finish()
}
- is ImportBookmarkAction.SignIn -> {
- accountManager.requestSignOn(this, REQUEST_SIGN_ON)
- }
+ is ImportBookmarkAction.SignIn -> loginActivity.launch(null)
}.exhaustive
}
@@ -69,7 +77,9 @@ class ImportBookmarkActivity : AbstractActionBarActivity() {
}
override fun onProgressCancel(requestId: Int) {
- (supportFragmentManager.findFragmentById(R.id.fragment) as? BaseBookmarkFragment)?.onProgressCancel(requestId)
+ (supportFragmentManager.findFragmentById(R.id.fragment) as? BaseBookmarkFragment)?.onProgressCancel(
+ requestId
+ )
}
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
@@ -80,20 +90,12 @@ class ImportBookmarkActivity : AbstractActionBarActivity() {
else -> super.onOptionsItemSelected(item)
}
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
+ object Contract : ActivityResultContract() {
+ override fun createIntent(context: Context, input: Void?) =
+ Intent(context, ImportBookmarkActivity::class.java)
- // restart update process after log in
- if (requestCode == REQUEST_SIGN_ON) {
- if (resultCode == Activity.RESULT_OK) {
- viewModel.init()
- } else {
- finish()
- }
+ override fun parseResult(resultCode: Int, intent: Intent?): Boolean {
+ return resultCode == Activity.RESULT_OK
}
}
-
- companion object {
- private const val REQUEST_SIGN_ON = 1
- }
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/adapter/BookmarkGeocachesAdapter.kt b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/adapter/BookmarkGeocachesAdapter.kt
index c20999bd..bfbe45fe 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/adapter/BookmarkGeocachesAdapter.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/adapter/BookmarkGeocachesAdapter.kt
@@ -3,7 +3,7 @@ package com.arcao.geocaching4locus.import_bookmarks.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
-import androidx.paging.PagedListAdapter
+import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.arcao.geocaching4locus.R
@@ -13,24 +13,22 @@ import com.arcao.geocaching4locus.base.usecase.entity.ListGeocacheEntity
import com.arcao.geocaching4locus.databinding.ViewBookmarkItemBinding
class BookmarkGeocachesAdapter :
- PagedListAdapter(DiffCallback) {
- init {
- setHasStableIds(true)
- }
+ PagingDataAdapter(DiffCallback) {
val tracker by lazy {
- SelectionTracker(object : SelectionAdapter {
+ val selectionAdapter = object : SelectionAdapter {
override val itemCount: Int
- get() = currentList?.loadedCount ?: 0
+ get() = snapshot().size
override fun registerAdapterDataObserver(adapterDataObserver: RecyclerView.AdapterDataObserver) =
this@BookmarkGeocachesAdapter.registerAdapterDataObserver(adapterDataObserver)
- override fun findPosition(value: ListGeocacheEntity): Int =
- currentList?.indexOf(value) ?: RecyclerView.NO_POSITION
+ override fun findPosition(value: ListGeocacheEntity): Int = snapshot().indexOf(value)
+
+ override fun getItem(position: Int) = snapshot()[position]
+ }
- override fun getItem(position: Int) = currentList?.get(position)
- }).apply {
+ SelectionTracker(selectionAdapter).apply {
addSelectionChangeListener { startPosition: Int, count: Int ->
notifyItemRangeChanged(startPosition, count)
}
@@ -40,11 +38,16 @@ class BookmarkGeocachesAdapter :
val selected: List
get() = tracker.selectedValues
- override fun getItemId(position: Int) = getItem(position)?.id ?: RecyclerView.NO_ID
-
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
- return ViewHolder(DataBindingUtil.inflate(inflater, R.layout.view_bookmark_item, parent, false))
+ return ViewHolder(
+ DataBindingUtil.inflate(
+ inflater,
+ R.layout.view_bookmark_item,
+ parent,
+ false
+ )
+ )
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
@@ -67,11 +70,17 @@ class BookmarkGeocachesAdapter :
class ViewHolder(val binding: ViewBookmarkItemBinding) : RecyclerView.ViewHolder(binding.root)
private object DiffCallback : DiffUtil.ItemCallback() {
- override fun areItemsTheSame(oldItem: ListGeocacheEntity, newItem: ListGeocacheEntity): Boolean {
+ override fun areItemsTheSame(
+ oldItem: ListGeocacheEntity,
+ newItem: ListGeocacheEntity
+ ): Boolean {
return oldItem.referenceCode == newItem.referenceCode
}
- override fun areContentsTheSame(oldItem: ListGeocacheEntity, newItem: ListGeocacheEntity): Boolean {
+ override fun areContentsTheSame(
+ oldItem: ListGeocacheEntity,
+ newItem: ListGeocacheEntity
+ ): Boolean {
return oldItem == newItem
}
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/adapter/BookmarkListAdapter.kt b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/adapter/BookmarkListAdapter.kt
index 3dd891ac..daa781a3 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/adapter/BookmarkListAdapter.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/adapter/BookmarkListAdapter.kt
@@ -3,7 +3,7 @@ package com.arcao.geocaching4locus.import_bookmarks.adapter
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
-import androidx.paging.PagedListAdapter
+import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.arcao.geocaching4locus.R
@@ -12,17 +12,18 @@ import com.arcao.geocaching4locus.databinding.ViewBookmarkListItemBinding
class BookmarkListAdapter(
private val onClickListener: (geocacheList: GeocacheListEntity, importAll: Boolean) -> Unit
-) : PagedListAdapter(DiffCallback) {
-
- init {
- setHasStableIds(true)
- }
-
- override fun getItemId(position: Int) = getItem(position)?.id ?: RecyclerView.NO_ID
+) : PagingDataAdapter(DiffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
- return ViewHolder(DataBindingUtil.inflate(inflater, R.layout.view_bookmark_list_item, parent, false))
+ return ViewHolder(
+ DataBindingUtil.inflate(
+ inflater,
+ R.layout.view_bookmark_list_item,
+ parent,
+ false
+ )
+ )
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
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 16be9fe7..6da9d958 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
@@ -10,10 +10,13 @@ import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
-import androidx.databinding.DataBindingUtil
+import androidx.core.view.MenuProvider
+import androidx.lifecycle.lifecycleScope
+import androidx.paging.LoadState
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.arcao.geocaching4locus.R
+import com.arcao.geocaching4locus.base.paging.handleErrors
import com.arcao.geocaching4locus.base.usecase.entity.GeocacheListEntity
import com.arcao.geocaching4locus.base.util.exhaustive
import com.arcao.geocaching4locus.base.util.invoke
@@ -22,6 +25,8 @@ import com.arcao.geocaching4locus.databinding.FragmentBookmarkBinding
import com.arcao.geocaching4locus.error.hasPositiveAction
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.viewModel
import org.koin.core.parameter.parametersOf
@@ -38,24 +43,40 @@ class BookmarkFragment : BaseBookmarkFragment() {
private val adapter = BookmarkGeocachesAdapter()
private val toolbar get() = (activity as? AppCompatActivity)?.supportActionBar
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
+ private val menuProvider = object : MenuProvider {
+ override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
+ menuInflater.inflate(R.menu.toolbar_select_deselect, menu)
+ }
- setHasOptionsMenu(true)
+ override fun onMenuItemSelected(menuItem: MenuItem) = when (menuItem.itemId) {
+ R.id.selectAll -> {
+ adapter.selectAll()
+ true
+ }
+ R.id.deselectAll -> {
+ adapter.selectNone()
+ true
+ }
+ else -> false
+ }
}
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
toolbar?.subtitle = bookmarkList.name
- val binding = DataBindingUtil.inflate(
+ val binding = FragmentBookmarkBinding.inflate(
inflater,
- R.layout.fragment_bookmark,
container,
false
)
binding.lifecycleOwner = viewLifecycleOwner
binding.vm = viewModel
+ binding.isLoading = true
binding.list.apply {
adapter = this@BookmarkFragment.adapter
layoutManager = LinearLayoutManager(context)
@@ -65,9 +86,23 @@ class BookmarkFragment : BaseBookmarkFragment() {
viewModel.selection(adapter.selected)
}
- viewModel.list.withObserve(viewLifecycleOwner) { list ->
- adapter.submitList(list)
- adapter.tracker.onRestoreInstanceState(savedInstanceState)
+ var savedState = savedInstanceState
+
+ viewLifecycleOwner.lifecycleScope.launch {
+ viewModel.pagerFlow.collectLatest { data ->
+ adapter.submitData(data)
+
+ if (savedState != null) {
+ adapter.tracker.onRestoreInstanceState(savedState)
+ savedState = null
+ }
+ }
+ adapter.loadStateFlow.collect { state ->
+ val isListEmpty = state.refresh is LoadState.NotLoading && adapter.itemCount == 0
+ binding.isEmpty = isListEmpty
+ binding.isLoading = state.source.refresh is LoadState.Loading
+ state.handleErrors(viewModel::handleLoadError)
+ }
}
viewModel.action.withObserve(viewLifecycleOwner, ::handleAction)
@@ -78,25 +113,15 @@ class BookmarkFragment : BaseBookmarkFragment() {
return binding.root
}
- override fun onSaveInstanceState(outState: Bundle) {
- super.onSaveInstanceState(outState)
- adapter.tracker.onSaveInstanceState(outState)
- }
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
- override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
- inflater.inflate(R.menu.toolbar_select_deselect, menu)
+ requireActivity().addMenuProvider(menuProvider, viewLifecycleOwner)
}
- override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
- R.id.selectAll -> {
- adapter.selectAll()
- true
- }
- R.id.deselectAll -> {
- adapter.selectNone()
- true
- }
- else -> super.onOptionsItemSelected(item)
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ adapter.tracker.onSaveInstanceState(outState)
}
@Suppress("IMPLICIT_CAST_TO_ANY")
@@ -106,10 +131,11 @@ class BookmarkFragment : BaseBookmarkFragment() {
startActivity(action.intent)
requireActivity().apply {
setResult(
- if (intent.hasPositiveAction())
+ if (action.intent.hasPositiveAction()) {
Activity.RESULT_OK
- else
+ } else {
Activity.RESULT_CANCELED
+ }
)
finish()
}
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 8dae428d..36fb7d6c 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
@@ -8,8 +8,11 @@ import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.core.os.bundleOf
import androidx.databinding.DataBindingUtil
+import androidx.lifecycle.lifecycleScope
+import androidx.paging.LoadState
import androidx.recyclerview.widget.LinearLayoutManager
import com.arcao.geocaching4locus.R
+import com.arcao.geocaching4locus.base.paging.handleErrors
import com.arcao.geocaching4locus.base.util.exhaustive
import com.arcao.geocaching4locus.base.util.invoke
import com.arcao.geocaching4locus.base.util.withObserve
@@ -18,6 +21,8 @@ import com.arcao.geocaching4locus.error.hasPositiveAction
import com.arcao.geocaching4locus.import_bookmarks.ImportBookmarkViewModel
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.viewModel
@@ -34,7 +39,11 @@ class BookmarkListFragment : BaseBookmarkFragment() {
}
}
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
toolbar?.subtitle = null
val binding = DataBindingUtil.inflate(
@@ -46,13 +55,24 @@ class BookmarkListFragment : BaseBookmarkFragment() {
binding.lifecycleOwner = viewLifecycleOwner
binding.vm = viewModel
+ binding.isLoading = true
binding.list.apply {
adapter = this@BookmarkListFragment.adapter
layoutManager = LinearLayoutManager(context)
addItemDecoration(MarginItemDecoration(context, R.dimen.cardview_space))
}
- viewModel.list.withObserve(viewLifecycleOwner, adapter::submitList)
+ viewLifecycleOwner.lifecycleScope.launch {
+ viewModel.pagerFlow.collectLatest { data ->
+ adapter.submitData(data)
+ }
+ adapter.loadStateFlow.collect { state ->
+ val isListEmpty = state.refresh is LoadState.NotLoading && adapter.itemCount == 0
+ binding.isEmpty = isListEmpty
+ binding.isLoading = state.source.refresh is LoadState.Loading
+ state.handleErrors(viewModel::handleLoadError)
+ }
+ }
viewModel.action.withObserve(viewLifecycleOwner, ::handleAction)
viewModel.progress.withObserve(viewLifecycleOwner) { state ->
@@ -69,10 +89,11 @@ class BookmarkListFragment : BaseBookmarkFragment() {
startActivity(action.intent)
requireActivity().apply {
setResult(
- if (intent.hasPositiveAction())
+ if (action.intent.hasPositiveAction()) {
Activity.RESULT_OK
- else
+ } else {
Activity.RESULT_CANCELED
+ }
)
finish()
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkListViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkListViewModel.kt
index f4618837..7ba5dd65 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkListViewModel.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkListViewModel.kt
@@ -1,16 +1,16 @@
package com.arcao.geocaching4locus.import_bookmarks.fragment
-import android.content.Context
-import androidx.lifecycle.LiveData
-import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.Transformations
-import androidx.paging.LivePagedListBuilder
-import androidx.paging.PagedList
+import android.app.Application
+import androidx.lifecycle.viewModelScope
+import androidx.paging.Pager
+import androidx.paging.PagingConfig
+import androidx.paging.PagingData
+import androidx.paging.cachedIn
import com.arcao.geocaching4locus.R
import com.arcao.geocaching4locus.base.BaseViewModel
import com.arcao.geocaching4locus.base.coroutine.CoroutinesDispatcherProvider
-import com.arcao.geocaching4locus.base.paging.DataSourceState
import com.arcao.geocaching4locus.base.usecase.GetListGeocachesUseCase
+import com.arcao.geocaching4locus.base.usecase.GetUserListsUseCase
import com.arcao.geocaching4locus.base.usecase.WritePointToPackPointsFileUseCase
import com.arcao.geocaching4locus.base.usecase.entity.GeocacheListEntity
import com.arcao.geocaching4locus.base.util.Command
@@ -18,58 +18,41 @@ import com.arcao.geocaching4locus.base.util.invoke
import com.arcao.geocaching4locus.error.exception.IntendedException
import com.arcao.geocaching4locus.error.handler.ExceptionHandler
import com.arcao.geocaching4locus.import_bookmarks.paging.GeocacheUserListsDataSource
-import com.arcao.geocaching4locus.import_bookmarks.paging.GeocacheUserListsDataSourceFactory
import com.arcao.geocaching4locus.settings.manager.FilterPreferenceManager
import com.arcao.geocaching4locus.update.UpdateActivity
import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import locus.api.manager.LocusMapManager
import timber.log.Timber
@Suppress("EXPERIMENTAL_API_USAGE")
class BookmarkListViewModel(
- private val context: Context,
+ private val context: Application,
private val exceptionHandler: ExceptionHandler,
- private val dataSourceFactory: GeocacheUserListsDataSourceFactory,
+ private val getUserLists: GetUserListsUseCase,
private val getListGeocaches: GetListGeocachesUseCase,
private val writePointToPackPointsFile: WritePointToPackPointsFileUseCase,
private val filterPreferenceManager: FilterPreferenceManager,
private val locusMapManager: LocusMapManager,
dispatcherProvider: CoroutinesDispatcherProvider
) : BaseViewModel(dispatcherProvider) {
- val loading = MutableLiveData()
- val list: LiveData>
+ val pagerFlow: Flow>
val action = Command()
private var job: Job? = null
- val state: LiveData
- get() = Transformations.switchMap(
- dataSourceFactory.dataSource,
- GeocacheUserListsDataSource::state
- )
-
init {
val pageSize = 25
- val config = PagedList.Config.Builder()
- .setPageSize(pageSize)
- .setInitialLoadSizeHint(pageSize * 2)
- .setEnablePlaceholders(false)
- .build()
-
- list = LivePagedListBuilder(dataSourceFactory, config).build()
+ val config = PagingConfig(
+ pageSize = pageSize,
+ enablePlaceholders = false,
+ initialLoadSize = 2 * pageSize
+ )
- state.observeForever { state ->
- if (state == DataSourceState.LoadingInitial) {
- loading(true)
- } else {
- if (loading.value == true) {
- loading(false)
- }
- }
- if (state is DataSourceState.Error) {
- action(BookmarkListAction.LoadingError(exceptionHandler(state.e)))
- }
- }
+ pagerFlow = Pager(
+ config,
+ pagingSourceFactory = { GeocacheUserListsDataSource(getUserLists, config) }
+ ).flow.cachedIn(viewModelScope)
}
fun importAll(geocacheList: GeocacheListEntity) {
@@ -109,12 +92,14 @@ class BookmarkListViewModel(
// apply additional downloading full geocache if required
if (filterPreferenceManager.simpleCacheData) {
list.forEach { point ->
- point.setExtraOnDisplay(
- context.packageName,
- UpdateActivity::class.java.name,
- UpdateActivity.PARAM_SIMPLE_CACHE_ID,
- point.gcData.cacheID
- )
+ point.gcData?.cacheID?.let { cacheId ->
+ point.setExtraOnDisplay(
+ context.packageName,
+ UpdateActivity::class.java.name,
+ UpdateActivity.PARAM_SIMPLE_CACHE_ID,
+ cacheId
+ )
+ }
}
}
list
@@ -146,6 +131,10 @@ class BookmarkListViewModel(
action(BookmarkListAction.ChooseBookmarks(geocacheList))
}
+ fun handleLoadError(e: Throwable) {
+ action(BookmarkListAction.LoadingError(exceptionHandler(e)))
+ }
+
fun cancelProgress() {
job?.cancel()
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkViewModel.kt
index 4903c23a..c0c0ed68 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkViewModel.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/fragment/BookmarkViewModel.kt
@@ -1,15 +1,17 @@
package com.arcao.geocaching4locus.import_bookmarks.fragment
+import android.annotation.SuppressLint
import android.content.Context
-import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
-import androidx.lifecycle.Transformations
-import androidx.paging.LivePagedListBuilder
-import androidx.paging.PagedList
+import androidx.lifecycle.viewModelScope
+import androidx.paging.Pager
+import androidx.paging.PagingConfig
+import androidx.paging.PagingData
+import androidx.paging.cachedIn
import com.arcao.geocaching4locus.R
import com.arcao.geocaching4locus.base.BaseViewModel
import com.arcao.geocaching4locus.base.coroutine.CoroutinesDispatcherProvider
-import com.arcao.geocaching4locus.base.paging.DataSourceState
+import com.arcao.geocaching4locus.base.usecase.GetListGeocachesUseCase
import com.arcao.geocaching4locus.base.usecase.GetPointsFromGeocacheCodesUseCase
import com.arcao.geocaching4locus.base.usecase.WritePointToPackPointsFileUseCase
import com.arcao.geocaching4locus.base.usecase.entity.GeocacheListEntity
@@ -20,18 +22,18 @@ import com.arcao.geocaching4locus.base.util.invoke
import com.arcao.geocaching4locus.error.exception.IntendedException
import com.arcao.geocaching4locus.error.handler.ExceptionHandler
import com.arcao.geocaching4locus.import_bookmarks.paging.ListGeocachesDataSource
-import com.arcao.geocaching4locus.import_bookmarks.paging.ListGeocachesDataSourceFactory
import com.arcao.geocaching4locus.settings.manager.FilterPreferenceManager
import com.arcao.geocaching4locus.update.UpdateActivity
import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import locus.api.manager.LocusMapManager
import timber.log.Timber
-@Suppress("EXPERIMENTAL_API_USAGE")
+@SuppressLint("StaticFieldLeak")
class BookmarkViewModel(
geocacheList: GeocacheListEntity,
- private val dataSourceFactory: ListGeocachesDataSourceFactory,
+ private val getListGeocaches: GetListGeocachesUseCase,
private val context: Context,
private val exceptionHandler: ExceptionHandler,
private val getPointsFromGeocacheCodes: GetPointsFromGeocacheCodesUseCase,
@@ -42,44 +44,32 @@ class BookmarkViewModel(
dispatcherProvider: CoroutinesDispatcherProvider
) : BaseViewModel(dispatcherProvider) {
- val loading = MutableLiveData()
- val list: LiveData>
+ val pagerFlow: Flow>
val selection = MutableLiveData>().apply {
value = emptyList()
}
val action = Command()
- val state: LiveData
- get() = Transformations.switchMap(
- dataSourceFactory.dataSource,
- ListGeocachesDataSource::state
- )
-
private var job: Job? = null
init {
val pageSize = 25
- val config = PagedList.Config.Builder()
- .setPageSize(pageSize)
- .setInitialLoadSizeHint(pageSize * 2)
- .setEnablePlaceholders(false)
- .build()
-
- dataSourceFactory.referenceCode = geocacheList.guid
- list = LivePagedListBuilder(dataSourceFactory, config).build()
-
- state.observeForever { state ->
- if (state == DataSourceState.LoadingInitial) {
- loading(true)
- } else {
- if (loading.value == true) {
- loading(false)
- }
- }
- if (state is DataSourceState.Error) {
- action(BookmarkAction.LoadingError(exceptionHandler(state.e)))
+ val config = PagingConfig(
+ pageSize = pageSize,
+ enablePlaceholders = false,
+ initialLoadSize = 2 * pageSize
+ )
+
+ pagerFlow = Pager(
+ config,
+ pagingSourceFactory = {
+ ListGeocachesDataSource(
+ geocacheList.guid,
+ getListGeocaches,
+ config
+ )
}
- }
+ ).flow.cachedIn(viewModelScope)
}
fun download() {
@@ -121,12 +111,14 @@ class BookmarkViewModel(
// apply additional downloading full geocache if required
if (filterPreferenceManager.simpleCacheData) {
list.forEach { point ->
- point.setExtraOnDisplay(
- context.packageName,
- UpdateActivity::class.java.name,
- UpdateActivity.PARAM_SIMPLE_CACHE_ID,
- point.gcData.cacheID
- )
+ point.gcData?.cacheID?.let { cacheId ->
+ point.setExtraOnDisplay(
+ context.packageName,
+ UpdateActivity::class.java.name,
+ UpdateActivity.PARAM_SIMPLE_CACHE_ID,
+ cacheId
+ )
+ }
}
}
list
@@ -158,4 +150,8 @@ class BookmarkViewModel(
fun cancelProgress() {
job?.cancel()
}
+
+ fun handleLoadError(e: Throwable) {
+ action(BookmarkAction.LoadingError(exceptionHandler(e)))
+ }
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/paging/GeocacheUserListsDataSource.kt b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/paging/GeocacheUserListsDataSource.kt
index bac11931..4a723bb6 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/paging/GeocacheUserListsDataSource.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/paging/GeocacheUserListsDataSource.kt
@@ -1,97 +1,44 @@
package com.arcao.geocaching4locus.import_bookmarks.paging
-import androidx.annotation.MainThread
-import androidx.annotation.WorkerThread
-import androidx.lifecycle.MutableLiveData
-import androidx.paging.PageKeyedDataSource
-import com.arcao.geocaching4locus.base.coroutine.CoroutinesDispatcherProvider
-import com.arcao.geocaching4locus.base.paging.DataSourceState
+import androidx.paging.PagingConfig
+import androidx.paging.PagingSource
+import androidx.paging.PagingState
import com.arcao.geocaching4locus.base.usecase.GetUserListsUseCase
import com.arcao.geocaching4locus.base.usecase.entity.GeocacheListEntity
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.cancelChildren
-import kotlinx.coroutines.launch
-import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CancellationException
class GeocacheUserListsDataSource(
private val getUserLists: GetUserListsUseCase,
- private val dispatcherProvider: CoroutinesDispatcherProvider
-) : PageKeyedDataSource(), CoroutineScope {
- private val job = Job()
-
- override val coroutineContext: CoroutineContext
- get() = job + dispatcherProvider.computation
-
- val state = MutableLiveData().apply {
- postValue(DataSourceState.LoadingInitial)
- }
-
- init {
- addInvalidatedCallback(object : InvalidatedCallback {
- override fun onInvalidated() {
- removeInvalidatedCallback(this)
- job.cancel()
- }
- })
- }
-
- @WorkerThread
- override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback) {
- state.postValue(DataSourceState.LoadingInitial)
-
- job.cancelChildren()
- launch {
- try {
- val response = getUserLists(
- skip = 0,
- take = params.requestedLoadSize
- )
-
- val itemCount = response.totalCount
- val hasNext = response.size < itemCount
- callback.onResult(
- response,
- 0,
- itemCount.toInt(),
- null,
- if (hasNext) response.size else null
- )
-
- state.postValue(DataSourceState.Done)
- } catch (e: Exception) {
- state.postValue(DataSourceState.Error(e))
- }
+ private val pagingConfig: PagingConfig
+) : PagingSource() {
+ override suspend fun load(params: LoadParams): LoadResult {
+ return try {
+ val page = params.key ?: 0
+ val skip = page * params.loadSize
+ val response = getUserLists(
+ skip = skip,
+ take = params.loadSize
+ )
+
+ val currentCount = skip + response.size
+ val totalCount = response.totalCount
+
+ LoadResult.Page(
+ data = response,
+ prevKey = if (page == 0) null else page - 1,
+ nextKey = if (currentCount < totalCount) page + (params.loadSize / pagingConfig.pageSize) else null
+
+ )
+ } catch (e: Exception) {
+ if (e is CancellationException) throw e
+ LoadResult.Error(e)
}
}
- @WorkerThread
- override fun loadAfter(params: LoadParams, callback: LoadCallback) {
- state.postValue(DataSourceState.LoadingNext)
-
- job.cancelChildren()
- launch {
- try {
- val response = getUserLists(
- skip = params.key,
- take = params.requestedLoadSize
- )
-
- val itemCount = response.totalCount
- val hasNext = (params.key + response.size) < itemCount
-
- callback.onResult(
- response,
- if (hasNext) params.key + response.size else null
- )
- state.postValue(DataSourceState.Done)
- } catch (e: Exception) {
- state.postValue(DataSourceState.Error(e))
- }
+ override fun getRefreshKey(state: PagingState): Int? {
+ return state.anchorPosition?.let { anchorPosition ->
+ state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
+ ?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
}
}
-
- @MainThread
- override fun loadBefore(params: LoadParams, callback: LoadCallback) {
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/paging/GeocacheUserListsDataSourceFactory.kt b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/paging/GeocacheUserListsDataSourceFactory.kt
deleted file mode 100644
index 2a52b37d..00000000
--- a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/paging/GeocacheUserListsDataSourceFactory.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package com.arcao.geocaching4locus.import_bookmarks.paging
-
-import androidx.annotation.WorkerThread
-import androidx.lifecycle.MutableLiveData
-import androidx.paging.DataSource
-import com.arcao.geocaching4locus.base.coroutine.CoroutinesDispatcherProvider
-import com.arcao.geocaching4locus.base.usecase.GetUserListsUseCase
-import com.arcao.geocaching4locus.base.usecase.entity.GeocacheListEntity
-
-class GeocacheUserListsDataSourceFactory(
- private val getUserLists: GetUserListsUseCase,
- private val dispatcherProvider: CoroutinesDispatcherProvider
-) : DataSource.Factory() {
- val dataSource = MutableLiveData()
-
- @WorkerThread
- override fun create(): DataSource {
- return GeocacheUserListsDataSource(getUserLists, dispatcherProvider).also {
- dataSource.postValue(it)
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/paging/ListGeocachesDataSource.kt b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/paging/ListGeocachesDataSource.kt
index 7866e4fc..45d95ccd 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/paging/ListGeocachesDataSource.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/paging/ListGeocachesDataSource.kt
@@ -1,100 +1,46 @@
package com.arcao.geocaching4locus.import_bookmarks.paging
-import androidx.annotation.MainThread
-import androidx.annotation.WorkerThread
-import androidx.lifecycle.MutableLiveData
-import androidx.paging.PageKeyedDataSource
-import com.arcao.geocaching4locus.base.coroutine.CoroutinesDispatcherProvider
-import com.arcao.geocaching4locus.base.paging.DataSourceState
+import androidx.paging.PagingConfig
+import androidx.paging.PagingSource
+import androidx.paging.PagingState
import com.arcao.geocaching4locus.base.usecase.GetListGeocachesUseCase
import com.arcao.geocaching4locus.base.usecase.entity.ListGeocacheEntity
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Job
-import kotlinx.coroutines.cancelChildren
-import kotlinx.coroutines.launch
-import kotlin.coroutines.CoroutineContext
+import kotlinx.coroutines.CancellationException
class ListGeocachesDataSource(
private val referenceCode: String,
private val getListGeocaches: GetListGeocachesUseCase,
- private val dispatcherProvider: CoroutinesDispatcherProvider
-) : PageKeyedDataSource(), CoroutineScope {
- private val job = Job()
-
- override val coroutineContext: CoroutineContext
- get() = job + dispatcherProvider.computation
-
- val state = MutableLiveData().apply {
- postValue(DataSourceState.LoadingInitial)
- }
-
- init {
- addInvalidatedCallback(object : InvalidatedCallback {
- override fun onInvalidated() {
- removeInvalidatedCallback(this)
- job.cancel()
- }
- })
- }
-
- @WorkerThread
- override fun loadInitial(params: LoadInitialParams, callback: LoadInitialCallback) {
- state.postValue(DataSourceState.LoadingInitial)
-
- job.cancelChildren()
- launch {
- try {
- val response = getListGeocaches(
- referenceCode = referenceCode,
- skip = 0,
- take = params.requestedLoadSize
- )
-
- val itemCount = response.totalCount
- val hasNext = response.size < itemCount
- callback.onResult(
- response,
- 0,
- itemCount.toInt(),
- null,
- if (hasNext) response.size else null
- )
-
- state.postValue(DataSourceState.Done)
- } catch (e: Exception) {
- state.postValue(DataSourceState.Error(e))
- }
+ private val pagingConfig: PagingConfig
+) : PagingSource() {
+ override suspend fun load(params: LoadParams): LoadResult {
+ return try {
+ val page = params.key ?: 0
+ val skip = page * params.loadSize
+ val response = getListGeocaches(
+ referenceCode = referenceCode,
+ skip = skip,
+ take = params.loadSize
+ )
+
+ val currentCount = skip + response.size
+ val totalCount = response.totalCount
+
+ LoadResult.Page(
+ data = response,
+ prevKey = if (page == 0) null else page - 1,
+ nextKey = if (currentCount < totalCount) page + (params.loadSize / pagingConfig.pageSize) else null
+
+ )
+ } catch (e: Exception) {
+ if (e is CancellationException) throw e
+ LoadResult.Error(e)
}
}
- @WorkerThread
- override fun loadAfter(params: LoadParams, callback: LoadCallback) {
- state.postValue(DataSourceState.LoadingNext)
-
- job.cancelChildren()
- launch {
- try {
- val response = getListGeocaches(
- referenceCode = referenceCode,
- skip = params.key,
- take = params.requestedLoadSize
- )
-
- val itemCount = response.totalCount
- val hasNext = (params.key + response.size) < itemCount
-
- callback.onResult(
- response,
- if (hasNext) params.key + response.size else null
- )
- state.postValue(DataSourceState.Done)
- } catch (e: Exception) {
- state.postValue(DataSourceState.Error(e))
- }
+ override fun getRefreshKey(state: PagingState): Int? {
+ return state.anchorPosition?.let { anchorPosition ->
+ state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
+ ?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
}
}
-
- @MainThread
- override fun loadBefore(params: LoadParams, callback: LoadCallback) {
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/paging/ListGeocachesDataSourceFactory.kt b/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/paging/ListGeocachesDataSourceFactory.kt
deleted file mode 100644
index dbc8586c..00000000
--- a/app/src/main/java/com/arcao/geocaching4locus/import_bookmarks/paging/ListGeocachesDataSourceFactory.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.arcao.geocaching4locus.import_bookmarks.paging
-
-import androidx.annotation.WorkerThread
-import androidx.lifecycle.MutableLiveData
-import androidx.paging.DataSource
-import com.arcao.geocaching4locus.base.coroutine.CoroutinesDispatcherProvider
-import com.arcao.geocaching4locus.base.usecase.GetListGeocachesUseCase
-import com.arcao.geocaching4locus.base.usecase.entity.ListGeocacheEntity
-
-class ListGeocachesDataSourceFactory(
- private val getListGeocaches: GetListGeocachesUseCase,
- private val dispatcherProvider: CoroutinesDispatcherProvider
-) : DataSource.Factory() {
- val dataSource = MutableLiveData()
-
- var referenceCode: String? = null
-
- @WorkerThread
- override fun create(): DataSource {
- return ListGeocachesDataSource(requireNotNull(referenceCode), getListGeocaches, dispatcherProvider).also {
- dataSource.postValue(it)
- }
- }
-}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportGeocacheCodeActivity.kt b/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportGeocacheCodeActivity.kt
index fbf40b93..1a5ac02d 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportGeocacheCodeActivity.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportGeocacheCodeActivity.kt
@@ -1,23 +1,30 @@
package com.arcao.geocaching4locus.importgc
import android.app.Activity
+import android.content.Context
import android.content.Intent
import android.os.Bundle
-import androidx.annotation.NonNull
-import com.arcao.geocaching4locus.authentication.util.requestSignOn
+import androidx.activity.result.contract.ActivityResultContract
+import com.arcao.geocaching4locus.authentication.LoginActivity
import com.arcao.geocaching4locus.base.AbstractActionBarActivity
import com.arcao.geocaching4locus.base.util.exhaustive
import com.arcao.geocaching4locus.base.util.showLocusMissingError
import com.arcao.geocaching4locus.base.util.withObserve
-import com.arcao.geocaching4locus.data.account.AccountManager
import com.arcao.geocaching4locus.error.hasPositiveAction
import com.arcao.geocaching4locus.importgc.fragment.GeocacheCodesInputDialogFragment
-import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
class ImportGeocacheCodeActivity : AbstractActionBarActivity(), GeocacheCodesInputDialogFragment.DialogListener {
private val viewModel by viewModel()
- private val accountManager by inject()
+
+ private val loginActivity = registerForActivityResult(LoginActivity.Contract) { success ->
+ if (success) {
+ viewModel.init(intent.getStringArrayExtra(PARAM_GEOCACHES))
+ } else {
+ setResult(Activity.RESULT_CANCELED)
+ finish()
+ }
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -35,16 +42,15 @@ class ImportGeocacheCodeActivity : AbstractActionBarActivity(), GeocacheCodesInp
@Suppress("IMPLICIT_CAST_TO_ANY")
fun handleAction(action: ImportGeocacheCodeAction) {
when (action) {
- ImportGeocacheCodeAction.SignIn -> {
- accountManager.requestSignOn(this, REQUEST_SIGN_ON)
- }
+ ImportGeocacheCodeAction.SignIn -> loginActivity.launch(null)
is ImportGeocacheCodeAction.Error -> {
startActivity(action.intent)
setResult(
- if (intent.hasPositiveAction())
+ if (action.intent.hasPositiveAction()) {
Activity.RESULT_OK
- else
+ } else {
Activity.RESULT_CANCELED
+ }
)
finish()
}
@@ -68,26 +74,20 @@ class ImportGeocacheCodeActivity : AbstractActionBarActivity(), GeocacheCodesInp
}.exhaustive
}
- override fun onInputFinished(@NonNull input: Array) {
+ override fun onInputFinished(input: Array) {
viewModel.importGeocacheCodes(input)
}
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
-
- // restart update process after log in
- if (requestCode == REQUEST_SIGN_ON) {
- if (resultCode == Activity.RESULT_OK) {
- viewModel.init(intent.getStringArrayExtra(PARAM_GEOCACHES))
- } else {
- setResult(Activity.RESULT_CANCELED)
- finish()
- }
- }
- }
-
companion object {
- private const val REQUEST_SIGN_ON = 1
private const val PARAM_GEOCACHES = "com.arcao.geocaching4locus.GEOCACHES"
}
+
+ object Contract : ActivityResultContract() {
+ override fun createIntent(context: Context, input: Void?) =
+ Intent(context, ImportGeocacheCodeActivity::class.java)
+
+ override fun parseResult(resultCode: Int, intent: Intent?): Boolean {
+ return resultCode == Activity.RESULT_OK
+ }
+ }
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportUrlActivity.kt b/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportUrlActivity.kt
index 7c6e2eb0..3e7c8815 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportUrlActivity.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportUrlActivity.kt
@@ -1,21 +1,26 @@
package com.arcao.geocaching4locus.importgc
import android.app.Activity
-import android.content.Intent
import android.os.Bundle
-import com.arcao.geocaching4locus.authentication.util.requestSignOn
+import com.arcao.geocaching4locus.authentication.LoginActivity
import com.arcao.geocaching4locus.base.AbstractActionBarActivity
import com.arcao.geocaching4locus.base.util.exhaustive
import com.arcao.geocaching4locus.base.util.showLocusMissingError
import com.arcao.geocaching4locus.base.util.withObserve
-import com.arcao.geocaching4locus.data.account.AccountManager
-import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import timber.log.Timber
class ImportUrlActivity : AbstractActionBarActivity() {
private val viewModel by viewModel()
- private val accountManager by inject()
+
+ private val loginActivity = registerForActivityResult(LoginActivity.Contract) { success ->
+ if (success) {
+ processIntent()
+ } else {
+ setResult(Activity.RESULT_CANCELED)
+ finish()
+ }
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -67,26 +72,7 @@ class ImportUrlActivity : AbstractActionBarActivity() {
setResult(Activity.RESULT_CANCELED)
finish()
}
- is ImportUrlAction.SignIn -> {
- accountManager.requestSignOn(this, REQUEST_SIGN_ON)
- }
+ is ImportUrlAction.SignIn -> loginActivity.launch(null)
}.exhaustive
}
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
-
- if (requestCode == REQUEST_SIGN_ON) {
- if (resultCode == Activity.RESULT_OK) {
- processIntent()
- } else {
- setResult(Activity.RESULT_CANCELED)
- finish()
- }
- }
- }
-
- companion object {
- private const val REQUEST_SIGN_ON = 1
- }
}
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 949afe68..f95d5e98 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
@@ -3,16 +3,16 @@ package com.arcao.geocaching4locus.live_map
import android.content.ComponentName
import android.content.Context
import android.content.Intent
+import androidx.lifecycle.LifecycleService
import com.arcao.geocaching4locus.base.ProgressState
import com.arcao.geocaching4locus.base.constants.AppConstants
import com.arcao.geocaching4locus.base.util.ServiceUtil
import com.arcao.geocaching4locus.base.util.exhaustive
import com.arcao.geocaching4locus.base.util.withObserve
-import com.arcao.geocaching4locus.live_map.util.LifecycleServiceFixed
import com.arcao.geocaching4locus.live_map.util.LiveMapNotificationManager
import org.koin.android.ext.android.inject
-class LiveMapService : LifecycleServiceFixed() {
+class LiveMapService : LifecycleService() {
private val notificationManager by inject()
private val viewModel by inject()
private val onCompleteCallback: (Intent) -> Unit = { ServiceUtil.completeWakefulIntent(it) }
diff --git a/app/src/main/java/com/arcao/geocaching4locus/live_map/LiveMapViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/live_map/LiveMapViewModel.kt
index 49bcbb5b..d2c1f201 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/live_map/LiveMapViewModel.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/live_map/LiveMapViewModel.kt
@@ -1,10 +1,10 @@
package com.arcao.geocaching4locus.live_map
+import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleObserver
-import androidx.lifecycle.OnLifecycleEvent
+import androidx.lifecycle.DefaultLifecycleObserver
+import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.viewModelScope
import com.arcao.geocaching4locus.R
import com.arcao.geocaching4locus.base.AccountNotFoundException
@@ -37,6 +37,7 @@ import java.io.IOException
import java.util.concurrent.CancellationException
import java.util.concurrent.Executors
+@SuppressLint("StaticFieldLeak")
class LiveMapViewModel(
private val context: Context,
private val notificationManager: LiveMapNotificationManager,
@@ -47,7 +48,7 @@ class LiveMapViewModel(
private val removeLocusMapPoints: RemoveLocusMapPointsUseCase,
private val accountManager: AccountManager,
dispatcherProvider: CoroutinesDispatcherProvider
-) : BaseViewModel(dispatcherProvider), LifecycleObserver {
+) : BaseViewModel(dispatcherProvider), DefaultLifecycleObserver {
private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
fun addTask(intent: Intent, completionCallback: (Intent) -> Unit) {
@@ -100,8 +101,7 @@ class LiveMapViewModel(
filterPreferenceManager.difficultyMin,
filterPreferenceManager.difficultyMax,
filterPreferenceManager.terrainMin,
- filterPreferenceManager.terrainMax,
- filterPreferenceManager.excludeIgnoreList
+ filterPreferenceManager.terrainMax
) { count = it }.map { list ->
receivedGeocaches += list.size
requests++
@@ -113,7 +113,7 @@ class LiveMapViewModel(
context.packageName,
UpdateActivity::class.java.name,
UpdateActivity.PARAM_SIMPLE_CACHE_ID,
- point.gcData.cacheID
+ requireNotNull(point.gcData).cacheID
)
}
list
@@ -178,8 +178,7 @@ class LiveMapViewModel(
}
}
- @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
- override fun onCleared() {
+ override fun onDestroy(owner: LifecycleOwner) {
viewModelScope.cancel()
}
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/live_map/receiver/LiveMapBroadcastReceiver.kt b/app/src/main/java/com/arcao/geocaching4locus/live_map/receiver/LiveMapBroadcastReceiver.kt
index b2dd3ef5..1671577f 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/live_map/receiver/LiveMapBroadcastReceiver.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/live_map/receiver/LiveMapBroadcastReceiver.kt
@@ -10,8 +10,8 @@ import locus.api.android.ActionBasics
import locus.api.android.utils.LocusUtils
import locus.api.extension.isInvalid
import locus.api.objects.extra.Location
-import org.koin.core.KoinComponent
-import org.koin.core.inject
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
import timber.log.Timber
import kotlin.math.max
import kotlin.math.min
@@ -71,17 +71,17 @@ class LiveMapBroadcastReceiver : BroadcastReceiver(), KoinComponent {
return
// bug in Locus Map?
- val leftLongitude = min(mapTopLeft.getLongitude(), mapBottomRight.getLongitude())
- val rightLongitude = max(mapTopLeft.getLongitude(), mapBottomRight.getLongitude())
+ val leftLongitude = min(mapTopLeft.longitude, mapBottomRight.longitude)
+ val rightLongitude = max(mapTopLeft.longitude, mapBottomRight.longitude)
// Start service to retrieve caches
LiveMapService.start(
context,
- mapCenter.getLatitude(),
- mapCenter.getLongitude(),
- mapTopLeft.getLatitude(),
+ mapCenter.latitude,
+ mapCenter.longitude,
+ mapTopLeft.latitude,
leftLongitude,
- mapBottomRight.getLatitude(),
+ mapBottomRight.latitude,
rightLongitude
)
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/live_map/util/LifecycleServiceFixed.kt b/app/src/main/java/com/arcao/geocaching4locus/live_map/util/LifecycleServiceFixed.kt
deleted file mode 100644
index d7707829..00000000
--- a/app/src/main/java/com/arcao/geocaching4locus/live_map/util/LifecycleServiceFixed.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.arcao.geocaching4locus.live_map.util
-
-import android.app.Service
-import android.content.Intent
-import android.os.IBinder
-
-import androidx.annotation.CallSuper
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.LifecycleOwner
-import androidx.lifecycle.ServiceLifecycleDispatcher
-
-/**
- * A Service that is also a [LifecycleOwner].
- */
-abstract class LifecycleServiceFixed : Service(), LifecycleOwner {
-
- private val mDispatcher = ServiceLifecycleDispatcher(this)
-
- @CallSuper
- override fun onCreate() {
- mDispatcher.onServicePreSuperOnCreate()
- super.onCreate()
- }
-
- @CallSuper
- override fun onBind(intent: Intent): IBinder? {
- mDispatcher.onServicePreSuperOnBind()
- return null
- }
-
- @Suppress("DEPRECATION")
- @CallSuper
- override fun onStart(intent: Intent?, startId: Int) {
- mDispatcher.onServicePreSuperOnStart()
- super.onStart(intent, startId)
- }
-
- // this method is added only to annotate it with @CallSuper.
- // In usual service super.onStartCommand is no-op, but in LifecycleService
- // it results in mDispatcher.onServicePreSuperOnStart() call, because
- // super.onStartCommand calls onStart().
- @CallSuper
- override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
- return super.onStartCommand(intent, flags, startId)
- }
-
- @CallSuper
- override fun onDestroy() {
- mDispatcher.onServicePreSuperOnDestroy()
- super.onDestroy()
- }
-
- override fun getLifecycle(): Lifecycle {
- return mDispatcher.lifecycle
- }
-}
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 2029fef4..438908c3 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
@@ -31,6 +31,7 @@ import com.arcao.geocaching4locus.live_map.receiver.LiveMapBroadcastReceiver
import com.arcao.geocaching4locus.settings.SettingsActivity
import com.arcao.geocaching4locus.settings.fragment.LiveMapPreferenceFragment
import com.arcao.geocaching4locus.settings.manager.DefaultPreferenceManager
+import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import locus.api.manager.LocusMapManager
@@ -44,8 +45,10 @@ class LiveMapNotificationManager(
private val locusMapManager: LocusMapManager,
private val dispatcherProvider: CoroutinesDispatcherProvider
) : SharedPreferences.OnSharedPreferenceChangeListener {
- private val preferences: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
- private val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ private val preferences: SharedPreferences =
+ PreferenceManager.getDefaultSharedPreferences(context)
+ private val notificationManager =
+ context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
private val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
private val stateChangeListeners = CopyOnWriteArraySet()
@@ -79,9 +82,6 @@ class LiveMapNotificationManager(
}
}
- // make sure Live Map broadcast receiver is always enabled
- locusMapManager.enablePeriodicUpdatesReceiver(LiveMapBroadcastReceiver::class)
-
preferences.edit {
putBoolean(PrefConstants.LIVE_MAP, willBeEnabled)
}
@@ -213,7 +213,10 @@ class LiveMapNotificationManager(
private fun showNotification() {
notificationShown = true
- notificationManager.notify(AppConstants.NOTIFICATION_ID_LIVEMAP, createNotification().build())
+ notificationManager.notify(
+ AppConstants.NOTIFICATION_ID_LIVEMAP,
+ createNotification().build()
+ )
}
private fun hideNotification() {
@@ -253,7 +256,12 @@ class LiveMapNotificationManager(
}
val pendingIntent =
- createPendingActivityIntent(SettingsActivity.createIntent(context, LiveMapPreferenceFragment::class.java))
+ createPendingActivityIntent(
+ SettingsActivity.Contract.createIntent(
+ context,
+ LiveMapPreferenceFragment::class.java
+ )
+ )
nb.addAction(
R.drawable.ic_stat_live_map_settings,
context.getText(R.string.notify_live_map_action_settings),
@@ -271,18 +279,26 @@ class LiveMapNotificationManager(
return nb
}
- private fun createPendingActivityIntent(intent: Intent): PendingIntent {
- return PendingIntent.getActivity(
- context, 0,
- intent,
+ 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
- )
- }
-
- private fun createPendingBroadcastIntent(action: String): PendingIntent {
- val intent = Intent(action, null, context, LiveMapBroadcastReceiver::class.java)
- return PendingIntent.getBroadcast(context, 0, intent, 0)
- }
+ }
+ )
+
+ 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
+ }
+ )
private fun showError(@StringRes message: Int) {
context.startActivity(
@@ -331,6 +347,7 @@ class LiveMapNotificationManager(
}
}
+ @OptIn(DelicateCoroutinesApi::class)
fun removeLiveMapItems() = GlobalScope.launch(dispatcherProvider.computation) {
val lastRequests = defaultPreferenceManager.liveMapLastRequests
if (lastRequests > 0) {
@@ -346,9 +363,12 @@ class LiveMapNotificationManager(
companion object {
private const val VAR_B_MAP_VISIBLE = "1300"
- private const val ACTION_HIDE_NOTIFICATION = "com.arcao.geocaching4locus.action.HIDE_NOTIFICATION"
- private const val ACTION_LIVE_MAP_ENABLE = "com.arcao.geocaching4locus.action.LIVE_MAP_ENABLE"
- private const val ACTION_LIVE_MAP_DISABLE = "com.arcao.geocaching4locus.action.LIVE_MAP_DISABLE"
+ private const val ACTION_HIDE_NOTIFICATION =
+ "com.arcao.geocaching4locus.action.HIDE_NOTIFICATION"
+ private const val ACTION_LIVE_MAP_ENABLE =
+ "com.arcao.geocaching4locus.action.LIVE_MAP_ENABLE"
+ private const val ACTION_LIVE_MAP_DISABLE =
+ "com.arcao.geocaching4locus.action.LIVE_MAP_DISABLE"
private const val NOTIFICATION_TIMEOUT_MS: Long = 2200
private const val NOTIFICATION_CHANNEL_ID = "LIVE_MAP_NOTIFICATION_CHANNEL"
diff --git a/app/src/main/java/com/arcao/geocaching4locus/search_nearest/SearchNearestActivity.kt b/app/src/main/java/com/arcao/geocaching4locus/search_nearest/SearchNearestActivity.kt
index af3060d2..61927b9a 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/search_nearest/SearchNearestActivity.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/search_nearest/SearchNearestActivity.kt
@@ -1,14 +1,17 @@
package com.arcao.geocaching4locus.search_nearest
import android.app.Activity
+import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
+import androidx.activity.result.contract.ActivityResultContract
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.Toolbar
import androidx.databinding.DataBindingUtil
import com.arcao.geocaching4locus.R
-import com.arcao.geocaching4locus.authentication.util.requestSignOn
+import com.arcao.geocaching4locus.authentication.LoginActivity
import com.arcao.geocaching4locus.base.AbstractActionBarActivity
import com.arcao.geocaching4locus.base.fragment.SliderDialogFragment
import com.arcao.geocaching4locus.base.util.PermissionUtil
@@ -16,14 +19,12 @@ import com.arcao.geocaching4locus.base.util.exhaustive
import com.arcao.geocaching4locus.base.util.invoke
import com.arcao.geocaching4locus.base.util.showLocusMissingError
import com.arcao.geocaching4locus.base.util.withObserve
-import com.arcao.geocaching4locus.data.account.AccountManager
import com.arcao.geocaching4locus.databinding.ActivitySearchNearestBinding
import com.arcao.geocaching4locus.error.ErrorActivity
import com.arcao.geocaching4locus.search_nearest.fragment.NoLocationPermissionErrorDialogFragment
import com.arcao.geocaching4locus.search_nearest.fragment.NoLocationProviderDialogFragment
import com.arcao.geocaching4locus.settings.SettingsActivity
import com.arcao.geocaching4locus.settings.fragment.FilterPreferenceFragment
-import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
@@ -32,10 +33,23 @@ class SearchNearestActivity : AbstractActionBarActivity(), SliderDialogFragment.
parametersOf(intent)
}
- private val accountManager by inject()
-
private lateinit var binding: ActivitySearchNearestBinding
+ private val settingsActivity = registerForActivityResult(SettingsActivity.Contract) {}
+ private val requestLocationPermission = registerForActivityResult(
+ ActivityResultContracts.RequestMultiplePermissions()
+ ) { result ->
+ if (result.all { it.value }) {
+ viewModel.retrieveCoordinates()
+ } else {
+ NoLocationPermissionErrorDialogFragment.newInstance().show(supportFragmentManager)
+ }
+ }
+
+ private val loginActivity = registerForActivityResult(LoginActivity.Contract) { success ->
+ if (success) viewModel.download()
+ }
+
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -43,6 +57,7 @@ class SearchNearestActivity : AbstractActionBarActivity(), SliderDialogFragment.
binding.lifecycleOwner = this
binding.vm = viewModel
+ @Suppress("USELESS_CAST")
val toolbar = binding.toolbar as Toolbar
val latitude = binding.incCoordinates.latitude
val longitude = binding.incCoordinates.longitude
@@ -68,9 +83,7 @@ class SearchNearestActivity : AbstractActionBarActivity(), SliderDialogFragment.
@Suppress("IMPLICIT_CAST_TO_ANY")
fun handleAction(action: SearchNearestAction) {
when (action) {
- SearchNearestAction.SignIn -> {
- accountManager.requestSignOn(this, REQUEST_SIGN_ON)
- }
+ SearchNearestAction.SignIn -> loginActivity.launch(null)
is SearchNearestAction.Error -> {
startActivity(action.intent)
setResult(Activity.RESULT_CANCELED)
@@ -80,33 +93,30 @@ class SearchNearestActivity : AbstractActionBarActivity(), SliderDialogFragment.
setResult(Activity.RESULT_OK)
finish()
}
- is SearchNearestAction.LocusMapNotInstalled -> {
- showLocusMissingError()
- }
- SearchNearestAction.RequestGpsLocationPermission -> {
- PermissionUtil.requestGpsLocationPermission(this, REQUEST_LOCATION_PERMISSION)
- }
- SearchNearestAction.RequestWifiLocationPermission -> {
- PermissionUtil.requestWifiLocationPermission(this, REQUEST_LOCATION_PERMISSION)
- }
- SearchNearestAction.WrongCoordinatesFormat -> {
- startActivity(ErrorActivity.IntentBuilder(this).message(R.string.error_coordinates_format).build())
- }
+ is SearchNearestAction.LocusMapNotInstalled -> showLocusMissingError()
+ SearchNearestAction.RequestGpsLocationPermission -> requestLocationPermission.launch(
+ PermissionUtil.PERMISSION_LOCATION_GPS
+ )
+ SearchNearestAction.RequestWifiLocationPermission -> requestLocationPermission.launch(
+ PermissionUtil.PERMISSION_LOCATION_WIFI
+ )
+ SearchNearestAction.WrongCoordinatesFormat -> startActivity(
+ ErrorActivity.IntentBuilder(this)
+ .message(R.string.error_coordinates_format)
+ .build()
+ )
SearchNearestAction.ShowFilters -> {
- startActivity(SettingsActivity.createIntent(this, FilterPreferenceFragment::class.java))
+ settingsActivity.launch(FilterPreferenceFragment::class.java)
}
- SearchNearestAction.LocationProviderDisabled -> {
+ SearchNearestAction.LocationProviderDisabled ->
NoLocationProviderDialogFragment.newInstance().show(supportFragmentManager)
- }
- is SearchNearestAction.RequestCacheCount -> {
- SliderDialogFragment.newInstance(
- title = R.string.title_geocache_count,
- min = action.step,
- max = action.max,
- step = action.step,
- defaultValue = action.value
- ).show(supportFragmentManager, "COUNTER")
- }
+ is SearchNearestAction.RequestCacheCount -> SliderDialogFragment.newInstance(
+ title = R.string.title_geocache_count,
+ min = action.step,
+ max = action.max,
+ step = action.step,
+ defaultValue = action.value
+ ).show(supportFragmentManager, "COUNTER")
}.exhaustive
}
@@ -117,7 +127,7 @@ class SearchNearestActivity : AbstractActionBarActivity(), SliderDialogFragment.
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.main_activity_option_menu_preferences -> {
- startActivity(SettingsActivity.createIntent(this))
+ settingsActivity.launch(null)
true
}
android.R.id.home -> {
@@ -127,27 +137,6 @@ class SearchNearestActivity : AbstractActionBarActivity(), SliderDialogFragment.
else -> super.onOptionsItemSelected(item)
}
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
-
- // restart download process after log in
- if (requestCode == REQUEST_SIGN_ON && resultCode == Activity.RESULT_OK) {
- viewModel.download()
- }
- }
-
- override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
-
- if (requestCode == REQUEST_LOCATION_PERMISSION) {
- if (PermissionUtil.verifyPermissions(grantResults)) {
- viewModel.retrieveCoordinates()
- } else {
- NoLocationPermissionErrorDialogFragment.newInstance().show(supportFragmentManager)
- }
- }
- }
-
override fun onProgressCancel(requestId: Int) {
viewModel.cancelProgress()
}
@@ -157,8 +146,14 @@ class SearchNearestActivity : AbstractActionBarActivity(), SliderDialogFragment.
viewModel.requestedCaches(fragment.getValue())
}
- companion object {
- private const val REQUEST_SIGN_ON = 1
- private const val REQUEST_LOCATION_PERMISSION = 2
+ object Contract : ActivityResultContract() {
+ override fun createIntent(context: Context, input: Intent?) =
+ Intent(context, SearchNearestActivity::class.java).apply {
+ input?.let { putExtras(it) }
+ }
+
+ override fun parseResult(resultCode: Int, intent: Intent?): Boolean {
+ return resultCode == Activity.RESULT_OK
+ }
}
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/search_nearest/SearchNearestViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/search_nearest/SearchNearestViewModel.kt
index d183560d..ea3a6b1a 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/search_nearest/SearchNearestViewModel.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/search_nearest/SearchNearestViewModel.kt
@@ -1,6 +1,6 @@
package com.arcao.geocaching4locus.search_nearest
-import android.content.Context
+import android.app.Application
import android.content.Intent
import androidx.lifecycle.MutableLiveData
import com.arcao.geocaching4locus.R
@@ -32,7 +32,7 @@ import timber.log.Timber
class SearchNearestViewModel(
intent: Intent,
- private val context: Context,
+ private val context: Application,
private val accountManager: AccountManager,
private val preferenceManager: DefaultPreferenceManager,
private val filterPreferenceManager: FilterPreferenceManager,
@@ -212,7 +212,6 @@ class SearchNearestViewModel(
filterPreferenceManager.difficultyMax,
filterPreferenceManager.terrainMin,
filterPreferenceManager.terrainMax,
- filterPreferenceManager.excludeIgnoreList,
maxCount
) { count = it }.map { list ->
receivedGeocaches += list.size
@@ -221,12 +220,14 @@ class SearchNearestViewModel(
// apply additional downloading full geocache if required
if (filterPreferenceManager.simpleCacheData) {
list.forEach { point ->
- point.setExtraOnDisplay(
- context.packageName,
- UpdateActivity::class.java.name,
- UpdateActivity.PARAM_SIMPLE_CACHE_ID,
- point.gcData.cacheID
- )
+ point.gcData?.cacheID?.let { cacheId ->
+ point.setExtraOnDisplay(
+ context.packageName,
+ UpdateActivity::class.java.name,
+ UpdateActivity.PARAM_SIMPLE_CACHE_ID,
+ cacheId
+ )
+ }
}
}
list
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 739ec7f8..7aaed440 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/settings/SettingsActivity.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/settings/SettingsActivity.kt
@@ -1,9 +1,11 @@
package com.arcao.geocaching4locus.settings
+import android.app.Activity
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
+import androidx.activity.result.contract.ActivityResultContract
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
@@ -65,7 +67,10 @@ class SettingsActivity : AbstractActionBarActivity(),
supportFragmentManager.commit {
replace(
R.id.fragment,
- supportFragmentManager.fragmentFactory.instantiate(classLoader, pref.fragment)
+ supportFragmentManager.fragmentFactory.instantiate(
+ classLoader,
+ pref.fragment ?: return@commit
+ )
)
addToBackStack(null)
}
@@ -75,7 +80,7 @@ class SettingsActivity : AbstractActionBarActivity(),
override fun onPreferenceDisplayDialog(
caller: PreferenceFragmentCompat,
- pref: Preference?
+ pref: Preference
): Boolean {
if (pref is PreferenceFragmentCompat.OnPreferenceDisplayDialogCallback) {
return pref.onPreferenceDisplayDialog(caller, pref)
@@ -86,16 +91,18 @@ class SettingsActivity : AbstractActionBarActivity(),
companion object {
private const val EXTRA_SHOW_FRAGMENT = ":android:show_fragment"
+ }
- fun createIntent(context: Context): Intent {
- return Intent(context, SettingsActivity::class.java)
- }
+ object Contract : ActivityResultContract?, Boolean>() {
+ override fun createIntent(context: Context, input: Class?) =
+ Intent(context, SettingsActivity::class.java).apply {
+ if (input != null) {
+ putExtra(EXTRA_SHOW_FRAGMENT, input.name)
+ }
+ }
- fun createIntent(
- context: Context,
- preferenceFragment: Class
- ): Intent {
- return createIntent(context).putExtra(EXTRA_SHOW_FRAGMENT, preferenceFragment.name)
+ override fun parseResult(resultCode: Int, intent: Intent?): Boolean {
+ return resultCode == Activity.RESULT_OK
}
}
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/AboutPreferenceFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/AboutPreferenceFragment.kt
index d50ef5c6..28158997 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/AboutPreferenceFragment.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/AboutPreferenceFragment.kt
@@ -66,7 +66,7 @@ class AboutPreferenceFragment : AbstractPreferenceFragment(), CoroutineScope {
R.string.feedback_body
)
- startActivityForResult(intent, REQ_FEEDBACK)
+ startActivity(intent)
}
true
}
@@ -99,8 +99,4 @@ class AboutPreferenceFragment : AbstractPreferenceFragment(), CoroutineScope {
const val TAG = "DonatePaypalDialogFragment"
}
}
-
- companion object {
- const val REQ_FEEDBACK = 1
- }
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/AccountsPreferenceFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/AccountsPreferenceFragment.kt
index 72c5d77e..a5c1fe11 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/AccountsPreferenceFragment.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/AccountsPreferenceFragment.kt
@@ -2,7 +2,7 @@ package com.arcao.geocaching4locus.settings.fragment
import androidx.preference.Preference
import com.arcao.geocaching4locus.R
-import com.arcao.geocaching4locus.authentication.util.requestSignOn
+import com.arcao.geocaching4locus.authentication.LoginActivity
import com.arcao.geocaching4locus.base.constants.AppConstants
import com.arcao.geocaching4locus.base.constants.PrefConstants.ACCOUNT_POWERED_BY
import com.arcao.geocaching4locus.base.fragment.AbstractPreferenceFragment
@@ -14,6 +14,8 @@ import org.koin.android.ext.android.inject
class AccountsPreferenceFragment : AbstractPreferenceFragment() {
val accountManager by inject()
+ private val loginActivity = registerForActivityResult(LoginActivity.Contract) {}
+
override val preferenceResource: Int
get() = R.xml.preference_category_accounts
@@ -27,7 +29,7 @@ class AccountsPreferenceFragment : AbstractPreferenceFragment() {
setTitle(R.string.pref_login)
setSummary(R.string.pref_login_summary)
} else {
- accountManager.requestSignOn(requireActivity(), 0)
+ loginActivity.launch(null)
}
true
diff --git a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/CacheTypeFilterPreferenceFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/CacheTypeFilterPreferenceFragment.kt
index a20911d6..9bbe2d94 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/CacheTypeFilterPreferenceFragment.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/CacheTypeFilterPreferenceFragment.kt
@@ -1,52 +1,60 @@
package com.arcao.geocaching4locus.settings.fragment.filter
+import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
+import android.view.View
+import androidx.core.view.MenuProvider
import androidx.preference.CheckBoxPreference
import com.arcao.geocaching4locus.R
import com.arcao.geocaching4locus.base.constants.AppConstants
-import com.arcao.geocaching4locus.base.constants.PrefConstants.FILTER_CACHE_TYPE_PREFIX
+import com.arcao.geocaching4locus.base.constants.PrefConstants
import com.arcao.geocaching4locus.base.fragment.AbstractPreferenceFragment
class CacheTypeFilterPreferenceFragment : AbstractPreferenceFragment() {
override val preferenceResource: Int
get() = R.xml.preference_category_filter_cache_type
- override fun preparePreference() {
- super.preparePreference()
-
- setHasOptionsMenu(true)
- }
-
- override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
- super.onCreateOptionsMenu(menu, inflater)
- inflater.inflate(R.menu.toolbar_select_deselect, menu)
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- val geocacheTypeLength = AppConstants.GEOCACHE_TYPES.size
-
- when (item.itemId) {
- android.R.id.home -> {
- // app icon in action bar clicked; go home
- requireActivity().finish()
- return true
- }
+ private val menuProvider = object : MenuProvider {
+ override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
+ menuInflater.inflate(R.menu.toolbar_select_deselect, menu)
+ }
- R.id.selectAll -> {
- for (i in 0 until geocacheTypeLength)
- preference(FILTER_CACHE_TYPE_PREFIX + i).isChecked = true
- return true
+ override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
+ val geocacheTypeLength = AppConstants.GEOCACHE_TYPES.size
+
+ return when (menuItem.itemId) {
+ android.R.id.home -> {
+ // app icon in action bar clicked; go home
+ requireActivity().finish()
+ true
+ }
+
+ R.id.selectAll -> {
+ for (i in 0 until geocacheTypeLength) {
+ preference(PrefConstants.FILTER_CACHE_TYPE_PREFIX + i)
+ .isChecked = true
+ }
+ true
+ }
+
+ R.id.deselectAll -> {
+ for (i in 0 until geocacheTypeLength) {
+ preference(PrefConstants.FILTER_CACHE_TYPE_PREFIX + i)
+ .isChecked = false
+ }
+ true
+ }
+
+ else -> false
}
+ }
+ }
- R.id.deselectAll -> {
- for (i in 0 until geocacheTypeLength)
- preference(FILTER_CACHE_TYPE_PREFIX + i).isChecked = false
- return true
- }
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
- else -> return super.onOptionsItemSelected(item)
- }
+ requireActivity().addMenuProvider(menuProvider, viewLifecycleOwner)
}
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/ContainerTypeFilterPreferenceFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/ContainerTypeFilterPreferenceFragment.kt
index e39f8ae3..1d0f29ee 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/ContainerTypeFilterPreferenceFragment.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/settings/fragment/filter/ContainerTypeFilterPreferenceFragment.kt
@@ -1,8 +1,11 @@
package com.arcao.geocaching4locus.settings.fragment.filter
+import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
+import android.view.View
+import androidx.core.view.MenuProvider
import androidx.preference.CheckBoxPreference
import com.arcao.geocaching4locus.R
import com.arcao.geocaching4locus.base.constants.AppConstants
@@ -13,40 +16,43 @@ class ContainerTypeFilterPreferenceFragment : AbstractPreferenceFragment() {
override val preferenceResource: Int
get() = R.xml.preference_category_filter_container_type
- override fun preparePreference() {
- super.preparePreference()
-
- setHasOptionsMenu(true)
- }
-
- override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
- super.onCreateOptionsMenu(menu, inflater)
- inflater.inflate(R.menu.toolbar_select_deselect, menu)
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- val containerTypeLength = AppConstants.GEOCACHE_SIZES.size
-
- when (item.itemId) {
- android.R.id.home -> {
- // app icon in action bar clicked; go home
- requireActivity().finish()
- return true
- }
+ private val menuProvider = object : MenuProvider {
+ override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
+ menuInflater.inflate(R.menu.toolbar_select_deselect, menu)
+ }
- R.id.selectAll -> {
- for (i in 0 until containerTypeLength)
- preference(FILTER_CONTAINER_TYPE_PREFIX + i).isChecked = true
- return true
+ override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
+ val containerTypeLength = AppConstants.GEOCACHE_SIZES.size
+
+ return when (menuItem.itemId) {
+ android.R.id.home -> {
+ // app icon in action bar clicked; go home
+ requireActivity().finish()
+ true
+ }
+
+ R.id.selectAll -> {
+ for (i in 0 until containerTypeLength)
+ preference(FILTER_CONTAINER_TYPE_PREFIX + i).isChecked =
+ true
+ true
+ }
+
+ R.id.deselectAll -> {
+ for (i in 0 until containerTypeLength)
+ preference(FILTER_CONTAINER_TYPE_PREFIX + i).isChecked =
+ false
+ true
+ }
+
+ else -> false
}
+ }
+ }
- R.id.deselectAll -> {
- for (i in 0 until containerTypeLength)
- preference(FILTER_CONTAINER_TYPE_PREFIX + i).isChecked = false
- return true
- }
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
- else -> return super.onOptionsItemSelected(item)
- }
+ requireActivity().addMenuProvider(menuProvider, viewLifecycleOwner)
}
}
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 f7c5942c..0e67a511 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
@@ -49,7 +49,7 @@ class DifficultyFilterPreferenceFragment : AbstractPreferenceFragment() {
FILTER_DIFFICULTY_MIN,
FILTER_DIFFICULTY_MAX -> {
preference(key).apply {
- summary = prepareRatingSummary(entry)
+ summary = prepareRatingSummary(entry ?: return)
}
}
}
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 8f38db12..df513698 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
@@ -49,7 +49,7 @@ class TerrainFilterPreferenceFragment : AbstractPreferenceFragment() {
FILTER_TERRAIN_MIN,
FILTER_TERRAIN_MAX -> {
preference(key).apply {
- summary = prepareRatingSummary(entry)
+ summary = prepareRatingSummary(entry ?: return)
}
}
}
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 8fddc99c..4c9a5773 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
@@ -5,7 +5,6 @@ import android.content.res.TypedArray
import android.os.Parcel
import android.os.Parcelable
import android.util.AttributeSet
-import androidx.annotation.Nullable
import androidx.core.content.withStyledAttributes
import androidx.preference.DialogPreference
import androidx.preference.Preference
@@ -50,7 +49,7 @@ class SliderPreference @JvmOverloads constructor(
return R.layout.view_slider
}
- override fun onSetInitialValue(@Nullable defaultValue: Any?) {
+ override fun onSetInitialValue(defaultValue: Any?) {
progress = getPersistedInt(defaultValue as? Int ?: 0)
}
@@ -58,7 +57,7 @@ class SliderPreference @JvmOverloads constructor(
return a.getInt(index, 0)
}
- override fun onSaveInstanceState(): Parcelable {
+ override fun onSaveInstanceState(): Parcelable? {
val superState = super.onSaveInstanceState()
if (isPersistent) {
@@ -85,7 +84,10 @@ class SliderPreference @JvmOverloads constructor(
value = myState.value
}
- override fun onPreferenceDisplayDialog(caller: PreferenceFragmentCompat, preference: Preference): Boolean {
+ override fun onPreferenceDisplayDialog(
+ caller: PreferenceFragmentCompat,
+ preference: Preference
+ ): Boolean {
// check if dialog is already showing
val fragmentManager = caller.parentFragmentManager
if (fragmentManager.findFragmentByTag(DIALOG_FRAGMENT_TAG) != null) return true
@@ -99,9 +101,9 @@ class SliderPreference @JvmOverloads constructor(
}
private class SavedState : BaseSavedState {
- internal var value: Int = 0
+ var value: Int = 0
- internal constructor(source: Parcel) : super(source) {
+ constructor(source: Parcel) : super(source) {
value = source.readInt()
}
@@ -110,7 +112,7 @@ class SliderPreference @JvmOverloads constructor(
dest.writeInt(value)
}
- internal constructor(superState: Parcelable) : super(superState)
+ constructor(superState: Parcelable?) : super(superState)
companion object {
@Suppress("unused")
diff --git a/app/src/main/java/com/arcao/geocaching4locus/settings/widget/SliderPreferenceDialogFragment.kt b/app/src/main/java/com/arcao/geocaching4locus/settings/widget/SliderPreferenceDialogFragment.kt
index e1f5184b..e234e075 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/settings/widget/SliderPreferenceDialogFragment.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/settings/widget/SliderPreferenceDialogFragment.kt
@@ -10,7 +10,6 @@ import android.view.View
import android.widget.EditText
import android.widget.SeekBar
import android.widget.TextView
-import androidx.annotation.NonNull
import androidx.core.os.bundleOf
import androidx.preference.PreferenceDialogFragmentCompat
import com.arcao.geocaching4locus.R
@@ -40,12 +39,12 @@ class SliderPreferenceDialogFragment : PreferenceDialogFragmentCompat() {
}
}
- override fun onSaveInstanceState(@NonNull outState: Bundle) {
+ override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt(SAVE_STATE_VALUE, value)
}
- override fun onBindDialogView(@NonNull v: View) {
+ override fun onBindDialogView(v: View) {
val messageView = v.findViewById(R.id.message)
val seekBar = v.findViewById(R.id.seekbar)
val editText = v.findViewById(R.id.input)
@@ -110,8 +109,8 @@ class SliderPreferenceDialogFragment : PreferenceDialogFragmentCompat() {
}
}
- private class InputTextFilter internal constructor(
- internal val editText: EditText,
+ private class InputTextFilter(
+ val editText: EditText,
private val min: Int,
private val max: Int,
step: Int
@@ -136,19 +135,18 @@ class SliderPreferenceDialogFragment : PreferenceDialogFragmentCompat() {
return InputType.TYPE_CLASS_TEXT
}
- @NonNull
override fun getAcceptedChars(): CharArray {
return DIGIT_CHARACTERS
}
override fun filter(
- @NonNull source: CharSequence,
+ source: CharSequence,
start: Int,
end: Int,
dest: Spanned,
dstart: Int,
dend: Int
- ): CharSequence? {
+ ): CharSequence {
if (availableValues == null || availableValues.isEmpty()) {
var filtered: CharSequence? = super.filter(source, start, end, dest, dstart, dend)
if (filtered == null) {
diff --git a/app/src/main/java/com/arcao/geocaching4locus/update/UpdateActivity.kt b/app/src/main/java/com/arcao/geocaching4locus/update/UpdateActivity.kt
index 3dfbdab7..c6dca802 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/update/UpdateActivity.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/update/UpdateActivity.kt
@@ -1,23 +1,28 @@
package com.arcao.geocaching4locus.update
import android.app.Activity
-import android.content.Intent
import android.os.Bundle
import com.arcao.geocaching4locus.R
-import com.arcao.geocaching4locus.authentication.util.requestSignOn
+import com.arcao.geocaching4locus.authentication.LoginActivity
import com.arcao.geocaching4locus.base.AbstractActionBarActivity
import com.arcao.geocaching4locus.base.util.exhaustive
import com.arcao.geocaching4locus.base.util.showLocusMissingError
import com.arcao.geocaching4locus.base.util.withObserve
-import com.arcao.geocaching4locus.data.account.AccountManager
import com.arcao.geocaching4locus.error.ErrorActivity
-import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import timber.log.Timber
class UpdateActivity : AbstractActionBarActivity() {
private val viewModel by viewModel()
- private val accountManager by inject()
+
+ private val loginActivity = registerForActivityResult(LoginActivity.Contract) { success ->
+ if (success) {
+ viewModel.processIntent(intent)
+ } else {
+ setResult(Activity.RESULT_CANCELED)
+ finish()
+ }
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -33,9 +38,7 @@ class UpdateActivity : AbstractActionBarActivity() {
@Suppress("IMPLICIT_CAST_TO_ANY")
fun handleAction(action: UpdateAction) {
when (action) {
- UpdateAction.SignIn -> {
- accountManager.requestSignOn(this, REQUEST_SIGN_ON)
- }
+ UpdateAction.SignIn -> loginActivity.launch(null)
is UpdateAction.Error -> {
Timber.d("UpdateAction.Error intent: %s", intent)
startActivity(action.intent)
@@ -64,20 +67,6 @@ class UpdateActivity : AbstractActionBarActivity() {
}.exhaustive
}
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
-
- // restart update process after log in
- if (requestCode == REQUEST_SIGN_ON) {
- if (resultCode == Activity.RESULT_OK) {
- viewModel.processIntent(intent)
- } else {
- setResult(Activity.RESULT_CANCELED)
- finish()
- }
- }
- }
-
override fun onProgressCancel(requestId: Int) {
viewModel.cancelProgress()
}
@@ -85,7 +74,5 @@ class UpdateActivity : AbstractActionBarActivity() {
companion object {
const val PARAM_CACHE_ID = "cacheId"
const val PARAM_SIMPLE_CACHE_ID = "simpleCacheId"
-
- private const val REQUEST_SIGN_ON = 1
}
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/update/UpdateMoreActivity.kt b/app/src/main/java/com/arcao/geocaching4locus/update/UpdateMoreActivity.kt
index 92994850..0528f65b 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/update/UpdateMoreActivity.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/update/UpdateMoreActivity.kt
@@ -1,21 +1,26 @@
package com.arcao.geocaching4locus.update
import android.app.Activity
-import android.content.Intent
import android.os.Bundle
-import com.arcao.geocaching4locus.authentication.util.requestSignOn
+import com.arcao.geocaching4locus.authentication.LoginActivity
import com.arcao.geocaching4locus.base.AbstractActionBarActivity
import com.arcao.geocaching4locus.base.util.exhaustive
import com.arcao.geocaching4locus.base.util.showLocusMissingError
import com.arcao.geocaching4locus.base.util.withObserve
-import com.arcao.geocaching4locus.data.account.AccountManager
-import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import timber.log.Timber
class UpdateMoreActivity : AbstractActionBarActivity() {
private val viewModel by viewModel()
- private val accountManager by inject()
+
+ private val loginActivity = registerForActivityResult(LoginActivity.Contract) { success ->
+ if (success) {
+ viewModel.processIntent(intent)
+ } else {
+ setResult(Activity.RESULT_CANCELED)
+ finish()
+ }
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -31,9 +36,7 @@ class UpdateMoreActivity : AbstractActionBarActivity() {
@Suppress("IMPLICIT_CAST_TO_ANY")
fun handleAction(action: UpdateMoreAction) {
when (action) {
- UpdateMoreAction.SignIn -> {
- accountManager.requestSignOn(this, REQUEST_SIGN_ON)
- }
+ UpdateMoreAction.SignIn -> loginActivity.launch(null)
is UpdateMoreAction.Error -> {
Timber.d("UpdateMoreAction.Error intent: %s", action.intent)
startActivity(action.intent)
@@ -57,24 +60,7 @@ class UpdateMoreActivity : AbstractActionBarActivity() {
}.exhaustive
}
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
-
- // restart update process after log in
- if (requestCode == REQUEST_SIGN_ON) {
- if (resultCode == Activity.RESULT_OK) {
- viewModel.processIntent(intent)
- } else {
- setResult(Activity.RESULT_CANCELED)
- finish()
- }
- }
- }
-
override fun onProgressCancel(requestId: Int) {
viewModel.cancelProgress()
}
- companion object {
- private const val REQUEST_SIGN_ON = 1
- }
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/update/UpdateMoreViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/update/UpdateMoreViewModel.kt
index 673132c9..fb8e92e9 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/update/UpdateMoreViewModel.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/update/UpdateMoreViewModel.kt
@@ -13,9 +13,7 @@ import com.arcao.geocaching4locus.base.util.invoke
import com.arcao.geocaching4locus.data.account.AccountManager
import com.arcao.geocaching4locus.error.handler.ExceptionHandler
import com.arcao.geocaching4locus.settings.manager.DefaultPreferenceManager
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
-import kotlinx.coroutines.flow.collect
import locus.api.android.utils.IntentHelper
import locus.api.manager.LocusMapManager
import locus.api.mapper.PointMerger
@@ -35,7 +33,6 @@ class UpdateMoreViewModel(
val action = Command()
private var job: Job? = null
- @OptIn(ExperimentalCoroutinesApi::class)
fun processIntent(intent: Intent) {
if (locusMapManager.isLocusMapNotInstalled) {
action(UpdateMoreAction.LocusMapNotInstalled)
diff --git a/app/src/main/java/com/arcao/geocaching4locus/update/UpdateViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/update/UpdateViewModel.kt
index c2d13302..3e0497d5 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/update/UpdateViewModel.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/update/UpdateViewModel.kt
@@ -1,6 +1,6 @@
package com.arcao.geocaching4locus.update
-import android.content.Context
+import android.app.Application
import android.content.Intent
import com.arcao.geocaching4locus.R
import com.arcao.geocaching4locus.authentication.util.isPremium
@@ -23,12 +23,11 @@ import locus.api.android.utils.LocusUtils
import locus.api.manager.LocusMapManager
import locus.api.mapper.PointMerger
import locus.api.mapper.Util
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
import timber.log.Timber
-import java.util.Locale
class UpdateViewModel(
- private val context: Context,
+ private val context: Application,
private val accountManager: AccountManager,
private val defaultPreferenceManager: DefaultPreferenceManager,
private val getPointFromGeocacheCode: GetPointFromGeocacheCodeUseCase,
@@ -85,13 +84,9 @@ class UpdateViewModel(
getPointFromGeocacheCode(updateData.geocacheCode, lite, logsCount)
if (updateData.downloadLogs) {
- var progress = updateData.newPoint.gcData.logs.count()
+ var progress = updateData.newPoint.gcData?.logs?.count() ?: 0
- logsCount = if (updateData.downloadLogs) {
- AppConstants.LOGS_TO_UPDATE_MAX
- } else {
- defaultPreferenceManager.downloadingGeocacheLogsCount
- }
+ logsCount = AppConstants.LOGS_TO_UPDATE_MAX
updateProgress(
R.string.progress_download_logs,
@@ -109,7 +104,7 @@ class UpdateViewModel(
it
}.toList()
- updateData.newPoint.gcData.logs.apply {
+ updateData.newPoint.gcData?.logs?.apply {
addAll(logs.flatten())
sortBy {
it.date
@@ -180,7 +175,7 @@ class UpdateViewModel(
val p = IntentHelper.getPointFromIntent(context, intent)
if (p?.gcData != null) {
- cacheId = p.gcData.cacheID
+ cacheId = p.gcData?.cacheID
oldPoint = p
}
} catch (t: Throwable) {
@@ -197,7 +192,7 @@ class UpdateViewModel(
}
}
- if (cacheId == null || !cacheId.toUpperCase(Locale.US).startsWith("GC")) {
+ if (cacheId == null || !cacheId.uppercase().startsWith("GC")) {
Timber.e("cacheId/simpleCacheId not found")
return null
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/weblink/BookmarkGeocacheWebLinkViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/weblink/BookmarkGeocacheWebLinkViewModel.kt
index 509b8529..ac7c6c3b 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/weblink/BookmarkGeocacheWebLinkViewModel.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/weblink/BookmarkGeocacheWebLinkViewModel.kt
@@ -7,8 +7,11 @@ import com.arcao.geocaching4locus.base.usecase.GetPointFromGeocacheCodeUseCase
import com.arcao.geocaching4locus.data.account.AccountManager
import com.arcao.geocaching4locus.data.api.model.GeocacheType
import com.arcao.geocaching4locus.error.handler.ExceptionHandler
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
import locus.api.objects.geocaching.GeocachingData
+import locus.api.objects.geocaching.GeocachingData.Companion.CACHE_TYPE_COMMUNITY_CELEBRATION
+import locus.api.objects.geocaching.GeocachingData.Companion.CACHE_TYPE_GC_HQ
+import locus.api.objects.geocaching.GeocachingData.Companion.CACHE_TYPE_GC_HQ_CELEBRATION
import java.util.Locale
import java.util.regex.Pattern
@@ -17,20 +20,25 @@ class BookmarkGeocacheWebLinkViewModel(
getPointFromGeocacheCode: GetPointFromGeocacheCodeUseCase,
exceptionHandler: ExceptionHandler,
dispatcherProvider: CoroutinesDispatcherProvider
-) : WebLinkViewModel(accountManager, getPointFromGeocacheCode, exceptionHandler, dispatcherProvider) {
+) : WebLinkViewModel(
+ accountManager,
+ getPointFromGeocacheCode,
+ exceptionHandler,
+ dispatcherProvider
+) {
override val isPremiumMemberRequired: Boolean
get() = true
override fun isRefreshRequired(point: Point): Boolean {
- return point.gcData != null &&
- !point.gcData.cacheUrl.isNullOrEmpty() &&
- getGuid(point.gcData.cacheUrl) == null
+ val gcData = point.gcData
+ return gcData != null && gcData.cacheUrl.isNotEmpty() && getGuid(gcData.cacheUrl) == null
}
override fun getWebLink(point: Point): Uri {
- val guid = getGuid(point.gcData.cacheUrl)
- val cacheType = getCacheType(point.gcData.type)
+ val gcData = requireNotNull(point.gcData)
+ val guid = getGuid(gcData.cacheUrl)
+ val cacheType = getCacheType(gcData.type)
return if (BuildConfig.GEOCACHING_API_STAGING) {
Uri.parse(String.format(Locale.ROOT, URL_FORMAT_STAGING, guid, cacheType))
@@ -53,11 +61,11 @@ class BookmarkGeocacheWebLinkViewModel(
GeocachingData.CACHE_TYPE_EARTH -> return GeocacheType.EARTHCACHE
GeocachingData.CACHE_TYPE_EVENT -> return GeocacheType.EVENT
GeocachingData.CACHE_TYPE_GPS_ADVENTURE -> return GeocacheType.GPS_ADVENTURES_EXHIBIT
- GeocachingData.CACHE_TYPE_GROUNDSPEAK -> return GeocacheType.GEOCACHING_HQ
- GeocachingData.CACHE_TYPE_LF_CELEBRATION -> return GeocacheType.GEOCACHING_LOST_AND_FOUND_CELEBRATION
+ CACHE_TYPE_GC_HQ -> return GeocacheType.GEOCACHING_HQ
+ CACHE_TYPE_GC_HQ_CELEBRATION -> return GeocacheType.GEOCACHING_LOST_AND_FOUND_CELEBRATION
GeocachingData.CACHE_TYPE_LETTERBOX -> return GeocacheType.LETTERBOX_HYBRID
GeocachingData.CACHE_TYPE_LOCATIONLESS -> return GeocacheType.LOCATIONLESS_CACHE
- GeocachingData.CACHE_TYPE_LF_EVENT -> return GeocacheType.LOST_AND_FOUND_EVENT_CACHE
+ CACHE_TYPE_COMMUNITY_CELEBRATION -> return GeocacheType.LOST_AND_FOUND_EVENT_CACHE
GeocachingData.CACHE_TYPE_MEGA_EVENT -> return GeocacheType.MEGA_EVENT
GeocachingData.CACHE_TYPE_MULTI -> return GeocacheType.MULTI_CACHE
GeocachingData.CACHE_TYPE_PROJECT_APE -> return GeocacheType.PROJECT_APE
@@ -72,8 +80,11 @@ class BookmarkGeocacheWebLinkViewModel(
}
companion object {
- private const val URL_FORMAT = "https://www.geocaching.com/bookmarks/mark.aspx?guid=%s&WptTypeID=%d"
- private const val URL_FORMAT_STAGING = "https://staging.geocaching.com/bookmarks/mark.aspx?guid=%s&WptTypeID=%d"
- private val GUID_URL_PATTERN = Pattern.compile("guid=([a-f0-9-]+)", Pattern.CASE_INSENSITIVE)
+ private const val URL_FORMAT =
+ "https://www.geocaching.com/bookmarks/mark.aspx?guid=%s&WptTypeID=%d"
+ private const val URL_FORMAT_STAGING =
+ "https://staging.geocaching.com/bookmarks/mark.aspx?guid=%s&WptTypeID=%d"
+ private val GUID_URL_PATTERN =
+ Pattern.compile("guid=([a-f0-9-]+)", Pattern.CASE_INSENSITIVE)
}
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/weblink/WatchGeocacheWebLinkViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/weblink/WatchGeocacheWebLinkViewModel.kt
index 75148dd9..8a9eca5e 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/weblink/WatchGeocacheWebLinkViewModel.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/weblink/WatchGeocacheWebLinkViewModel.kt
@@ -7,7 +7,7 @@ import com.arcao.geocaching4locus.base.usecase.GetPointFromGeocacheCodeUseCase
import com.arcao.geocaching4locus.data.account.AccountManager
import com.arcao.geocaching4locus.data.api.util.ReferenceCode
import com.arcao.geocaching4locus.error.handler.ExceptionHandler
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
import java.util.Locale
class WatchGeocacheWebLinkViewModel(
@@ -18,7 +18,8 @@ class WatchGeocacheWebLinkViewModel(
) : WebLinkViewModel(accountManager, getPointFromGeocacheCode, exceptionHandler, dispatcherProvider) {
override fun getWebLink(point: Point): Uri {
- val cacheId = ReferenceCode.toId(point.gcData.cacheID)
+ val gcData = requireNotNull(point.gcData)
+ val cacheId = ReferenceCode.toId(gcData.cacheID)
return if (BuildConfig.GEOCACHING_API_STAGING) {
Uri.parse(String.format(Locale.ROOT, URL_FORMAT_STAGING, cacheId))
diff --git a/app/src/main/java/com/arcao/geocaching4locus/weblink/WebLinkActivity.kt b/app/src/main/java/com/arcao/geocaching4locus/weblink/WebLinkActivity.kt
index 9e1f8f7e..2cf1c5be 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/weblink/WebLinkActivity.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/weblink/WebLinkActivity.kt
@@ -1,26 +1,30 @@
package com.arcao.geocaching4locus.weblink
import android.app.Activity
-import android.content.Intent
import android.os.Bundle
-import androidx.annotation.Nullable
import com.arcao.geocaching4locus.R
-import com.arcao.geocaching4locus.authentication.util.requestSignOn
+import com.arcao.geocaching4locus.authentication.LoginActivity
import com.arcao.geocaching4locus.base.AbstractActionBarActivity
import com.arcao.geocaching4locus.base.util.exhaustive
import com.arcao.geocaching4locus.base.util.showWebPage
import com.arcao.geocaching4locus.base.util.withObserve
-import com.arcao.geocaching4locus.data.account.AccountManager
import com.arcao.geocaching4locus.error.ErrorActivity
import locus.api.android.utils.IntentHelper
-import org.koin.android.ext.android.inject
import timber.log.Timber
abstract class WebLinkActivity : AbstractActionBarActivity() {
protected abstract val viewModel: WebLinkViewModel
- private val accountManager by inject()
- override fun onCreate(@Nullable savedInstanceState: Bundle?) {
+ private val loginActivity = registerForActivityResult(LoginActivity.Contract) { success ->
+ if (success) {
+ processIntent()
+ } else {
+ setResult(Activity.RESULT_CANCELED)
+ finish()
+ }
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.progress.withObserve(this, ::handleProgress)
@@ -56,8 +60,7 @@ abstract class WebLinkActivity : AbstractActionBarActivity() {
@Suppress("IMPLICIT_CAST_TO_ANY")
private fun handleAction(action: WebLinkAction) {
when (action) {
- WebLinkAction.SignIn ->
- accountManager.requestSignOn(this, REQUEST_SIGN_ON)
+ WebLinkAction.SignIn -> loginActivity.launch(null)
is WebLinkAction.ShowUri -> {
if (showWebPage(action.uri)) {
setResult(Activity.RESULT_OK)
@@ -76,28 +79,13 @@ abstract class WebLinkActivity : AbstractActionBarActivity() {
finish()
}
WebLinkAction.PremiumMembershipRequired -> {
- startActivity(ErrorActivity.IntentBuilder(this).message(R.string.error_premium_feature).build())
+ startActivity(
+ ErrorActivity.IntentBuilder(this).message(R.string.error_premium_feature)
+ .build()
+ )
setResult(Activity.RESULT_CANCELED)
finish()
}
}.exhaustive
}
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- super.onActivityResult(requestCode, resultCode, data)
-
- // restart update process after log in
- if (requestCode == REQUEST_SIGN_ON) {
- if (resultCode == Activity.RESULT_OK) {
- processIntent()
- } else {
- setResult(Activity.RESULT_CANCELED)
- finish()
- }
- }
- }
-
- companion object {
- private const val REQUEST_SIGN_ON = 1
- }
}
diff --git a/app/src/main/java/com/arcao/geocaching4locus/weblink/WebLinkViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/weblink/WebLinkViewModel.kt
index cec0271c..e757b3ba 100644
--- a/app/src/main/java/com/arcao/geocaching4locus/weblink/WebLinkViewModel.kt
+++ b/app/src/main/java/com/arcao/geocaching4locus/weblink/WebLinkViewModel.kt
@@ -11,7 +11,7 @@ import com.arcao.geocaching4locus.base.util.invoke
import com.arcao.geocaching4locus.data.account.AccountManager
import com.arcao.geocaching4locus.error.handler.ExceptionHandler
import kotlinx.coroutines.Job
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
abstract class WebLinkViewModel(
private val accountManager: AccountManager,
@@ -32,7 +32,8 @@ abstract class WebLinkViewModel(
}
fun resolveUri(point: Point) {
- if (point.gcData == null || point.gcData.cacheID.isNullOrEmpty()) {
+ val gcData = point.gcData
+ if (gcData == null || gcData.cacheID.isEmpty()) {
action(WebLinkAction.Cancel)
return
}
@@ -57,7 +58,7 @@ abstract class WebLinkViewModel(
}
val newPoint = showProgress(R.string.progress_download_geocache) {
- getPointFromGeocacheCode(point.gcData.cacheID)
+ getPointFromGeocacheCode(gcData.cacheID)
}
getWebLink(newPoint)
}
diff --git a/app/src/main/java/locus/api/android/ActionDisplayInternal.kt b/app/src/main/java/locus/api/android/ActionDisplayInternal.kt
deleted file mode 100644
index 7ceb21ed..00000000
--- a/app/src/main/java/locus/api/android/ActionDisplayInternal.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package locus.api.android
-
-import android.content.Context
-import android.content.Intent
-import locus.api.android.utils.exceptions.RequiredVersionMissingException
-
-object ActionDisplayInternal {
- @Throws(RequiredVersionMissingException::class)
- internal fun sendData(
- action: String,
- context: Context,
- intent: Intent,
- callImport: Boolean,
- center: Boolean
- ): Boolean = ActionDisplay.sendData(action, context, intent, callImport, center)
-}
\ No newline at end of file
diff --git a/app/src/main/java/locus/api/extension/LocationExt.kt b/app/src/main/java/locus/api/extension/LocationExt.kt
index 2c5ecbf4..3fd1a8c9 100644
--- a/app/src/main/java/locus/api/extension/LocationExt.kt
+++ b/app/src/main/java/locus/api/extension/LocationExt.kt
@@ -9,5 +9,5 @@ fun Location?.isInvalid(): Boolean {
contract {
returns(false) implies (this@isInvalid is Location)
}
- return this == null || getLatitude().isNaN() || getLongitude().isNaN()
+ return this == null || latitude.isNaN() || longitude.isNaN()
}
diff --git a/app/src/main/java/locus/api/manager/LocusMapManager.kt b/app/src/main/java/locus/api/manager/LocusMapManager.kt
index ab8c3087..e437d605 100644
--- a/app/src/main/java/locus/api/manager/LocusMapManager.kt
+++ b/app/src/main/java/locus/api/manager/LocusMapManager.kt
@@ -1,6 +1,5 @@
package locus.api.manager
-import android.content.BroadcastReceiver
import android.content.ClipData
import android.content.Context
import android.content.Intent
@@ -9,18 +8,15 @@ import com.arcao.geocaching4locus.base.constants.AppConstants
import com.arcao.geocaching4locus.error.exception.LocusMapRuntimeException
import locus.api.android.ActionBasics
import locus.api.android.ActionDisplayPoints
-import locus.api.android.ActionTools
import locus.api.android.objects.PackPoints
import locus.api.android.utils.IntentHelper
import locus.api.android.utils.LocusConst
import locus.api.android.utils.LocusUtils
-import locus.api.android.utils.exceptions.RequiredVersionMissingException
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
import timber.log.Timber
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
-import kotlin.reflect.KClass
class LocusMapManager(
private val context: Context
@@ -33,7 +29,10 @@ class LocusMapManager(
ActionBasics.getLocusInfo(context, locusVersion)?.isPeriodicUpdatesEnabled
?: false
} catch (e: Throwable) {
- Timber.e(e, "Unable to receive info about periodic update state from Locus Map.")
+ Timber.e(
+ e,
+ "Unable to receive info about periodic update state from Locus Map."
+ )
return true
}
} else {
@@ -42,10 +41,8 @@ class LocusMapManager(
}
val isLocusMapNotInstalled: Boolean
- get() {
- val lv = LocusUtils.getActiveVersion(context)
- return lv == null || !lv.isVersionValid(AppConstants.LOCUS_MIN_VERSION_CODE)
- }
+ get() = LocusUtils.getActiveVersion(context)
+ ?.isVersionValid(AppConstants.LOCUS_MIN_VERSION_CODE)?.not() ?: false
fun createSendPointsIntent(callImport: Boolean, center: Boolean): Intent {
val uri = FileProvider.getUriForFile(context, "${context.packageName}.provider", cacheFile)
@@ -111,37 +108,14 @@ class LocusMapManager(
* @param packName name of pack
* @throws LocusMapRuntimeException exception in case ane exception occurs while Locus Map API calls
*/
- @Throws(RequiredVersionMissingException::class)
fun removePackFromLocus(packName: String) {
try {
- // create empty pack
- val pw = PackPoints(packName)
-
- // create and send intent
- val intent = Intent()
- intent.putExtra(LocusConst.INTENT_EXTRA_POINTS_DATA, pw.asBytes)
- ActionDisplayPoints.sendPackSilent(context, pw, false)
+ ActionDisplayPoints.removePackFromLocus(context, packName)
} catch (t: Throwable) {
throw LocusMapRuntimeException(t)
}
}
- // make sure Live Map broadcast receiver is always enabled
- fun enablePeriodicUpdatesReceiver(clazz: KClass) {
- try {
- val locusVersion = LocusUtils.getActiveVersion(context)
- if (locusVersion != null) {
- ActionTools.enablePeriodicUpdatesReceiver(
- context,
- locusVersion,
- clazz.java
- )
- }
- } catch (e: Throwable) {
- Timber.e(e, "Unable to enable ${clazz.java.simpleName}.")
- }
- }
-
@Throws(LocusMapRuntimeException::class)
fun sendPointsSilent(packName: String, points: List, centerOnData: Boolean = false) {
try {
diff --git a/app/src/main/java/locus/api/mapper/DataMapper.kt b/app/src/main/java/locus/api/mapper/DataMapper.kt
index 9ed2e9e8..ab770972 100644
--- a/app/src/main/java/locus/api/mapper/DataMapper.kt
+++ b/app/src/main/java/locus/api/mapper/DataMapper.kt
@@ -3,7 +3,7 @@ package locus.api.mapper
import com.arcao.geocaching4locus.data.api.model.Geocache
import com.arcao.geocaching4locus.data.api.model.GeocacheLog
import com.arcao.geocaching4locus.data.api.model.Trackable
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
import locus.api.utils.addIgnoreNull
class DataMapper(
diff --git a/app/src/main/java/locus/api/mapper/GeocacheConverter.kt b/app/src/main/java/locus/api/mapper/GeocacheConverter.kt
index 4395daf1..808d2bda 100644
--- a/app/src/main/java/locus/api/mapper/GeocacheConverter.kt
+++ b/app/src/main/java/locus/api/mapper/GeocacheConverter.kt
@@ -15,9 +15,10 @@ import com.arcao.geocaching4locus.data.api.util.ReferenceCode
import com.arcao.geocaching4locus.settings.manager.DefaultPreferenceManager
import locus.api.mapper.Util.applyUnavailabilityForGeocache
import locus.api.objects.extra.Location
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
import locus.api.objects.geocaching.GeocachingAttribute
import locus.api.objects.geocaching.GeocachingData
+import locus.api.objects.geocaching.GeocachingImage
import timber.log.Timber
import java.text.ParseException
import java.util.regex.Pattern
@@ -31,9 +32,10 @@ class GeocacheConverter(
private val waypointConverter: WaypointConverter
) {
fun createLocusPoint(cache: Geocache): Point {
- val loc = Location()
- .setLatitude(cache.postedCoordinates?.latitude ?: throw IllegalArgumentException("Coordinates missing"))
- .setLongitude(cache.postedCoordinates?.longitude ?: throw IllegalArgumentException("Coordinates missing"))
+ val loc = Location().apply {
+ latitude = requireNotNull(cache.postedCoordinates?.latitude) { "Coordinates missing" }
+ longitude = requireNotNull(cache.postedCoordinates?.longitude) { "Coordinates missing" }
+ }
val p = Point(cache.name, loc).apply {
gcData = GeocachingData().apply {
@@ -44,12 +46,12 @@ class GeocacheConverter(
type = cache.geocacheType.toLocusMapGeocacheType()
difficulty = cache.difficulty ?: 1F
terrain = cache.terrain ?: 1F
- owner = cache.owner?.username ?: cache.ownerAlias
- placedBy = cache.ownerAlias
+ owner = cache.owner?.username ?: cache.ownerAlias.orEmpty()
+ placedBy = cache.ownerAlias.orEmpty()
isAvailable = cache.status == GeocacheStatus.ACTIVE
isArchived = cache.status == GeocacheStatus.ARCHIVED
isPremiumOnly = cache.isPremiumOnly ?: false
- cacheUrl = cache.url
+ cacheUrl = cache.url.orEmpty()
dateHidden = cache.placedDateInstant?.toEpochMilli() ?: 0
datePublished = cache.publishedDateInstant?.toEpochMilli() ?: 0
@@ -58,19 +60,23 @@ class GeocacheConverter(
container = cache.geocacheSize.getLocusMapGeocacheSize()
isFound = cache.userData?.foundDate != null
- country = cache.location?.country
- state = cache.location?.state
+ country = cache.location?.country.orEmpty()
+ state = cache.location?.state.orEmpty()
setDescriptions(
- BadBBCodeFixer.fix(cache.shortDescription), cache.containsHtml ?: false,
- BadBBCodeFixer.fix(cache.longDescription), cache.containsHtml ?: false
+ BadBBCodeFixer.fix(cache.shortDescription).orEmpty(),
+ cache.containsHtml ?: false,
+ BadBBCodeFixer.fix(cache.longDescription).orEmpty(),
+ cache.containsHtml ?: false
)
- encodedHints = cache.hints
- notes = cache.userData?.note
+ encodedHints = cache.hints.orEmpty()
+ notes = cache.userData?.note.orEmpty()
favoritePoints = cache.favoritePoints ?: 0
- for (image in cache.images.orEmpty()) {
- addImage(imageDataConverter.createLocusGeocachingImage(image))
+ images = mutableListOf().apply {
+ for (image in cache.images.orEmpty()) {
+ imageDataConverter.createLocusGeocachingImage(image)?.let(this::add)
+ }
}
for (attribute in cache.attributes.orEmpty()) {
@@ -88,7 +94,10 @@ class GeocacheConverter(
updateGeocacheLocationByCorrectedCoordinates(p, cache)
if (defaultPreferenceManager.disableDnfNmNaGeocaches)
- applyUnavailabilityForGeocache(p, defaultPreferenceManager.disableDnfNmNaGeocachesThreshold)
+ applyUnavailabilityForGeocache(
+ p,
+ defaultPreferenceManager.disableDnfNmNaGeocachesThreshold
+ )
return p
}
@@ -99,12 +108,12 @@ class GeocacheConverter(
GeocacheType.EARTHCACHE -> GeocachingData.CACHE_TYPE_EARTH
GeocacheType.EVENT -> GeocachingData.CACHE_TYPE_EVENT
GeocacheType.GPS_ADVENTURES_EXHIBIT -> GeocachingData.CACHE_TYPE_GPS_ADVENTURE
- GeocacheType.GEOCACHING_BLOCK_PARTY -> GeocachingData.CACHE_TYPE_GROUNDSPEAK
- GeocacheType.GEOCACHING_HQ -> GeocachingData.CACHE_TYPE_GROUNDSPEAK
- GeocacheType.GEOCACHING_LOST_AND_FOUND_CELEBRATION -> GeocachingData.CACHE_TYPE_LF_CELEBRATION
+ GeocacheType.GEOCACHING_BLOCK_PARTY -> GeocachingData.CACHE_TYPE_GC_HQ
+ GeocacheType.GEOCACHING_HQ -> GeocachingData.CACHE_TYPE_GC_HQ
+ GeocacheType.GEOCACHING_LOST_AND_FOUND_CELEBRATION -> GeocachingData.CACHE_TYPE_GC_HQ_CELEBRATION
GeocacheType.LETTERBOX_HYBRID -> GeocachingData.CACHE_TYPE_LETTERBOX
GeocacheType.LOCATIONLESS_CACHE -> GeocachingData.CACHE_TYPE_LOCATIONLESS
- GeocacheType.LOST_AND_FOUND_EVENT_CACHE -> GeocachingData.CACHE_TYPE_LF_EVENT
+ GeocacheType.LOST_AND_FOUND_EVENT_CACHE -> GeocachingData.CACHE_TYPE_COMMUNITY_CELEBRATION
GeocacheType.MEGA_EVENT -> GeocachingData.CACHE_TYPE_MEGA_EVENT
GeocacheType.MULTI_CACHE -> GeocachingData.CACHE_TYPE_MULTI
GeocacheType.PROJECT_APE -> GeocachingData.CACHE_TYPE_PROJECT_APE
@@ -124,7 +133,7 @@ class GeocacheConverter(
GeocacheSize.MICRO -> GeocachingData.CACHE_SIZE_MICRO
GeocacheSize.NOT_CHOSEN -> GeocachingData.CACHE_SIZE_NOT_CHOSEN
GeocacheSize.OTHER -> GeocachingData.CACHE_SIZE_OTHER
- GeocacheSize.MEDIUM -> GeocachingData.CACHE_SIZE_REGULAR
+ GeocacheSize.REGULAR -> GeocachingData.CACHE_SIZE_REGULAR
GeocacheSize.SMALL -> GeocachingData.CACHE_SIZE_SMALL
else -> GeocachingData.CACHE_SIZE_OTHER
}
@@ -137,17 +146,18 @@ class GeocacheConverter(
val location = p.location
- p.gcData.apply {
+ p.gcData?.apply {
isComputed = true
- latOriginal = location.getLatitude()
- lonOriginal = location.getLongitude()
+ latOriginal = location.latitude
+ lonOriginal = location.longitude
}
// update coordinates to new location
location.set(
- Location()
- .setLatitude(correctedCoordinates.latitude)
- .setLongitude(correctedCoordinates.longitude)
+ Location().apply {
+ latitude = correctedCoordinates.latitude
+ longitude = correctedCoordinates.longitude
+ }
)
}
@@ -239,9 +249,11 @@ class GeocacheConverter(
companion object {
private val WAYPOINT_BASE_ID = ReferenceCode.base31Decode("N0")
- private val FINAL_WAYPOINT_NAME_PATTERN = Pattern.compile("fin[a|á]+[l|ł]", Pattern.CASE_INSENSITIVE)
+ private val FINAL_WAYPOINT_NAME_PATTERN =
+ Pattern.compile("fin[a|á]+[l|ł]", Pattern.CASE_INSENSITIVE)
- private val NOTE_COORDINATE_PATTERN = Pattern.compile("\\b[nNsS]\\s*\\d") // begin of coordinates
+ private val NOTE_COORDINATE_PATTERN =
+ Pattern.compile("\\b[nNsS]\\s*\\d") // begin of coordinates
private val NOTE_NAME_PATTERN = Pattern.compile("^(.+):\\s*\\z")
}
}
diff --git a/app/src/main/java/locus/api/mapper/GeocacheLogConverter.kt b/app/src/main/java/locus/api/mapper/GeocacheLogConverter.kt
index d7607f1a..cddba544 100644
--- a/app/src/main/java/locus/api/mapper/GeocacheLogConverter.kt
+++ b/app/src/main/java/locus/api/mapper/GeocacheLogConverter.kt
@@ -2,7 +2,7 @@ package locus.api.mapper
import com.arcao.geocaching4locus.data.api.model.GeocacheLog
import com.arcao.geocaching4locus.data.api.model.GeocacheLogType
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
import locus.api.objects.geocaching.GeocachingLog
import locus.api.utils.addIgnoreNull
@@ -15,7 +15,7 @@ class GeocacheLogConverter(
return
for (log in logs) {
- point.gcData.logs.addIgnoreNull(createLocusGeocachingLog(log))
+ point.gcData?.logs?.addIgnoreNull(createLocusGeocachingLog(log))
}
sortLocusGeocachingLogsByDate(point)
@@ -29,18 +29,18 @@ class GeocacheLogConverter(
return GeocachingLog().apply {
id = log.id
date = log.loggedDateInstant?.toEpochMilli() ?: 0
- logText = log.text
+ logText = log.text.orEmpty()
type = log.geocacheLogType.toLocusMapLogType()
val author = log.owner
if (author != null) {
- finder = author.username
+ finder = author.username.orEmpty()
findersFound = author.findCount
findersId = author.id
}
for (image in log.images ?: emptyList()) {
- addImage(imageDataConverter.createLocusGeocachingImage(image))
+ imageDataConverter.createLocusGeocachingImage(image)?.let(this::addImage)
}
log.updatedCoordinates?.let { coordinates ->
cooLat = coordinates.latitude
@@ -61,6 +61,7 @@ class GeocacheLogConverter(
GeocacheLogType.OWNER_MAINTENANCE -> GeocachingLog.CACHE_LOG_TYPE_OWNER_MAINTENANCE
GeocacheLogType.POST_REVIEWER_NOTE -> GeocachingLog.CACHE_LOG_TYPE_POST_REVIEWER_NOTE
GeocacheLogType.PUBLISH_LISTING -> GeocachingLog.CACHE_LOG_TYPE_PUBLISH_LISTING
+ GeocacheLogType.RETRACT_LISTING -> GeocachingLog.CACHE_LOG_TYPE_RETRACT_LISTING
GeocacheLogType.TEMPORARILY_DISABLE_LISTING -> GeocachingLog.CACHE_LOG_TYPE_TEMPORARILY_DISABLE_LISTING
GeocacheLogType.UPDATE_COORDINATES -> GeocachingLog.CACHE_LOG_TYPE_UPDATE_COORDINATES
GeocacheLogType.WEBCAM_PHOTO_TAKEN -> GeocachingLog.CACHE_LOG_TYPE_WEBCAM_PHOTO_TAKEN
@@ -68,6 +69,7 @@ class GeocacheLogConverter(
GeocacheLogType.WRITE_NOTE -> GeocachingLog.CACHE_LOG_TYPE_WRITE_NOTE
GeocacheLogType.ARCHIVE -> GeocachingLog.CACHE_LOG_TYPE_ARCHIVE
GeocacheLogType.UNARCHIVE -> GeocachingLog.CACHE_LOG_TYPE_UNARCHIVE
+ GeocacheLogType.SUBMIT_FOR_REVIEW -> GeocachingLog.CACHE_LOG_TYPE_WRITE_NOTE
else -> GeocachingLog.CACHE_LOG_TYPE_WRITE_NOTE
}
}
@@ -76,7 +78,6 @@ class GeocacheLogConverter(
if (waypoint.gcData?.logs?.isEmpty() != false)
return
- // Note: Long.compareTo was introduced in API 19
- waypoint.gcData.logs.sortWith(Comparator { lhs, rhs -> if (lhs.date < rhs.date) 1 else if (lhs.date == rhs.date) 0 else -1 })
+ waypoint.gcData?.logs?.sortWith { lhs, rhs -> lhs.date.compareTo(rhs.date) }
}
}
diff --git a/app/src/main/java/locus/api/mapper/ImageDataConverter.kt b/app/src/main/java/locus/api/mapper/ImageDataConverter.kt
index 95a36271..7f38a7ab 100644
--- a/app/src/main/java/locus/api/mapper/ImageDataConverter.kt
+++ b/app/src/main/java/locus/api/mapper/ImageDataConverter.kt
@@ -11,9 +11,9 @@ class ImageDataConverter {
return null
return GeocachingImage().apply {
- name = imageData.description
- description = imageData.description
- thumbUrl = imageData.thumbnailUrl
+ name = imageData.description.orEmpty()
+ description = imageData.description.orEmpty()
+ thumbUrl = imageData.thumbnailUrl.orEmpty()
url = imageData.url
}
}
diff --git a/app/src/main/java/locus/api/mapper/PointMerger.kt b/app/src/main/java/locus/api/mapper/PointMerger.kt
index bed96561..7c8bfa33 100644
--- a/app/src/main/java/locus/api/mapper/PointMerger.kt
+++ b/app/src/main/java/locus/api/mapper/PointMerger.kt
@@ -3,7 +3,7 @@ package locus.api.mapper
import com.arcao.geocaching4locus.settings.manager.DefaultPreferenceManager
import locus.api.mapper.Util.GSAK_USERNAME
import locus.api.mapper.Util.applyUnavailabilityForGeocache
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
import locus.api.objects.geocaching.GeocachingLog
class PointMerger(
@@ -12,11 +12,11 @@ class PointMerger(
fun mergePoints(dest: Point, src: Point?) {
dest.removeExtraOnDisplay()
- if (src?.gcData == null)
- return
+ val srcGcData = src?.gcData ?: return
+ val destGcData = dest.gcData ?: return
copyArchivedGeocacheLocation(dest, src)
- copyGsakGeocachingLogs(dest.gcData.logs, src.gcData.logs)
+ copyGsakGeocachingLogs(destGcData.logs, srcGcData.logs)
copyComputedCoordinates(dest, src)
copyPointId(dest, src)
copyGcVote(dest, src)
@@ -33,20 +33,26 @@ class PointMerger(
return
// store original logs
- val originalLogs = ArrayList(dest.gcData.logs)
+ val originalLogs = ArrayList(dest.gcData?.logs.orEmpty())
// replace logs with new one
- dest.gcData.logs.apply {
+ dest.gcData?.logs?.apply {
clear()
- addAll(src.gcData.logs)
+ src.gcData?.logs?.let(this::addAll)
}
// copy GSAK logs from original logs
- copyGsakGeocachingLogs(dest.gcData.logs, originalLogs)
+ copyGsakGeocachingLogs(dest.gcData?.logs, originalLogs)
}
// issue #14: Keep cache logs from GSAK when updating cache
- private fun copyGsakGeocachingLogs(dest: MutableList, src: List) {
+ private fun copyGsakGeocachingLogs(
+ dest: MutableList?,
+ src: List?
+ ) {
+ src ?: return
+ dest ?: return
+
for (fromLog in src.reversed()) {
if (GSAK_USERNAME.equals(fromLog.finder, ignoreCase = true)) {
fromLog.date = System.currentTimeMillis()
@@ -57,40 +63,40 @@ class PointMerger(
// issue #13: Use old coordinates when cache is archived after update
private fun copyArchivedGeocacheLocation(dest: Point, src: Point) {
- if (src.gcData == null || dest.gcData == null)
- return
+ val srcGcData = src.gcData ?: return
+ val destGcData = dest.gcData ?: return
- val latitude = src.location.getLatitude()
- val longitude = src.location.getLongitude()
+ val latitude = src.location.latitude
+ val longitude = src.location.longitude
// are valid coordinates
- if (java.lang.Double.isNaN(latitude) || java.lang.Double.isNaN(longitude) || latitude == 0.0 && longitude == 0.0)
+ if (latitude.isNaN() || longitude.isNaN() || latitude == 0.0 && longitude == 0.0)
return
// is new point not archived or has computed coordinates
- if (!dest.gcData.isArchived || src.gcData.isComputed)
+ if (!destGcData.isArchived || srcGcData.isComputed)
return
// store coordinates to new point
dest.location.apply {
- setLatitude(latitude)
- setLongitude(longitude)
+ this.latitude = latitude
+ this.longitude = longitude
}
}
// Copy computed coordinates to new point
private fun copyComputedCoordinates(dest: Point, src: Point) {
- if (src.gcData == null || dest.gcData == null)
- return
+ val srcGcData = src.gcData ?: return
+ val destGcData = dest.gcData ?: return
- if (!src.gcData.isComputed || dest.gcData.isComputed)
+ if (!srcGcData.isComputed || destGcData.isComputed)
return
val location = dest.location
- dest.gcData.apply {
- latOriginal = location.getLatitude()
- lonOriginal = location.getLongitude()
+ destGcData.apply {
+ latOriginal = location.latitude
+ lonOriginal = location.longitude
isComputed = true
}
@@ -99,33 +105,36 @@ class PointMerger(
}
private fun copyPointId(dest: Point, src: Point) {
- if (src.getId() == 0L)
+ if (src.id == 0L)
return
- dest.setId(src.getId())
+ dest.id = src.id
}
private fun copyGcVote(dest: Point, src: Point) {
- if (src.gcData == null || dest.gcData == null)
- return
+ val srcGcData = src.gcData ?: return
+ val destGcData = dest.gcData ?: return
- dest.gcData.apply {
- gcVoteAverage = src.gcData.gcVoteAverage
- gcVoteNumOfVotes = src.gcData.gcVoteNumOfVotes
- gcVoteUserVote = src.gcData.gcVoteUserVote
+ destGcData.apply {
+ gcVoteAverage = srcGcData.gcVoteAverage
+ gcVoteNumOfVotes = srcGcData.gcVoteNumOfVotes
+ gcVoteUserVote = srcGcData.gcVoteUserVote
}
}
private fun copyEditedGeocachingWaypointLocation(dest: Point, src: Point) {
- if (dest.gcData?.waypoints?.isEmpty() != false || src.gcData.waypoints.isEmpty())
+ val destWaypoints = dest.gcData?.waypoints ?: return
+ val srcWaypoints = src.gcData?.waypoints ?: return
+
+ if (destWaypoints.isEmpty() || srcWaypoints.isEmpty())
return
// find Waypoint with zero coordinates
- for (waypoint in dest.gcData.waypoints) {
+ for (waypoint in destWaypoints) {
if (waypoint.lat == 0.0 && waypoint.lon == 0.0) {
// replace with coordinates from src Waypoint
- for (fromWaypoint in src.gcData.waypoints) {
+ for (fromWaypoint in srcWaypoints) {
if (waypoint.code.equals(fromWaypoint.code, ignoreCase = true)) {
waypoint.apply {
diff --git a/app/src/main/java/locus/api/mapper/TrackableConverter.kt b/app/src/main/java/locus/api/mapper/TrackableConverter.kt
index b27ef851..6b6b168e 100644
--- a/app/src/main/java/locus/api/mapper/TrackableConverter.kt
+++ b/app/src/main/java/locus/api/mapper/TrackableConverter.kt
@@ -1,15 +1,17 @@
package locus.api.mapper
import com.arcao.geocaching4locus.data.api.model.Trackable
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
import locus.api.objects.geocaching.GeocachingTrackable
class TrackableConverter {
fun addTrackables(point: Point, trackables: Collection) {
- if (point.gcData?.trackables == null || trackables.isEmpty())
+ val gcData = point.gcData ?: return
+
+ if (trackables.isEmpty())
return
- point.gcData.trackables.addAll(createLocusGeocachingTrackables(trackables))
+ gcData.trackables.addAll(createLocusGeocachingTrackables(trackables))
}
fun createLocusGeocachingTrackables(trackables: Collection): Collection {
@@ -25,8 +27,8 @@ class TrackableConverter {
id = trackable.id
imgUrl = trackable.iconUrl.orEmpty()
name = trackable.name
- originalOwner = trackable.owner.username
- currentOwner = trackable.owner.username
+ originalOwner = trackable.owner.username.orEmpty()
+ currentOwner = trackable.owner.username.orEmpty()
srcDetails = trackable.url.orEmpty()
released = trackable.releasedDate.toEpochMilli()
origin = trackable.originCountry.orEmpty()
diff --git a/app/src/main/java/locus/api/mapper/Util.kt b/app/src/main/java/locus/api/mapper/Util.kt
index ec5c8594..6ce028f1 100644
--- a/app/src/main/java/locus/api/mapper/Util.kt
+++ b/app/src/main/java/locus/api/mapper/Util.kt
@@ -1,7 +1,7 @@
package locus.api.mapper
import androidx.annotation.NonNull
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
import locus.api.objects.geocaching.GeocachingLog
object Util {
@@ -10,16 +10,18 @@ object Util {
fun applyUnavailabilityForGeocache(@NonNull point: Point, threshold: Int) {
var counter = 0
+ val gcData = point.gcData ?: return
+
// only when there is any log
- if (point.gcData?.logs?.isEmpty() != false)
+ if (gcData.logs.isEmpty())
return
// skip analyzing already archived geocache
- if (point.gcData.isArchived)
+ if (gcData.isArchived)
return
// go through all logs (must be sorted by visited date, newest first)
- val geocachingLogs = point.gcData.logs
+ val geocachingLogs = gcData.logs
loop@ for (log in geocachingLogs) {
// skip GSAK log
@@ -40,7 +42,7 @@ object Util {
// if counter contains required threshold
if (counter >= threshold) {
// set geocache as not available
- point.gcData.isAvailable = false
+ gcData.isAvailable = false
}
}
}
diff --git a/app/src/main/java/locus/api/mapper/WaypointConverter.kt b/app/src/main/java/locus/api/mapper/WaypointConverter.kt
index 555f9b7e..4f2dd572 100644
--- a/app/src/main/java/locus/api/mapper/WaypointConverter.kt
+++ b/app/src/main/java/locus/api/mapper/WaypointConverter.kt
@@ -3,30 +3,30 @@ package locus.api.mapper
import com.arcao.geocaching4locus.data.api.model.AdditionalWaypoint
import com.arcao.geocaching4locus.data.api.model.enums.AdditionalWaypointType
import com.arcao.geocaching4locus.data.api.util.ReferenceCode
-import locus.api.objects.extra.Point
+import locus.api.objects.geoData.Point
import locus.api.objects.geocaching.GeocachingWaypoint
-import locus.api.utils.addIgnoreNull
import locus.api.utils.isNullOrEmpty
class WaypointConverter {
fun addWaypoints(point: Point, waypoints: Collection?, geocacheId: Long) {
- if (point.gcData?.waypoints == null || waypoints.isNullOrEmpty())
+ val pointWaypoints = point.gcData?.waypoints ?: return
+
+ if (waypoints.isNullOrEmpty())
return
for (waypoint in waypoints) {
- point.gcData.waypoints.addIgnoreNull(createLocusGeocachingWaypoint(waypoint, geocacheId))
+ createLocusGeocachingWaypoint(waypoint, geocacheId)?.let(pointWaypoints::add)
}
}
private fun createLocusGeocachingWaypoint(waypoint: AdditionalWaypoint?, geocacheId: Long): GeocachingWaypoint? {
- if (waypoint == null)
- return null
+ waypoint ?: return null
return GeocachingWaypoint().apply {
code = ReferenceCode.toReferenceCode(waypoint.prefix, geocacheId)
lat = waypoint.coordinates?.latitude ?: 0.0
lon = waypoint.coordinates?.longitude ?: 0.0
- desc = waypoint.description
+ desc = waypoint.description.orEmpty()
name = waypoint.name
type = waypoint.type.toLocusMapWaypointType()
}
diff --git a/app/src/main/java/org/oshkimaadziig/george/androidutils/SpanFormatter.kt b/app/src/main/java/org/oshkimaadziig/george/androidutils/SpanFormatter.kt
index 9ef275ba..8544fd57 100644
--- a/app/src/main/java/org/oshkimaadziig/george/androidutils/SpanFormatter.kt
+++ b/app/src/main/java/org/oshkimaadziig/george/androidutils/SpanFormatter.kt
@@ -20,7 +20,6 @@ import android.text.SpannableString
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.SpannedString
-import androidx.annotation.NonNull
import java.util.Locale
import java.util.regex.Pattern
@@ -30,7 +29,8 @@ import java.util.regex.Pattern
* @author George T. Steel
*/
object SpanFormatter {
- private val FORMAT_SEQUENCE = Pattern.compile("%([0-9]+\\$|)([^a-zA-z%]*)([[a-zA-Z%]&&[^tT]]|[tT][a-zA-Z])")
+ private val FORMAT_SEQUENCE =
+ Pattern.compile("%([0-9]+\\$|)([^a-zA-z%]*)([a-zA-Z%&&[^tT]]|[tT][a-zA-Z])")
/**
* Version of [String.format] that works on [Spanned] strings to preserve rich text formatting.
@@ -108,9 +108,9 @@ object SpanFormatter {
return SpannedString(out)
}
- private fun spannedToUpperCase(@NonNull s: Spanned): Spanned {
+ private fun spannedToUpperCase(s: Spanned): Spanned {
val spans = s.getSpans(0, s.length, Any::class.java)
- val spannableString = SpannableString(s.toString().toUpperCase(Locale.getDefault()))
+ val spannableString = SpannableString(s.toString().uppercase())
// reapply the spans to the now uppercase string
for (span in spans) {
diff --git a/app/src/main/res/drawable-v21/btn_dashboard_bg.xml b/app/src/main/res/drawable-v21/btn_dashboard_bg.xml
deleted file mode 100644
index fd2a8cd3..00000000
--- a/app/src/main/res/drawable-v21/btn_dashboard_bg.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
- -
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/drawable/btn_dashboard_bg.xml b/app/src/main/res/drawable/btn_dashboard_bg.xml
index bc6ed12c..127f4752 100644
--- a/app/src/main/res/drawable/btn_dashboard_bg.xml
+++ b/app/src/main/res/drawable/btn_dashboard_bg.xml
@@ -1,24 +1,31 @@
- -
-
-
-
+
-
+
- -
-
-
-
-
+
-
+
+
-
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+
+
+
+
-
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_dashboard.xml b/app/src/main/res/layout/activity_dashboard.xml
index 588c7ab8..db7913f2 100644
--- a/app/src/main/res/layout/activity_dashboard.xml
+++ b/app/src/main/res/layout/activity_dashboard.xml
@@ -2,109 +2,110 @@
+
+ name="vm"
+ type="com.arcao.geocaching4locus.dashboard.DashboardViewModel" />
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ tools:context=".dashboard.DashboardActivity">
+ android:id="@+id/toolbar"
+ layout="@layout/toolbar"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent" />
+ android:id="@+id/db_search_nearest"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="8dp"
+ android:drawableTop="@drawable/ic_action_search"
+ android:onClick="@{() -> vm.onClickSearchNearest()}"
+ android:text="@string/menu_nearest"
+ app:layout_constraintEnd_toStartOf="@+id/db_import_gc"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/toolbar" />
+ android:id="@+id/db_import_gc"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:drawableTop="@drawable/ic_action_gc_input"
+ android:onClick="@{() -> vm.onClickImportGcCode()}"
+ android:text="@string/menu_import_from_gc"
+ app:layout_constraintEnd_toStartOf="@+id/db_import_bookmark"
+ app:layout_constraintStart_toEndOf="@+id/db_search_nearest"
+ app:layout_constraintTop_toTopOf="@+id/db_search_nearest" />
+ android:id="@+id/db_import_bookmark"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:drawableTop="@drawable/ic_action_import_bookmark"
+ android:enabled="@{vm.premium}"
+ android:onClick="@{() -> vm.onClickImportBookmarks()}"
+ android:text="@{vm.premium ? @string/menu_import_bookmarks : @string/format_premium(@string/menu_import_bookmarks)}"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@+id/db_import_gc"
+ app:layout_constraintTop_toTopOf="@+id/db_search_nearest"
+ tools:text="@string/menu_import_bookmarks" />
+ android:id="@+id/db_live_map"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:checked="@{safeUnbox(vm.liveMapEnabled)}"
+ android:drawableTop="@drawable/ic_action_live_map"
+ android:onClick="@{() -> vm.onClickLiveMap()}"
+ android:text="@string/menu_live_map"
+ app:layout_constraintEnd_toEndOf="@+id/db_search_nearest"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/db_search_nearest"
+ app:toggleable="true" />
+ android:id="@+id/db_live_map_download_caches"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:drawableTop="@drawable/ic_action_live_map_download_caches"
+ android:enabled="@{safeUnbox(vm.liveMapEnabled)}"
+ android:onClick="@{() -> vm.onClickImportLiveMapGc()}"
+ android:text="@string/menu_live_map_download_caches"
+ app:layout_constraintEnd_toStartOf="@+id/db_import_bookmark"
+ app:layout_constraintStart_toEndOf="@+id/db_search_nearest"
+ app:layout_constraintTop_toBottomOf="@+id/db_search_nearest" />
+ android:id="@+id/db_preferences"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:drawableTop="@drawable/ic_action_settings"
+ android:onClick="@{() -> vm.onClickPreferences()}"
+ android:text="@string/menu_settings"
+ app:layout_constraintEnd_toStartOf="@+id/db_live_map_download_caches"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@+id/db_live_map" />
+ android:id="@+id/db_users_guide"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:drawableTop="@drawable/ic_action_help"
+ android:onClick="@{() -> vm.onClickUsersGuide()}"
+ android:text="@string/menu_users_guide"
+ app:layout_constraintEnd_toEndOf="@+id/db_live_map_download_caches"
+ app:layout_constraintStart_toStartOf="@+id/db_live_map_download_caches"
+ app:layout_constraintTop_toTopOf="@+id/db_preferences" />
diff --git a/app/src/main/res/layout/activity_import_bookmark.xml b/app/src/main/res/layout/activity_import_bookmark.xml
index 6bffb447..b857c0eb 100644
--- a/app/src/main/res/layout/activity_import_bookmark.xml
+++ b/app/src/main/res/layout/activity_import_bookmark.xml
@@ -1,16 +1,19 @@
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:minHeight="400dp"
+ android:orientation="vertical"
+ tools:context=".import_bookmarks.ImportBookmarkActivity">
-
+
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml
index e4c50864..8a4131d1 100644
--- a/app/src/main/res/layout/activity_settings.xml
+++ b/app/src/main/res/layout/activity_settings.xml
@@ -6,9 +6,12 @@
android:orientation="vertical"
tools:context=".settings.SettingsActivity">
-
+
-
diff --git a/app/src/main/res/layout/fragment_bookmark.xml b/app/src/main/res/layout/fragment_bookmark.xml
index db9ea06f..2504ba17 100644
--- a/app/src/main/res/layout/fragment_bookmark.xml
+++ b/app/src/main/res/layout/fragment_bookmark.xml
@@ -10,6 +10,14 @@
+
+
+
+
+ android:visibility="@{isLoading ? View.GONE : View.VISIBLE}">
+ android:visibility="@{isEmpty ? View.VISIBLE : View.GONE}" />
+ xmlns:tools="http://schemas.android.com/tools">
-
+
+ name="vm"
+ type="com.arcao.geocaching4locus.import_bookmarks.fragment.BookmarkListViewModel" />
+
+
+
+
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/card_window_background"
+ tools:context="com.arcao.geocaching4locus.import_bookmarks.ImportBookmarkActivity">
+ android:id="@+id/progressContainer"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:orientation="vertical"
+ android:visibility="@{isLoading ? View.VISIBLE : View.GONE}">
+ style="?android:attr/progressBarStyleLarge"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+ android:id="@+id/listContainer"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="@{isLoading ? View.GONE : View.VISIBLE}">
+ android:id="@+id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scrollbarStyle="outsideOverlay"
+ android:scrollbars="vertical"
+ tools:listitem="@layout/view_bookmark_list_item" />
+ android:id="@+id/textEmpty"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center"
+ android:textAppearance="@style/TextAppearance.AppCompat.Body1"
+ android:visibility="@{isEmpty ? View.VISIBLE : View.GONE}" />
diff --git a/app/src/main/res/layout/toolbar.xml b/app/src/main/res/layout/toolbar.xml
index 37a4cbd8..363dd873 100644
--- a/app/src/main/res/layout/toolbar.xml
+++ b/app/src/main/res/layout/toolbar.xml
@@ -1,11 +1,9 @@
-
\ No newline at end of file
+ android:minHeight="?attr/actionBarSize"
+ app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
+ app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_bookmark_list_item.xml b/app/src/main/res/layout/view_bookmark_list_item.xml
index 21fc47c1..f61b054a 100644
--- a/app/src/main/res/layout/view_bookmark_list_item.xml
+++ b/app/src/main/res/layout/view_bookmark_list_item.xml
@@ -92,7 +92,6 @@
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/button"
app:layout_constraintTop_toBottomOf="@+id/divider"
- tools:targetApi="jelly_bean"
tools:text="3 geocaches"/>
Skjul geocaches på deaktiveret
Skjul live kort geocaches når live kort er deaktiveret
+ Deaktivér DNF-, NM- og NA-caches
Se geocache
Bogmærke geocache
Importer live-kortgeocacher
diff --git a/app/src/main/res/values-no/strings.xml b/app/src/main/res/values-no/strings.xml
index d56485d6..e32e0eca 100644
--- a/app/src/main/res/values-no/strings.xml
+++ b/app/src/main/res/values-no/strings.xml
@@ -1,10 +1,10 @@
- Laster ned cache
- Locus Map-programmet er ikke funnet, men Geocaching4Locus det krever å fungere ordentlig. Vennligst installer Locus Map.
+ Laster ned cacher…
+ Locus Map-programmet ble ikke funnet, men Geocaching4Locus det krever å fungere ordentlig. Vennligst installer Locus Map.
Vennligst slå på WiFi eller GPS posisjonering i innstillinger.
- Henter posisjon via GPS
- Henter posisjon via trådløst nettverk…
+ Henter posisjon fra GPS…
+ Henter posisjon fra trådløst nettverk…
Innstillinger
Feil koordinatformat!
Koordinater
@@ -17,8 +17,8 @@
OK
Locusversjonen din er for gamal. Du må ha versjon %s eller nyare for å fungera skikkeleg.
Avbryt
- Vis funne
- Vis funne caches
+ Vis funnede
+ Vis funnede cacher
Vis eigne løynde
Vis eigne løynde caches (løynde av deg)
Vel alle
@@ -166,7 +166,7 @@
Locus Map feil: %s
Klarer ikke å opprette datafil for Locus Map. Har du gitt skrivetilgang til lagring?
Autorisasjonskode
- Lim inn autorisasjonskoden fra Geocaching4Locus nettsted og klikk på Fortsett for å fullføre Logg på.
+ Lim inn autorisasjonskoden fra Geocaching4Locus nettstedet og klikk på Fortsett for å fullføre innloggingen.
Autorisasjonskode
Den angitte autorisasjonskoden er ikke gyldig. Vær så snill, prøv på nytt.
Geocaching API er for øyeblikket nede på grunn av vedlikehold. Prøv det senere.
diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml
index 5495e30b..c72ad91a 100644
--- a/app/src/main/res/values-ru/strings.xml
+++ b/app/src/main/res/values-ru/strings.xml
@@ -163,9 +163,11 @@
Описание
Ошибка Locus Map: %s
Не удается создать файл данных для Locus Map. Вы одобрили разрешение на доступ к внешнему файлу?
+ Код авторизации
Код авторизации
Введенный код авторизации недействителен. Пожалуйста, попробуйте еще раз.
Geocaching API в настоящее время не работает из-за технического обслуживания. Пожалуйста, попробуйте позже.
При поддержке Geocaching API
Это стало возможным благодаря поддержке Geocaching Premium Memberships, программа API дает сторонним разработчикам возможность работать с Geocaching HQ над полным набором интегрированных продуктов и услуг для сообщества. Приложения для разработчиков API предназначены для работы с основными службами geocaching.com и предоставляют дополнительные возможности сообществу геокешинга.
+ Продолжить
diff --git a/app/src/main/res/values-si-rLK/strings.xml b/app/src/main/res/values-si-rLK/strings.xml
new file mode 100644
index 00000000..aa21ca21
--- /dev/null
+++ b/app/src/main/res/values-si-rLK/strings.xml
@@ -0,0 +1,56 @@
+
+
+ නිහිතයන් බාගතවෙමින්…
+ සැකසුම්
+ හරි
+ අවලංගු
+ නිහිතය යාවත්කාල වෙමින්…
+ නිහිතය බාගතවෙමින්…
+ අනුවාදය
+ නිහිත වර්ග
+ සජීවී සිතියම
+ සැකසුම්
+ නිහිත යාවත්කාල වෙමින්…
+ සජීවී සිතියම අබලයි.
+ සැකසුම්
+ නිහිතය යාවත්කාල කරන්න
+ නිහිත යාවත්කාල කරන්න
+
+ - නිහිත %d
+ - නිහිත %d
+
+
+ - පැය %d
+ - පැය %d
+
+
+ - විනාඩි %d
+ - විනාඩි %d
+
+ සජීවී සිතියම සබල කර ඇත.
+ සජීවී සිතියම අබල කර ඇත.
+ සබල කරන්න
+ අබල කරන්න
+ සැකසුම්
+ දැනුම්දීම් අබල කර ඇත
+ සියල්ල
+ පෙරහන
+ ගිණුම
+ පෙරහන
+ සජීවී සිතියම
+ බාගත වෙමින්
+ වැඩිදුර
+ පිළිබඳව
+ ඉඟි බාගන්න
+ පොත්යොමු ආයාතකරන්න
+ පොත්යොමු ආයාතකරන්න
+ සියල්ල ආයාත කරන්න
+ ලෝකස් සිතියමේ දෝෂයකි
+ දෝෂ වාර්තාව යවන්න
+ ඔව්
+ නැහැ
+ අවවාදයයි
+ තව තොරතුරු
+ ලෝකස් සිතියමේ දෝෂය: %s
+ ඉදිරියට
+
diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr-rTR/strings.xml
new file mode 100644
index 00000000..1f6fbd6b
--- /dev/null
+++ b/app/src/main/res/values-tr-rTR/strings.xml
@@ -0,0 +1,152 @@
+
+
+ Geocache\'ler indiriliyor…
+ GPS\'den konum alınıyor…
+ Konum kablosuz ağlardan alınıyor…
+ Ayarlar
+ Hatalı koordinat formatı!
+ Koordinatlar
+ Mesafe
+ Km cinsinden mesafe
+ Mil cinsinden mesafe
+ İngiliz Ölçü Birimleri
+ Kilometre yerine mil kullan
+ Giriş yapmadınız. Lütfen önce hesap ayarlarından giriş yapın.
+ Tamam
+ Locus Haritaların eski bir sürümünü kullanıyorsunuz. Sorunsuz çalışabilmesi için Geocaching4Locus %s veya daha yeni bir versiyon gerektirir.
+ İptal
+ Bulduklarımı göster
+ Bulunan Geocache\'leri göster
+ Geocache\'lerimi gizle
+ Geocache\'lerimi göster (sakladıklarınız)
+ Tümünü seç
+ Tüm Seçimleri Kaldır
+ Geocache güncelleniyor…
+ Kayıt sayısı
+ Geocache ile indirilecek kayıt sayısı
+ GPS
+ Devredışı olanları göster
+ Geçici olarak devredışı bırakılmış Geocache\'leri göster
+ Geocache indiriliyor…
+ Version
+ İnternet sitesi, forum, vb.
+ Paypal ile bağış yap
+ Gelecek geliştirmeleri destekle…
+ Para biriminizi seçin
+ Geocache türleri
+ Zorluk
+ Arazi
+ Min. zorluk
+ Maks. zorluk
+ Min. arazi
+ Maks. arazi
+ Sadece temel bilgi
+ Geocache\'in sadece temel bilgilerini indir
+
+ - bir kez
+ - her
+ - asla
+
+ Canlı Harita
+ En Yakın
+ Kullanım Kılavuzu
+ Ayarlar
+ Kullanıcı yol noktası %1$d
+ Final Noktası Konumu
+ Giriş Yap
+ Geocaching.com hesabınıza giriş yapın
+ Oturumu kapatın
+ %s olarak giriş yapıldı
+ Ağ kullanılamıyor. Bağlantınızı kontrol edin.
+ Geocacheler güncelleniyor…
+ Kutu boyutu
+ Canlı harita aktif. Şimdi Geocache\'leri görüntülemek için haritayı ilerletin.
+ Canlı harita devredışı bırakıldı.
+ Konum hizmetlerine izin verilmiyor
+ Ayarlar
+ GC\'den içe aktar
+ GC kodundan içe aktar
+ GC kodu geçersiz.
+
+ - %s Geocache\'i bulunamadı.
+ - %s Geocache\'i bulunamadı.
+
+ Geocache sayısı
+ En yakın Geocache\'ler
+ Geocache\'i Locus Haritalara aktar
+ Geocache\'i Güncelle
+ Geocache\'leri Güncelle
+ GC kodundan içe aktar
+ Normal üye girişi
+ Ücretli üye girişi
+ <b>%2$s süresinde %1$s<b> tüm detay indirme limitine ulaştınız. Günlük kotanız %3$s\'de yenilenecek.<br/>
+ <br/>
+ <i> Günlük 6000\'e kadar Geocache\'in tüm detayları indirebilmek ve başka birçok özellik için geocaching.com üyeliğinizi ücretli üyeliğe yükseltin. Üyeliğinizi yükseltmek için geocaching.com\'u ziyaret edin.</i>
+ Hey, yavaş ol!
+
+ - %d Geocache
+ - %d Geocache
+
+
+ - %d saat
+ - %d saat
+
+
+ - %d dakika
+ - %d dakika
+
+ Geocaching4Locus Canlı Harita
+ Canlı harita aktifleştirildi.
+ Canlı harita devredışı.
+ Aktifleştir
+ Devre dışı bırak
+ Ayarlar
+ Geocaching4Locus canlı harita: %s
+ Devredışı bildirimler
+ Tümü
+ Filtre
+ Kayıtlar indiriliyor…
+ Kayıtları indir
+ Kayıtları indir ve Geocache\'i güncelle
+ \'\'Kayıtları indir\'\' işlemi aynı zamanda Geocache verisini de günceller
+ Bazı filtreleri kullanabilmeniz için ücretli üyelik sahibi olmanız gerekir. Uygulama temel üye moduna değiştirildi. Lütfen yeniden deneyiniz.
+ Hesap
+ Filtre
+ Canlı Harita
+ İndiriliyor
+ Gelişmiş
+ Hakkında
+ Giriş Yap
+ İpuçlarını indir
+ Daha yavaş yükleme ve daha fazla veri kullanımı
+ Geri Bildirim Gönder
+ Aramanızla eşleşen bir Geocache bulunamadı.
+ Yer imlerini içe aktar
+ Yer imlerini içe aktar
+ Uygulamanın konum servislerine erişim izni bulunmamaktadır.
+ Tümünü içe aktar
+ Bu özellik sadece ücretli üyeler için geçerlidir, üzgünüz.
+ Locus Harita hatası
+ Hata raporu gönder
+ Hatayı bildirdiğiniz için teşekkürler.
+ Kısmen indirilmiş veriyle Locus Haritalara devam etmek istiyor musunuz?
+ Evet
+ Hayır
+ Kullanım klavuzunu göster
+ Uygulamanın harici depo alanlarına veri kaydı izni bulunmamaktadır. Bu izin Locus Haritalarda Geocache verilerini saklamak için gereklidir.
+ Devredışı Geocache\'leri gizle
+ DNF, Bakım ve Arşiv kaydı girilmişleri gizle
+ Kontrol edilecek son kayıt sayısı
+ Geocache\'i izle
+ Geocache\'i işaretle
+ Canlı Geocache haritasını içe aktar
+ Canlı GC haritasını içe aktar
+ Bu mesajı bir daha gösterme
+ Uyarı
+ Daha fazla bilgi
+ Locus Harita Hatası:%s
+ Yetkilendirme kodu
+ Yetkilendirme kodu
+ Geocaching API tarafından sağlanmaktadır
+ Devam
+
diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml
deleted file mode 100644
index 1d0008a6..00000000
--- a/app/src/main/res/values-v21/styles.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml
index a15e1e43..e3204548 100644
--- a/app/src/main/res/values-zh/strings.xml
+++ b/app/src/main/res/values-zh/strings.xml
@@ -26,6 +26,7 @@
正在更新藏点……
日志计数
和藏点一起下载的日志计数
+ GPS
显示失效的
显示暂时失效的藏点
正在下载藏点……
@@ -52,6 +53,7 @@
在线地图
最近的
+ 用户指南
设置
用户航点%1$d
最终位置
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 56642ff1..9144c4f1 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -68,6 +68,7 @@
+
-
+