Skip to content

Commit

Permalink
Integrate FE for purchasing a sub
Browse files Browse the repository at this point in the history
  • Loading branch information
marcosholgado committed Nov 21, 2023
1 parent 292dba4 commit 444a064
Show file tree
Hide file tree
Showing 21 changed files with 679 additions and 644 deletions.
10 changes: 2 additions & 8 deletions subscriptions/subscriptions-impl/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.duckduckgo.subscriptions.impl">
<application android:supportsRtl="true">
<activity
android:name=".ui.SubscriptionsActivity"
android:exported="false"
android:label="Subscriptions Internal"
android:parentActivityName="com.duckduckgo.app.settings.SettingsActivity"
android:screenOrientation="portrait" />
<activity
android:name=".ui.SubscriptionsWebViewActivity"
android:exported="false"
android:label="Subscriptions"
android:parentActivityName="com.duckduckgo.subscriptions.impl.ui.SubscriptionsActivity"
android:parentActivityName="com.duckduckgo.app.settings.SettingsActivity"
android:screenOrientation="portrait" />
<activity
android:name=".ui.SubscriptionSettingsActivity"
Expand All @@ -47,7 +41,7 @@
android:name=".ui.RestoreSubscriptionActivity"
android:exported="false"
android:label="Activate Subscription"
android:parentActivityName=".ui.SubscriptionsActivity"
android:parentActivityName="com.duckduckgo.app.settings.SettingsActivity"
android:screenOrientation="portrait" />
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2023 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.subscriptions.impl

