Skip to content

Commit

Permalink
Updates to subscription settings UI (#4809)
Browse files Browse the repository at this point in the history
  • Loading branch information
lmac012 authored Aug 1, 2024
1 parent 506137a commit fd8877e
Show file tree
Hide file tree
Showing 15 changed files with 196 additions and 86 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ import com.duckduckgo.common.ui.view.gone
import com.duckduckgo.common.ui.view.show
import com.duckduckgo.common.ui.viewbinding.viewBinding
import com.duckduckgo.di.scopes.ViewScope
import com.duckduckgo.mobile.android.R as CommonR
import com.duckduckgo.navigation.api.GlobalActivityStarter
import com.duckduckgo.networkprotection.impl.R
import com.duckduckgo.networkprotection.impl.databinding.ViewSettingsNetpBinding
import com.duckduckgo.networkprotection.impl.subscription.settings.ProSettingNetPViewModel.Command
import com.duckduckgo.networkprotection.impl.subscription.settings.ProSettingNetPViewModel.Command.OpenNetPScreen
Expand Down Expand Up @@ -96,13 +96,11 @@ class ProSettingNetPView @JvmOverloads constructor(
Hidden -> this.gone()
Pending -> {
this.show()
this.setSecondaryText(context.getString(R.string.netpSubscriptionSettingsNeverEnabled))
this.setItemStatus(com.duckduckgo.common.ui.view.listitem.CheckListItem.CheckItemStatus.DISABLED)
this.setLeadingIconResource(CommonR.drawable.ic_check_grey_round_16)
}
is ShowState -> {
this.show()
this.setSecondaryText(context.getString(networkProtectionEntryState.subtitle))
this.setItemStatus(networkProtectionEntryState.icon)
this.setLeadingIconResource(networkProtectionEntryState.icon)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@
package com.duckduckgo.networkprotection.impl.subscription.settings

import android.annotation.SuppressLint
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.duckduckgo.app.statistics.pixels.Pixel
import com.duckduckgo.common.ui.view.listitem.CheckListItem
import com.duckduckgo.common.ui.view.listitem.CheckListItem.CheckItemStatus
import com.duckduckgo.common.utils.DispatcherProvider
import com.duckduckgo.mobile.android.R as CommonR
import com.duckduckgo.navigation.api.GlobalActivityStarter.ActivityParams
import com.duckduckgo.networkprotection.api.NetworkProtectionAccessState
import com.duckduckgo.networkprotection.api.NetworkProtectionAccessState.NetPAccessState
Expand Down Expand Up @@ -72,7 +72,7 @@ class ProSettingNetPViewModel(
data object Hidden : NetPEntryState()
data object Pending : NetPEntryState()
data class ShowState(
val icon: CheckItemStatus,
@DrawableRes val icon: Int,
@StringRes val subtitle: Int,
) : NetPEntryState()
}
Expand Down Expand Up @@ -119,14 +119,14 @@ class ProSettingNetPViewModel(
else -> R.string.netpSubscriptionSettingsDisconnected
}

val netPItemStatus = if (networkProtectionConnectionState != DISCONNECTED) {
CheckListItem.CheckItemStatus.ENABLED
val netPItemIcon = if (networkProtectionConnectionState != DISCONNECTED) {
CommonR.drawable.ic_check_green_round_16
} else {
CheckListItem.CheckItemStatus.WARNING
CommonR.drawable.ic_exclamation_yellow_16
}

ShowState(
icon = netPItemStatus,
icon = netPItemIcon,
subtitle = subtitle,
)
} else {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
~ limitations under the License.
-->

<com.duckduckgo.common.ui.view.listitem.CheckListItem
<com.duckduckgo.common.ui.view.listitem.OneLineListItem
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/netpPSetting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:primaryText="@string/netpSubscriptionSettingsTitle"
app:secondaryText="@string/netpSubscriptionSettingsDisconnected"
app:showBetaPill="false" />
app:leadingIconSize="small"
app:leadingIcon="@drawable/ic_check_grey_round_16"
app:primaryText="@string/netpSubscriptionSettingsTitle" />
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,6 @@
<string name="netpSubscriptionSettingsConnected">Enabled</string>
<string name="netpSubscriptionSettingsConnecting">Connecting…</string>
<string name="netpSubscriptionSettingsDisconnected">Disabled</string>
<string name="netpSubscriptionSettingsNeverEnabled">Secure your network connection anytime, anywhere</string>

<!-- Custom DNS -->
<string name="netpSetttingDnsHeader">DNS</string>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ package com.duckduckgo.networkprotection.impl.subscription.settings
import app.cash.turbine.test
import com.duckduckgo.app.statistics.pixels.Pixel
import com.duckduckgo.common.test.CoroutineTestRule
import com.duckduckgo.common.ui.view.listitem.CheckListItem.CheckItemStatus.ENABLED
import com.duckduckgo.common.ui.view.listitem.CheckListItem.CheckItemStatus.WARNING
import com.duckduckgo.mobile.android.R as CommonR
import com.duckduckgo.navigation.api.GlobalActivityStarter.ActivityParams
import com.duckduckgo.networkprotection.api.NetworkProtectionAccessState
import com.duckduckgo.networkprotection.api.NetworkProtectionAccessState.NetPAccessState.Locked
Expand Down Expand Up @@ -122,7 +121,7 @@ class ProSettingNetPViewModelTest {
proSettingNetPViewModel.viewState.test {
assertEquals(
ShowState(
icon = ENABLED,
icon = CommonR.drawable.ic_check_green_round_16,
subtitle = R.string.netpSubscriptionSettingsConnected,
),
expectMostRecentItem().networkProtectionEntryState,
Expand Down Expand Up @@ -157,7 +156,7 @@ class ProSettingNetPViewModelTest {
proSettingNetPViewModel.viewState.test {
assertEquals(
ShowState(
icon = ENABLED,
icon = CommonR.drawable.ic_check_green_round_16,
subtitle = R.string.netpSubscriptionSettingsConnected,
),
expectMostRecentItem().networkProtectionEntryState,
Expand All @@ -176,7 +175,7 @@ class ProSettingNetPViewModelTest {
proSettingNetPViewModel.viewState.test {
assertEquals(
ShowState(
icon = ENABLED,
icon = CommonR.drawable.ic_check_green_round_16,
subtitle = R.string.netpSubscriptionSettingsConnecting,
),
expectMostRecentItem().networkProtectionEntryState,
Expand All @@ -195,7 +194,7 @@ class ProSettingNetPViewModelTest {
proSettingNetPViewModel.viewState.test {
assertEquals(
ShowState(
icon = WARNING,
icon = CommonR.drawable.ic_exclamation_yellow_16,
subtitle = R.string.netpSubscriptionSettingsDisconnected,
),
expectMostRecentItem().networkProtectionEntryState,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import com.duckduckgo.common.ui.view.show
import com.duckduckgo.common.ui.viewbinding.viewBinding
import com.duckduckgo.common.utils.ConflatedJob
import com.duckduckgo.common.utils.ViewViewModelFactory
import com.duckduckgo.common.utils.extensions.html
import com.duckduckgo.di.scopes.ViewScope
import com.duckduckgo.navigation.api.GlobalActivityStarter
import com.duckduckgo.subscriptions.api.SubscriptionStatus.AUTO_RENEWABLE
Expand Down Expand Up @@ -152,7 +151,6 @@ class ProSettingView @JvmOverloads constructor(
binding.subscriptionBuy.setSecondaryText(context.getString(R.string.subscriptionSettingExpiredSubtitle))
binding.subscriptionBuy.setItemStatus(ALERT)
binding.subscriptionGet.setText(R.string.subscriptionSettingExpiredViewPlans)
binding.subscribeSecondary.gone()
binding.subscriptionBuyContainer.show()
binding.subscriptionSettingContainer.show()
binding.subscriptionWaitingContainer.gone()
Expand All @@ -163,9 +161,6 @@ class ProSettingView @JvmOverloads constructor(
binding.subscriptionBuy.setSecondaryText(context.getString(R.string.subscriptionSettingSubscribeSubtitle))
binding.subscriptionBuy.setItemStatus(DISABLED)
binding.subscriptionGet.setText(R.string.subscriptionSettingGet)
val htmlText = context.getString(R.string.subscriptionSettingFeaturesList).html(context)
binding.subscribeSecondary.text = htmlText.noTrailingWhiteLines()
binding.subscribeSecondary.show()
binding.subscriptionBuyContainer.show()
binding.subscriptionSettingContainer.gone()
binding.subscriptionWaitingContainer.gone()
Expand Down Expand Up @@ -203,11 +198,3 @@ class SubscriptionSettingLayout @JvmOverloads constructor(
return true
}
}

private fun CharSequence.noTrailingWhiteLines(): CharSequence {
var text = this
while (text[text.length - 1] == '\n') {
text = text.subSequence(0, text.length - 1)
}
return text
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import com.duckduckgo.anvil.annotations.ContributeToActivityStarter
import com.duckduckgo.anvil.annotations.InjectWith
import com.duckduckgo.browser.api.ui.BrowserScreens.WebViewActivityWithParams
import com.duckduckgo.common.ui.DuckDuckGoActivity
import com.duckduckgo.common.ui.view.dialog.TextAlertDialogBuilder
import com.duckduckgo.common.ui.viewbinding.viewBinding
Expand All @@ -34,7 +35,7 @@ import com.duckduckgo.navigation.api.GlobalActivityStarter
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.impl.R.string
import com.duckduckgo.subscriptions.impl.R.*
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.BASIC_SUBSCRIPTION
import com.duckduckgo.subscriptions.impl.SubscriptionsConstants.FAQS_URL
Expand Down Expand Up @@ -126,6 +127,10 @@ class SubscriptionSettingsActivity : DuckDuckGoActivity() {
goToPurchasePage()
}

binding.privacyPolicy.setOnClickListener {
goToPrivacyPolicy()
}

if (savedInstanceState == null) {
pixelSender.reportSubscriptionSettingsShown()
}
Expand All @@ -140,12 +145,14 @@ class SubscriptionSettingsActivity : DuckDuckGoActivity() {
if (viewState.status in listOf(INACTIVE, EXPIRED)) {
binding.viewPlans.isVisible = true
binding.changePlan.isVisible = false
binding.expiredWarningContainer.isVisible = true
binding.description.text = getString(string.subscriptionsExpiredData, viewState.date)
binding.subscriptionActiveStatusContainer.isVisible = false
binding.subscriptionExpiredStatusContainer.isVisible = true
binding.subscriptionExpiredStatusText.text = getString(string.subscriptionsExpiredData, viewState.date)
} else {
binding.viewPlans.isVisible = false
binding.changePlan.isVisible = true
binding.expiredWarningContainer.isVisible = false
binding.subscriptionActiveStatusContainer.isVisible = true
binding.subscriptionExpiredStatusContainer.isVisible = false

val status = when (viewState.status) {
AUTO_RENEWABLE -> getString(string.renews)
Expand Down Expand Up @@ -265,11 +272,22 @@ class SubscriptionSettingsActivity : DuckDuckGoActivity() {
)
}

private fun goToPrivacyPolicy() {
globalActivityStarter.start(
this,
WebViewActivityWithParams(
url = PRIVACY_POLICY_URL,
screenTitle = getString(string.privacyPolicyAndTermsOfService),
),
)
}

companion object {
const val URL = "https://play.google.com/store/account/subscriptions?sku=%s&package=%s"
const val ADD_EMAIL_URL = "https://duckduckgo.com/subscriptions/add-email"
const val MANAGE_URL = "https://duckduckgo.com/subscriptions/manage"
const val LEARN_MORE_URL = "https://duckduckgo.com/duckduckgo-help-pages/privacy-pro/adding-email"
const val PRIVACY_POLICY_URL = "https://duckduckgo.com/pro/privacy-terms"
data object SubscriptionsSettingsScreenWithEmptyParams : GlobalActivityStarter.ActivityParams
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2024 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.
-->

<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">

<size
android:width="6dp"
android:height="6dp" />

<solid android:color="#21C000" />

</shape>
Loading

0 comments on commit fd8877e

Please sign in to comment.