For #1146: Extract AccountUiView from settings

releases/v80.0.0
Tiger Oakes 4 years ago committed by Mihai Branescu
parent 5a4c391b52
commit eab9660146

@ -4,13 +4,11 @@
package org.mozilla.fenix.ext
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.util.Patterns
import android.webkit.URLUtil
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
import androidx.core.net.toUri
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
@ -115,16 +113,6 @@ fun String.simplifiedUrl(): String {
return afterScheme
}
/**
* Gets a rounded drawable from a URL if possible, else null.
*/
suspend fun String.toRoundedDrawable(context: Context, client: Client) = bitmapForUrl(this, client)?.let { bitmap ->
RoundedBitmapDrawableFactory.create(context.resources, bitmap).also {
it.isCircular = true
it.setAntiAlias(true)
}
}
suspend fun bitmapForUrl(url: String, client: Client): Bitmap? = withContext(Dispatchers.IO) {
// Code below will cache it in Gecko's cache, which ensures that as long as we've fetched it once,
// we will be able to display this avatar as long as the cache isn't purged (e.g. via 'clear user data').

@ -5,7 +5,6 @@
package org.mozilla.fenix.settings
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
@ -13,16 +12,13 @@ import android.os.Bundle
import android.os.Handler
import android.provider.Settings
import android.widget.Toast
import androidx.appcompat.content.res.AppCompatResources
import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavDirections
import androidx.navigation.findNavController
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import mozilla.components.concept.sync.AccountObserver
@ -41,19 +37,19 @@ import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.settings
import org.mozilla.fenix.ext.showToolbar
import org.mozilla.fenix.ext.toRoundedDrawable
import org.mozilla.fenix.settings.account.AccountAuthErrorPreference
import org.mozilla.fenix.settings.account.AccountPreference
import org.mozilla.fenix.settings.account.AccountUiView
import kotlin.system.exitProcess
@Suppress("LargeClass", "TooManyFunctions")
class SettingsFragment : PreferenceFragmentCompat() {
private lateinit var accountUiView: AccountUiView
private val accountObserver = object : AccountObserver {
private fun updateAccountUi(profile: Profile? = null) {
val context = context ?: return
lifecycleScope.launch {
updateAccountUIState(
accountUiView.updateAccountUIState(
context = context,
profile = profile
?: context.components.backgroundServices.accountManager.accountProfile()
@ -75,6 +71,13 @@ class SettingsFragment : PreferenceFragmentCompat() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
accountUiView = AccountUiView(
fragment = this,
accountManager = requireComponents.backgroundServices.accountManager,
httpClient = requireComponents.core.client,
updateFxASyncOverrideMenu = ::updateFxASyncOverrideMenu
)
// Observe account changes to keep the UI up-to-date.
requireComponents.backgroundServices.accountManager.register(
accountObserver,
@ -88,7 +91,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
// For example, if user is signed-in, and we don't perform this call in onCreate, we'll briefly
// display a "Sign In" preference, which will then get replaced by the correct account information
// once this call is ran in onResume shortly after.
updateAccountUIState(
accountUiView.updateAccountUIState(
requireContext(),
requireComponents.backgroundServices.accountManager.accountProfile()
)
@ -162,7 +165,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
setupPreferences()
if (shouldUpdateAccountUIState) {
updateAccountUIState(
accountUiView.updateAccountUIState(
requireContext(),
requireComponents.backgroundServices.accountManager.accountProfile()
)
@ -295,9 +298,9 @@ class SettingsFragment : PreferenceFragmentCompat() {
}
}
preferenceRemoteDebugging?.setOnPreferenceChangeListener { preference, newValue ->
preferenceRemoteDebugging?.setOnPreferenceChangeListener<Boolean> { preference, newValue ->
preference.context.settings().preferences.edit()
.putBoolean(preference.key, newValue as Boolean).apply()
.putBoolean(preference.key, newValue).apply()
requireComponents.core.engine.settings.remoteDebuggingEnabled = newValue
true
}
@ -378,68 +381,6 @@ class SettingsFragment : PreferenceFragmentCompat() {
}
}
/**
* Updates the UI to reflect current account state.
* Possible conditions are logged-in without problems, logged-out, and logged-in but needs to re-authenticate.
*/
private fun updateAccountUIState(context: Context, profile: Profile?) {
val preferenceSignIn =
requirePreference<Preference>(R.string.pref_key_sign_in)
val preferenceFirefoxAccount =
requirePreference<AccountPreference>(R.string.pref_key_account)
val preferenceFirefoxAccountAuthError =
requirePreference<AccountAuthErrorPreference>(R.string.pref_key_account_auth_error)
val accountPreferenceCategory =
requirePreference<PreferenceCategory>(R.string.pref_key_account_category)
val accountManager = requireComponents.backgroundServices.accountManager
val account = accountManager.authenticatedAccount()
updateFxASyncOverrideMenu()
// Signed-in, no problems.
if (account != null && !accountManager.accountNeedsReauth()) {
preferenceSignIn.isVisible = false
profile?.avatar?.url?.let { avatarUrl ->
lifecycleScope.launch(Main) {
val roundedDrawable =
avatarUrl.toRoundedDrawable(context, requireComponents.core.client)
preferenceFirefoxAccount.icon =
roundedDrawable ?: AppCompatResources.getDrawable(
context,
R.drawable.ic_account
)
}
}
preferenceSignIn.onPreferenceClickListener = null
preferenceFirefoxAccountAuthError.isVisible = false
preferenceFirefoxAccount.isVisible = true
accountPreferenceCategory.isVisible = true
preferenceFirefoxAccount.displayName = profile?.displayName
preferenceFirefoxAccount.email = profile?.email
// Signed-in, need to re-authenticate.
} else if (account != null && accountManager.accountNeedsReauth()) {
preferenceFirefoxAccount.isVisible = false
preferenceFirefoxAccountAuthError.isVisible = true
accountPreferenceCategory.isVisible = true
preferenceSignIn.isVisible = false
preferenceSignIn.onPreferenceClickListener = null
preferenceFirefoxAccountAuthError.email = profile?.email
// Signed-out.
} else {
preferenceSignIn.isVisible = true
preferenceFirefoxAccount.isVisible = false
preferenceFirefoxAccountAuthError.isVisible = false
accountPreferenceCategory.isVisible = false
}
}
private fun updateFxASyncOverrideMenu() {
val preferenceFxAOverride =
findPreference<Preference>(getPreferenceKey(R.string.pref_key_override_fxa_server))

@ -0,0 +1,103 @@
/* 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.settings.account
import android.content.Context
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory
import androidx.lifecycle.lifecycleScope
import androidx.preference.Preference
import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceFragmentCompat
import kotlinx.coroutines.launch
import mozilla.components.concept.fetch.Client
import mozilla.components.concept.sync.Profile
import mozilla.components.service.fxa.manager.FxaAccountManager
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.bitmapForUrl
import org.mozilla.fenix.settings.requirePreference
class AccountUiView(
fragment: PreferenceFragmentCompat,
private val accountManager: FxaAccountManager,
private val httpClient: Client,
private val updateFxASyncOverrideMenu: () -> Unit
) {
private val lifecycleScope = fragment.viewLifecycleOwner.lifecycleScope
private val preferenceSignIn =
fragment.requirePreference<Preference>(R.string.pref_key_sign_in)
private val preferenceFirefoxAccount =
fragment.requirePreference<AccountPreference>(R.string.pref_key_account)
private val preferenceFirefoxAccountAuthError =
fragment.requirePreference<AccountAuthErrorPreference>(R.string.pref_key_account_auth_error)
private val accountPreferenceCategory =
fragment.requirePreference<PreferenceCategory>(R.string.pref_key_account_category)
/**
* Updates the UI to reflect current account state.
* Possible conditions are logged-in without problems, logged-out, and logged-in but needs to re-authenticate.
*/
fun updateAccountUIState(context: Context, profile: Profile?) {
val account = accountManager.authenticatedAccount()
updateFxASyncOverrideMenu()
// Signed-in, no problems.
if (account != null && !accountManager.accountNeedsReauth()) {
preferenceSignIn.isVisible = false
profile?.avatar?.url?.let { avatarUrl ->
lifecycleScope.launch {
val roundedDrawable = toRoundedDrawable(avatarUrl, context)
preferenceFirefoxAccount.icon =
roundedDrawable ?: AppCompatResources.getDrawable(
context,
R.drawable.ic_account
)
}
}
preferenceSignIn.onPreferenceClickListener = null
preferenceFirefoxAccountAuthError.isVisible = false
preferenceFirefoxAccount.isVisible = true
accountPreferenceCategory.isVisible = true
preferenceFirefoxAccount.displayName = profile?.displayName
preferenceFirefoxAccount.email = profile?.email
// Signed-in, need to re-authenticate.
} else if (account != null && accountManager.accountNeedsReauth()) {
preferenceFirefoxAccount.isVisible = false
preferenceFirefoxAccountAuthError.isVisible = true
accountPreferenceCategory.isVisible = true
preferenceSignIn.isVisible = false
preferenceSignIn.onPreferenceClickListener = null
preferenceFirefoxAccountAuthError.email = profile?.email
// Signed-out.
} else {
preferenceSignIn.isVisible = true
preferenceFirefoxAccount.isVisible = false
preferenceFirefoxAccountAuthError.isVisible = false
accountPreferenceCategory.isVisible = false
}
}
/**
* Gets a rounded drawable from a URL if possible, else null.
*/
private suspend fun toRoundedDrawable(
url: String,
context: Context
) = bitmapForUrl(url, httpClient)?.let { bitmap ->
RoundedBitmapDrawableFactory.create(context.resources, bitmap).apply {
isCircular = true
setAntiAlias(true)
}
}
}
Loading…
Cancel
Save