object SubscriptionsConstants {

// List of subscriptions
const val BASIC_SUBSCRIPTION = "ddg_privacy_pro"
val LIST_OF_PRODUCTS = listOf(BASIC_SUBSCRIPTION)

// List of plans
const val YEARLY_PLAN = "ddg-privacy-pro-sandbox-yearly-renews-us"
const val MONTHLY_PLAN = "ddg-privacy-pro-sandbox-monthly-renews-us"

// List of features
const val NETP = "vpn"
const val ITR = "identity-theft-restoration"
const val PIR = "personal-information-removal"

// Platform
const val PLATFORM = "android"

// Recurrence
const val MONTHLY = "monthly"
const val YEARLY = "yearly"

// URLs
const val BUY_URL = "https://abrown.duckduckgo.com/subscriptions"
}
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ class RealSubscriptionsManager @Inject constructor(
offerToken: String,
isReset: Boolean,
) {
_currentPurchaseState.emit(CurrentPurchase.PreFlowInProgress)
when (val response = prePurchaseFlow()) {
is Success -> {
if (response.entitlements.isEmpty()) {
Expand All @@ -251,6 +252,7 @@ class RealSubscriptionsManager @Inject constructor(
isReset = isReset,
).build()
logcat(LogPriority.DEBUG) { "Subs: external id is ${response.externalId}" }
_currentPurchaseState.emit(CurrentPurchase.PreFlowFinished)
withContext(dispatcherProvider.main()) {
billingClientWrapper.launchBillingFlow(activity, billingParams)
}
Expand Down Expand Up @@ -290,7 +292,13 @@ class RealSubscriptionsManager @Inject constructor(
override suspend fun getAuthToken(): AuthToken {
return if (isUserAuthenticated()) {
when (val response = getSubscriptionDataFromToken(authDataStore.authToken!!)) {
is Success -> return AuthToken.Success(authDataStore.authToken!!)
is Success -> {
return if (response.entitlements.isEmpty()) {
AuthToken.Failure("")
} else {
AuthToken.Success(authDataStore.authToken!!)
}
}
is Failure -> {
when (response.message) {
"expired_token" -> {
Expand Down Expand Up @@ -371,6 +379,8 @@ sealed class SubscriptionsData {
}

sealed class CurrentPurchase {
object PreFlowInProgress : CurrentPurchase()
object PreFlowFinished : CurrentPurchase()
object InProgress : CurrentPurchase()
object Success : CurrentPurchase()
object Recovered : CurrentPurchase()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import com.duckduckgo.app.di.AppCoroutineScope
import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver
import com.duckduckgo.common.utils.DispatcherProvider
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.LIST_OF_PRODUCTS
import com.duckduckgo.subscriptions.impl.billing.PurchaseState.Canceled
import com.duckduckgo.subscriptions.impl.billing.PurchaseState.InProgress
import com.duckduckgo.subscriptions.impl.billing.PurchaseState.Purchased
Expand Down Expand Up @@ -296,16 +297,6 @@ class RealBillingClientWrapper @Inject constructor(
.setObfuscatedAccountId(finalId)
.setObfuscatedProfileId(finalId)
}

companion object {
// List of subscriptions
const val BASIC_SUBSCRIPTION = "ddg_privacy_pro"
private val LIST_OF_PRODUCTS = listOf(BASIC_SUBSCRIPTION)

// List of plans
const val YEARLY_PLAN = "ddg-privacy-pro-sandbox-yearly-renews-us"
const val MONTHLY_PLAN = "ddg-privacy-pro-sandbox-monthly-renews-us"
}
}

sealed class PurchaseState {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ class SubscriptionMessagingInterface @Inject constructor(

private val handlers = listOf(
BackToSettingsMessage(),
GetSubscriptionOptions(),
SubscriptionSelected(),
GetSubscriptionMessage(subscriptionsManager, dispatcherProvider),
SetSubscriptionMessage(subscriptionsManager, appCoroutineScope, dispatcherProvider),
)
Expand Down Expand Up @@ -98,14 +100,46 @@ class SubscriptionMessagingInterface @Inject constructor(
}

override fun onResponse(response: JsCallbackData) {
// NOOP
val jsResponse = JsRequestResponse.Success(
context = context,
featureName = response.featureName,
method = response.method,
id = response.id,
result = response.params,
)

jsMessageHelper.sendJsResponse(jsResponse, callbackName, secret, webView)
}

override val context: String = "subscriptionPages"
override val callbackName: String = "messageCallback"
override val secret: String = "duckduckgo-android-messaging-secret"
override val allowedDomains: List<String> = listOf("abrown.duckduckgo.com")

inner class SubscriptionSelected : JsMessageHandler {
override fun process(jsMessage: JsMessage, secret: String, webView: WebView, jsMessageCallback: JsMessageCallback): JsRequestResponse? {
if (jsMessage.featureName != featureName && jsMessage.method != method) return null
jsMessageCallback.process(featureName, method, "id", jsMessage.params)
return null
}

override val allowedDomains: List<String> = emptyList()
override val featureName: String = "useSubscription"
override val method: String = "subscriptionSelected"
}

inner class GetSubscriptionOptions : JsMessageHandler {
override fun process(jsMessage: JsMessage, secret: String, webView: WebView, jsMessageCallback: JsMessageCallback): JsRequestResponse? {
if (jsMessage.featureName != featureName && jsMessage.method != method) return null
jsMessageCallback.process(featureName, method, jsMessage.id!!, jsMessage.params)
return null
}

override val allowedDomains: List<String> = emptyList()
override val featureName: String = "useSubscription"
override val method: String = "getSubscriptionOptions"
}

inner class BackToSettingsMessage : JsMessageHandler {
override fun process(jsMessage: JsMessage, secret: String, webView: WebView, jsMessageCallback: JsMessageCallback): JsRequestResponse? {
if (jsMessage.featureName != featureName && jsMessage.method != method) return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ package com.duckduckgo.subscriptions.impl.repository
import com.android.billingclient.api.ProductDetails
import com.android.billingclient.api.ProductDetails.SubscriptionOfferDetails
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.BASIC_SUBSCRIPTION
import com.duckduckgo.subscriptions.impl.billing.BillingClientWrapper
import com.duckduckgo.subscriptions.impl.billing.RealBillingClientWrapper.Companion.BASIC_SUBSCRIPTION
import com.squareup.anvil.annotations.ContributesBinding
import dagger.SingleInstanceIn
import javax.inject.Inject
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ import com.duckduckgo.common.ui.viewbinding.viewBinding
import com.duckduckgo.common.utils.ConflatedJob
import com.duckduckgo.di.scopes.ViewScope
import com.duckduckgo.navigation.api.GlobalActivityStarter
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.BUY_URL
import com.duckduckgo.subscriptions.impl.databinding.ViewSettingsBuyBinding
import com.duckduckgo.subscriptions.impl.settings.views.ProSettingBuyViewModel.Command
import com.duckduckgo.subscriptions.impl.settings.views.ProSettingBuyViewModel.Command.OpenBuyScreen
import com.duckduckgo.subscriptions.impl.settings.views.ProSettingBuyViewModel.Factory
import com.duckduckgo.subscriptions.impl.ui.SubscriptionsActivity.Companion.SubscriptionsScreenWithEmptyParams
import com.duckduckgo.subscriptions.impl.ui.SubscriptionsWebViewActivityWithParams
import dagger.android.support.AndroidSupportInjection
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
Expand Down Expand Up @@ -90,7 +91,7 @@ class ProSettingBuyView @JvmOverloads constructor(
private fun processCommands(command: Command) {
when (command) {
is OpenBuyScreen -> {
globalActivityStarter.start(context, SubscriptionsScreenWithEmptyParams)
globalActivityStarter.start(context, SubscriptionsWebViewActivityWithParams(url = BUY_URL, "Buy Subscription"))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import com.duckduckgo.common.ui.viewbinding.viewBinding
import com.duckduckgo.di.scopes.ActivityScope
import com.duckduckgo.navigation.api.GlobalActivityStarter
import com.duckduckgo.subscriptions.impl.R.string
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.BUY_URL
import com.duckduckgo.subscriptions.impl.databinding.ActivityRestoreSubscriptionBinding
import com.duckduckgo.subscriptions.impl.ui.RestoreSubscriptionActivity.Companion.RestoreSubscriptionScreenWithEmptyParams
import com.duckduckgo.subscriptions.impl.ui.RestoreSubscriptionViewModel.Command
Expand All @@ -36,7 +37,6 @@ import com.duckduckgo.subscriptions.impl.ui.RestoreSubscriptionViewModel.Command
import com.duckduckgo.subscriptions.impl.ui.RestoreSubscriptionViewModel.Command.SubscriptionNotFound
import com.duckduckgo.subscriptions.impl.ui.RestoreSubscriptionViewModel.Command.Success
import com.duckduckgo.subscriptions.impl.ui.SubscriptionSettingsActivity.Companion.SubscriptionsSettingsScreenWithEmptyParams
import com.duckduckgo.subscriptions.impl.ui.SubscriptionsActivity.Companion.SubscriptionsScreenWithEmptyParams
import javax.inject.Inject
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
Expand Down Expand Up @@ -109,7 +109,10 @@ class RestoreSubscriptionActivity : DuckDuckGoActivity() {
.addEventListener(
object : TextAlertDialogBuilder.EventListener() {
override fun onPositiveButtonClicked() {
globalActivityStarter.start(this@RestoreSubscriptionActivity, SubscriptionsScreenWithEmptyParams)
globalActivityStarter.start(
this@RestoreSubscriptionActivity,
SubscriptionsWebViewActivityWithParams(url = BUY_URL, "Buy Subscription"),
)
}
},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import com.duckduckgo.common.ui.viewbinding.viewBinding
import com.duckduckgo.di.scopes.ActivityScope
import com.duckduckgo.navigation.api.GlobalActivityStarter
import com.duckduckgo.subscriptions.impl.R.string
import com.duckduckgo.subscriptions.impl.billing.RealBillingClientWrapper.Companion.BASIC_SUBSCRIPTION
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.BASIC_SUBSCRIPTION
import com.duckduckgo.subscriptions.impl.databinding.ActivitySubscriptionSettingsBinding
import com.duckduckgo.subscriptions.impl.ui.AddDeviceActivity.Companion.AddDeviceScreenWithEmptyParams
import com.duckduckgo.subscriptions.impl.ui.SubscriptionSettingsActivity.Companion.SubscriptionsSettingsScreenWithEmptyParams
Expand Down
Loading

0 comments on commit 444a064

Please sign in to comment.