From e07796052693eac13b23ca6faa9be62b385ccf51 Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Sun, 7 Mar 2021 19:14:31 -0500 Subject: [PATCH 01/19] Removed review actions from about fragment --- .../features/about/fragments/AboutFragment.kt | 30 --------- app/src/main/res/layout/fragment_about.xml | 64 ------------------- 2 files changed, 94 deletions(-) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/about/fragments/AboutFragment.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/about/fragments/AboutFragment.kt index ea4580c..fd48c75 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/about/fragments/AboutFragment.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/about/fragments/AboutFragment.kt @@ -60,27 +60,6 @@ class AboutFragment : Fragment() { private fun subscribeToViewComponents() { buttonViewOnGitHub.setOnClickListener { openGitHubProjectUri() } - buttonViewReview.setOnClickListener { openReviewPlayStore() } - buttonViewShare.setOnClickListener { onShareButtonTapped() } - } - - private fun onShareButtonTapped() = activity.notNull { activity -> - analyticService.logEvent(AnalyticEvent.ShareManeki) - - val chooserTitle = activity.getString(R.string.share_chooser_title) - val shareText = activity.getString( - R.string.share_text, - activity.getPlayStoreUri().toString() - ) - - val intent = ShareCompat - .IntentBuilder - .from(activity) - .setType("text/plain") - .setText(shareText) - .intent - - activity.startActivity(Intent.createChooser(intent, chooserTitle)) } private fun openGitHubProjectUri() = context.notNull { context -> @@ -96,15 +75,6 @@ class AboutFragment : Fragment() { } } - private fun openReviewPlayStore() = context.notNull { context -> - try { - context.startPlayStoreActivity() - } catch (exception: ActivityNotFoundException) { - analyticService.logException(exception, "No activity found to handle open GitHub Uri") - presentUnableToOpenPlayStoreDialog() - } - } - private fun presentUnableToOpenPlayStoreDialog() = context.notNull { context -> MaterialDialog(context).show { title(res = R.string.dialog_header_whoops) diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml index a065635..5673583 100644 --- a/app/src/main/res/layout/fragment_about.xml +++ b/app/src/main/res/layout/fragment_about.xml @@ -70,68 +70,4 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/textViewAboutVersion" /> - - - - - - - - \ No newline at end of file From d3643aec8ae0ee009eab167893ba17d17ffcd12c Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Wed, 10 Mar 2021 19:32:16 -0500 Subject: [PATCH 02/19] Progress on in app reviews --- app/build.gradle | 3 ++ .../di/modules/ServiceModule.kt | 9 ++++++ .../fragments/IndexerQueryResultsFragment.kt | 28 ++++++++++++++----- .../query/viewmodels/QueryViewModel.kt | 2 ++ 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b573ff9..1be1fbd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -71,6 +71,9 @@ dependencies { def lifecycle_version = '2.2.0' def dagger_version = '2.28.1' + implementation 'com.google.android.play:core:1.10.0' + implementation 'com.google.android.play:core-ktx:1.8.1' + implementation 'androidx.appcompat:appcompat:1.1.0' implementation 'androidx.constraintlayout:constraintlayout:1.1.3' diff --git a/app/src/main/java/com/masterwok/shrimplesearch/di/modules/ServiceModule.kt b/app/src/main/java/com/masterwok/shrimplesearch/di/modules/ServiceModule.kt index 80b831f..b3e74f6 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/di/modules/ServiceModule.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/di/modules/ServiceModule.kt @@ -1,5 +1,8 @@ package com.masterwok.shrimplesearch.di.modules +import android.content.Context +import com.google.android.play.core.review.ReviewManager +import com.google.android.play.core.review.ReviewManagerFactory import com.masterwok.shrimplesearch.common.INDEXER_BLOCK_LIST import com.masterwok.shrimplesearch.common.data.repositories.JackettServiceImpl import com.masterwok.shrimplesearch.common.data.repositories.contracts.JackettService @@ -44,4 +47,10 @@ class ServiceModule { INDEXER_BLOCK_LIST ) + @Suppress("unused") + @Singleton + @Provides + fun provideReviewManager( + appContext: Context + ): ReviewManager = ReviewManagerFactory.create(appContext) } \ No newline at end of file diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt index 4919a92..72e7a6e 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt @@ -6,10 +6,11 @@ import android.content.Intent import android.os.Bundle import android.view.* import androidx.core.app.ShareCompat -import androidx.fragment.app.Fragment import androidx.core.view.isVisible +import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import androidx.lifecycle.observe import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -19,6 +20,8 @@ import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.bottomsheets.BottomSheet import com.afollestad.materialdialogs.list.customListAdapter import com.google.android.material.snackbar.Snackbar +import com.google.android.play.core.ktx.requestReview +import com.google.android.play.core.review.ReviewManager import com.masterwok.shrimplesearch.R import com.masterwok.shrimplesearch.common.constants.AnalyticEvent import com.masterwok.shrimplesearch.common.data.models.UserSettings @@ -34,12 +37,10 @@ import com.masterwok.shrimplesearch.features.query.adapters.MaterialDialogIconLi import com.masterwok.shrimplesearch.features.query.components.SortComponent import com.masterwok.shrimplesearch.features.query.constants.IndexerQueryResultSortBy import com.masterwok.shrimplesearch.features.query.constants.OrderBy -import com.masterwok.xamarininterface.enums.QueryState import com.masterwok.shrimplesearch.features.query.viewmodels.QueryViewModel +import com.masterwok.xamarininterface.enums.QueryState import com.masterwok.xamarininterface.models.QueryResultItem import kotlinx.android.synthetic.main.fragment_indexer_query_results.* -import kotlinx.android.synthetic.main.fragment_indexer_query_results.progressBar -import kotlinx.android.synthetic.main.fragment_indexer_query_results.recyclerView import javax.inject.Inject @@ -51,18 +52,31 @@ class IndexerQueryResultsFragment : Fragment() { @Inject lateinit var analyticService: AnalyticService + @Inject + lateinit var reviewManager: ReviewManager + private lateinit var linearLayoutManager: LinearLayoutManager private val viewModel: QueryViewModel by viewModels(this::requireActivity) { viewModelFactory } - private val queryResultsAdapter = IndexerQueryResultsAdapter { queryResultItem -> - presentBottomSheet(queryResultItem) - } + private val queryResultsAdapter = IndexerQueryResultsAdapter(this::onQueryResultTapped) private val userSettings: UserSettings get() = viewModel.getUserSettings() private var snackbarNewResults: Snackbar? = null + private fun onQueryResultTapped(queryResultItem: QueryResultItem) { + lifecycleScope.launchWhenResumed { + with(reviewManager) { + val reviewInfo = requestReview() + + reviewManager + .launchReviewFlow(requireActivity(), reviewInfo) + .addOnCompleteListener { presentBottomSheet(queryResultItem) } + } + } + } + private fun openQueryResultItem(queryResultItem: QueryResultItem) = activity.notNull { val linkInfo = queryResultItem.linkInfo val uri = linkInfo.magnetUri ?: linkInfo.link ?: return diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt index 7506ef5..e6c764a 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt @@ -1,6 +1,8 @@ package com.masterwok.shrimplesearch.features.query.viewmodels import androidx.lifecycle.* +import com.google.android.play.core.ktx.requestReview +import com.google.android.play.core.review.ReviewManager import com.masterwok.shrimplesearch.common.constants.AnalyticEvent import com.masterwok.shrimplesearch.common.data.models.UserSettings import com.masterwok.shrimplesearch.common.data.repositories.contracts.JackettService From 7596256ecb4d6719b8cc80e9e420fa049ea5df1c Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Wed, 10 Mar 2021 23:08:58 -0500 Subject: [PATCH 03/19] Test build --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 1be1fbd..e51064d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { applicationId "com.masterwok.shrimplesearch" minSdkVersion project.minSdkVersion targetSdkVersion project.targetSdkVersion - versionCode 500053 - versionName "2.1.6" + versionCode 500054 + versionName "2.1.7" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } From fb9f505d2d682f9ad9466a3ae854e2ac0593c361 Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Wed, 10 Mar 2021 23:22:53 -0500 Subject: [PATCH 04/19] Cleanup --- .../extensions/ReviewManagerExtensions.kt | 18 ++++++++ .../fragments/IndexerQueryResultsFragment.kt | 45 +++++++++---------- 2 files changed, 39 insertions(+), 24 deletions(-) create mode 100644 app/src/main/java/com/masterwok/shrimplesearch/common/extensions/ReviewManagerExtensions.kt diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/extensions/ReviewManagerExtensions.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/extensions/ReviewManagerExtensions.kt new file mode 100644 index 0000000..c1c5fb1 --- /dev/null +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/extensions/ReviewManagerExtensions.kt @@ -0,0 +1,18 @@ +package com.masterwok.shrimplesearch.common.extensions + +import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.lifecycleScope +import com.google.android.play.core.ktx.requestReview +import com.google.android.play.core.review.ReviewManager + + +fun ReviewManager.attemptToPresentInAppReview( + activity: FragmentActivity, + onCompletionAction: () -> Unit +) { + activity.lifecycleScope.launchWhenResumed { + val reviewInfo = requestReview() + + launchReviewFlow(activity, reviewInfo).addOnCompleteListener { onCompletionAction() } + } +} diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt index 72e7a6e..867a516 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt @@ -10,7 +10,6 @@ import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope import androidx.lifecycle.observe import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -20,12 +19,12 @@ import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.bottomsheets.BottomSheet import com.afollestad.materialdialogs.list.customListAdapter import com.google.android.material.snackbar.Snackbar -import com.google.android.play.core.ktx.requestReview import com.google.android.play.core.review.ReviewManager import com.masterwok.shrimplesearch.R import com.masterwok.shrimplesearch.common.constants.AnalyticEvent import com.masterwok.shrimplesearch.common.data.models.UserSettings import com.masterwok.shrimplesearch.common.data.services.contracts.AnalyticService +import com.masterwok.shrimplesearch.common.extensions.attemptToPresentInAppReview import com.masterwok.shrimplesearch.common.extensions.copyToClipboard import com.masterwok.shrimplesearch.common.extensions.getColorByAttribute import com.masterwok.shrimplesearch.common.extensions.showSnackbar @@ -59,24 +58,12 @@ class IndexerQueryResultsFragment : Fragment() { private val viewModel: QueryViewModel by viewModels(this::requireActivity) { viewModelFactory } - private val queryResultsAdapter = IndexerQueryResultsAdapter(this::onQueryResultTapped) + private val queryResultsAdapter = IndexerQueryResultsAdapter { presentBottomSheet(it) } private val userSettings: UserSettings get() = viewModel.getUserSettings() private var snackbarNewResults: Snackbar? = null - private fun onQueryResultTapped(queryResultItem: QueryResultItem) { - lifecycleScope.launchWhenResumed { - with(reviewManager) { - val reviewInfo = requestReview() - - reviewManager - .launchReviewFlow(requireActivity(), reviewInfo) - .addOnCompleteListener { presentBottomSheet(queryResultItem) } - } - } - } - private fun openQueryResultItem(queryResultItem: QueryResultItem) = activity.notNull { val linkInfo = queryResultItem.linkInfo val uri = linkInfo.magnetUri ?: linkInfo.link ?: return @@ -268,6 +255,10 @@ class IndexerQueryResultsFragment : Fragment() { context.copyToClipboard(CLIPBOARD_LABEL, uri.toString()) } + private fun attemptToPresentInAppReview(deferredAction: () -> Unit) { + reviewManager.attemptToPresentInAppReview(requireActivity(), deferredAction) + } + private fun presentBottomSheet(queryResultItem: QueryResultItem) = context.notNull { context -> val hasMagnetUri = queryResultItem .linkInfo @@ -280,25 +271,31 @@ class IndexerQueryResultsFragment : Fragment() { R.drawable.ic_baseline_share_24, if (hasMagnetUri) R.string.share_magnet else R.string.share_link ) { - analyticService.logEvent(AnalyticEvent.ShareResult) - shareQueryResultItem(queryResultItem) - dismiss() + attemptToPresentInAppReview { + analyticService.logEvent(AnalyticEvent.ShareResult) + shareQueryResultItem(queryResultItem) + dismiss() + } }, MaterialDialogIconListItemAdapter.Item( R.drawable.ic_content_copy_black_24dp, if (hasMagnetUri) R.string.copy_magnet else R.string.copy_torrent ) { - analyticService.logEvent(AnalyticEvent.CopyResult) - copyQueryResultItem(queryResultItem) - dismiss() + attemptToPresentInAppReview { + analyticService.logEvent(AnalyticEvent.CopyResult) + copyQueryResultItem(queryResultItem) + dismiss() + } }, MaterialDialogIconListItemAdapter.Item( R.drawable.ic_baseline_open_in_new_24, if (hasMagnetUri) R.string.open_magnet else R.string.open_link ) { - analyticService.logEvent(AnalyticEvent.OpenResult) - openQueryResultItem(queryResultItem) - dismiss() + attemptToPresentInAppReview { + analyticService.logEvent(AnalyticEvent.OpenResult) + openQueryResultItem(queryResultItem) + dismiss() + } } ) From 1d58b629d5ad987b79072da0de53354cd496fbed Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Wed, 10 Mar 2021 23:53:04 -0500 Subject: [PATCH 05/19] Showing snack --- ...haredPreferencesConfigurationRepository.kt | 36 ++++++++++ .../contracts/ConfigurationRepository.kt | 6 ++ .../extensions/ReviewManagerExtensions.kt | 1 - .../di/modules/RepositoryModule.kt | 8 +++ .../fragments/IndexerQueryResultsFragment.kt | 70 +++++++++++-------- .../query/viewmodels/QueryViewModel.kt | 14 +++- 6 files changed, 105 insertions(+), 30 deletions(-) create mode 100644 app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt create mode 100644 app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/ConfigurationRepository.kt diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt new file mode 100644 index 0000000..4755338 --- /dev/null +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt @@ -0,0 +1,36 @@ +package com.masterwok.shrimplesearch.common.data.repositories + +import android.content.Context +import com.masterwok.shrimplesearch.common.data.repositories.contracts.ConfigurationRepository +import javax.inject.Inject +import javax.inject.Named + +class SharedPreferencesConfigurationRepository @Inject constructor( + appContext: Context, + @Named("shared_preferences_name") sharedPreferencesName: String +) : ConfigurationRepository { + + private val sharedPreferences = appContext.getSharedPreferences( + sharedPreferencesName, + Context.MODE_PRIVATE + ) + + override suspend fun incrementResultTapCount() { + val resultItemCount = getResultItemTapCount() + + sharedPreferences + .edit() + .putInt(NAME_RESULT_ITEM_TAP_COUNT, resultItemCount + 1) + .apply() + } + + override suspend fun getResultItemTapCount(): Int = sharedPreferences.getInt( + NAME_RESULT_ITEM_TAP_COUNT, + 0 + ) + + companion object { + private const val NAME_RESULT_ITEM_TAP_COUNT = "configuration.result_item_tap_count" + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/ConfigurationRepository.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/ConfigurationRepository.kt new file mode 100644 index 0000000..9490876 --- /dev/null +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/ConfigurationRepository.kt @@ -0,0 +1,6 @@ +package com.masterwok.shrimplesearch.common.data.repositories.contracts + +interface ConfigurationRepository { + suspend fun incrementResultTapCount() + suspend fun getResultItemTapCount(): Int +} \ No newline at end of file diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/extensions/ReviewManagerExtensions.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/extensions/ReviewManagerExtensions.kt index c1c5fb1..ae80215 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/extensions/ReviewManagerExtensions.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/extensions/ReviewManagerExtensions.kt @@ -13,6 +13,5 @@ fun ReviewManager.attemptToPresentInAppReview( activity.lifecycleScope.launchWhenResumed { val reviewInfo = requestReview() - launchReviewFlow(activity, reviewInfo).addOnCompleteListener { onCompletionAction() } } } diff --git a/app/src/main/java/com/masterwok/shrimplesearch/di/modules/RepositoryModule.kt b/app/src/main/java/com/masterwok/shrimplesearch/di/modules/RepositoryModule.kt index 94421db..338efbf 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/di/modules/RepositoryModule.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/di/modules/RepositoryModule.kt @@ -3,7 +3,9 @@ package com.masterwok.shrimplesearch.di.modules import com.masterwok.shrimplesearch.common.DEFAULT_USER_SETTINGS import com.masterwok.shrimplesearch.common.SHARED_PREFERENCES_NAME import com.masterwok.shrimplesearch.common.data.models.UserSettings +import com.masterwok.shrimplesearch.common.data.repositories.SharedPreferencesConfigurationRepository import com.masterwok.shrimplesearch.common.data.repositories.SharedPreferencesUserSettingsRepository +import com.masterwok.shrimplesearch.common.data.repositories.contracts.ConfigurationRepository import com.masterwok.shrimplesearch.common.data.repositories.contracts.UserSettingsRepository import dagger.Binds import dagger.Module @@ -26,6 +28,12 @@ class RepositoryModule { abstract fun bindSharedPreferencesUserSettingsRepository( sharedPreferencesUserSettingsRepository: SharedPreferencesUserSettingsRepository ): UserSettingsRepository + + @Singleton + @Binds + abstract fun bindConfigurationRepository( + sharedPreferencesUserConfigurationRepository: SharedPreferencesConfigurationRepository + ): ConfigurationRepository } @Provides diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt index 867a516..d9d6140 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt @@ -10,6 +10,7 @@ import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.viewModels import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import androidx.lifecycle.observe import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager @@ -19,6 +20,8 @@ import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.bottomsheets.BottomSheet import com.afollestad.materialdialogs.list.customListAdapter import com.google.android.material.snackbar.Snackbar +import com.google.android.play.core.ktx.requestReview +import com.google.android.play.core.review.ReviewInfo import com.google.android.play.core.review.ReviewManager import com.masterwok.shrimplesearch.R import com.masterwok.shrimplesearch.common.constants.AnalyticEvent @@ -54,16 +57,25 @@ class IndexerQueryResultsFragment : Fragment() { @Inject lateinit var reviewManager: ReviewManager - private lateinit var linearLayoutManager: LinearLayoutManager - private val viewModel: QueryViewModel by viewModels(this::requireActivity) { viewModelFactory } private val queryResultsAdapter = IndexerQueryResultsAdapter { presentBottomSheet(it) } private val userSettings: UserSettings get() = viewModel.getUserSettings() + private lateinit var linearLayoutManager: LinearLayoutManager + private lateinit var reviewInfo: ReviewInfo + private var snackbarNewResults: Snackbar? = null + init { + lifecycleScope.launchWhenResumed { + reviewInfo = reviewManager.requestReview() + + analyticService.logScreen(IndexerQueryResultsFragment::class.java) + } + } + private fun openQueryResultItem(queryResultItem: QueryResultItem) = activity.notNull { val linkInfo = queryResultItem.linkInfo val uri = linkInfo.magnetUri ?: linkInfo.link ?: return @@ -116,13 +128,6 @@ class IndexerQueryResultsFragment : Fragment() { subscribeToLiveData() } - override fun onResume() { - super.onResume() - - analyticService.logScreen(IndexerQueryResultsFragment::class.java) - } - - private fun subscribeToViewComponents() { recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { @@ -158,12 +163,13 @@ class IndexerQueryResultsFragment : Fragment() { adapter = queryResultsAdapter } - viewModel.liveDataQueryState.observe(viewLifecycleOwner, ::onQueryStateChange) + viewModel.liveDataQueryState.observe(owner = viewLifecycleOwner, ::onQueryStateChange) } private fun subscribeToLiveData() { viewModel.liveDataSelectedIndexerQueryResultItem.observe( - viewLifecycleOwner, ::configure + owner = viewLifecycleOwner, + ::configure ) } @@ -244,7 +250,6 @@ class IndexerQueryResultsFragment : Fragment() { .setType("text/plain") .setText(uri.toString()) .startChooser() - } private fun copyQueryResultItem(queryResultItem: QueryResultItem) = @@ -256,7 +261,19 @@ class IndexerQueryResultsFragment : Fragment() { } private fun attemptToPresentInAppReview(deferredAction: () -> Unit) { - reviewManager.attemptToPresentInAppReview(requireActivity(), deferredAction) + val isReviewInfoInitialized = this::reviewInfo.isInitialized + + lifecycleScope.launchWhenResumed { + if (isReviewInfoInitialized && viewModel.shouldAttemptToPresentInAppReview()) { + reviewManager + .launchReviewFlow(requireActivity(), reviewInfo) + .addOnCompleteListener { deferredAction() } + } else { + deferredAction() + } + + viewModel.incrementResultItemTapCount() + } } private fun presentBottomSheet(queryResultItem: QueryResultItem) = context.notNull { context -> @@ -271,31 +288,28 @@ class IndexerQueryResultsFragment : Fragment() { R.drawable.ic_baseline_share_24, if (hasMagnetUri) R.string.share_magnet else R.string.share_link ) { - attemptToPresentInAppReview { - analyticService.logEvent(AnalyticEvent.ShareResult) - shareQueryResultItem(queryResultItem) - dismiss() - } + attemptToPresentInAppReview { shareQueryResultItem(queryResultItem) } + dismiss() + + analyticService.logEvent(AnalyticEvent.ShareResult) }, MaterialDialogIconListItemAdapter.Item( R.drawable.ic_content_copy_black_24dp, if (hasMagnetUri) R.string.copy_magnet else R.string.copy_torrent ) { - attemptToPresentInAppReview { - analyticService.logEvent(AnalyticEvent.CopyResult) - copyQueryResultItem(queryResultItem) - dismiss() - } + attemptToPresentInAppReview { copyQueryResultItem(queryResultItem) } + dismiss() + + analyticService.logEvent(AnalyticEvent.CopyResult) }, MaterialDialogIconListItemAdapter.Item( R.drawable.ic_baseline_open_in_new_24, if (hasMagnetUri) R.string.open_magnet else R.string.open_link ) { - attemptToPresentInAppReview { - analyticService.logEvent(AnalyticEvent.OpenResult) - openQueryResultItem(queryResultItem) - dismiss() - } + dismiss() + attemptToPresentInAppReview { openQueryResultItem(queryResultItem) } + + analyticService.logEvent(AnalyticEvent.OpenResult) } ) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt index e6c764a..bb6068f 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt @@ -5,6 +5,7 @@ import com.google.android.play.core.ktx.requestReview import com.google.android.play.core.review.ReviewManager import com.masterwok.shrimplesearch.common.constants.AnalyticEvent import com.masterwok.shrimplesearch.common.data.models.UserSettings +import com.masterwok.shrimplesearch.common.data.repositories.contracts.ConfigurationRepository import com.masterwok.shrimplesearch.common.data.repositories.contracts.JackettService import com.masterwok.shrimplesearch.common.data.repositories.contracts.UserSettingsRepository import com.masterwok.shrimplesearch.common.data.services.contracts.AnalyticService @@ -23,7 +24,8 @@ import javax.inject.Inject class QueryViewModel @Inject constructor( private val jackettService: JackettService, private val userSettingsRepository: UserSettingsRepository, - private val analyticService: AnalyticService + private val analyticService: AnalyticService, + private val configurationRepository: ConfigurationRepository ) : ViewModel(), JackettService.Listener { private val _liveDataIndexerQueryResults = MutableLiveData( @@ -58,6 +60,16 @@ class QueryViewModel @Inject constructor( addSource(_liveDataIndexerQueryResults) { value = getIndexerQueryResults() } } + suspend fun shouldAttemptToPresentInAppReview(): Boolean { + val count = configurationRepository.getResultItemTapCount() + + val x = 1 + + return if(count == 0) false else count % 5 == 0 + } + + suspend fun incrementResultItemTapCount() = configurationRepository.incrementResultTapCount() + init { jackettService.addListener(this) } From 1b8826713a277f12105800bfd31da0119b5c1c2c Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Wed, 10 Mar 2021 23:57:06 -0500 Subject: [PATCH 06/19] DI configuration --- .../SharedPreferencesConfigurationRepository.kt | 3 ++- .../SharedPreferencesUserSettingsRepository.kt | 5 +++-- .../shrimplesearch/di/modules/RepositoryModule.kt | 9 +++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt index 4755338..0c9f761 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt @@ -2,12 +2,13 @@ package com.masterwok.shrimplesearch.common.data.repositories import android.content.Context import com.masterwok.shrimplesearch.common.data.repositories.contracts.ConfigurationRepository +import com.masterwok.shrimplesearch.di.modules.RepositoryModule import javax.inject.Inject import javax.inject.Named class SharedPreferencesConfigurationRepository @Inject constructor( appContext: Context, - @Named("shared_preferences_name") sharedPreferencesName: String + @Named(RepositoryModule.NAMED_SHARED_PREFERENCES_NAME) sharedPreferencesName: String ) : ConfigurationRepository { private val sharedPreferences = appContext.getSharedPreferences( diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesUserSettingsRepository.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesUserSettingsRepository.kt index 06ee2a3..7386f32 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesUserSettingsRepository.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesUserSettingsRepository.kt @@ -6,6 +6,7 @@ import com.masterwok.shrimplesearch.common.constants.Theme import com.masterwok.shrimplesearch.common.data.models.UserSettings import com.masterwok.shrimplesearch.common.data.models.from import com.masterwok.shrimplesearch.common.data.repositories.contracts.UserSettingsRepository +import com.masterwok.shrimplesearch.di.modules.RepositoryModule import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -14,8 +15,8 @@ import javax.inject.Named class SharedPreferencesUserSettingsRepository @Inject constructor( appContext: Context, - @Named("shared_preferences_name") sharedPreferencesName: String, - @Named("default_user_settings") private val defaultUserSettings: UserSettings + @Named(RepositoryModule.NAMED_SHARED_PREFERENCES_NAME) sharedPreferencesName: String, + @Named(RepositoryModule.NAMED_DEFAULT_USER_SETTINGS) private val defaultUserSettings: UserSettings ) : UserSettingsRepository { private val sharedPreferences = appContext.getSharedPreferences( diff --git a/app/src/main/java/com/masterwok/shrimplesearch/di/modules/RepositoryModule.kt b/app/src/main/java/com/masterwok/shrimplesearch/di/modules/RepositoryModule.kt index 338efbf..e4ae620 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/di/modules/RepositoryModule.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/di/modules/RepositoryModule.kt @@ -37,10 +37,15 @@ class RepositoryModule { } @Provides - @Named("shared_preferences_name") + @Named(NAMED_SHARED_PREFERENCES_NAME) fun provideSharedPreferencesName(): String = SHARED_PREFERENCES_NAME @Provides - @Named("default_user_settings") + @Named(NAMED_DEFAULT_USER_SETTINGS) fun provideDefaultUserSettings(): UserSettings = DEFAULT_USER_SETTINGS + + companion object { + const val NAMED_SHARED_PREFERENCES_NAME = "shared_preferences_name" + const val NAMED_DEFAULT_USER_SETTINGS = "default_user_settings" + } } \ No newline at end of file From 11d88d9bf77cdae9611a7383c6275d69ada9d66e Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Wed, 10 Mar 2021 23:59:07 -0500 Subject: [PATCH 07/19] Removed dead code --- .../shrimplesearch/features/query/viewmodels/QueryViewModel.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt index bb6068f..3d770c0 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt @@ -63,8 +63,6 @@ class QueryViewModel @Inject constructor( suspend fun shouldAttemptToPresentInAppReview(): Boolean { val count = configurationRepository.getResultItemTapCount() - val x = 1 - return if(count == 0) false else count % 5 == 0 } From 500477532a45aada2810bb2f8f8eef3b9ef79a31 Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Thu, 11 Mar 2021 00:07:06 -0500 Subject: [PATCH 08/19] Changed to long --- .../java/com/masterwok/shrimplesearch/common/Config.kt | 5 +++++ .../SharedPreferencesConfigurationRepository.kt | 4 ++-- .../data/repositories/contracts/ConfigurationRepository.kt | 2 +- .../shrimplesearch/di/modules/RepositoryModule.kt | 6 ++++++ .../features/query/viewmodels/QueryViewModel.kt | 7 +++++-- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt index 1aff17f..2f3e8ca 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt @@ -52,3 +52,8 @@ val DEFAULT_USER_SETTINGS = UserSettings( isExitDialogEnabled = true ) +/** + * The amount of times a user must tap a result item before being presented with an in-app review + * workflow. + */ +val IN_APP_REVIEW_RESULT_ITEM_TAP_COUNT = 5 \ No newline at end of file diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt index 0c9f761..ab5f0d4 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt @@ -21,11 +21,11 @@ class SharedPreferencesConfigurationRepository @Inject constructor( sharedPreferences .edit() - .putInt(NAME_RESULT_ITEM_TAP_COUNT, resultItemCount + 1) + .putLong(NAME_RESULT_ITEM_TAP_COUNT, resultItemCount + 1L) .apply() } - override suspend fun getResultItemTapCount(): Int = sharedPreferences.getInt( + override suspend fun getResultItemTapCount(): Long = sharedPreferences.getLong( NAME_RESULT_ITEM_TAP_COUNT, 0 ) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/ConfigurationRepository.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/ConfigurationRepository.kt index 9490876..e25ddf5 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/ConfigurationRepository.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/ConfigurationRepository.kt @@ -2,5 +2,5 @@ package com.masterwok.shrimplesearch.common.data.repositories.contracts interface ConfigurationRepository { suspend fun incrementResultTapCount() - suspend fun getResultItemTapCount(): Int + suspend fun getResultItemTapCount(): Long } \ No newline at end of file diff --git a/app/src/main/java/com/masterwok/shrimplesearch/di/modules/RepositoryModule.kt b/app/src/main/java/com/masterwok/shrimplesearch/di/modules/RepositoryModule.kt index e4ae620..76aaa45 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/di/modules/RepositoryModule.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/di/modules/RepositoryModule.kt @@ -1,6 +1,7 @@ package com.masterwok.shrimplesearch.di.modules import com.masterwok.shrimplesearch.common.DEFAULT_USER_SETTINGS +import com.masterwok.shrimplesearch.common.IN_APP_REVIEW_RESULT_ITEM_TAP_COUNT import com.masterwok.shrimplesearch.common.SHARED_PREFERENCES_NAME import com.masterwok.shrimplesearch.common.data.models.UserSettings import com.masterwok.shrimplesearch.common.data.repositories.SharedPreferencesConfigurationRepository @@ -44,8 +45,13 @@ class RepositoryModule { @Named(NAMED_DEFAULT_USER_SETTINGS) fun provideDefaultUserSettings(): UserSettings = DEFAULT_USER_SETTINGS + @Provides + @Named(NAMED_IN_APP_REVIEW_RESULT_ITEM_TAP_COUNT) + fun provideInAppReviewResultItemTapCount(): Int = IN_APP_REVIEW_RESULT_ITEM_TAP_COUNT + companion object { const val NAMED_SHARED_PREFERENCES_NAME = "shared_preferences_name" const val NAMED_DEFAULT_USER_SETTINGS = "default_user_settings" + const val NAMED_IN_APP_REVIEW_RESULT_ITEM_TAP_COUNT = "in_app_review_result_item_tap_count" } } \ No newline at end of file diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt index 3d770c0..a3988e0 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt @@ -9,6 +9,7 @@ import com.masterwok.shrimplesearch.common.data.repositories.contracts.Configura import com.masterwok.shrimplesearch.common.data.repositories.contracts.JackettService import com.masterwok.shrimplesearch.common.data.repositories.contracts.UserSettingsRepository import com.masterwok.shrimplesearch.common.data.services.contracts.AnalyticService +import com.masterwok.shrimplesearch.di.modules.RepositoryModule import com.masterwok.shrimplesearch.features.query.constants.IndexerQueryResultSortBy import com.masterwok.shrimplesearch.features.query.constants.OrderBy import com.masterwok.shrimplesearch.features.query.constants.QueryResultSortBy @@ -19,13 +20,15 @@ import com.masterwok.xamarininterface.models.Query import com.masterwok.xamarininterface.models.QueryResultItem import kotlinx.coroutines.launch import javax.inject.Inject +import javax.inject.Named class QueryViewModel @Inject constructor( private val jackettService: JackettService, private val userSettingsRepository: UserSettingsRepository, private val analyticService: AnalyticService, - private val configurationRepository: ConfigurationRepository + private val configurationRepository: ConfigurationRepository, + @Named(RepositoryModule.NAMED_IN_APP_REVIEW_RESULT_ITEM_TAP_COUNT) private val inAppReviewResultItemTapCount: Int ) : ViewModel(), JackettService.Listener { private val _liveDataIndexerQueryResults = MutableLiveData( @@ -63,7 +66,7 @@ class QueryViewModel @Inject constructor( suspend fun shouldAttemptToPresentInAppReview(): Boolean { val count = configurationRepository.getResultItemTapCount() - return if(count == 0) false else count % 5 == 0 + return if (count == 0L) false else count % inAppReviewResultItemTapCount == 0L } suspend fun incrementResultItemTapCount() = configurationRepository.incrementResultTapCount() From 048f0d7edb1c0834b3936a9a3f3fd74fb3f01b80 Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Thu, 11 Mar 2021 00:12:26 -0500 Subject: [PATCH 09/19] const val --- .../masterwok/shrimplesearch/common/Config.kt | 2 +- .../extensions/ReviewManagerExtensions.kt | 17 ----------------- .../fragments/IndexerQueryResultsFragment.kt | 1 - .../features/query/viewmodels/QueryViewModel.kt | 2 -- 4 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 app/src/main/java/com/masterwok/shrimplesearch/common/extensions/ReviewManagerExtensions.kt diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt index 2f3e8ca..662b73c 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt @@ -56,4 +56,4 @@ val DEFAULT_USER_SETTINGS = UserSettings( * The amount of times a user must tap a result item before being presented with an in-app review * workflow. */ -val IN_APP_REVIEW_RESULT_ITEM_TAP_COUNT = 5 \ No newline at end of file +const val IN_APP_REVIEW_RESULT_ITEM_TAP_COUNT = 5 \ No newline at end of file diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/extensions/ReviewManagerExtensions.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/extensions/ReviewManagerExtensions.kt deleted file mode 100644 index ae80215..0000000 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/extensions/ReviewManagerExtensions.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.masterwok.shrimplesearch.common.extensions - -import androidx.fragment.app.FragmentActivity -import androidx.lifecycle.lifecycleScope -import com.google.android.play.core.ktx.requestReview -import com.google.android.play.core.review.ReviewManager - - -fun ReviewManager.attemptToPresentInAppReview( - activity: FragmentActivity, - onCompletionAction: () -> Unit -) { - activity.lifecycleScope.launchWhenResumed { - val reviewInfo = requestReview() - - } -} diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt index d9d6140..9284e75 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt @@ -27,7 +27,6 @@ import com.masterwok.shrimplesearch.R import com.masterwok.shrimplesearch.common.constants.AnalyticEvent import com.masterwok.shrimplesearch.common.data.models.UserSettings import com.masterwok.shrimplesearch.common.data.services.contracts.AnalyticService -import com.masterwok.shrimplesearch.common.extensions.attemptToPresentInAppReview import com.masterwok.shrimplesearch.common.extensions.copyToClipboard import com.masterwok.shrimplesearch.common.extensions.getColorByAttribute import com.masterwok.shrimplesearch.common.extensions.showSnackbar diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt index a3988e0..1a1911b 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt @@ -1,8 +1,6 @@ package com.masterwok.shrimplesearch.features.query.viewmodels import androidx.lifecycle.* -import com.google.android.play.core.ktx.requestReview -import com.google.android.play.core.review.ReviewManager import com.masterwok.shrimplesearch.common.constants.AnalyticEvent import com.masterwok.shrimplesearch.common.data.models.UserSettings import com.masterwok.shrimplesearch.common.data.repositories.contracts.ConfigurationRepository From 5a4e3c01b0bff715ef54c8d8403b6baed251ea78 Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Thu, 11 Mar 2021 00:12:45 -0500 Subject: [PATCH 10/19] count --- app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt index 662b73c..8a67494 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt @@ -56,4 +56,4 @@ val DEFAULT_USER_SETTINGS = UserSettings( * The amount of times a user must tap a result item before being presented with an in-app review * workflow. */ -const val IN_APP_REVIEW_RESULT_ITEM_TAP_COUNT = 5 \ No newline at end of file +const val IN_APP_REVIEW_RESULT_ITEM_TAP_COUNT = 3 \ No newline at end of file From 56bb42bd6d47951e88ff063dc1f119a70f6dfd5a Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Fri, 12 Mar 2021 00:57:11 -0500 Subject: [PATCH 11/19] Bumped versions using flow for settings fragment --- ...haredPreferencesConfigurationRepository.kt | 1 + ...SharedPreferencesUserSettingsRepository.kt | 22 +++++++ .../contracts/UserSettingsRepository.kt | 5 ++ .../settings/fragments/SettingsFragment.kt | 61 +++++++++++-------- .../settings/viewmodels/SettingsViewModel.kt | 7 +++ build.gradle | 6 +- 6 files changed, 74 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt index ab5f0d4..8857d82 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt @@ -3,6 +3,7 @@ package com.masterwok.shrimplesearch.common.data.repositories import android.content.Context import com.masterwok.shrimplesearch.common.data.repositories.contracts.ConfigurationRepository import com.masterwok.shrimplesearch.di.modules.RepositoryModule +import kotlinx.coroutines.flow.flow import javax.inject.Inject import javax.inject.Named diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesUserSettingsRepository.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesUserSettingsRepository.kt index 7386f32..66b76c5 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesUserSettingsRepository.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesUserSettingsRepository.kt @@ -1,17 +1,24 @@ package com.masterwok.shrimplesearch.common.data.repositories import android.content.Context +import android.content.SharedPreferences import com.masterwok.shrimplesearch.R import com.masterwok.shrimplesearch.common.constants.Theme import com.masterwok.shrimplesearch.common.data.models.UserSettings import com.masterwok.shrimplesearch.common.data.models.from import com.masterwok.shrimplesearch.common.data.repositories.contracts.UserSettingsRepository import com.masterwok.shrimplesearch.di.modules.RepositoryModule +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.channels.sendBlocking +import kotlinx.coroutines.flow.callbackFlow +import kotlinx.coroutines.flow.flow import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import javax.inject.Inject import javax.inject.Named +import kotlin.system.measureTimeMillis class SharedPreferencesUserSettingsRepository @Inject constructor( appContext: Context, @@ -24,6 +31,21 @@ class SharedPreferencesUserSettingsRepository @Inject constructor( Context.MODE_PRIVATE ) + @ExperimentalCoroutinesApi + override fun getUserSettingsAsFlow() = callbackFlow { + send(read()) + + val callback = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> + if (key == NAME_USER_SETTINGS) { + sendBlocking(read()) + } + } + + sharedPreferences.registerOnSharedPreferenceChangeListener(callback) + + awaitClose { sharedPreferences.unregisterOnSharedPreferenceChangeListener(callback) } + } + override fun read(): UserSettings { val serialized = sharedPreferences .getString(NAME_USER_SETTINGS, null) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/UserSettingsRepository.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/UserSettingsRepository.kt index 6904d52..bee0714 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/UserSettingsRepository.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/UserSettingsRepository.kt @@ -1,6 +1,8 @@ package com.masterwok.shrimplesearch.common.data.repositories.contracts import com.masterwok.shrimplesearch.common.data.models.UserSettings +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow interface UserSettingsRepository { @@ -12,4 +14,7 @@ interface UserSettingsRepository { fun getSplashThemeId(): Int + @ExperimentalCoroutinesApi + fun getUserSettingsAsFlow(): Flow + } \ No newline at end of file diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/settings/fragments/SettingsFragment.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/settings/fragments/SettingsFragment.kt index d225a2f..4897c32 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/settings/fragments/SettingsFragment.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/settings/fragments/SettingsFragment.kt @@ -27,19 +27,25 @@ class SettingsFragment : Fragment() { private val viewModel: SettingsViewModel by viewModels { viewModelFactory } + private val currentSettings get() = checkNotNull(viewModel.liveDataUserSettings.value) + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View = inflater.inflate( - R.layout.fragment_settings, container, false + R.layout.fragment_settings, + container, + false ) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - configure(viewModel.readUserSettings()) + subscribeToLiveData() + } - subscribeToViewComponents() + private fun subscribeToLiveData() { + viewModel.liveDataUserSettings.observe(viewLifecycleOwner, this::configure) } override fun onResume() { @@ -55,10 +61,15 @@ class SettingsFragment : Fragment() { } private fun configure(userSettings: UserSettings) { + unsubscribeFromViewComponents() configureThemeSelection(userSettings.theme) + configureSwitches(userSettings) + subscribeToViewComponents() + } - switchScrollToTop.isChecked = checkNotNull(userSettings.isScrollToTopNotificationsEnabled) - switchMagnet.isChecked = checkNotNull(userSettings.isOnlyMagnetQueryResultItemsEnabled) + private fun configureSwitches(userSettings: UserSettings) { + switchScrollToTop. isChecked = checkNotNull(userSettings.isScrollToTopNotificationsEnabled) + switchMagnet. isChecked = checkNotNull(userSettings.isOnlyMagnetQueryResultItemsEnabled) } private fun configureThemeSelection(theme: Theme): Unit = when (theme) { @@ -66,6 +77,11 @@ class SettingsFragment : Fragment() { Theme.Oled -> radioButtonThemeOled.isChecked = true } + private fun unsubscribeFromViewComponents() { + switchScrollToTop.setOnCheckedChangeListener(null) + switchMagnet.setOnCheckedChangeListener(null) + } + private fun subscribeToViewComponents() { subscribeToThemeRadioGroup() subscribeToScrollToTopNotificationsSwitch() @@ -74,38 +90,33 @@ class SettingsFragment : Fragment() { private fun subscribeToScrollToTopNotificationsSwitch() { switchScrollToTop.setOnCheckedChangeListener { _, isChecked -> viewModel.updateUserSettings( - viewModel.readUserSettings().copy( - isScrollToTopNotificationsEnabled = isChecked - ) + currentSettings.copy(isScrollToTopNotificationsEnabled = isChecked) ) } switchMagnet.setOnCheckedChangeListener { _, isChecked -> viewModel.updateUserSettings( - viewModel.readUserSettings().copy( - isOnlyMagnetQueryResultItemsEnabled = isChecked - ) + currentSettings.copy(isOnlyMagnetQueryResultItemsEnabled = isChecked) ) } } private fun subscribeToThemeRadioGroup() = radioGroupTheme.setOnCheckedChangeListener { _, _ -> + val oldSettings = checkNotNull(viewModel.liveDataUserSettings.value) val selectedThemeId: Int - val userSettings = viewModel - .readUserSettings() - .copy( - theme = when (radioGroupTheme.checkedRadioButtonId) { - R.id.radioButtonThemeLight -> { - selectedThemeId = R.style.AppTheme - Theme.Light - } - R.id.radioButtonThemeOled -> { - selectedThemeId = R.style.AppTheme_Oled - Theme.Oled - } - else -> error("Theme not registered on settings.") + val userSettings = oldSettings.copy( + theme = when (radioGroupTheme.checkedRadioButtonId) { + R.id.radioButtonThemeLight -> { + selectedThemeId = R.style.AppTheme + Theme.Light } - ) + R.id.radioButtonThemeOled -> { + selectedThemeId = R.style.AppTheme_Oled + Theme.Oled + } + else -> error("Theme not registered on settings.") + } + ) viewModel.updateUserSettings(userSettings.copy()) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/settings/viewmodels/SettingsViewModel.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/settings/viewmodels/SettingsViewModel.kt index 6f04fe6..fa57bcb 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/settings/viewmodels/SettingsViewModel.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/settings/viewmodels/SettingsViewModel.kt @@ -1,14 +1,21 @@ package com.masterwok.shrimplesearch.features.settings.viewmodels import androidx.lifecycle.ViewModel +import androidx.lifecycle.asLiveData +import androidx.lifecycle.viewModelScope import com.masterwok.shrimplesearch.common.data.models.UserSettings import com.masterwok.shrimplesearch.common.data.repositories.contracts.UserSettingsRepository +import kotlinx.coroutines.ExperimentalCoroutinesApi import javax.inject.Inject class SettingsViewModel @Inject constructor( private val userSettingsRepository: UserSettingsRepository ) : ViewModel() { + val liveDataUserSettings = userSettingsRepository + .getUserSettingsAsFlow() + .asLiveData(viewModelScope.coroutineContext) + fun readUserSettings(): UserSettings = userSettingsRepository.read() fun updateUserSettings(userSettings: UserSettings) = userSettingsRepository.update(userSettings) diff --git a/build.gradle b/build.gradle index 960dc44..a13448e 100644 --- a/build.gradle +++ b/build.gradle @@ -7,14 +7,14 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:4.0.1' + classpath 'com.android.tools.build:gradle:4.0.2' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files - classpath 'com.google.gms:google-services:4.3.3' - classpath 'com.google.firebase:firebase-crashlytics-gradle:2.2.1' + classpath 'com.google.gms:google-services:4.3.5' + classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.1' classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" } From ba9f3ff3dd53cadeab0a22da4cd8c2f4180ce7d1 Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Fri, 12 Mar 2021 01:00:47 -0500 Subject: [PATCH 12/19] Update settings using coroutine --- .../repositories/SharedPreferencesUserSettingsRepository.kt | 4 +++- .../data/repositories/contracts/UserSettingsRepository.kt | 2 +- .../features/settings/viewmodels/SettingsViewModel.kt | 6 +++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesUserSettingsRepository.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesUserSettingsRepository.kt index 66b76c5..5829fef 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesUserSettingsRepository.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesUserSettingsRepository.kt @@ -8,11 +8,13 @@ import com.masterwok.shrimplesearch.common.data.models.UserSettings import com.masterwok.shrimplesearch.common.data.models.from import com.masterwok.shrimplesearch.common.data.repositories.contracts.UserSettingsRepository import com.masterwok.shrimplesearch.di.modules.RepositoryModule +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.sendBlocking import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.withContext import kotlinx.serialization.decodeFromString import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json @@ -61,7 +63,7 @@ class SharedPreferencesUserSettingsRepository @Inject constructor( } } - override fun update(userSettings: UserSettings) { + override suspend fun update(userSettings: UserSettings) = withContext(Dispatchers.IO) { sharedPreferences .edit() .putString(NAME_USER_SETTINGS, Json.encodeToString(userSettings)) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/UserSettingsRepository.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/UserSettingsRepository.kt index bee0714..45e738e 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/UserSettingsRepository.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/contracts/UserSettingsRepository.kt @@ -8,7 +8,7 @@ interface UserSettingsRepository { fun read(): UserSettings - fun update(userSettings: UserSettings) + suspend fun update(userSettings: UserSettings) fun getThemeId(): Int diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/settings/viewmodels/SettingsViewModel.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/settings/viewmodels/SettingsViewModel.kt index fa57bcb..9ac18a5 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/settings/viewmodels/SettingsViewModel.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/settings/viewmodels/SettingsViewModel.kt @@ -6,8 +6,10 @@ import androidx.lifecycle.viewModelScope import com.masterwok.shrimplesearch.common.data.models.UserSettings import com.masterwok.shrimplesearch.common.data.repositories.contracts.UserSettingsRepository import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.launch import javax.inject.Inject +@ExperimentalCoroutinesApi class SettingsViewModel @Inject constructor( private val userSettingsRepository: UserSettingsRepository ) : ViewModel() { @@ -18,6 +20,8 @@ class SettingsViewModel @Inject constructor( fun readUserSettings(): UserSettings = userSettingsRepository.read() - fun updateUserSettings(userSettings: UserSettings) = userSettingsRepository.update(userSettings) + fun updateUserSettings(userSettings: UserSettings) = viewModelScope.launch { + userSettingsRepository.update(userSettings) + } } \ No newline at end of file From 1aaa64b8334624610fbc6a540f6d15609b4cb1bc Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Fri, 12 Mar 2021 01:01:45 -0500 Subject: [PATCH 13/19] build eerror --- .../shrimplesearch/main/MainActivityViewModel.kt | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/main/MainActivityViewModel.kt b/app/src/main/java/com/masterwok/shrimplesearch/main/MainActivityViewModel.kt index d4b3c54..ea96843 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/main/MainActivityViewModel.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/main/MainActivityViewModel.kt @@ -19,11 +19,13 @@ class MainActivityViewModel @Inject constructor( .read() .isExitDialogEnabled - fun disableExitDialog() = userSettingsRepository.update( - userSettingsRepository - .read() - .copy(isExitDialogEnabled = false) - ) + fun disableExitDialog() = viewModelScope.launch { + userSettingsRepository.update( + userSettingsRepository + .read() + .copy(isExitDialogEnabled = false) + ) + } fun cancelQuery() = viewModelScope.launch { jackettService.cancelQuery() From 37b7d2691d4c5f378f695873c03a0fcc33996a42 Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Fri, 12 Mar 2021 01:06:40 -0500 Subject: [PATCH 14/19] Removed dead code --- .../features/settings/viewmodels/SettingsViewModel.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/settings/viewmodels/SettingsViewModel.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/settings/viewmodels/SettingsViewModel.kt index 9ac18a5..8cbc098 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/settings/viewmodels/SettingsViewModel.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/settings/viewmodels/SettingsViewModel.kt @@ -18,8 +18,6 @@ class SettingsViewModel @Inject constructor( .getUserSettingsAsFlow() .asLiveData(viewModelScope.coroutineContext) - fun readUserSettings(): UserSettings = userSettingsRepository.read() - fun updateUserSettings(userSettings: UserSettings) = viewModelScope.launch { userSettingsRepository.update(userSettings) } From bfead57f292158757106f090048c773422a26a73 Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Fri, 12 Mar 2021 01:19:39 -0500 Subject: [PATCH 15/19] Using inner class --- .../data/repositories/JackettServiceImpl.kt | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/JackettServiceImpl.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/JackettServiceImpl.kt index 1e05994..8a7988e 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/JackettServiceImpl.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/JackettServiceImpl.kt @@ -2,16 +2,14 @@ package com.masterwok.shrimplesearch.common.data.repositories import com.masterwok.shrimplesearch.common.data.repositories.contracts.JackettService import com.masterwok.shrimplesearch.common.data.repositories.contracts.UserSettingsRepository -import com.masterwok.shrimplesearch.common.utils.notNull -import com.masterwok.xamarininterface.enums.QueryState import com.masterwok.xamarininterface.contracts.IJackettHarness import com.masterwok.xamarininterface.contracts.IJackettHarnessListener +import com.masterwok.xamarininterface.enums.QueryState import com.masterwok.xamarininterface.models.IndexerQueryResult import com.masterwok.xamarininterface.models.Query import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.withContext -import java.lang.ref.WeakReference class JackettServiceImpl constructor( private val jackettHarness: IJackettHarness, @@ -19,7 +17,7 @@ class JackettServiceImpl constructor( private val indexerBlockList: List ) : JackettService { - private val jackettHarnessListener: IJackettHarnessListener = JackettHarnessListener(this) + private val jackettHarnessListener: IJackettHarnessListener = JackettHarnessListener() private val listeners = mutableListOf() @@ -78,29 +76,25 @@ class JackettServiceImpl constructor( listeners.remove(listener) } - private class JackettHarnessListener(jackettService: JackettServiceImpl) : - IJackettHarnessListener { - - private val weakJackettService = WeakReference(jackettService) + private inner class JackettHarnessListener : IJackettHarnessListener { - override fun onIndexersInitialized() = weakJackettService.get().notNull { jackettService -> - jackettService.listeners.forEach { it.onIndexersInitialized() } + override fun onIndexersInitialized() = listeners.forEach { + it.onIndexersInitialized() } - override fun onIndexerInitialized() = weakJackettService.get().notNull { jackettService -> - jackettService.listeners.forEach { it.onIndexerInitialized() } + override fun onIndexerInitialized() = listeners.forEach { + it.onIndexerInitialized() } - override fun onResultsUpdated() = weakJackettService.get().notNull { jackettService -> - if (jackettService.queryState != QueryState.Aborted) { - jackettService.listeners.forEach { it.onResultsUpdated() } + override fun onResultsUpdated() { + if (queryState != QueryState.Aborted) { + listeners.forEach { it.onResultsUpdated() } } } - override fun onQueryStateChange(queryState: QueryState) = - weakJackettService.get().notNull { jackettService -> - jackettService.listeners.forEach { it.onQueryStateChange(queryState) } - } + override fun onQueryStateChange(queryState: QueryState) = listeners.forEach { + it.onQueryStateChange(queryState) + } } } \ No newline at end of file From efa4af59d8f8f4c902cb57734e8a90d46c5a4a25 Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Sat, 13 Mar 2021 22:06:24 -0500 Subject: [PATCH 16/19] Fixed review --- .../fragments/IndexerQueryResultsFragment.kt | 41 ++++++++----------- .../query/viewmodels/QueryViewModel.kt | 26 ++++++++++-- 2 files changed, 40 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt index 9284e75..b763975 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt @@ -20,8 +20,6 @@ import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.bottomsheets.BottomSheet import com.afollestad.materialdialogs.list.customListAdapter import com.google.android.material.snackbar.Snackbar -import com.google.android.play.core.ktx.requestReview -import com.google.android.play.core.review.ReviewInfo import com.google.android.play.core.review.ReviewManager import com.masterwok.shrimplesearch.R import com.masterwok.shrimplesearch.common.constants.AnalyticEvent @@ -42,6 +40,7 @@ import com.masterwok.shrimplesearch.features.query.viewmodels.QueryViewModel import com.masterwok.xamarininterface.enums.QueryState import com.masterwok.xamarininterface.models.QueryResultItem import kotlinx.android.synthetic.main.fragment_indexer_query_results.* +import kotlinx.coroutines.Job import javax.inject.Inject @@ -63,18 +62,9 @@ class IndexerQueryResultsFragment : Fragment() { private val userSettings: UserSettings get() = viewModel.getUserSettings() private lateinit var linearLayoutManager: LinearLayoutManager - private lateinit var reviewInfo: ReviewInfo private var snackbarNewResults: Snackbar? = null - init { - lifecycleScope.launchWhenResumed { - reviewInfo = reviewManager.requestReview() - - analyticService.logScreen(IndexerQueryResultsFragment::class.java) - } - } - private fun openQueryResultItem(queryResultItem: QueryResultItem) = activity.notNull { val linkInfo = queryResultItem.linkInfo val uri = linkInfo.magnetUri ?: linkInfo.link ?: return @@ -127,6 +117,12 @@ class IndexerQueryResultsFragment : Fragment() { subscribeToLiveData() } + override fun onResume() { + super.onResume() + + analyticService.logScreen(IndexerQueryResultsFragment::class.java) + } + private fun subscribeToViewComponents() { recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { @@ -259,20 +255,19 @@ class IndexerQueryResultsFragment : Fragment() { context.copyToClipboard(CLIPBOARD_LABEL, uri.toString()) } - private fun attemptToPresentInAppReview(deferredAction: () -> Unit) { - val isReviewInfoInitialized = this::reviewInfo.isInitialized + private fun attemptToPresentInAppReview( + deferredAction: () -> Unit + ): Job = lifecycleScope.launchWhenResumed { + viewModel.incrementResultItemTapCount() - lifecycleScope.launchWhenResumed { - if (isReviewInfoInitialized && viewModel.shouldAttemptToPresentInAppReview()) { - reviewManager - .launchReviewFlow(requireActivity(), reviewInfo) - .addOnCompleteListener { deferredAction() } - } else { - deferredAction() - } - - viewModel.incrementResultItemTapCount() + if (viewModel.reviewInfo == null || !viewModel.shouldAttemptToPresentInAppReview()) { + deferredAction() + return@launchWhenResumed } + + reviewManager + .launchReviewFlow(requireActivity(), checkNotNull(viewModel.reviewInfo)) + .addOnCompleteListener { deferredAction() } } private fun presentBottomSheet(queryResultItem: QueryResultItem) = context.notNull { context -> diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt index 1a1911b..c993ef9 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/query/viewmodels/QueryViewModel.kt @@ -1,6 +1,9 @@ package com.masterwok.shrimplesearch.features.query.viewmodels import androidx.lifecycle.* +import com.google.android.play.core.ktx.requestReview +import com.google.android.play.core.review.ReviewInfo +import com.google.android.play.core.review.ReviewManager import com.masterwok.shrimplesearch.common.constants.AnalyticEvent import com.masterwok.shrimplesearch.common.data.models.UserSettings import com.masterwok.shrimplesearch.common.data.repositories.contracts.ConfigurationRepository @@ -26,6 +29,7 @@ class QueryViewModel @Inject constructor( private val userSettingsRepository: UserSettingsRepository, private val analyticService: AnalyticService, private val configurationRepository: ConfigurationRepository, + private val reviewManager: ReviewManager, @Named(RepositoryModule.NAMED_IN_APP_REVIEW_RESULT_ITEM_TAP_COUNT) private val inAppReviewResultItemTapCount: Int ) : ViewModel(), JackettService.Listener { @@ -61,6 +65,24 @@ class QueryViewModel @Inject constructor( addSource(_liveDataIndexerQueryResults) { value = getIndexerQueryResults() } } + var reviewInfo: ReviewInfo? = null + private set + + init { + jackettService.addListener(this) + + viewModelScope.launch { + reviewInfo = requestReviewInfo() + } + } + + private suspend fun requestReviewInfo(): ReviewInfo? = try { + reviewManager.requestReview() + } catch (exception: Exception) { + analyticService.logException(exception, "Failed to request review information.") + null + } + suspend fun shouldAttemptToPresentInAppReview(): Boolean { val count = configurationRepository.getResultItemTapCount() @@ -69,10 +91,6 @@ class QueryViewModel @Inject constructor( suspend fun incrementResultItemTapCount() = configurationRepository.incrementResultTapCount() - init { - jackettService.addListener(this) - } - override fun onCleared() { jackettService.removeListener(this@QueryViewModel) From a2a7f1e2fdf3fab803ee684166d5d3cd8f11d241 Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Sat, 13 Mar 2021 22:07:43 -0500 Subject: [PATCH 17/19] PR Change --- .../query/fragments/IndexerQueryResultsFragment.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt b/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt index b763975..bbc1724 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/features/query/fragments/IndexerQueryResultsFragment.kt @@ -282,28 +282,31 @@ class IndexerQueryResultsFragment : Fragment() { R.drawable.ic_baseline_share_24, if (hasMagnetUri) R.string.share_magnet else R.string.share_link ) { - attemptToPresentInAppReview { shareQueryResultItem(queryResultItem) } dismiss() analyticService.logEvent(AnalyticEvent.ShareResult) + + attemptToPresentInAppReview { shareQueryResultItem(queryResultItem) } }, MaterialDialogIconListItemAdapter.Item( R.drawable.ic_content_copy_black_24dp, if (hasMagnetUri) R.string.copy_magnet else R.string.copy_torrent ) { - attemptToPresentInAppReview { copyQueryResultItem(queryResultItem) } dismiss() analyticService.logEvent(AnalyticEvent.CopyResult) + + attemptToPresentInAppReview { copyQueryResultItem(queryResultItem) } }, MaterialDialogIconListItemAdapter.Item( R.drawable.ic_baseline_open_in_new_24, if (hasMagnetUri) R.string.open_magnet else R.string.open_link ) { dismiss() - attemptToPresentInAppReview { openQueryResultItem(queryResultItem) } analyticService.logEvent(AnalyticEvent.OpenResult) + + attemptToPresentInAppReview { openQueryResultItem(queryResultItem) } } ) From 0e877298aebe005953f5c1305b4b10c04ec9b1cd Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Thu, 25 Mar 2021 01:24:23 -0400 Subject: [PATCH 18/19] Increased review count --- app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt index 8a67494..51b9291 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/Config.kt @@ -56,4 +56,4 @@ val DEFAULT_USER_SETTINGS = UserSettings( * The amount of times a user must tap a result item before being presented with an in-app review * workflow. */ -const val IN_APP_REVIEW_RESULT_ITEM_TAP_COUNT = 3 \ No newline at end of file +const val IN_APP_REVIEW_RESULT_ITEM_TAP_COUNT = 6 \ No newline at end of file From 959b58f01711f0f0075dd73affb206cc35ca9aac Mon Sep 17 00:00:00 2001 From: Jonathan Trowbridge Date: Thu, 25 Mar 2021 01:24:36 -0400 Subject: [PATCH 19/19] Import cleanup --- .../repositories/SharedPreferencesConfigurationRepository.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt index 8857d82..ab5f0d4 100644 --- a/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt +++ b/app/src/main/java/com/masterwok/shrimplesearch/common/data/repositories/SharedPreferencesConfigurationRepository.kt @@ -3,7 +3,6 @@ package com.masterwok.shrimplesearch.common.data.repositories import android.content.Context import com.masterwok.shrimplesearch.common.data.repositories.contracts.ConfigurationRepository import com.masterwok.shrimplesearch.di.modules.RepositoryModule -import kotlinx.coroutines.flow.flow import javax.inject.Inject import javax.inject.Named