1
0
Fork 0

For #2389 - Create Theme Onboarding Card

master
Emily Kager 2019-05-16 14:41:58 -07:00 committed by Emily Kager
parent 42d1491976
commit d347f73e69
13 changed files with 356 additions and 15 deletions

View File

@ -6,9 +6,14 @@ package org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding
import android.content.Context
import android.view.View
import androidx.appcompat.app.AppCompatDelegate
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.onboarding_section_header.view.*
import kotlinx.android.synthetic.main.onboarding_theme_picker.view.*
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.asActivity
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.utils.Settings
class OnboardingThemePickerViewHolder(private val view: View) : RecyclerView.ViewHolder(view) {
@ -19,4 +24,71 @@ class OnboardingThemePickerViewHolder(private val view: View) : RecyclerView.Vie
companion object {
const val LAYOUT_ID = R.layout.onboarding_theme_picker
}
init {
val radioLightTheme = view.theme_light_radio_button
val radioDarkTheme = view.theme_dark_radio_button
val radioFollowDeviceTheme = view.theme_automatic_radio_button
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
radioFollowDeviceTheme?.key = R.string.pref_key_follow_device_theme
} else {
radioFollowDeviceTheme?.key = R.string.pref_key_auto_battery_theme
}
radioLightTheme.addToRadioGroup(radioDarkTheme)
radioDarkTheme.addToRadioGroup(radioLightTheme)
radioLightTheme.addToRadioGroup(radioFollowDeviceTheme)
radioDarkTheme.addToRadioGroup(radioFollowDeviceTheme)
radioFollowDeviceTheme.addToRadioGroup(radioDarkTheme)
radioFollowDeviceTheme.addToRadioGroup(radioLightTheme)
view.theme_dark_image.setOnClickListener {
radioDarkTheme.performClick()
}
view.theme_light_image.setOnClickListener {
radioLightTheme.performClick()
}
view.clickable_region_automatic.setOnClickListener {
radioFollowDeviceTheme.performClick()
}
radioLightTheme.onClickListener {
setNewTheme(AppCompatDelegate.MODE_NIGHT_NO)
}
radioDarkTheme.onClickListener {
setNewTheme(AppCompatDelegate.MODE_NIGHT_YES)
}
radioFollowDeviceTheme.onClickListener {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
setNewTheme(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
} else {
setNewTheme(AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY)
}
}
with(Settings.getInstance(view.context)) {
when {
this.shouldFollowDeviceTheme -> radioFollowDeviceTheme.isChecked = true
this.shouldUseLightTheme -> radioLightTheme.isChecked = true
else -> radioDarkTheme.isChecked = true
}
}
}
private fun setNewTheme(mode: Int) {
if (AppCompatDelegate.getDefaultNightMode() == mode) return
AppCompatDelegate.setDefaultNightMode(mode)
view.context?.asActivity()?.recreate()
view.context?.components?.core?.let {
it.engine.settings.preferredColorScheme = it.getPreferredColorScheme()
}
view.context?.components?.useCases?.sessionUseCases?.reload?.invoke()
}
}

View File

@ -0,0 +1,64 @@
package org.mozilla.fenix.onboarding
/* 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/. */
import android.content.Context
import android.util.AttributeSet
import android.widget.RadioButton
import org.mozilla.fenix.R
import org.mozilla.fenix.utils.Settings
class OnboardingRadioButton : RadioButton {
private val radioGroups = mutableListOf<OnboardingRadioButton>()
private var clickListener: (() -> Unit)? = null
var key: Int = 0
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
attrs.let {
context.theme.obtainStyledAttributes(
it,
R.styleable.OnboardingRadioButton,
0, 0
).apply {
try {
key = getResourceId(
R.styleable.OnboardingRadioButton_onboardingKey, 0
)
} finally {
recycle()
}
}
}
}
fun addToRadioGroup(radioButton: OnboardingRadioButton) {
radioGroups.add(radioButton)
}
fun onClickListener(listener: (() -> Unit)) {
clickListener = listener
}
init {
setOnClickListener {
updateRadioValue(true)
toggleRadioGroups()
clickListener?.invoke()
true
}
}
private fun updateRadioValue(isChecked: Boolean) {
this.isChecked = isChecked
Settings.getInstance(context).preferences.edit().putBoolean(context.getString(key), isChecked)
.apply()
}
private fun toggleRadioGroups() {
if (this.isChecked) {
radioGroups.forEach { it.updateRadioValue(false) }
}
}
}

