1
0
Fork 0

No issue: Use ImageView rather than rebuilding drawable (#3616)

HomeFragment's onboarding items included drawableStart values, but also
built drawables in the view holders to replace them. Instead, we should
just use ImageViews so that work isn't duplicated.
master
Tiger Oakes 2019-06-26 19:03:06 -04:00 committed by Sawyer Blatz
parent 4994554576
commit e8bd090a8e
19 changed files with 317 additions and 285 deletions

View File

@ -45,7 +45,7 @@ fun Context.getPreferenceKey(@StringRes resourceId: Int): String =
resources.getString(resourceId) resources.getString(resourceId)
/** /**
* Shares content via [ACTION_SEND] intent. * Shares content via [ACTION_SEND] intent.
* *
* @param text the data to be shared [EXTRA_TEXT] * @param text the data to be shared [EXTRA_TEXT]
* @param subject of the intent [EXTRA_TEXT] * @param subject of the intent [EXTRA_TEXT]
@ -74,7 +74,7 @@ fun Context.share(text: String, subject: String = ""): Boolean {
} }
/** /**
* Gets the Root View with an activity context * Gets the Root View with an activity context
* *
* @return ViewGroup? if it is able to get a root view from the context * @return ViewGroup? if it is able to get a root view from the context
*/ */

View File

@ -0,0 +1,11 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.ext
import android.graphics.drawable.Drawable
fun Drawable.setBounds(size: Int) {
setBounds(0, 0, size, size)
}

View File

@ -88,7 +88,7 @@ class HomeFragment : Fragment(), AccountObserver {
private val singleSessionObserver = object : Session.Observer { private val singleSessionObserver = object : Session.Observer {
override fun onTitleChanged(session: Session, title: String) { override fun onTitleChanged(session: Session, title: String) {
super.onTitleChanged(session, title) super.onTitleChanged(session, title)
if (deleteAllSessionsJob != null) { return } if (deleteAllSessionsJob != null) return
emitSessionChanges() emitSessionChanges()
} }
} }

View File

@ -30,9 +30,9 @@ import org.mozilla.fenix.home.sessioncontrol.onNext
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class TabViewHolder( class TabViewHolder(
val view: View, view: View,
actionEmitter: Observer<SessionControlAction>, actionEmitter: Observer<SessionControlAction>,
val job: Job, private val job: Job,
override val containerView: View? = view override val containerView: View? = view
) : ) :
RecyclerView.ViewHolder(view), LayoutContainer, CoroutineScope { RecyclerView.ViewHolder(view), LayoutContainer, CoroutineScope {

View File

@ -23,6 +23,7 @@ class OnboardingFinishViewHolder(
actionEmitter.onNext(OnboardingAction.Finish) actionEmitter.onNext(OnboardingAction.Finish)
} }
} }
companion object { companion object {
const val LAYOUT_ID = R.layout.onboarding_finish const val LAYOUT_ID = R.layout.onboarding_finish
} }

View File

@ -0,0 +1,22 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.appcompat.content.res.AppCompatResources
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.setBounds
/**
* Sets the drawableStart of a header in an onboarding card.
*/
fun TextView.setOnboardingIcon(@DrawableRes id: Int) {
val icon = AppCompatResources.getDrawable(context, id)
val size = context.resources.getDimensionPixelSize(R.dimen.onboarding_header_icon_height_width)
icon?.setBounds(size)
setCompoundDrawablesRelative(icon, null, null, null)
}

View File

@ -5,21 +5,15 @@
package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding
import android.view.View import android.view.View
import androidx.appcompat.content.res.AppCompatResources
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.onboarding_privacy_notice.view.* import kotlinx.android.synthetic.main.onboarding_privacy_notice.view.*
import org.jetbrains.anko.dimen
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.settings.SupportUtils
class OnboardingPrivacyNoticeViewHolder(view: View) : RecyclerView.ViewHolder(view) { class OnboardingPrivacyNoticeViewHolder(view: View) : RecyclerView.ViewHolder(view) {
init { init {
val icon = AppCompatResources.getDrawable(view.context, R.drawable.ic_onboarding_privacy_notice) view.header_text.setOnboardingIcon(R.drawable.ic_onboarding_privacy_notice)
val size = view.context.dimen(R.dimen.onboarding_header_icon_height_width)
icon?.setBounds(0, 0, size, size)
view.header_text.setCompoundDrawables(icon, null, null, null)
val appName = view.context.getString(R.string.app_name) val appName = view.context.getString(R.string.app_name)
view.description_text.text = view.context.getString(R.string.onboarding_privacy_notice_description, appName) view.description_text.text = view.context.getString(R.string.onboarding_privacy_notice_description, appName)

View File

@ -4,59 +4,74 @@
package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding
import android.content.Context
import android.graphics.Canvas import android.graphics.Canvas
import android.graphics.Paint import android.graphics.Paint
import android.text.SpannableString import android.text.SpannableString
import android.text.Spanned import android.text.Spanned
import android.text.style.ImageSpan import android.text.style.ImageSpan
import android.view.View import android.view.View
import androidx.annotation.DrawableRes
import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.content.res.AppCompatResources
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.onboarding_private_browsing.view.* import kotlinx.android.synthetic.main.onboarding_private_browsing.view.*
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.setBounds
class OnboardingPrivateBrowsingViewHolder(view: View) : RecyclerView.ViewHolder(view) { class OnboardingPrivateBrowsingViewHolder(view: View) : RecyclerView.ViewHolder(view) {
init { init {
val iconDrawable = AppCompatResources.getDrawable(view.context, R.drawable.ic_private_browsing)!! view.header_text.setOnboardingIcon(R.drawable.ic_onboarding_private_browsing)
iconDrawable.setBounds(0, 0, view.description_text.lineHeight, view.description_text.lineHeight)
val icon = object : ImageSpan(iconDrawable) { // Display a private browsing icon as a character inside the description text.
override fun draw( val inlineIcon = PrivateBrowsingImageSpan(
canvas: Canvas, view.context,
text: CharSequence?, R.drawable.ic_private_browsing,
start: Int, view.description_text.lineHeight
end: Int,
x: Float,
top: Int,
y: Int,
bottom: Int,
paint: Paint
) {
canvas.save()
val fmPaint = paint.fontMetricsInt
val fontHeight = fmPaint.descent - fmPaint.ascent
val centerY = y + fmPaint.descent - fontHeight / 2
val transY = (centerY - (drawable.bounds.bottom - drawable.bounds.top) / 2).toFloat()
canvas.translate(x, transY)
drawable.draw(canvas)
canvas.restore()
}
}
val text = SpannableString(view.context.getString(R.string.onboarding_private_browsing_description))
val spanStartIndex = text.indexOf(IMAGE_PLACEHOLDER)
text.setSpan(
icon,
spanStartIndex,
spanStartIndex + IMAGE_PLACEHOLDER.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
) )
val text = SpannableString(view.context.getString(R.string.onboarding_private_browsing_description)).apply {
val spanStartIndex = indexOf(IMAGE_PLACEHOLDER)
setSpan(
inlineIcon,
spanStartIndex,
spanStartIndex + IMAGE_PLACEHOLDER.length,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
view.description_text.text = text view.description_text.text = text
} }
class PrivateBrowsingImageSpan(
context: Context,
@DrawableRes drawableId: Int,
size: Int
) : ImageSpan(
AppCompatResources.getDrawable(context, drawableId)!!.apply { setBounds(size) }
) {
override fun draw(
canvas: Canvas,
text: CharSequence?,
start: Int,
end: Int,
x: Float,
top: Int,
y: Int,
bottom: Int,
paint: Paint
) {
canvas.save()
val fmPaint = paint.fontMetricsInt
val fontHeight = fmPaint.descent - fmPaint.ascent
val centerY = y + fmPaint.descent - fontHeight / 2
val transY = (centerY - (drawable.bounds.bottom - drawable.bounds.top) / 2).toFloat()
canvas.translate(x, transY)
drawable.draw(canvas)
canvas.restore()
}
}
companion object { companion object {
const val IMAGE_PLACEHOLDER = "%s" const val IMAGE_PLACEHOLDER = "%s"
const val LAYOUT_ID = R.layout.onboarding_private_browsing const val LAYOUT_ID = R.layout.onboarding_private_browsing

View File

@ -4,37 +4,27 @@
package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding
import android.content.Context
import android.os.Build import android.os.Build
import android.os.Build.VERSION.SDK_INT import android.os.Build.VERSION.SDK_INT
import android.view.View import android.view.View
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.onboarding_section_header.view.*
import kotlinx.android.synthetic.main.onboarding_theme_picker.view.* import kotlinx.android.synthetic.main.onboarding_theme_picker.view.*
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.utils.Settings
class OnboardingThemePickerViewHolder(private val view: View) : RecyclerView.ViewHolder(view) { class OnboardingThemePickerViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(labelBuilder: (Context) -> String) {
view.section_header_text.text = labelBuilder(view.context)
}
companion object {
const val LAYOUT_ID = R.layout.onboarding_theme_picker
}
init { init {
val radioLightTheme = view.theme_light_radio_button val radioLightTheme = view.theme_light_radio_button
val radioDarkTheme = view.theme_dark_radio_button val radioDarkTheme = view.theme_dark_radio_button
val radioFollowDeviceTheme = view.theme_automatic_radio_button val radioFollowDeviceTheme = view.theme_automatic_radio_button
if (SDK_INT >= Build.VERSION_CODES.P) { radioFollowDeviceTheme.key = if (SDK_INT >= Build.VERSION_CODES.P) {
radioFollowDeviceTheme?.key = R.string.pref_key_follow_device_theme R.string.pref_key_follow_device_theme
} else { } else {
radioFollowDeviceTheme?.key = R.string.pref_key_auto_battery_theme R.string.pref_key_auto_battery_theme
} }
radioLightTheme.addToRadioGroup(radioDarkTheme) radioLightTheme.addToRadioGroup(radioDarkTheme)
@ -79,20 +69,25 @@ class OnboardingThemePickerViewHolder(private val view: View) : RecyclerView.Vie
} }
with(Settings.getInstance(view.context)) { with(Settings.getInstance(view.context)) {
when { val radio = when {
this.shouldUseLightTheme -> radioLightTheme.isChecked = true this.shouldUseLightTheme -> radioLightTheme
this.shouldUseDarkTheme -> radioDarkTheme.isChecked = true this.shouldUseDarkTheme -> radioDarkTheme
else -> radioFollowDeviceTheme.isChecked = true else -> radioFollowDeviceTheme
} }
radio.isChecked = true
} }
} }
private fun setNewTheme(mode: Int) { private fun setNewTheme(mode: Int) {
if (AppCompatDelegate.getDefaultNightMode() == mode) return if (AppCompatDelegate.getDefaultNightMode() == mode) return
AppCompatDelegate.setDefaultNightMode(mode) AppCompatDelegate.setDefaultNightMode(mode)
view.context?.components?.core?.let { with(itemView.context.components) {
it.engine.settings.preferredColorScheme = it.getPreferredColorScheme() core.engine.settings.preferredColorScheme = core.getPreferredColorScheme()
useCases.sessionUseCases.reload.invoke()
} }
view.context?.components?.useCases?.sessionUseCases?.reload?.invoke() }
companion object {
const val LAYOUT_ID = R.layout.onboarding_theme_picker
} }
} }

View File

@ -5,22 +5,16 @@
package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding
import android.view.View import android.view.View
import androidx.appcompat.content.res.AppCompatResources
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.onboarding_tracking_protection.view.* import kotlinx.android.synthetic.main.onboarding_tracking_protection.view.*
import org.jetbrains.anko.dimen
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.utils.Settings
class OnboardingTrackingProtectionViewHolder(val view: View) : RecyclerView.ViewHolder(view) { class OnboardingTrackingProtectionViewHolder(view: View) : RecyclerView.ViewHolder(view) {
init { init {
val icon = AppCompatResources.getDrawable(view.context, R.drawable.ic_onboarding_tracking_protection) view.header_text.setOnboardingIcon(R.drawable.ic_onboarding_tracking_protection)
val size = view.context.dimen(R.dimen.onboarding_header_icon_height_width)
icon?.setBounds(0, 0, size, size)
view.header_text.setCompoundDrawables(icon, null, null, null)
val appName = view.context.getString(R.string.app_name) val appName = view.context.getString(R.string.app_name)
view.description_text.text = view.context.getString( view.description_text.text = view.context.getString(
@ -28,24 +22,21 @@ class OnboardingTrackingProtectionViewHolder(val view: View) : RecyclerView.View
appName appName
) )
val switch = view.tracking_protection_toggle view.tracking_protection_toggle.apply {
isChecked = Settings.getInstance(view.context).shouldUseTrackingProtection
switch.isChecked = Settings.getInstance(view.context).shouldUseTrackingProtection setOnCheckedChangeListener { _, isChecked ->
updateTrackingProtectionSetting(isChecked)
switch.setOnCheckedChangeListener { _, isChecked -> }
updateTrackingProtectionSetting(isChecked)
} }
} }
private fun updateTrackingProtectionSetting(enabled: Boolean) { private fun updateTrackingProtectionSetting(enabled: Boolean) {
Settings.getInstance(view.context).setTrackingProtection(enabled) Settings.getInstance(itemView.context).setTrackingProtection(enabled)
with(view.context.components) { with(itemView.context.components) {
val policy = core.createTrackingProtectionPolicy(enabled) val policy = core.createTrackingProtectionPolicy(enabled)
useCases.settingsUseCases.updateTrackingProtection.invoke(policy) useCases.settingsUseCases.updateTrackingProtection.invoke(policy)
useCases.sessionUseCases.reload.invoke() useCases.sessionUseCases.reload.invoke()
} }
view.context.components.useCases.sessionUseCases.reload.invoke()
} }
companion object { companion object {

View File

@ -6,34 +6,32 @@ package org.mozilla.fenix.onboarding
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.core.content.edit
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
class FenixOnboarding(private val context: Context) { class FenixOnboarding(context: Context) {
private val onboardingPrefs = context.applicationContext.getSharedPreferences( private val metrics = context.components.analytics.metrics
OnboardingKeys.PREF_NAME.key, private val onboardingPrefs = context.getSharedPreferences(
PREF_NAME_ONBOARDING_KEY,
Context.MODE_PRIVATE Context.MODE_PRIVATE
) )
private var SharedPreferences.onboardedVersion: Int private var SharedPreferences.onboardedVersion: Int
get() = getInt(OnboardingKeys.LAST_VERSION.key, 0) get() = getInt(LAST_VERSION_ONBOARDING_KEY, 0)
set(version) { edit().putInt(OnboardingKeys.LAST_VERSION.key, version).apply() } set(version) { edit { putInt(LAST_VERSION_ONBOARDING_KEY, version) } }
fun finish() { fun finish() {
onboardingPrefs.onboardedVersion = CURRENT_ONBOARDING_VERSION onboardingPrefs.onboardedVersion = CURRENT_ONBOARDING_VERSION
context.components.analytics.metrics.track(Event.DismissedOnboarding) metrics.track(Event.DismissedOnboarding)
} }
fun userHasBeenOnboarded(): Boolean { fun userHasBeenOnboarded() = onboardingPrefs.onboardedVersion == CURRENT_ONBOARDING_VERSION
return onboardingPrefs.onboardedVersion == CURRENT_ONBOARDING_VERSION
}
private enum class OnboardingKeys(val key: String) {
PREF_NAME("fenix.onboarding"),
LAST_VERSION("fenix.onboarding.last_version")
}
companion object { companion object {
private const val CURRENT_ONBOARDING_VERSION = 1 private const val CURRENT_ONBOARDING_VERSION = 1
private const val PREF_NAME_ONBOARDING_KEY = "fenix.onboarding"
private const val LAST_VERSION_ONBOARDING_KEY = "fenix.onboarding.last_version"
} }
} }

View File

@ -7,6 +7,8 @@ package org.mozilla.fenix.onboarding
import android.content.Context import android.content.Context
import android.util.AttributeSet import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatRadioButton import androidx.appcompat.widget.AppCompatRadioButton
import androidx.core.content.edit
import androidx.core.content.withStyledAttributes
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.utils.Settings import org.mozilla.fenix.utils.Settings
@ -16,20 +18,12 @@ class OnboardingRadioButton(context: Context, attrs: AttributeSet) : AppCompatRa
var key: Int = 0 var key: Int = 0
init { init {
attrs.let { context.withStyledAttributes(
context.theme.obtainStyledAttributes( attrs,
it, R.styleable.OnboardingRadioButton,
R.styleable.OnboardingRadioButton, 0, 0
0, 0 ) {
).apply { key = getResourceId(R.styleable.OnboardingRadioButton_onboardingKey, 0)
try {
key = getResourceId(
R.styleable.OnboardingRadioButton_onboardingKey, 0
)
} finally {
recycle()
}
}
} }
} }
@ -37,7 +31,7 @@ class OnboardingRadioButton(context: Context, attrs: AttributeSet) : AppCompatRa
radioGroups.add(radioButton) radioGroups.add(radioButton)
} }
fun onClickListener(listener: (() -> Unit)) { fun onClickListener(listener: () -> Unit) {
clickListener = listener clickListener = listener
} }
@ -51,12 +45,13 @@ class OnboardingRadioButton(context: Context, attrs: AttributeSet) : AppCompatRa
private fun updateRadioValue(isChecked: Boolean) { private fun updateRadioValue(isChecked: Boolean) {
this.isChecked = isChecked this.isChecked = isChecked
Settings.getInstance(context).preferences.edit().putBoolean(context.getString(key), isChecked) Settings.getInstance(context).preferences.edit {
.apply() putBoolean(context.getString(key), isChecked)
}
} }
private fun toggleRadioGroups() { private fun toggleRadioGroups() {
if (this.isChecked) { if (isChecked) {
radioGroups.forEach { it.updateRadioValue(false) } radioGroups.forEach { it.updateRadioValue(false) }
} }
} }

View File

@ -2,22 +2,24 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public <!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this - License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/onboarding_card" xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/OnboardingCardDark" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" style="@style/OnboardingCardDark"
android:layout_height="wrap_content" android:id="@+id/onboarding_card"
android:orientation="vertical"> android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView <androidx.appcompat.widget.AppCompatTextView
android:id="@+id/header_text" android:id="@+id/header_text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="14dp" android:layout_marginBottom="14dp"
app:drawableStartCompat="@drawable/ic_onboarding_firefox_accounts" tools:text="@string/onboarding_firefox_account_header"
tools:drawableStart="@drawable/ic_onboarding_firefox_accounts"
android:drawablePadding="12dp" android:drawablePadding="12dp"
android:text="@string/onboarding_firefox_account_header"
android:textAppearance="@style/Header16TextStyle" android:textAppearance="@style/Header16TextStyle"
android:textColor="@color/onboarding_card_primary_text_dark" /> android:textColor="@color/onboarding_card_primary_text_dark" />

View File

@ -3,16 +3,17 @@
- License, v. 2.0. If a copy of the MPL was not distributed with this - License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<FrameLayout <FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/onboarding_header" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:id="@+id/onboarding_header"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp">
<TextView
android:id="@+id/header_text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/onboarding_header" android:layout_marginBottom="8dp">
android:textAppearance="@style/HeaderTextStyle" <TextView
android:textSize="22sp" /> android:id="@+id/header_text"
</FrameLayout> android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="@string/onboarding_header"
android:textAppearance="@style/HeaderTextStyle"
android:textSize="22sp" />
</FrameLayout>

View File

@ -2,50 +2,62 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public <!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this - License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<LinearLayout <androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/onboarding_card" xmlns:tools="http://schemas.android.com/tools"
style="@style/OnboardingCardLight" android:id="@+id/onboarding_card"
android:layout_width="match_parent" style="@style/OnboardingCardLight"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:orientation="vertical"> android:layout_height="wrap_content">
<TextView <TextView
android:id="@+id/header_text" android:id="@+id/header_text"
app:drawableStartCompat="@drawable/ic_onboarding_privacy_notice" android:layout_width="0dp"
android:drawablePadding="12dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="14dp"
android:text="@string/onboarding_privacy_notice_header"
android:textAppearance="@style/HeaderTextStyle" />
<TextView
android:id="@+id/description_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/onboarding_privacy_notice_description"
android:textAppearance="@style/Body14TextStyle" />
<FrameLayout
android:id="@+id/read_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@drawable/button_background"
android:backgroundTint="?neutralFaded"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
android:padding="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center" android:text="@string/onboarding_privacy_notice_header"
android:clickable="false" tools:drawableStart="@drawable/ic_onboarding_privacy_notice"
android:focusable="false" android:drawablePadding="12dp"
android:textStyle="bold" android:textAppearance="@style/HeaderTextStyle"
android:gravity="center" android:gravity="center_vertical"
android:text="@string/onboarding_privacy_notice_read_button" android:lines="1"
android:textColor="?primaryText" app:layout_constraintStart_toStartOf="parent"
android:textSize="14sp" /> app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/description_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/Body14TextStyle"
android:layout_marginTop="14dp"
tools:text="@string/onboarding_privacy_notice_description"
app:layout_constraintTop_toBottomOf="@id/header_text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<FrameLayout
android:id="@+id/read_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@drawable/button_background"
android:backgroundTint="?neutralFaded"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
android:padding="10dp"
app:layout_constraintTop_toBottomOf="@id/description_text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:clickable="false"
android:focusable="false"
android:textStyle="bold"
android:gravity="center"
android:text="@string/onboarding_privacy_notice_read_button"
android:textColor="?primaryText"
android:textSize="14sp" />
</FrameLayout> </FrameLayout>
</LinearLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -2,43 +2,36 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public <!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this - License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/onboarding_card" xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/OnboardingCardLight" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:id="@+id/onboarding_card"
android:layout_height="wrap_content"> style="@style/OnboardingCardLight"
<ImageView
android:importantForAccessibility="no"
android:id="@+id/private_browsing_icon"
android:layout_width="30dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,1:1"
app:srcCompat="@drawable/ic_onboarding_private_browsing"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/header_text"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="@string/onboarding_private_browsing_header"
android:gravity="center_vertical"
android:lines="1"
android:textAppearance="@style/HeaderTextStyle"
android:layout_marginStart="12dp"
app:layout_constraintStart_toEndOf="@id/private_browsing_icon"
app:layout_constraintTop_toTopOf="@id/private_browsing_icon"
app:layout_constraintBottom_toBottomOf="@id/private_browsing_icon"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/description_text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content">
android:text="@string/onboarding_private_browsing_description" <TextView
android:textAppearance="@style/Body14TextStyle" android:id="@+id/header_text"
android:layout_marginTop="14dp" android:layout_width="0dp"
app:layout_constraintTop_toBottomOf="@id/private_browsing_icon" android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent" tools:drawableStart="@drawable/ic_onboarding_private_browsing"
app:layout_constraintEnd_toEndOf="parent" android:drawablePadding="12dp"
app:layout_constraintBottom_toBottomOf="parent" /> android:text="@string/onboarding_private_browsing_header"
android:textAppearance="@style/HeaderTextStyle"
android:gravity="center_vertical"
android:lines="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/description_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/Body14TextStyle"
android:layout_marginTop="14dp"
tools:text="@string/onboarding_private_browsing_description"
app:layout_constraintTop_toBottomOf="@id/header_text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -2,15 +2,12 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public <!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this - License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<FrameLayout <TextView
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/onboarding_header" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:id="@+id/section_header_text"
android:layout_height="wrap_content" android:layout_width="match_parent"
android:layout_marginBottom="16dp"> android:layout_height="wrap_content"
<TextView android:textAppearance="@style/HeaderTextStyle"
android:id="@+id/section_header_text" tools:text="@tools:sample/lorem"
android:layout_width="match_parent" android:layout_marginBottom="16dp" />
android:layout_height="wrap_content"
android:textAppearance="@style/HeaderTextStyle" tools:text="@tools:sample/lorem"/>
</FrameLayout>

View File

@ -2,38 +2,43 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public <!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this - License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.constraintlayout.widget.ConstraintLayout
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/onboarding_card" xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/OnboardingCardLight" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:id="@+id/onboarding_card"
android:layout_height="wrap_content" style="@style/OnboardingCardLight"
android:orientation="vertical">
<TextView
android:id="@+id/header_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:drawableStartCompat="@drawable/ic_onboarding_tracking_protection"
android:drawablePadding="12dp"
android:text="@string/onboarding_tracking_protection_header"
android:textAppearance="@style/HeaderTextStyle"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/tracking_protection_toggle"/>
<Switch
android:id="@+id/tracking_protection_toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/description_text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content">
android:text="@string/onboarding_tracking_protection_description" <TextView
android:textAppearance="@style/Body14TextStyle" android:id="@+id/header_text"
android:layout_marginTop="12dp" android:layout_width="0dp"
app:layout_constraintStart_toStartOf="parent" android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/header_text" android:text="@string/onboarding_tracking_protection_header"
app:layout_constraintBottom_toBottomOf="parent"/> tools:drawableStart="@drawable/ic_onboarding_tracking_protection"
android:drawablePadding="12dp"
android:textAppearance="@style/HeaderTextStyle"
android:gravity="center_vertical"
android:lines="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toStartOf="@id/tracking_protection_toggle" />
<Switch
android:id="@+id/tracking_protection_toggle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/header_text"
app:layout_constraintBottom_toBottomOf="@id/header_text"/>
<TextView
android:id="@+id/description_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/Body14TextStyle"
android:layout_marginTop="12dp"
tools:text="@string/onboarding_tracking_protection_description"
app:layout_constraintTop_toBottomOf="@id/header_text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -3,27 +3,27 @@
- License, v. 2.0. If a copy of the MPL was not distributed with this - License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/private_session_description_wrapper" android:id="@+id/private_session_description_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:orientation="vertical">
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
android:textColor="?primaryText"
android:text="@string/private_browsing_title"
android:layout_marginBottom="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/private_session_description"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:ellipsize="none" android:layout_margin="16dp"
android:gravity="center_vertical" android:orientation="vertical">
android:scrollHorizontally="false" <TextView
android:text="@string/private_browsing_explanation" android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
android:textColor="?primaryText" android:textColor="?primaryText"
android:textSize="14sp" /> android:text="@string/private_browsing_title"
</LinearLayout> android:layout_marginBottom="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/private_session_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="none"
android:gravity="center_vertical"
android:scrollHorizontally="false"
tools:text="@string/private_browsing_explanation"
android:textColor="?primaryText"
android:textSize="14sp" />
</LinearLayout>