Skip to content

Commit

Permalink
Update Settings design: Add new SettingsListItem (#5318)
Browse files Browse the repository at this point in the history
Task/Issue URL:
https://app.asana.com/0/1207908166761516/1208785622935231/f

### Description

- Adds all new Icons for Settings (not all are implemented)
- Adds new SettingsListItem
   - Also added to the ADS screen
-
[Designs](https://www.figma.com/design/CjH849hL53lhsPlf6Ufeo4/%E2%9A%99%EF%B8%8F-Browser-Settings-Documentation-(All-Platforms)?node-id=7605-431390&t=loz3Qauz2ZOadWY7-4)
- Tackles the privacy section without any copy changes which will be
done in a later PR

### Steps to test this PR

Pre-requisites: 
- `newSettings` feature flag must be enabled
- Easier to start with a fresh launch
- Don't enable DDG as default browser

_Default Browser On/Off_
- [x] Open New Settings screen
- [x] Default browser should be `off` ⚪ 
- [x] Press default browser
- [x] Select DDG
- [x] Press back to get back to the New Settings screen
- [x] Default browser should be `on` 🟢 
- [x] Press default browser
- [x] Select another browser
- [x] Press back to get back to the New Settings screen
- [x] Default browser should be `off` ⚪ 

_Private Search_
- [x] Should be `on` and is always on

_Web Tracking Protection_
- [x] Should be `on` and is always on

_Cookie Pop-Up Protection_
- [x] Open New Settings screen
- [x] Cookie Pop-Up Protection should be `on` 🟢 
- [x] Press Cookie Pop-Up Protection
- [x] Toggle **off** "Let DuckDuckGo handle cookie pop-ups"
- [x] Press back 
- [x] Cookie Pop-Up Protection should be `off` ⚪ 
- [x] Press Cookie Pop-Up Protection
- [x] Toggle **on** "Let DuckDuckGo handle cookie pop-ups"
- [x] Press back 
- [x] Cookie Pop-Up Protection should be `on` 🟢 


_App Tracking Protection_
- [x] Open New Settings screen
- [x] App Tracking Protection should be `off` ⚪ 
- [x] Press App Tracking Protection
- [x] Toggle **on** App Tracking Protection
- [x] Press back 
- [x] App Tracking Protection should be `on` 🟢 
- [x] Press App Tracking Protection
- [x] Toggle **off** App Tracking Protection
- [x] Press back 
- [x] App Tracking Protection should be `off` ⚪ 

_Email Protection_
- [x] Open New Settings screen
- [x] Email Protection should be `off` ⚪ 
- [x] Press Email Protection
- [x] Follow steps to turn on Email Protection
- [x] Open New Settings screen
- [x] Email Protection should be `on` 🟢 
- [x] Press Email Protection
- [x] Sign out
- [x] Open New Settings screen
- [x] Email Protection should be `off` ⚪ 

### UI changes
| Before  | After |
| ------ | ----- |

![Screenshot_20241126_145126](https://github.com/user-attachments/assets/5ec4e3a0-4c0a-4e33-ae30-891115a1e9f7)|![Screenshot_20241126_145056](https://github.com/user-attachments/assets/11998eff-03eb-4449-99cc-4bf1ecb1b09e)|

![Screenshot_20241126_145134](https://github.com/user-attachments/assets/e354dbe9-dfd3-4040-a179-bff6ce5cd936)|![Screenshot_20241126_145109](https://github.com/user-attachments/assets/fd538cc6-f873-4a55-b373-6c02623e04cd)

![Screenshot_20241126_145502](https://github.com/user-attachments/assets/b3955b96-8c5d-49fd-a5eb-a15e2ec4d083)|![Screenshot_20241126_145543](https://github.com/user-attachments/assets/661c22ac-b037-460f-b62e-f37a8e89083d)

### Demo


https://github.com/user-attachments/assets/df4c0a75-05f9-4ddd-afe8-b9dfb58b7fb9
  • Loading branch information
mikescamell authored Dec 2, 2024
1 parent 04e0326 commit 010d9cf
Show file tree
Hide file tree
Showing 43 changed files with 1,258 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ import com.duckduckgo.autofill.api.AutofillScreens.AutofillSettingsScreen
import com.duckduckgo.autofill.api.AutofillSettingsLaunchSource
import com.duckduckgo.common.ui.DuckDuckGoActivity
import com.duckduckgo.common.ui.view.gone
import com.duckduckgo.common.ui.view.listitem.CheckListItem
import com.duckduckgo.common.ui.view.listitem.TwoLineListItem
import com.duckduckgo.common.ui.view.show
import com.duckduckgo.common.ui.viewbinding.viewBinding
Expand Down Expand Up @@ -204,7 +203,6 @@ class NewSettingsActivity : DuckDuckGoActivity() {
updateDefaultBrowserViewVisibility(it)
updateDeviceShieldSettings(
it.appTrackingProtectionEnabled,
it.appTrackingProtectionOnboardingShown,
)
updateEmailSubtitle(it.emailAddress)
updateAutofill(it.showAutofill)
Expand Down Expand Up @@ -247,13 +245,7 @@ class NewSettingsActivity : DuckDuckGoActivity() {
}

private fun updateEmailSubtitle(emailAddress: String?) {
if (emailAddress.isNullOrEmpty()) {
viewsPrivacy.emailSetting.setSecondaryText(getString(com.duckduckgo.app.browser.R.string.settingsEmailProtectionSubtitle))
viewsPrivacy.emailSetting.setItemStatus(CheckListItem.CheckItemStatus.DISABLED)
} else {
viewsPrivacy.emailSetting.setSecondaryText(emailAddress)
viewsPrivacy.emailSetting.setItemStatus(CheckListItem.CheckItemStatus.ENABLED)
}
viewsPrivacy.emailSetting.setStatus(isOn = !emailAddress.isNullOrEmpty())
}

private fun updateSyncSetting(visible: Boolean) {
Expand All @@ -263,15 +255,7 @@ class NewSettingsActivity : DuckDuckGoActivity() {
}

private fun updateAutoconsent(enabled: Boolean) {
if (enabled) {
viewsPrivacy.cookiePopupProtectionSetting.setSecondaryText(getString(com.duckduckgo.app.browser.R.string.cookiePopupProtectionEnabled))
viewsPrivacy.cookiePopupProtectionSetting.setItemStatus(CheckListItem.CheckItemStatus.ENABLED)
} else {
viewsPrivacy.cookiePopupProtectionSetting.setSecondaryText(
getString(com.duckduckgo.app.browser.R.string.cookiePopupProtectionDescription),
)
viewsPrivacy.cookiePopupProtectionSetting.setItemStatus(CheckListItem.CheckItemStatus.DISABLED)
}
viewsPrivacy.cookiePopupProtectionSetting.setStatus(isOn = enabled)
}

private fun processCommand(it: Command?) {
Expand Down Expand Up @@ -302,38 +286,16 @@ class NewSettingsActivity : DuckDuckGoActivity() {
private fun updateDefaultBrowserViewVisibility(it: NewSettingsViewModel.ViewState) {
with(viewsPrivacy.setAsDefaultBrowserSetting) {
visibility = if (it.showDefaultBrowserSetting) {
if (it.isAppDefaultBrowser) {
setItemStatus(CheckListItem.CheckItemStatus.ENABLED)
setSecondaryText(getString(com.duckduckgo.app.browser.R.string.settingsDefaultBrowserSetDescription))
} else {
setItemStatus(CheckListItem.CheckItemStatus.DISABLED)
setSecondaryText(getString(com.duckduckgo.app.browser.R.string.settingsDefaultBrowserNotSetDescription))
}
setStatus(isOn = it.isAppDefaultBrowser)
View.VISIBLE
} else {
View.GONE
}
}
}

private fun updateDeviceShieldSettings(
appTPEnabled: Boolean,
appTrackingProtectionOnboardingShown: Boolean,
) {
with(viewsPrivacy) {
if (appTPEnabled) {
vpnSetting.setSecondaryText(getString(com.duckduckgo.app.browser.R.string.atp_SettingsDeviceShieldEnabled))
vpnSetting.setItemStatus(CheckListItem.CheckItemStatus.ENABLED)
} else {
if (appTrackingProtectionOnboardingShown) {
vpnSetting.setSecondaryText(getString(com.duckduckgo.app.browser.R.string.atp_SettingsDeviceShieldDisabled))
vpnSetting.setItemStatus(CheckListItem.CheckItemStatus.WARNING)
} else {
vpnSetting.setSecondaryText(getString(com.duckduckgo.app.browser.R.string.atp_SettingsDeviceShieldNeverEnabled))
vpnSetting.setItemStatus(CheckListItem.CheckItemStatus.DISABLED)
}
}
}
private fun updateDeviceShieldSettings(appTPEnabled: Boolean) {
viewsPrivacy.vpnSetting.setStatus(isOn = appTPEnabled)
}

private fun launchDefaultAppScreen() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,22 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.duckduckgo.anvil.annotations.ContributesViewModel
import com.duckduckgo.app.browser.defaultbrowsing.DefaultBrowserDetector
import com.duckduckgo.app.pixels.AppPixelName.*
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_ABOUT_PRESSED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_ACCESSIBILITY_PRESSED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_APPEARANCE_PRESSED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_APPTP_PRESSED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_COOKIE_POPUP_PROTECTION_PRESSED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_DEFAULT_BROWSER_PRESSED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_EMAIL_PROTECTION_PRESSED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_FIRE_BUTTON_PRESSED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_GENERAL_PRESSED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_MAC_APP_PRESSED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_OPENED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_PERMISSIONS_PRESSED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_PRIVATE_SEARCH_PRESSED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_SYNC_PRESSED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_WEB_TRACKING_PROTECTION_PRESSED
import com.duckduckgo.app.pixels.AppPixelName.SETTINGS_WINDOWS_APP_PRESSED
import com.duckduckgo.app.settings.NewSettingsViewModel.Command.LaunchAboutScreen
import com.duckduckgo.app.settings.NewSettingsViewModel.Command.LaunchAccessibilitySettings
import com.duckduckgo.app.settings.NewSettingsViewModel.Command.LaunchAddHomeScreenWidget
Expand Down Expand Up @@ -86,7 +101,6 @@ class NewSettingsViewModel @Inject constructor(
data class ViewState(
val showDefaultBrowserSetting: Boolean = false,
val isAppDefaultBrowser: Boolean = false,
val appTrackingProtectionOnboardingShown: Boolean = false,
val appTrackingProtectionEnabled: Boolean = false,
val emailAddress: String? = null,
val showAutofill: Boolean = false,
Expand Down Expand Up @@ -147,7 +161,6 @@ class NewSettingsViewModel @Inject constructor(
currentViewState().copy(
isAppDefaultBrowser = defaultBrowserAlready,
showDefaultBrowserSetting = defaultWebBrowserCapability.deviceSupportsDefaultBrowserConfiguration(),
appTrackingProtectionOnboardingShown = appTrackingProtection.isOnboarded(),
appTrackingProtectionEnabled = appTrackingProtection.isRunning(),
emailAddress = emailManager.getEmailAddress(),
showAutofill = autofillCapabilityChecker.canAccessCredentialManagementScreen(),
Expand All @@ -170,7 +183,6 @@ class NewSettingsViewModel @Inject constructor(
val isDeviceShieldEnabled = appTrackingProtection.isRunning()
val currentState = currentViewState()
viewState.value = currentState.copy(
appTrackingProtectionOnboardingShown = appTrackingProtection.isOnboarded(),
appTrackingProtectionEnabled = isDeviceShieldEnabled,
isPrivacyProEnabled = subscriptions.isEligible(),
)
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/layout/activity_settings_new.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@

<include
android:id="@+id/includeSettings"
layout="@layout/content_settings" />
layout="@layout/content_settings_new" />

</androidx.coordinatorlayout.widget.CoordinatorLayout>
68 changes: 68 additions & 0 deletions app/src/main/res/layout/content_settings_new.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2017 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.
-->

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:ignore="Overdraw">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="20dp">

<include
android:id="@+id/contentSettingsPrivacy"
layout="@layout/content_settings_new_privacy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/keyline_4" />

<LinearLayout
android:id="@+id/settingsSectionPro"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<com.duckduckgo.common.ui.view.divider.HorizontalDivider
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

<include
android:id="@+id/contentSettingsSettings"
layout="@layout/content_settings_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<include
android:id="@+id/contentSettingsMore"
layout="@layout/content_settings_other"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<include
android:id="@+id/contentSettingsInternal"
layout="@layout/content_settings_internal"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

</LinearLayout>

</ScrollView>
75 changes: 75 additions & 0 deletions app/src/main/res/layout/content_settings_new_privacy.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (c) 2018 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.
-->

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/settingsSectionPrivacy"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<com.duckduckgo.common.ui.view.listitem.SectionHeaderListItem
android:id="@+id/settingsPrivacyTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:primaryText="@string/settingsHeadingPrivacy" />

<com.duckduckgo.common.ui.view.listitem.SettingsListItem
android:id="@+id/setAsDefaultBrowserSetting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:leadingIcon="@drawable/ic_default_browser_mobile_color_24"
app:primaryText="@string/settingsDefaultBrowserTitle" />

<com.duckduckgo.common.ui.view.listitem.SettingsListItem
android:id="@+id/privateSearchSetting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:isOn="true"
app:leadingIcon="@drawable/ic_find_search_color_24"
app:primaryText="@string/settingsPrivateSearchTitle" />

<com.duckduckgo.common.ui.view.listitem.SettingsListItem
android:id="@+id/webTrackingProtectionSetting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:isOn="true"
app:leadingIcon="@drawable/ic_shield_color_24"
app:primaryText="@string/settingsWebTrackingProtectionTitle" />

<com.duckduckgo.common.ui.view.listitem.SettingsListItem
android:id="@+id/cookiePopupProtectionSetting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:leadingIcon="@drawable/ic_cookie_color_24"
app:primaryText="@string/cookiePopupProtectionTitle" />

<com.duckduckgo.common.ui.view.listitem.SettingsListItem
android:id="@+id/vpnSetting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:leadingIcon="@drawable/ic_lock_color_24"
app:primaryText="@string/atp_SettingsTitle" />

<com.duckduckgo.common.ui.view.listitem.SettingsListItem
android:id="@+id/emailSetting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:leadingIcon="@drawable/ic_email_protection_color_24"
app:primaryText="@string/settingsEmailProtectionTitle"
app:showBetaPill="true" />

</LinearLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,6 @@ enum class Component {
SECTION_HEADER_LIST_ITEM,
SINGLE_LINE_LIST_ITEM,
TWO_LINE_LIST_ITEM,
SETTINGS_LIST_ITEM,
SECTION_DIVIDER,
}
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,9 @@ sealed class ComponentViewHolder(val view: View) : RecyclerView.ViewHolder(view)
}
}

class SettingsListItemComponentViewHolder(parent: ViewGroup) :
ComponentViewHolder(inflate(parent, R.layout.component_settings))

companion object {
fun create(
parent: ViewGroup,
Expand All @@ -408,6 +411,7 @@ sealed class ComponentViewHolder(val view: View) : RecyclerView.ViewHolder(view)
Component.SECTION_DIVIDER -> DividerComponentViewHolder(parent)
Component.CARD -> CardComponentViewHolder(parent)
Component.EXPANDABLE_LAYOUT -> ExpandableComponentViewHolder(parent)
Component.SETTINGS_LIST_ITEM -> SettingsListItemComponentViewHolder(parent)
else -> {
TODO()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ import com.duckduckgo.common.ui.themepreview.ui.component.Component
import com.duckduckgo.common.ui.themepreview.ui.component.Component.MENU_ITEM
import com.duckduckgo.common.ui.themepreview.ui.component.Component.POPUP_MENU_ITEM
import com.duckduckgo.common.ui.themepreview.ui.component.Component.SECTION_HEADER_LIST_ITEM
import com.duckduckgo.common.ui.themepreview.ui.component.Component.SETTINGS_LIST_ITEM
import com.duckduckgo.common.ui.themepreview.ui.component.Component.SINGLE_LINE_LIST_ITEM
import com.duckduckgo.common.ui.themepreview.ui.component.Component.TWO_LINE_LIST_ITEM
import com.duckduckgo.common.ui.themepreview.ui.component.ComponentFragment

class ComponentListItemsElementsFragment : ComponentFragment() {
override fun getComponents(): List<Component> {
return listOf(SECTION_HEADER_LIST_ITEM, SINGLE_LINE_LIST_ITEM, TWO_LINE_LIST_ITEM, MENU_ITEM, POPUP_MENU_ITEM)
return listOf(SECTION_HEADER_LIST_ITEM, SINGLE_LINE_LIST_ITEM, TWO_LINE_LIST_ITEM, SETTINGS_LIST_ITEM, MENU_ITEM, POPUP_MENU_ITEM)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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.
*/

package com.duckduckgo.common.ui.view

import android.content.Context
import android.util.AttributeSet
import android.widget.LinearLayout
import com.duckduckgo.common.ui.viewbinding.viewBinding
import com.duckduckgo.mobile.android.databinding.ViewStatusIndicatorBinding

class StatusIndicator @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
) : LinearLayout(context, attrs, defStyleAttr) {

private val binding: ViewStatusIndicatorBinding by viewBinding()

fun setStatus(isOn: Boolean) {
if (isOn) {
binding.icon.isEnabled = true
// TODO copy changes
binding.label.text = "On"
} else {
binding.icon.isEnabled = false
// TODO copy changes
binding.label.text = "Off"
}
}
}
Loading

0 comments on commit 010d9cf

Please sign in to comment.