diff --git a/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewActivity.kt b/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewActivity.kt index f21ebf35373d..076b0cd1c35f 100644 --- a/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewActivity.kt +++ b/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewActivity.kt @@ -70,6 +70,7 @@ import com.duckduckgo.duckchat.impl.ui.filechooser.capture.launcher.UploadFromEx import com.duckduckgo.duckchat.impl.ui.filechooser.capture.launcher.UploadFromExternalMediaAppLauncher.MediaCaptureResult.NoMediaCaptured import com.duckduckgo.js.messaging.api.JsMessageCallback import com.duckduckgo.js.messaging.api.JsMessaging +import com.duckduckgo.js.messaging.api.SubscriptionEventData import com.duckduckgo.navigation.api.GlobalActivityStarter import com.duckduckgo.navigation.api.getActivityParams import com.duckduckgo.subscriptions.api.SUBSCRIPTIONS_FEATURE_NAME @@ -80,6 +81,8 @@ import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.cancellable +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.json.JSONObject @@ -92,6 +95,8 @@ internal data class DuckChatWebViewActivityWithParams( @ContributeToActivityStarter(DuckChatWebViewActivityWithParams::class) open class DuckChatWebViewActivity : DuckDuckGoActivity(), DownloadConfirmationDialogListener { + private val viewModel: DuckChatWebViewActivityViewModel by bindViewModel() + @Inject lateinit var webViewClient: DuckChatWebViewClient @@ -284,6 +289,21 @@ open class DuckChatWebViewActivity : DuckDuckGoActivity(), DownloadConfirmationD } pendingUploadTask = null } + + // Observe ViewModel commands + viewModel.commands + .onEach { command -> + when (command) { + is DuckChatWebViewActivityViewModel.Command.SendSubscriptionAuthUpdateEvent -> { + val authUpdateEvent = SubscriptionEventData( + featureName = SUBSCRIPTIONS_FEATURE_NAME, + subscriptionName = "authUpdate", + params = org.json.JSONObject(), + ) + contentScopeScripts.sendSubscriptionEvent(authUpdateEvent) + } + } + }.launchIn(lifecycleScope) } data class FileChooserRequestedParams( diff --git a/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewActivityViewModel.kt b/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewActivityViewModel.kt new file mode 100644 index 000000000000..1bc3277e7c2a --- /dev/null +++ b/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewActivityViewModel.kt @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.duckchat.impl.ui + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.duckduckgo.anvil.annotations.ContributesViewModel +import com.duckduckgo.di.scopes.ActivityScope +import com.duckduckgo.subscriptions.api.Subscriptions +import javax.inject.Inject +import kotlinx.coroutines.channels.BufferOverflow.DROP_OLDEST +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.receiveAsFlow + +@ContributesViewModel(ActivityScope::class) +class DuckChatWebViewActivityViewModel @Inject constructor( + private val subscriptions: Subscriptions, +) : ViewModel() { + + private val commandChannel = Channel(capacity = 1, onBufferOverflow = DROP_OLDEST) + val commands = commandChannel.receiveAsFlow() + + sealed class Command { + data object SendSubscriptionAuthUpdateEvent : Command() + } + + init { + observeSubscriptionChanges() + } + + private fun observeSubscriptionChanges() { + subscriptions.getSubscriptionStatusFlow() + .distinctUntilChanged() + .onEach { _ -> + commandChannel.trySend(Command.SendSubscriptionAuthUpdateEvent) + }.launchIn(viewModelScope) + } +} diff --git a/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewFragment.kt b/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewFragment.kt index 202847d6f69e..99c619d69d14 100644 --- a/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewFragment.kt +++ b/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewFragment.kt @@ -37,6 +37,7 @@ import android.webkit.WebView import androidx.annotation.AnyThread import androidx.appcompat.widget.Toolbar import androidx.core.content.ContextCompat +import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import com.duckduckgo.anvil.annotations.InjectWith import com.duckduckgo.app.di.AppCoroutineScope @@ -48,6 +49,7 @@ import com.duckduckgo.common.ui.view.makeSnackbarWithNoBottomInset import com.duckduckgo.common.ui.viewbinding.viewBinding import com.duckduckgo.common.utils.ConflatedJob import com.duckduckgo.common.utils.DispatcherProvider +import com.duckduckgo.common.utils.FragmentViewModelFactory import com.duckduckgo.di.scopes.FragmentScope import com.duckduckgo.downloads.api.DOWNLOAD_SNACKBAR_DELAY import com.duckduckgo.downloads.api.DOWNLOAD_SNACKBAR_LENGTH @@ -72,6 +74,7 @@ import com.duckduckgo.duckchat.impl.ui.filechooser.capture.launcher.UploadFromEx import com.duckduckgo.duckchat.impl.ui.filechooser.capture.launcher.UploadFromExternalMediaAppLauncher.MediaCaptureResult.NoMediaCaptured import com.duckduckgo.js.messaging.api.JsMessageCallback import com.duckduckgo.js.messaging.api.JsMessaging +import com.duckduckgo.js.messaging.api.SubscriptionEventData import com.duckduckgo.subscriptions.api.SUBSCRIPTIONS_FEATURE_NAME import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.snackbar.Snackbar @@ -80,6 +83,8 @@ import javax.inject.Inject import javax.inject.Named import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.cancellable +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.json.JSONObject @@ -87,6 +92,13 @@ import org.json.JSONObject @InjectWith(FragmentScope::class) open class DuckChatWebViewFragment : DuckDuckGoFragment(R.layout.activity_duck_chat_webview), DownloadConfirmationDialogListener { + @Inject + lateinit var viewModelFactory: FragmentViewModelFactory + + private val viewModel: DuckChatWebViewViewModel by lazy { + ViewModelProvider(this, viewModelFactory)[DuckChatWebViewViewModel::class.java] + } + @Inject lateinit var webViewClient: DuckChatWebViewClient @@ -279,6 +291,21 @@ open class DuckChatWebViewFragment : DuckDuckGoFragment(R.layout.activity_duck_c } pendingUploadTask = null } + + // Observe ViewModel commands + viewModel.commands + .onEach { command -> + when (command) { + is DuckChatWebViewViewModel.Command.SendSubscriptionAuthUpdateEvent -> { + val authUpdateEvent = SubscriptionEventData( + featureName = SUBSCRIPTIONS_FEATURE_NAME, + subscriptionName = "authUpdate", + params = JSONObject(), + ) + contentScopeScripts.sendSubscriptionEvent(authUpdateEvent) + } + } + }.launchIn(lifecycleScope) } data class FileChooserRequestedParams( diff --git a/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewViewModel.kt b/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewViewModel.kt new file mode 100644 index 000000000000..6fb3206b8504 --- /dev/null +++ b/duckchat/duckchat-impl/src/main/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewViewModel.kt @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2025 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.duckchat.impl.ui + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.duckduckgo.anvil.annotations.ContributesViewModel +import com.duckduckgo.di.scopes.FragmentScope +import com.duckduckgo.subscriptions.api.Subscriptions +import javax.inject.Inject +import kotlinx.coroutines.channels.BufferOverflow.DROP_OLDEST +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.receiveAsFlow + +@ContributesViewModel(FragmentScope::class) +class DuckChatWebViewViewModel @Inject constructor( + private val subscriptions: Subscriptions, +) : ViewModel() { + + private val commandChannel = Channel(capacity = 1, onBufferOverflow = DROP_OLDEST) + val commands = commandChannel.receiveAsFlow() + + sealed class Command { + data object SendSubscriptionAuthUpdateEvent : Command() + } + + init { + observeSubscriptionChanges() + } + + private fun observeSubscriptionChanges() { + subscriptions.getSubscriptionStatusFlow() + .distinctUntilChanged() + .onEach { _ -> + commandChannel.trySend(Command.SendSubscriptionAuthUpdateEvent) + }.launchIn(viewModelScope) + } +} diff --git a/duckchat/duckchat-impl/src/test/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewActivityViewModelTest.kt b/duckchat/duckchat-impl/src/test/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewActivityViewModelTest.kt new file mode 100644 index 000000000000..1e727b5164d7 --- /dev/null +++ b/duckchat/duckchat-impl/src/test/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewActivityViewModelTest.kt @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2025 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.duckchat.impl.ui + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import app.cash.turbine.test +import com.duckduckgo.common.test.CoroutineTestRule +import com.duckduckgo.duckchat.impl.ui.DuckChatWebViewActivityViewModel.Command +import com.duckduckgo.subscriptions.api.SubscriptionStatus +import com.duckduckgo.subscriptions.api.SubscriptionStatus.AUTO_RENEWABLE +import com.duckduckgo.subscriptions.api.SubscriptionStatus.EXPIRED +import com.duckduckgo.subscriptions.api.SubscriptionStatus.INACTIVE +import com.duckduckgo.subscriptions.api.SubscriptionStatus.UNKNOWN +import com.duckduckgo.subscriptions.api.Subscriptions +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever + +@RunWith(AndroidJUnit4::class) +class DuckChatWebViewActivityViewModelTest { + + @get:Rule + val coroutineTestRule: CoroutineTestRule = CoroutineTestRule() + + private val subscriptions: Subscriptions = mock() + private val subscriptionStatusFlow = MutableSharedFlow() + + private lateinit var viewModel: DuckChatWebViewActivityViewModel + + @Before + fun setup() { + whenever(subscriptions.getSubscriptionStatusFlow()).thenReturn(subscriptionStatusFlow) + viewModel = DuckChatWebViewActivityViewModel(subscriptions) + } + + @Test + fun whenSubscriptionStatusChangesToActiveThenSendSubscriptionAuthUpdateEventCommand() = runTest { + viewModel.commands.test { + subscriptionStatusFlow.emit(AUTO_RENEWABLE) + + val command = awaitItem() + assertTrue(command is Command.SendSubscriptionAuthUpdateEvent) + } + } + + @Test + fun whenSubscriptionStatusChangesToInactiveThenSendSubscriptionAuthUpdateEventCommand() = runTest { + viewModel.commands.test { + subscriptionStatusFlow.emit(INACTIVE) + + val command = awaitItem() + assertTrue(command is Command.SendSubscriptionAuthUpdateEvent) + } + } + + @Test + fun whenSubscriptionStatusChangesToExpiredThenSendSubscriptionAuthUpdateEventCommand() = runTest { + viewModel.commands.test { + subscriptionStatusFlow.emit(EXPIRED) + + val command = awaitItem() + assertTrue(command is Command.SendSubscriptionAuthUpdateEvent) + } + } + + @Test + fun whenSubscriptionStatusChangesToUnknownThenSendSubscriptionAuthUpdateEventCommand() = runTest { + viewModel.commands.test { + subscriptionStatusFlow.emit(UNKNOWN) + + val command = awaitItem() + assertTrue(command is Command.SendSubscriptionAuthUpdateEvent) + } + } + + @Test + fun whenSubscriptionStatusChangesTwiceToSameValueThenOnlyOneCommandSent() = runTest { + viewModel.commands.test { + // Emit the same status twice + subscriptionStatusFlow.emit(AUTO_RENEWABLE) + subscriptionStatusFlow.emit(AUTO_RENEWABLE) + + // Should only receive one command due to distinctUntilChanged + val command = awaitItem() + assertTrue(command is Command.SendSubscriptionAuthUpdateEvent) + expectNoEvents() + } + } + + @Test + fun whenSubscriptionStatusChangesTwiceToDifferentValuesThenTwoCommandsSent() = runTest { + viewModel.commands.test { + subscriptionStatusFlow.emit(AUTO_RENEWABLE) + subscriptionStatusFlow.emit(EXPIRED) + + val firstCommand = awaitItem() + assertTrue(firstCommand is Command.SendSubscriptionAuthUpdateEvent) + + val secondCommand = awaitItem() + assertTrue(secondCommand is Command.SendSubscriptionAuthUpdateEvent) + } + } + + @Test + fun whenMultipleSubscriptionStatusChangesOccurThenCorrespondingCommandsSent() = runTest { + viewModel.commands.test { + subscriptionStatusFlow.emit(UNKNOWN) + subscriptionStatusFlow.emit(INACTIVE) + subscriptionStatusFlow.emit(AUTO_RENEWABLE) + subscriptionStatusFlow.emit(EXPIRED) + + repeat(4) { + val command = awaitItem() + assertTrue(command is Command.SendSubscriptionAuthUpdateEvent) + } + } + } +} diff --git a/duckchat/duckchat-impl/src/test/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewViewModelTest.kt b/duckchat/duckchat-impl/src/test/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewViewModelTest.kt new file mode 100644 index 000000000000..6e2c33e42ef9 --- /dev/null +++ b/duckchat/duckchat-impl/src/test/java/com/duckduckgo/duckchat/impl/ui/DuckChatWebViewViewModelTest.kt @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2025 DuckDuckGo + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.duckduckgo.duckchat.impl.ui + +import androidx.test.ext.junit.runners.AndroidJUnit4 +import app.cash.turbine.test +import com.duckduckgo.common.test.CoroutineTestRule +import com.duckduckgo.duckchat.impl.ui.DuckChatWebViewViewModel.Command +import com.duckduckgo.subscriptions.api.SubscriptionStatus +import com.duckduckgo.subscriptions.api.SubscriptionStatus.AUTO_RENEWABLE +import com.duckduckgo.subscriptions.api.SubscriptionStatus.EXPIRED +import com.duckduckgo.subscriptions.api.SubscriptionStatus.INACTIVE +import com.duckduckgo.subscriptions.api.SubscriptionStatus.UNKNOWN +import com.duckduckgo.subscriptions.api.Subscriptions +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.test.runTest +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.kotlin.mock +import org.mockito.kotlin.whenever + +@RunWith(AndroidJUnit4::class) +class DuckChatWebViewViewModelTest { + + @get:Rule + val coroutineTestRule: CoroutineTestRule = CoroutineTestRule() + + private val subscriptions: Subscriptions = mock() + private val subscriptionStatusFlow = MutableSharedFlow() + + private lateinit var viewModel: DuckChatWebViewViewModel + + @Before + fun setup() { + whenever(subscriptions.getSubscriptionStatusFlow()).thenReturn(subscriptionStatusFlow) + viewModel = DuckChatWebViewViewModel(subscriptions) + } + + @Test + fun whenSubscriptionStatusChangesToActiveThenSendSubscriptionAuthUpdateEventCommand() = runTest { + viewModel.commands.test { + subscriptionStatusFlow.emit(AUTO_RENEWABLE) + + val command = awaitItem() + assertTrue(command is Command.SendSubscriptionAuthUpdateEvent) + } + } + + @Test + fun whenSubscriptionStatusChangesToInactiveThenSendSubscriptionAuthUpdateEventCommand() = runTest { + viewModel.commands.test { + subscriptionStatusFlow.emit(INACTIVE) + + val command = awaitItem() + assertTrue(command is Command.SendSubscriptionAuthUpdateEvent) + } + } + + @Test + fun whenSubscriptionStatusChangesToExpiredThenSendSubscriptionAuthUpdateEventCommand() = runTest { + viewModel.commands.test { + subscriptionStatusFlow.emit(EXPIRED) + + val command = awaitItem() + assertTrue(command is Command.SendSubscriptionAuthUpdateEvent) + } + } + + @Test + fun whenSubscriptionStatusChangesToUnknownThenSendSubscriptionAuthUpdateEventCommand() = runTest { + viewModel.commands.test { + subscriptionStatusFlow.emit(UNKNOWN) + + val command = awaitItem() + assertTrue(command is Command.SendSubscriptionAuthUpdateEvent) + } + } + + @Test + fun whenSubscriptionStatusChangesTwiceToSameValueThenOnlyOneCommandSent() = runTest { + viewModel.commands.test { + // Emit the same status twice + subscriptionStatusFlow.emit(AUTO_RENEWABLE) + subscriptionStatusFlow.emit(AUTO_RENEWABLE) + + // Should only receive one command due to distinctUntilChanged + val command = awaitItem() + assertTrue(command is Command.SendSubscriptionAuthUpdateEvent) + expectNoEvents() + } + } + + @Test + fun whenSubscriptionStatusChangesTwiceToDifferentValuesThenTwoCommandsSent() = runTest { + viewModel.commands.test { + subscriptionStatusFlow.emit(AUTO_RENEWABLE) + subscriptionStatusFlow.emit(EXPIRED) + + val firstCommand = awaitItem() + assertTrue(firstCommand is Command.SendSubscriptionAuthUpdateEvent) + + val secondCommand = awaitItem() + assertTrue(secondCommand is Command.SendSubscriptionAuthUpdateEvent) + } + } + + @Test + fun whenMultipleSubscriptionStatusChangesOccurThenCorrespondingCommandsSent() = runTest { + viewModel.commands.test { + subscriptionStatusFlow.emit(UNKNOWN) + subscriptionStatusFlow.emit(INACTIVE) + subscriptionStatusFlow.emit(AUTO_RENEWABLE) + subscriptionStatusFlow.emit(EXPIRED) + + repeat(4) { + val command = awaitItem() + assertTrue(command is Command.SendSubscriptionAuthUpdateEvent) + } + } + } +} diff --git a/subscriptions/subscriptions-api/src/main/java/com/duckduckgo/subscriptions/api/Subscriptions.kt b/subscriptions/subscriptions-api/src/main/java/com/duckduckgo/subscriptions/api/Subscriptions.kt index 0524d100ff18..09f66815d04e 100644 --- a/subscriptions/subscriptions-api/src/main/java/com/duckduckgo/subscriptions/api/Subscriptions.kt +++ b/subscriptions/subscriptions-api/src/main/java/com/duckduckgo/subscriptions/api/Subscriptions.kt @@ -49,6 +49,8 @@ interface Subscriptions { */ suspend fun isEligible(): Boolean + fun getSubscriptionStatusFlow(): Flow + /** * @return `SubscriptionStatus` with the current subscription status */ diff --git a/subscriptions/subscriptions-dummy-impl/src/main/java/com/duckduckgo/subscriptions/impl/SubscriptionsDummy.kt b/subscriptions/subscriptions-dummy-impl/src/main/java/com/duckduckgo/subscriptions/impl/SubscriptionsDummy.kt index 8bd21d9fc006..3527248b269a 100644 --- a/subscriptions/subscriptions-dummy-impl/src/main/java/com/duckduckgo/subscriptions/impl/SubscriptionsDummy.kt +++ b/subscriptions/subscriptions-dummy-impl/src/main/java/com/duckduckgo/subscriptions/impl/SubscriptionsDummy.kt @@ -38,6 +38,8 @@ class SubscriptionsDummy @Inject constructor() : Subscriptions { override suspend fun isEligible(): Boolean = false + override fun getSubscriptionStatusFlow(): Flow = flowOf(UNKNOWN) + override suspend fun getSubscriptionStatus(): SubscriptionStatus = UNKNOWN override suspend fun getAvailableProducts(): Set = emptySet() diff --git a/subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/RealSubscriptions.kt b/subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/RealSubscriptions.kt index 28df3d5f11a4..c3beae4e99b8 100644 --- a/subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/RealSubscriptions.kt +++ b/subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/RealSubscriptions.kt @@ -82,6 +82,10 @@ class RealSubscriptions @Inject constructor( return isActive || (isEligible && supportsEncryption) } + override fun getSubscriptionStatusFlow(): Flow { + return subscriptionsManager.subscriptionStatus + } + override suspend fun getSubscriptionStatus(): SubscriptionStatus { return subscriptionsManager.subscriptionStatus() } diff --git a/subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/messaging/SubscriptionsJSHelper.kt b/subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/messaging/SubscriptionsJSHelper.kt index f28484d9bd6a..b55cb7549208 100644 --- a/subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/messaging/SubscriptionsJSHelper.kt +++ b/subscriptions/subscriptions-impl/src/main/java/com/duckduckgo/subscriptions/impl/messaging/SubscriptionsJSHelper.kt @@ -49,6 +49,7 @@ class RealSubscriptionsJSHelper @Inject constructor( put(SUBSCRIPTION_DETAILS) put(GET_AUTH_ACCESS_TOKEN) put(GET_FEATURE_CONFIG) + put(AUTH_UPDATE) } } else { JSONArray().apply { @@ -140,6 +141,7 @@ class RealSubscriptionsJSHelper @Inject constructor( private const val AVAILABLE_MESSAGES = "availableMessages" private const val SUBSCRIPTION_DETAILS = "subscriptionDetails" private const val GET_AUTH_ACCESS_TOKEN = "getAuthAccessToken" + private const val AUTH_UPDATE = "authUpdate" private const val GET_FEATURE_CONFIG = "getFeatureConfig" private const val PLATFORM = "platform" private const val ANDROID = "android" diff --git a/subscriptions/subscriptions-impl/src/test/java/com/duckduckgo/subscriptions/impl/RealProductSubscriptionManagerTest.kt b/subscriptions/subscriptions-impl/src/test/java/com/duckduckgo/subscriptions/impl/RealProductSubscriptionManagerTest.kt index c5572a08c51d..89c2185da075 100644 --- a/subscriptions/subscriptions-impl/src/test/java/com/duckduckgo/subscriptions/impl/RealProductSubscriptionManagerTest.kt +++ b/subscriptions/subscriptions-impl/src/test/java/com/duckduckgo/subscriptions/impl/RealProductSubscriptionManagerTest.kt @@ -263,6 +263,8 @@ private class FakeSubscriptions( override suspend fun isEligible(): Boolean = true + override fun getSubscriptionStatusFlow(): Flow = flowOf(subscriptionStatus) + override suspend fun getSubscriptionStatus(): SubscriptionStatus = subscriptionStatus override suspend fun getAvailableProducts(): Set = emptySet() diff --git a/subscriptions/subscriptions-impl/src/test/java/com/duckduckgo/subscriptions/impl/messaging/RealSubscriptionsJSHelperTest.kt b/subscriptions/subscriptions-impl/src/test/java/com/duckduckgo/subscriptions/impl/messaging/RealSubscriptionsJSHelperTest.kt index e2bbf5450fe6..5b9b7754470c 100644 --- a/subscriptions/subscriptions-impl/src/test/java/com/duckduckgo/subscriptions/impl/messaging/RealSubscriptionsJSHelperTest.kt +++ b/subscriptions/subscriptions-impl/src/test/java/com/duckduckgo/subscriptions/impl/messaging/RealSubscriptionsJSHelperTest.kt @@ -78,6 +78,7 @@ class RealSubscriptionsJSHelperTest { put("subscriptionDetails") put("getAuthAccessToken") put("getFeatureConfig") + put("authUpdate") }, ) put("platform", "android")