From 3bfe28efe1a669869bac54e96ddb57456cd0da1a Mon Sep 17 00:00:00 2001 From: Arcao Date: Sun, 10 Nov 2019 21:01:05 +0100 Subject: [PATCH] Use viewModelScope for coroutines --- .../java/com/arcao/geocaching4locus/App.kt | 7 +- .../com/arcao/geocaching4locus/AppModule.kt | 2 +- .../authentication/LoginViewModel.kt | 52 +++-- .../geocaching4locus/base/BaseViewModel.kt | 36 ++-- .../dashboard/DashboardViewModel.kt | 3 +- .../DownloadRectangleViewModel.kt | 167 ++++++++-------- .../fragment/BookmarkListViewModel.kt | 119 ++++++----- .../fragment/BookmarkViewModel.kt | 12 +- .../importgc/ImportGeocacheCodeViewModel.kt | 87 ++++---- .../importgc/ImportUrlViewModel.kt | 23 ++- .../live_map/LiveMapViewModel.kt | 7 +- .../search_nearest/SearchNearestViewModel.kt | 10 +- .../geocaching4locus/update/UpdateActivity.kt | 4 + .../update/UpdateMoreActivity.kt | 3 + .../update/UpdateMoreViewModel.kt | 88 ++++---- .../update/UpdateViewModel.kt | 188 ++++++++++-------- .../weblink/WebLinkViewModel.kt | 52 +++-- 17 files changed, 476 insertions(+), 384 deletions(-) diff --git a/app/src/main/java/com/arcao/geocaching4locus/App.kt b/app/src/main/java/com/arcao/geocaching4locus/App.kt index cf982355..21803ad5 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/App.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/App.kt @@ -35,7 +35,7 @@ import java.util.UUID class App : Application() { val accountManager by inject() - val deviceId: String by lazy { + private val deviceId: String by lazy { val pref = PreferenceManager.getDefaultSharedPreferences(this) var value = pref.getString(PrefConstants.DEVICE_ID, null) @@ -92,10 +92,6 @@ class App : Application() { modules(listOf(appModule, geocachingApiModule, locusMapApiModule, feedbackModule)) } -// if (BuildConfig.DEBUG) { -// StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder().detectAll().build()) -// StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder().detectAll().build()) -// } prepareCrashlytics() @@ -150,6 +146,7 @@ class App : Application() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { CookieManager.getInstance().flush() } else { + @Suppress("DEPRECATION") CookieSyncManager.createInstance(this).sync() } } diff --git a/app/src/main/java/com/arcao/geocaching4locus/AppModule.kt b/app/src/main/java/com/arcao/geocaching4locus/AppModule.kt index f6b16dbd..31e6a00d 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/AppModule.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/AppModule.kt @@ -127,7 +127,7 @@ internal val appModule = module { ) } // update - viewModel { UpdateViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get(), get()) } + viewModel { UpdateViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get()) } viewModel { UpdateMoreViewModel(get(), get(), get(), get(), get(), get(), get(), get()) } // web link viewModel { BookmarkGeocacheWebLinkViewModel(get(), get(), get(), get()) } 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 24dd1825..9b642d79 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/authentication/LoginViewModel.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/authentication/LoginViewModel.kt @@ -15,7 +15,7 @@ import com.arcao.geocaching4locus.base.util.invoke import com.arcao.geocaching4locus.data.account.AccountManager import com.arcao.geocaching4locus.error.handler.ExceptionHandler import com.crashlytics.android.Crashlytics -import kotlinx.coroutines.cancelChildren +import kotlinx.coroutines.Job class LoginViewModel( private val app: App, @@ -25,13 +25,15 @@ class LoginViewModel( private val accountManager: AccountManager, dispatcherProvider: CoroutinesDispatcherProvider ) : BaseViewModel(dispatcherProvider) { - val action = Command() + private var job: Job? = null fun startLogin() { - if (job.isActive) coroutineContext.cancelChildren() + if (job?.isActive == true) { + job?.cancel() + } - mainLaunch { + job = mainLaunch { try { showProgress { app.clearGeocachingCookies() @@ -47,28 +49,34 @@ class LoginViewModel( } } - fun finishLogin(input: String) = mainLaunch { - if (input.isBlank()) { - action(LoginAction.Cancel) - return@mainLaunch + fun finishLogin(input: String) { + if (job?.isActive == true) { + job?.cancel() } - try { - showProgress { - // create account - val account = createAccount(input) + job = mainLaunch { + if (input.isBlank()) { + action(LoginAction.Cancel) + return@mainLaunch + } - val premium = account.isPremium() + try { + showProgress { + // create account + val account = createAccount(input) - // handle analytics and crashlytics - Crashlytics.setBool(CrashlyticsConstants.PREMIUM_MEMBER, premium) - AnalyticsUtil.setPremiumUser(app, premium) - AnalyticsUtil.actionLogin(true, premium) + val premium = account.isPremium() - action(LoginAction.Finish(!premium)) + // handle analytics and crashlytics + Crashlytics.setBool(CrashlyticsConstants.PREMIUM_MEMBER, premium) + AnalyticsUtil.setPremiumUser(app, premium) + AnalyticsUtil.actionLogin(true, premium) + + action(LoginAction.Finish(!premium)) + } + } catch (e: Exception) { + handleException(e) } - } catch (e: Exception) { - handleException(e) } } @@ -93,7 +101,7 @@ class LoginViewModel( fun cancelLogin() { AnalyticsUtil.actionLogin(success = false, premiumMember = false) - job.cancel() + job?.cancel() action(LoginAction.Cancel) } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/arcao/geocaching4locus/base/BaseViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/base/BaseViewModel.kt index bcd6a2e1..fe948c68 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/base/BaseViewModel.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/base/BaseViewModel.kt @@ -3,58 +3,46 @@ package com.arcao.geocaching4locus.base import androidx.annotation.StringRes import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope import com.arcao.geocaching4locus.base.coroutine.CoroutinesDispatcherProvider import com.arcao.geocaching4locus.base.util.runIfIsSuspended import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch import kotlinx.coroutines.withContext -import kotlin.coroutines.CoroutineContext abstract class BaseViewModel( val dispatcherProvider: CoroutinesDispatcherProvider -) : ViewModel(), CoroutineScope { - val job = Job() +) : ViewModel() { val progress: MutableLiveData = MutableLiveData() - // Better to start on main context to minimize cost of switching between computation and main context - // Also it is better to read referenceCode without switching - // If you need more time to do work, switch to computation context - override val coroutineContext: CoroutineContext - get() = dispatcherProvider.main + job - - override fun onCleared() { - job.cancel() - super.onCleared() - } - - fun mainLaunch(block: suspend CoroutineScope.() -> R) = launch(dispatcherProvider.main) { - block() - } + inline fun mainLaunch(crossinline block: suspend CoroutineScope.() -> R) = + viewModelScope.launch(dispatcherProvider.main) { + block() + } - fun computationLaunch(block: suspend CoroutineScope.() -> R) = - launch(dispatcherProvider.computation) { + inline fun computationLaunch(crossinline block: suspend CoroutineScope.() -> R) = + viewModelScope.launch(dispatcherProvider.computation) { block() } - suspend fun mainContext(block: suspend CoroutineScope.() -> R): R = + suspend inline fun mainContext(crossinline block: suspend CoroutineScope.() -> R): R = withContext(dispatcherProvider.main) { block() } - suspend fun computationContext(block: suspend CoroutineScope.() -> R): R = + suspend inline fun computationContext(crossinline block: suspend CoroutineScope.() -> R): R = withContext(dispatcherProvider.computation) { block() } - suspend fun showProgress( + suspend inline fun showProgress( @StringRes message: Int = 0, messageArgs: Array? = null, progress: Int = 0, maxProgress: Int = 0, requestId: Int = 0, - block: suspend CoroutineScope.() -> R + crossinline block: suspend CoroutineScope.() -> R ): R = coroutineScope { this@BaseViewModel.progress.postValue( 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 aed95076..1a128610 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/dashboard/DashboardViewModel.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/dashboard/DashboardViewModel.kt @@ -12,7 +12,6 @@ import com.arcao.geocaching4locus.base.util.hidePowerManagementWarning import com.arcao.geocaching4locus.base.util.invoke import com.arcao.geocaching4locus.data.account.AccountManager import com.arcao.geocaching4locus.live_map.util.LiveMapNotificationManager -import kotlinx.coroutines.launch import locus.api.manager.LocusMapManager class DashboardViewModel( @@ -104,7 +103,7 @@ class DashboardViewModel( liveMapEnabled(newState) } - fun onPowerSaveWarningConfirmed() = launch { + fun onPowerSaveWarningConfirmed() = mainLaunch { toggleLiveMap() } } 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 a6bbd17d..868b86c3 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 @@ -16,6 +16,7 @@ import com.arcao.geocaching4locus.live_map.model.LastLiveMapCoordinates import com.arcao.geocaching4locus.settings.manager.FilterPreferenceManager import com.arcao.geocaching4locus.update.UpdateActivity import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.Job import kotlinx.coroutines.channels.map import locus.api.manager.LocusMapManager import timber.log.Timber @@ -31,107 +32,115 @@ class DownloadRectangleViewModel constructor( private val locusMapManager: LocusMapManager, dispatcherProvider: CoroutinesDispatcherProvider ) : BaseViewModel(dispatcherProvider) { - val action = Command() + private var job: Job? = null - fun startDownload() = mainLaunch { - if (locusMapManager.isLocusMapNotInstalled) { - action(DownloadRectangleAction.LocusMapNotInstalled) - return@mainLaunch + fun startDownload() { + if (job?.isActive == true) { + job?.cancel() } - if (accountManager.account == null) { - action(DownloadRectangleAction.SignIn) - return@mainLaunch - } + job = mainLaunch { + if (locusMapManager.isLocusMapNotInstalled) { + action(DownloadRectangleAction.LocusMapNotInstalled) + return@mainLaunch + } - val liveMapCoordinates = LastLiveMapCoordinates.value - if (liveMapCoordinates == null) { - action(DownloadRectangleAction.LastLiveMapDataInvalid) - return@mainLaunch - } + if (accountManager.account == null) { + action(DownloadRectangleAction.SignIn) + return@mainLaunch + } + + val liveMapCoordinates = LastLiveMapCoordinates.value + if (liveMapCoordinates == null) { + action(DownloadRectangleAction.LastLiveMapDataInvalid) + return@mainLaunch + } - Timber.i( - "source=download_rectangle;center=%s;topLeft=%s;bottomRight=%s", - liveMapCoordinates.center, - liveMapCoordinates.topLeft, - liveMapCoordinates.bottomRight - ) + Timber.i( + "source=download_rectangle;center=%s;topLeft=%s;bottomRight=%s", + liveMapCoordinates.center, + liveMapCoordinates.topLeft, + liveMapCoordinates.bottomRight + ) - doDownload(liveMapCoordinates) + doDownload(liveMapCoordinates) + } } @Suppress("EXPERIMENTAL_API_USAGE") - private suspend fun doDownload(liveMapCoordinates: LastLiveMapCoordinates) = computationContext { - val downloadIntent = locusMapManager.createSendPointsIntent( - callImport = true, - center = true - ) + private suspend fun doDownload(liveMapCoordinates: LastLiveMapCoordinates) = + computationContext { + val downloadIntent = locusMapManager.createSendPointsIntent( + callImport = true, + center = true + ) - var count = AppConstants.ITEMS_PER_REQUEST - var receivedGeocaches = 0 + var count = AppConstants.ITEMS_PER_REQUEST + var receivedGeocaches = 0 - try { - showProgress(R.string.progress_download_geocaches, maxProgress = count) { - val geocaches = getPointsFromRectangleCoordinates( - this, - liveMapCoordinates.center, - liveMapCoordinates.topLeft, - liveMapCoordinates.bottomRight, - filterPreferenceManager.simpleCacheData, - filterPreferenceManager.geocacheLogsCount, - filterPreferenceManager.showDisabled, - filterPreferenceManager.showFound, - filterPreferenceManager.showOwn, - filterPreferenceManager.geocacheTypes, - filterPreferenceManager.containerTypes, - filterPreferenceManager.difficultyMin, - filterPreferenceManager.difficultyMax, - filterPreferenceManager.terrainMin, - filterPreferenceManager.terrainMax, - filterPreferenceManager.excludeIgnoreList, - AppConstants.LIVEMAP_CACHES_COUNT - ) { count = it }.map { list -> - receivedGeocaches += list.size - updateProgress(progress = receivedGeocaches, maxProgress = count) + try { + showProgress(R.string.progress_download_geocaches, maxProgress = count) { + val geocaches = getPointsFromRectangleCoordinates( + this, + liveMapCoordinates.center, + liveMapCoordinates.topLeft, + liveMapCoordinates.bottomRight, + filterPreferenceManager.simpleCacheData, + filterPreferenceManager.geocacheLogsCount, + filterPreferenceManager.showDisabled, + filterPreferenceManager.showFound, + filterPreferenceManager.showOwn, + filterPreferenceManager.geocacheTypes, + filterPreferenceManager.containerTypes, + filterPreferenceManager.difficultyMin, + filterPreferenceManager.difficultyMax, + filterPreferenceManager.terrainMin, + filterPreferenceManager.terrainMax, + filterPreferenceManager.excludeIgnoreList, + AppConstants.LIVEMAP_CACHES_COUNT + ) { count = it }.map { list -> + receivedGeocaches += list.size + updateProgress(progress = receivedGeocaches, maxProgress = count) - // 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 - ) + // 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 + ) + } } + list } - list + writePointToPackPointsFile(geocaches) } - writePointToPackPointsFile(geocaches) + } catch (e: Exception) { + mainContext { + action( + DownloadRectangleAction.Error( + if (receivedGeocaches > 0) { + exceptionHandler(IntendedException(e, downloadIntent)) + } else { + exceptionHandler(e) + } + ) + ) + } + return@computationContext } - } catch (e: Exception) { + mainContext { - action( - DownloadRectangleAction.Error( - if (receivedGeocaches > 0) { - exceptionHandler(IntendedException(e, downloadIntent)) - } else { - exceptionHandler(e) - } - ) - ) + action(DownloadRectangleAction.Finish(downloadIntent)) } - return@computationContext - } - mainContext { - action(DownloadRectangleAction.Finish(downloadIntent)) } - } fun cancelDownload() { - job.cancel() + job?.cancel() action(DownloadRectangleAction.Cancel) } -} \ No newline at end of file +} 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 52defae0..45058105 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 @@ -21,7 +21,7 @@ import com.arcao.geocaching4locus.import_bookmarks.paging.GeocacheUserListsDataS import com.arcao.geocaching4locus.import_bookmarks.paging.GeocacheUserListsDataSourceFactory import com.arcao.geocaching4locus.settings.manager.FilterPreferenceManager import com.arcao.geocaching4locus.update.UpdateActivity -import kotlinx.coroutines.cancelChildren +import kotlinx.coroutines.Job import kotlinx.coroutines.channels.map import locus.api.manager.LocusMapManager import timber.log.Timber @@ -40,6 +40,7 @@ class BookmarkListViewModel( val loading = MutableLiveData() val list: LiveData> val action = Command() + private var job: Job? = null val state: LiveData get() = Transformations.switchMap(dataSourceFactory.dataSource, GeocacheUserListsDataSource::state) @@ -68,64 +69,74 @@ class BookmarkListViewModel( } } - fun importAll(geocacheList: GeocacheListEntity) = computationLaunch { - val importIntent = locusMapManager.createSendPointsIntent( - callImport = true, - center = true - ) - - var receivedGeocaches = 0 - - try { - showProgress(R.string.progress_download_geocaches) { - Timber.d("source: import_from_bookmark;guid=%s", geocacheList.guid) - - var count = 0 - - val channel = getListGeocaches( - this, - geocacheList.guid, - filterPreferenceManager.simpleCacheData, - filterPreferenceManager.geocacheLogsCount - ) { - count = it - Timber.d("source: import_from_bookmark; guid=%s; count=%d", geocacheList.guid, count) - }.map { list -> - receivedGeocaches += list.size - updateProgress(progress = receivedGeocaches, maxProgress = count) - - // 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 - ) + fun importAll(geocacheList: GeocacheListEntity) { + if (job?.isActive == true) { + job?.cancel() + } + + job = computationLaunch { + val importIntent = locusMapManager.createSendPointsIntent( + callImport = true, + center = true + ) + + var receivedGeocaches = 0 + + try { + showProgress(R.string.progress_download_geocaches) { + Timber.d("source: import_from_bookmark;guid=%s", geocacheList.guid) + + var count = 0 + + val channel = getListGeocaches( + this, + geocacheList.guid, + filterPreferenceManager.simpleCacheData, + filterPreferenceManager.geocacheLogsCount + ) { + count = it + Timber.d( + "source: import_from_bookmark; guid=%s; count=%d", + geocacheList.guid, + count + ) + }.map { list -> + receivedGeocaches += list.size + updateProgress(progress = receivedGeocaches, maxProgress = count) + + // 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 + ) + } } + list } - list + writePointToPackPointsFile(channel) } - writePointToPackPointsFile(channel) - } - } catch (e: Exception) { - mainContext { - action( - BookmarkListAction.Error( - if (receivedGeocaches > 0) { - exceptionHandler(IntendedException(e, importIntent)) - } else { - exceptionHandler(e) - } + } catch (e: Exception) { + mainContext { + action( + BookmarkListAction.Error( + if (receivedGeocaches > 0) { + exceptionHandler(IntendedException(e, importIntent)) + } else { + exceptionHandler(e) + } + ) ) - ) + } + return@computationLaunch } - return@computationLaunch - } - mainContext { - action(BookmarkListAction.Finish(importIntent)) + mainContext { + action(BookmarkListAction.Finish(importIntent)) + } } } @@ -134,6 +145,6 @@ class BookmarkListViewModel( } fun cancelProgress() { - job.cancelChildren() + 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 e2906778..4b4c0eca 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 @@ -23,6 +23,7 @@ import com.arcao.geocaching4locus.import_bookmarks.paging.ListGeocachesDataSourc 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.cancelChildren import kotlinx.coroutines.channels.map import locus.api.manager.LocusMapManager @@ -51,6 +52,8 @@ class BookmarkViewModel( val state: LiveData get() = Transformations.switchMap(dataSourceFactory.dataSource, ListGeocachesDataSource::state) + private var job: Job? = null + init { val pageSize = 25 val config = PagedList.Config.Builder() @@ -60,7 +63,6 @@ class BookmarkViewModel( .build() dataSourceFactory.referenceCode = geocacheList.guid - list = LivePagedListBuilder(dataSourceFactory, config).build() state.observeForever { state -> @@ -78,7 +80,11 @@ class BookmarkViewModel( } fun download() { - mainLaunch { + if (job?.isActive == true) { + job?.cancel() + } + + job = mainLaunch { val selection = selection.value ?: return@mainLaunch AnalyticsUtil.actionImportBookmarks(selection.size, false) @@ -142,6 +148,6 @@ class BookmarkViewModel( } fun cancelProgress() { - job.cancelChildren() + job?.cancelChildren() } } diff --git a/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportGeocacheCodeViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportGeocacheCodeViewModel.kt index 61940931..c8400b9d 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportGeocacheCodeViewModel.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportGeocacheCodeViewModel.kt @@ -14,6 +14,7 @@ import com.arcao.geocaching4locus.data.api.util.ReferenceCode import com.arcao.geocaching4locus.error.exception.IntendedException import com.arcao.geocaching4locus.error.handler.ExceptionHandler import com.arcao.geocaching4locus.settings.manager.FilterPreferenceManager +import kotlinx.coroutines.Job import kotlinx.coroutines.channels.map import locus.api.manager.LocusMapManager import java.util.regex.Pattern @@ -28,6 +29,7 @@ class ImportGeocacheCodeViewModel( dispatcherProvider: CoroutinesDispatcherProvider ) : BaseViewModel(dispatcherProvider) { val action = Command() + private var job: Job? = null fun init(geocacheCodes: Array?) = mainLaunch { if (locusMapManager.isLocusMapNotInstalled) { @@ -47,47 +49,56 @@ class ImportGeocacheCodeViewModel( } } - fun importGeocacheCodes(geocacheCodes: Array) = computationLaunch { - AnalyticsUtil.actionImportGC(accountManager.isPremium) - - val importIntent = locusMapManager.createSendPointsIntent( - callImport = true, - center = true - ) - - var receivedGeocaches = 0 - - try { - showProgress(R.string.progress_download_geocaches, maxProgress = geocacheCodes.size) { - val channel = getPointsFromGeocacheCodes( - this, - geocacheCodes, - !accountManager.isPremium, - filterPreferenceManager.geocacheLogsCount - ).map { - receivedGeocaches += it.size - updateProgress(progress = receivedGeocaches) - it + fun importGeocacheCodes(geocacheCodes: Array) { + if (job?.isActive == true) { + job?.cancel() + } + + job = computationLaunch { + AnalyticsUtil.actionImportGC(accountManager.isPremium) + + val importIntent = locusMapManager.createSendPointsIntent( + callImport = true, + center = true + ) + + var receivedGeocaches = 0 + + try { + showProgress( + R.string.progress_download_geocaches, + maxProgress = geocacheCodes.size + ) { + val channel = getPointsFromGeocacheCodes( + this, + geocacheCodes, + !accountManager.isPremium, + filterPreferenceManager.geocacheLogsCount + ).map { + receivedGeocaches += it.size + updateProgress(progress = receivedGeocaches) + it + } + writePointToPackPointsFile(channel) } - writePointToPackPointsFile(channel) - } - } catch (e: Exception) { - mainContext { - action( - ImportGeocacheCodeAction.Error( - if (receivedGeocaches > 0) { - exceptionHandler(IntendedException(e, importIntent)) - } else { - exceptionHandler(e) - } + } catch (e: Exception) { + mainContext { + action( + ImportGeocacheCodeAction.Error( + if (receivedGeocaches > 0) { + exceptionHandler(IntendedException(e, importIntent)) + } else { + exceptionHandler(e) + } + ) ) - ) + } + return@computationLaunch } - return@computationLaunch - } - mainContext { - action(ImportGeocacheCodeAction.Finish(importIntent)) + mainContext { + action(ImportGeocacheCodeAction.Finish(importIntent)) + } } } @@ -104,7 +115,7 @@ class ImportGeocacheCodeViewModel( } fun cancelImport() { - job.cancel() + job?.cancel() action(ImportGeocacheCodeAction.Cancel) } diff --git a/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportUrlViewModel.kt b/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportUrlViewModel.kt index 2568d6cb..02daa760 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportUrlViewModel.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/importgc/ImportUrlViewModel.kt @@ -14,6 +14,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.FilterPreferenceManager +import kotlinx.coroutines.Job import locus.api.manager.LocusMapManager import timber.log.Timber import java.util.regex.Pattern @@ -29,19 +30,26 @@ class ImportUrlViewModel( dispatcherProvider: CoroutinesDispatcherProvider ) : BaseViewModel(dispatcherProvider) { val action = Command() + private var job: Job? = null - fun startImport(uri: Uri) = mainLaunch { + fun startImport(uri: Uri) { if (locusMapManager.isLocusMapNotInstalled) { action(ImportUrlAction.LocusMapNotInstalled) - return@mainLaunch + return } if (accountManager.account == null) { action(ImportUrlAction.SignIn) - return@mainLaunch + return } - performImport(uri) + if (job?.isActive == true) { + job?.cancel() + } + + job = mainLaunch { + performImport(uri) + } } private suspend fun performImport(uri: Uri) = computationContext { @@ -100,15 +108,16 @@ class ImportUrlViewModel( } fun cancelImport() { - job.cancel() + job?.cancel() action(ImportUrlAction.Cancel) } companion object { - val CACHE_CODE_PATTERN: Pattern = Pattern.compile("(GC[A-HJKMNPQRTV-Z0-9]+)", Pattern.CASE_INSENSITIVE) + val CACHE_CODE_PATTERN: Pattern = + Pattern.compile("(GC[A-HJKMNPQRTV-Z0-9]+)", Pattern.CASE_INSENSITIVE) private val GUID_PATTERN = Pattern.compile( "guid=([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})", Pattern.CASE_INSENSITIVE ) } -} \ No newline at end of file +} 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 001ee0cb..91a309b4 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 @@ -5,6 +5,7 @@ import android.content.Intent import androidx.lifecycle.Lifecycle import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.OnLifecycleEvent +import androidx.lifecycle.viewModelScope import com.arcao.geocaching4locus.R import com.arcao.geocaching4locus.base.AccountNotFoundException import com.arcao.geocaching4locus.base.BaseViewModel @@ -46,7 +47,6 @@ class LiveMapViewModel( private val accountManager: AccountManager, dispatcherProvider: CoroutinesDispatcherProvider ) : BaseViewModel(dispatcherProvider), LifecycleObserver { - private val dispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher() fun addTask(intent: Intent, completionCallback: (Intent) -> Unit) { @@ -61,7 +61,7 @@ class LiveMapViewModel( } @Suppress("EXPERIMENTAL_API_USAGE") - private fun downloadLiveMapGeocaches(task: Intent) = launch(dispatcher) { + private fun downloadLiveMapGeocaches(task: Intent) = viewModelScope.launch(dispatcher) { var requests = 0 delay(200) @@ -159,8 +159,7 @@ class LiveMapViewModel( @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) override fun onCleared() { - super.onCleared() - dispatcher.cancel() + viewModelScope.cancel() } } 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 07443ad0..3dfd421c 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 @@ -25,6 +25,7 @@ import com.arcao.geocaching4locus.error.handler.ExceptionHandler import com.arcao.geocaching4locus.settings.manager.DefaultPreferenceManager import com.arcao.geocaching4locus.settings.manager.FilterPreferenceManager import com.arcao.geocaching4locus.update.UpdateActivity +import kotlinx.coroutines.Job import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.channels.map import locus.api.manager.LocusMapManager @@ -62,6 +63,7 @@ class SearchNearestViewModel( private var coordinatesSource = AnalyticsUtil.COORDINATES_SOURCE_MANUAL private var useFilter = false + private var job: Job? = null init { run { @@ -137,13 +139,17 @@ class SearchNearestViewModel( } fun cancelProgress() { - job.cancelChildren() + job?.cancelChildren() } fun download() { formatCoordinates() - mainLaunch { + if (job?.isActive == true) { + job?.cancel() + } + + job = mainLaunch { val latitude = CoordinatesFormatter.convertDegToDouble(latitude.value ?: "") val longitude = CoordinatesFormatter.convertDegToDouble(longitude.value ?: "") 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 4710d179..3dfbdab7 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/update/UpdateActivity.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/update/UpdateActivity.kt @@ -78,6 +78,10 @@ class UpdateActivity : AbstractActionBarActivity() { } } + override fun onProgressCancel(requestId: Int) { + viewModel.cancelProgress() + } + companion object { const val PARAM_CACHE_ID = "cacheId" const val PARAM_SIMPLE_CACHE_ID = "simpleCacheId" 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 96033e6f..92994850 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/update/UpdateMoreActivity.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/update/UpdateMoreActivity.kt @@ -71,6 +71,9 @@ class UpdateMoreActivity : AbstractActionBarActivity() { } } + 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 e01d1df4..a819f573 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/update/UpdateMoreViewModel.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/update/UpdateMoreViewModel.kt @@ -14,6 +14,7 @@ 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 locus.api.android.utils.IntentHelper import locus.api.manager.LocusMapManager import locus.api.mapper.PointMerger @@ -30,64 +31,79 @@ class UpdateMoreViewModel( dispatcherProvider: CoroutinesDispatcherProvider ) : BaseViewModel(dispatcherProvider) { val action = Command() + private var job: Job? = null @UseExperimental(ExperimentalCoroutinesApi::class) - fun processIntent(intent: Intent) = mainLaunch { + fun processIntent(intent: Intent) { if (locusMapManager.isLocusMapNotInstalled) { action(UpdateMoreAction.LocusMapNotInstalled) - return@mainLaunch + return } if (accountManager.account == null) { action(UpdateMoreAction.SignIn) - return@mainLaunch + return } - try { - var progress = 0 - showProgress(R.string.progress_update_geocaches, maxProgress = 1) { - computationContext { - var pointIndexes: LongArray? = null + if (job?.isActive == true) { + job?.cancel() + } - if (IntentHelper.isIntentPointsTools(intent)) - pointIndexes = IntentHelper.getPointsFromIntent(intent) + job = mainLaunch { + try { + var progress = 0 + showProgress(R.string.progress_update_geocaches, maxProgress = 1) { + computationContext { + var pointIndexes: LongArray? = null - AnalyticsUtil.actionUpdateMore(pointIndexes?.size ?: 0, accountManager.isPremium) - Timber.i("source: update;count=%d", pointIndexes?.size ?: 0) + if (IntentHelper.isIntentPointsTools(intent)) + pointIndexes = IntentHelper.getPointsFromIntent(intent) - if (pointIndexes?.isNotEmpty() != true) { - action(UpdateMoreAction.Cancel) - return@computationContext - } + AnalyticsUtil.actionUpdateMore( + pointIndexes?.size ?: 0, + accountManager.isPremium + ) + Timber.i("source: update;count=%d", pointIndexes?.size ?: 0) - updateProgress(maxProgress = pointIndexes.size) + if (pointIndexes?.isNotEmpty() != true) { + action(UpdateMoreAction.Cancel) + return@computationContext + } - val basicMember = !(accountManager.isPremium) - var logsCount = defaultPreferenceManager.downloadingGeocacheLogsCount - var lite = false + updateProgress(maxProgress = pointIndexes.size) - if (basicMember) { - logsCount = 0 - lite = true - } + val basicMember = !(accountManager.isPremium) + var logsCount = defaultPreferenceManager.downloadingGeocacheLogsCount + var lite = false + + if (basicMember) { + logsCount = 0 + lite = true + } - val existingPoints = getPointsFromPointIndexes(this, pointIndexes) + val existingPoints = getPointsFromPointIndexes(this, pointIndexes) - val pointPairs = getOldPointNewPointPairFromPoint(this, existingPoints, lite, logsCount) - for ((oldPoint, newPoint) in pointPairs) { - if (newPoint == null) continue + val pointPairs = + getOldPointNewPointPairFromPoint(this, existingPoints, lite, logsCount) + for ((oldPoint, newPoint) in pointPairs) { + if (newPoint == null) continue - merger.mergePoints(newPoint, oldPoint) - locusMapManager.updatePoint(newPoint) - progress++ - updateProgress(progress = progress) + merger.mergePoints(newPoint, oldPoint) + locusMapManager.updatePoint(newPoint) + progress++ + updateProgress(progress = progress) + } } } - } - action(UpdateMoreAction.Finish) - } catch (e: Exception) { - action(UpdateMoreAction.Error(exceptionHandler(e))) + action(UpdateMoreAction.Finish) + } catch (e: Exception) { + action(UpdateMoreAction.Error(exceptionHandler(e))) + } } } + + fun cancelProgress() { + job?.cancel() + } } 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 04dc9ffa..05d0984a 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/update/UpdateViewModel.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/update/UpdateViewModel.kt @@ -8,7 +8,6 @@ import com.arcao.geocaching4locus.base.BaseViewModel import com.arcao.geocaching4locus.base.constants.AppConstants import com.arcao.geocaching4locus.base.coroutine.CoroutinesDispatcherProvider import com.arcao.geocaching4locus.base.usecase.GetGeocachingLogsUseCase -import com.arcao.geocaching4locus.base.usecase.GetGeocachingTrackablesUseCase import com.arcao.geocaching4locus.base.usecase.GetPointFromGeocacheCodeUseCase import com.arcao.geocaching4locus.base.util.AnalyticsUtil import com.arcao.geocaching4locus.base.util.Command @@ -16,6 +15,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.Job import kotlinx.coroutines.channels.map import kotlinx.coroutines.channels.toList import locus.api.android.utils.IntentHelper @@ -32,7 +32,6 @@ class UpdateViewModel( private val accountManager: AccountManager, private val defaultPreferenceManager: DefaultPreferenceManager, private val getPointFromGeocacheCode: GetPointFromGeocacheCodeUseCase, - private val getGeocachingTrackables: GetGeocachingTrackablesUseCase, private val getGeocachingLogs: GetGeocachingLogsUseCase, private val pointMerger: PointMerger, private val locusMapManager: LocusMapManager, @@ -40,123 +39,132 @@ class UpdateViewModel( dispatcherProvider: CoroutinesDispatcherProvider ) : BaseViewModel(dispatcherProvider) { val action = Command() + private var job: Job? = null - fun processIntent(intent: Intent) = mainLaunch { + fun processIntent(intent: Intent) { if (locusMapManager.isLocusMapNotInstalled) { action(UpdateAction.LocusMapNotInstalled) - return@mainLaunch + return } if (accountManager.account == null) { action(UpdateAction.SignIn) - return@mainLaunch + return } if (!accountManager.isPremium && isUpdateLogsIntent(intent)) { action(UpdateAction.PremiumMembershipRequired) - return@mainLaunch + return } - val downloadFullGeocacheOnShow = defaultPreferenceManager.downloadFullGeocacheOnShow + if (job?.isActive == true) { + job?.cancel() + } - try { - showProgress(R.string.progress_update_geocache, maxProgress = 1) { + job = mainLaunch { + val downloadFullGeocacheOnShow = defaultPreferenceManager.downloadFullGeocacheOnShow - val updateData = computationContext { - val updateData = retrieveUpdateData(intent) ?: return@computationContext null + try { + showProgress(R.string.progress_update_geocache, maxProgress = 1) { - val basicMember = !(accountManager.isPremium) - var logsCount = defaultPreferenceManager.downloadingGeocacheLogsCount - var lite = false + val updateData = computationContext { + val updateData = + retrieveUpdateData(intent) ?: return@computationContext null - if (basicMember) { - logsCount = 0 - lite = true - } + val basicMember = !(accountManager.isPremium) + var logsCount = defaultPreferenceManager.downloadingGeocacheLogsCount + var lite = false - updateData.newPoint = getPointFromGeocacheCode(updateData.geocacheCode, lite, logsCount) + if (basicMember) { + logsCount = 0 + lite = true + } - // count to full geocache limit -// if (basicMember) { -// // get trackables -// val trackables = getGeocachingTrackables(this, updateData.geocacheCode, 0, 30) -// updateData.newPoint.gcData.trackables.addAll(trackables.toList().flatten()) -// } + updateData.newPoint = + getPointFromGeocacheCode(updateData.geocacheCode, lite, logsCount) - if (updateData.downloadLogs) { - var progress = updateData.newPoint.gcData.logs.count() + if (updateData.downloadLogs) { + var progress = updateData.newPoint.gcData.logs.count() - logsCount = if (updateData.downloadLogs) { - AppConstants.LOGS_TO_UPDATE_MAX - } else { - defaultPreferenceManager.downloadingGeocacheLogsCount - } + logsCount = if (updateData.downloadLogs) { + AppConstants.LOGS_TO_UPDATE_MAX + } else { + defaultPreferenceManager.downloadingGeocacheLogsCount + } - updateProgress(R.string.progress_download_logs, progress = progress, maxProgress = logsCount) - - val logs = getGeocachingLogs( - this, - updateData.geocacheCode, - progress, - logsCount - ).map { - progress += it.count() - updateProgress(progress = progress, maxProgress = logsCount) - it - }.toList() - - updateData.newPoint.gcData.logs.apply { - addAll(logs.flatten()) - sortBy { - it.date + updateProgress( + R.string.progress_download_logs, + progress = progress, + maxProgress = logsCount + ) + + val logs = getGeocachingLogs( + this, + updateData.geocacheCode, + progress, + logsCount + ).map { + progress += it.count() + updateProgress(progress = progress, maxProgress = logsCount) + it + }.toList() + + updateData.newPoint.gcData.logs.apply { + addAll(logs.flatten()) + sortBy { + it.date + } } } - } - if (updateData.downloadLogs && updateData.oldPoint != null && !defaultPreferenceManager.downloadLogsUpdateCache) { - pointMerger.mergeGeocachingLogs(updateData.oldPoint, updateData.newPoint) - - // only when this feature is enabled - if (defaultPreferenceManager.disableDnfNmNaGeocaches) - Util.applyUnavailabilityForGeocache( + if (updateData.downloadLogs && updateData.oldPoint != null && !defaultPreferenceManager.downloadLogsUpdateCache) { + pointMerger.mergeGeocachingLogs( updateData.oldPoint, - defaultPreferenceManager.disableDnfNmNaGeocachesThreshold + updateData.newPoint ) - updateData.newPoint = updateData.oldPoint - } else { - pointMerger.mergePoints(updateData.newPoint, updateData.oldPoint) + // only when this feature is enabled + if (defaultPreferenceManager.disableDnfNmNaGeocaches) + Util.applyUnavailabilityForGeocache( + updateData.oldPoint, + defaultPreferenceManager.disableDnfNmNaGeocachesThreshold + ) - if (downloadFullGeocacheOnShow) { - updateData.newPoint.removeExtraOnDisplay() + updateData.newPoint = updateData.oldPoint + } else { + pointMerger.mergePoints(updateData.newPoint, updateData.oldPoint) + + if (downloadFullGeocacheOnShow) { + updateData.newPoint.removeExtraOnDisplay() + } } - } - return@computationContext updateData - } + return@computationContext updateData + } - if (updateData == null) { - action(UpdateAction.Cancel) - return@showProgress - } + if (updateData == null) { + action(UpdateAction.Cancel) + return@showProgress + } - // if Point is already in DB we must update it manually - if (updateData.oldPoint != null) { - locusMapManager.updatePoint(updateData.newPoint) - action(UpdateAction.Finish()) - } else { - action( - UpdateAction.Finish( - LocusUtils.prepareResultExtraOnDisplayIntent( - updateData.newPoint, - downloadFullGeocacheOnShow + // if Point is already in DB we must update it manually + if (updateData.oldPoint != null) { + locusMapManager.updatePoint(updateData.newPoint) + action(UpdateAction.Finish()) + } else { + action( + UpdateAction.Finish( + LocusUtils.prepareResultExtraOnDisplayIntent( + updateData.newPoint, + downloadFullGeocacheOnShow + ) ) ) - ) + } } + } catch (e: Exception) { + action(UpdateAction.Error(exceptionHandler(e))) } - } catch (e: Exception) { - action(UpdateAction.Error(exceptionHandler(e))) } } @@ -194,15 +202,25 @@ class UpdateViewModel( return null } - val downloadLogs = AppConstants.UPDATE_WITH_LOGS_COMPONENT == intent.component?.className + val downloadLogs = + AppConstants.UPDATE_WITH_LOGS_COMPONENT == intent.component?.className AnalyticsUtil.actionUpdate(oldPoint != null, downloadLogs, accountManager.isPremium) return UpdateData(cacheId, downloadLogs, oldPoint) } - fun isUpdateLogsIntent(intent: Intent) = AppConstants.UPDATE_WITH_LOGS_COMPONENT == intent.component?.className + private fun isUpdateLogsIntent(intent: Intent) = + AppConstants.UPDATE_WITH_LOGS_COMPONENT == intent.component?.className + + fun cancelProgress() { + job?.cancel() + } - class UpdateData(val geocacheCode: String, val downloadLogs: Boolean, val oldPoint: Point? = null) { + class UpdateData( + val geocacheCode: String, + val downloadLogs: Boolean, + val oldPoint: Point? = null + ) { lateinit var newPoint: Point } } 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 2e56c99a..cec0271c 100644 --- a/app/src/main/java/com/arcao/geocaching4locus/weblink/WebLinkViewModel.kt +++ b/app/src/main/java/com/arcao/geocaching4locus/weblink/WebLinkViewModel.kt @@ -10,6 +10,7 @@ import com.arcao.geocaching4locus.base.util.Command 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 abstract class WebLinkViewModel( @@ -19,6 +20,7 @@ abstract class WebLinkViewModel( dispatcherProvider: CoroutinesDispatcherProvider ) : BaseViewModel(dispatcherProvider) { val action: Command = Command() + private var job: Job? = null protected open val isPremiumMemberRequired: Boolean get() = false @@ -29,45 +31,51 @@ abstract class WebLinkViewModel( return false } - fun resolveUri(point: Point) = mainLaunch { + fun resolveUri(point: Point) { if (point.gcData == null || point.gcData.cacheID.isNullOrEmpty()) { action(WebLinkAction.Cancel) - return@mainLaunch + return } if (isPremiumMemberRequired && !accountManager.isPremium) { action(WebLinkAction.PremiumMembershipRequired) - return@mainLaunch + return } - try { - val uri = if (!isRefreshRequired(point)) { - getWebLink(point) - } else { - if (accountManager.account == null) { - action(WebLinkAction.SignIn) - return@mainLaunch + if (job?.isActive == true) { + job?.cancel() + } + + job = mainLaunch { + try { + val uri = if (!isRefreshRequired(point)) { + getWebLink(point) + } else { + if (accountManager.account == null) { + action(WebLinkAction.SignIn) + return@mainLaunch + } + + val newPoint = showProgress(R.string.progress_download_geocache) { + getPointFromGeocacheCode(point.gcData.cacheID) + } + getWebLink(newPoint) } - val newPoint = showProgress(R.string.progress_download_geocache) { - getPointFromGeocacheCode(point.gcData.cacheID) + if (uri == null) { + action(WebLinkAction.Cancel) + return@mainLaunch } - getWebLink(newPoint) - } - if (uri == null) { - action(WebLinkAction.Cancel) - return@mainLaunch + action(WebLinkAction.ShowUri(uri)) + } catch (e: Throwable) { + action(WebLinkAction.Error(exceptionHandler(e))) } - - action(WebLinkAction.ShowUri(uri)) - } catch (e: Throwable) { - action(WebLinkAction.Error(exceptionHandler(e))) } } fun cancelRetrieveUri() { - job.cancel() + job?.cancel() action(WebLinkAction.Cancel) } }