View File

@ -4,17 +4,17 @@
package org.mozilla.fenix.settings
import android.view.View
import androidx.preference.PreferenceViewHolder
import android.widget.TextView
import android.content.Context
import android.content.res.TypedArray
import android.text.TextUtils
import android.util.AttributeSet
import android.view.View
import android.widget.RadioButton
import android.widget.TextView
import androidx.core.content.res.TypedArrayUtils
import androidx.core.text.HtmlCompat
import androidx.preference.Preference
import androidx.preference.PreferenceViewHolder
import org.mozilla.fenix.R
import org.mozilla.fenix.utils.Settings
@ -69,13 +69,13 @@ class RadioButtonPreference : Preference {
private fun updateRadioValue(isChecked: Boolean) {
persistBoolean(isChecked)
radioButton.isChecked = isChecked
Settings.getInstance(summaryView.context).preferences.edit().putBoolean(key, isChecked)
Settings.getInstance(context).preferences.edit().putBoolean(key, isChecked)
.apply()
}
private fun bindRadioButton(holder: PreferenceViewHolder) {
radioButton = holder.findViewById(R.id.radio_button) as RadioButton
radioButton.isChecked = getPersistedBoolean(defaultValue)
radioButton.isChecked = Settings.getInstance(context).preferences.getBoolean(key, false)
}
private fun initDefaultValue(typedArray: TypedArray) {

View File

@ -98,6 +98,7 @@ class ThemeFragment : PreferenceFragmentCompat() {
}
private fun setNewTheme(mode: Int) {
if (AppCompatDelegate.getDefaultNightMode() == mode) return
AppCompatDelegate.setDefaultNightMode(mode)
activity?.recreate()
with(requireComponents.core) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item android:id="@android:id/mask">
<shape>
<solid android:color="#000000" />
<corners
android:bottomLeftRadius="@dimen/tab_corner_radius"
android:bottomRightRadius="@dimen/tab_corner_radius" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<stroke
android:width="1dp"
android:color="?shadow" />
<solid android:color="?inset" />
<corners
android:bottomLeftRadius="@dimen/tab_corner_radius"
android:bottomRightRadius="@dimen/tab_corner_radius" />
</shape>
</item>
</ripple>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item android:id="@android:id/mask">
<shape>
<solid android:color="#000000" />
<corners android:radius="8dp" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<solid android:color="@android:color/transparent" />
<corners android:radius="8dp" />
</shape>
</item>
</ripple>

View File

@ -2,24 +2,168 @@
<!-- 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/. -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/onboarding_card"
style="@style/OnboardingCardLight"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:layout_marginBottom="16dp"
android:background="@drawable/onboarding_card_background_light"
android:paddingTop="16dp">
<TextView
android:id="@+id/header_text"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="14dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:paddingBottom="14dp"
android:text="@string/onboarding_theme_picker_header"
android:textAppearance="@style/HeaderTextStyle" />
android:textAppearance="@style/HeaderTextStyle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/description_text"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:text="@string/onboarding_theme_picker_description"
android:textAppearance="@style/Body14TextStyle" />
</LinearLayout>
android:textAppearance="@style/Body14TextStyle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/header_text" />
<TextView
android:id="@+id/light_theme_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/onboarding_theme_light_title"
android:textColor="?primaryText"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="@+id/theme_light_image"
app:layout_constraintStart_toStartOf="@id/theme_light_image"
app:layout_constraintTop_toBottomOf="@id/theme_light_image" />
<org.mozilla.fenix.onboarding.OnboardingRadioButton
android:id="@+id/theme_light_radio_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="1dp"
app:layout_constraintBottom_toBottomOf="@+id/theme_light_image"
app:layout_constraintCircle="@id/theme_light_image"
app:layout_constraintCircleAngle="298"
app:layout_constraintCircleRadius="66dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/description_text"
app:onboardingKey="@string/pref_key_light_theme" />
<ImageButton
android:id="@+id/theme_light_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:background="@drawable/onboarding_light_theme"
android:foreground="@drawable/rounded_ripple"
app:layout_constraintEnd_toStartOf="@+id/theme_dark_image"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/description_text" />
<org.mozilla.fenix.onboarding.OnboardingRadioButton
android:id="@+id/theme_dark_radio_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="1dp"
app:layout_constraintBottom_toBottomOf="@+id/theme_dark_image"
app:layout_constraintCircle="@id/theme_dark_image"
app:layout_constraintCircleAngle="298"
app:layout_constraintCircleRadius="66dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/description_text"
app:onboardingKey="@string/pref_key_dark_theme" />
<ImageButton
android:id="@+id/theme_dark_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:background="@drawable/onboarding_dark_theme"
android:foreground="@drawable/rounded_ripple"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/theme_light_image"
app:layout_constraintTop_toBottomOf="@+id/description_text" />
<TextView
android:id="@+id/dark_theme_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/onboarding_theme_dark_title"
android:textColor="?primaryText"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="@+id/theme_dark_image"
app:layout_constraintStart_toStartOf="@id/theme_dark_image"
app:layout_constraintTop_toBottomOf="@id/theme_dark_image" />
<View
android:id="@+id/divider"
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_marginStart="1dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="1dp"
android:layout_marginBottom="16dp"
android:background="?attr/neutralFaded"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/dark_theme_title" />
<View
android:id="@+id/clickable_region_automatic"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@drawable/onboarding_rounded_bottom_corners_ripple"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="@+id/divider" />
<org.mozilla.fenix.onboarding.OnboardingRadioButton
android:id="@+id/theme_automatic_radio_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:paddingEnd="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/divider"
app:onboardingKey="@string/pref_key_follow_device_theme" />
<TextView
android:id="@+id/automatic_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="9dp"
android:text="@string/onboarding_theme_automatic_title"
android:textColor="?primaryText"
android:textSize="16sp"
app:layout_constraintStart_toEndOf="@+id/theme_automatic_radio_button"
app:layout_constraintTop_toBottomOf="@+id/divider" />
<TextView
android:id="@+id/automatic_theme_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/onboarding_theme_automatic_summary"
android:textColor="?secondaryText"
android:textSize="14sp"
app:layout_constraintStart_toEndOf="@+id/theme_automatic_radio_button"
app:layout_constraintTop_toBottomOf="@id/automatic_title" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -32,4 +32,8 @@
<attr name="listItemTitle" format="reference" />
<attr name="listItemIcon" format="reference" />
</declare-styleable>
<declare-styleable name="OnboardingRadioButton">
<attr name="onboardingKey" format="reference" />
</declare-styleable>
</resources>

View File

@ -488,4 +488,15 @@
<string name="accessibility_text_size_sample_text">The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.</string>
<string name="preference_accessibility_text_size_summary">Make text on websites larger or smaller</string>
<string name="preference_accessibility_font_size_title">Font Size</string>
<!-- Onboarding theme -->
<!-- Automatic theme setting (will follow device setting) -->
<string name="onboarding_theme_automatic_title">Automatic</string>
<!-- Summary of automatic theme setting (will follow device setting) -->
<string name="onboarding_theme_automatic_summary">Adapts to your device settings</string>
<!-- Theme setting for dark mode -->
<string name="onboarding_theme_dark_title">Dark Theme</string>
<!-- Theme setting for light mode -->
<string name="onboarding_theme_light_title">Light Theme</string>
</resources>