Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Commit

Permalink
Refactor QuickSettingsStore
Browse files Browse the repository at this point in the history
  • Loading branch information
NotWoods committed Jun 1, 2020
1 parent 219ea56 commit a8d3159
Show file tree
Hide file tree
Showing 11 changed files with 301 additions and 697 deletions.
6 changes: 1 addition & 5 deletions app/src/main/java/org/mozilla/fenix/settings/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,15 @@

package org.mozilla.fenix.settings

import android.view.View
import android.widget.RadioButton
import android.widget.TextView
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.text.HtmlCompat
import androidx.preference.Preference
import mozilla.components.feature.sitepermissions.SitePermissions
import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelative
import org.mozilla.fenix.R
import org.mozilla.fenix.theme.ThemeManager

fun SitePermissions.toggle(featurePhone: PhoneFeature): SitePermissions {
return update(featurePhone, get(featurePhone))
return update(featurePhone, get(featurePhone).toggle())
}

fun SitePermissions.get(field: PhoneFeature) = when (field) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ interface QuickSettingsController {
* Default behavior of [QuickSettingsController]. Other implementations are possible.
*
* @param context [Context] used for various Android interactions.
* @param quickSettingsStore [QuickSettingsFragmentStore] holding the [State] for all Views displayed
* @param quickSettingsStore [QuickSettingsFragmentStore] holding the State for all Views displayed
* in this Controller's Fragment.
* @param coroutineScope [CoroutineScope] used for structed concurrency.
* @param navController NavController] used for navigation.
Expand Down Expand Up @@ -90,7 +90,7 @@ class DefaultQuickSettingsController(
}

override fun handlePermissionToggled(permission: WebsitePermission) {
val featureToggled = permission.getBackingFeature()
val featureToggled = permission.phoneFeature

when (permission.isBlockedByAndroid) {
true -> handleAndroidPermissionRequest(featureToggled.androidPermissionsList)
Expand All @@ -104,7 +104,7 @@ class DefaultQuickSettingsController(

quickSettingsStore.dispatch(
WebsitePermissionAction.TogglePermission(
permission,
featureToggled,
featureToggled.getActionLabel(context, newPermissions, settings),
featureToggled.shouldBeEnabled(context, newPermissions, settings)
)
Expand All @@ -119,7 +119,7 @@ class DefaultQuickSettingsController(
override fun handleAndroidPermissionGranted(feature: PhoneFeature) {
quickSettingsStore.dispatch(
WebsitePermissionAction.TogglePermission(
feature.getCorrespondingPermission(),
feature,
feature.getActionLabel(context, sitePermissions, settings),
feature.shouldBeEnabled(context, sitePermissions, settings)
)
Expand Down Expand Up @@ -152,56 +152,6 @@ class DefaultQuickSettingsController(
}
}

/**
* Each [WebsitePermission] is mapped after a [PhoneFeature].
*
* Get this [WebsitePermission]'s [PhoneFeature].
*/
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun WebsitePermission.getBackingFeature(): PhoneFeature = when (this) {
is WebsitePermission.Camera -> PhoneFeature.CAMERA
is WebsitePermission.Microphone -> PhoneFeature.MICROPHONE
is WebsitePermission.Notification -> PhoneFeature.NOTIFICATION
is WebsitePermission.Location -> PhoneFeature.LOCATION
is WebsitePermission.AutoplayAudible -> PhoneFeature.AUTOPLAY_AUDIBLE
is WebsitePermission.AutoplayInaudible -> PhoneFeature.AUTOPLAY_INAUDIBLE
}

/**
* Get the specific [WebsitePermission] implementation which this [PhoneFeature] is tied to.
*
* **The result only informs about the type of [WebsitePermission].
* The resulting object's properties are just stubs and not dependable.**
*/
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun PhoneFeature.getCorrespondingPermission(): WebsitePermission {
val defaultStatus = ""
val defaultEnabled = false
val defaultVisible = false
val defaultBlockedByAndroid = false

return when (this) {
PhoneFeature.CAMERA -> WebsitePermission.Camera(
defaultStatus, defaultVisible, defaultEnabled, defaultBlockedByAndroid
)
PhoneFeature.LOCATION -> WebsitePermission.Location(
defaultStatus, defaultVisible, defaultEnabled, defaultBlockedByAndroid
)
PhoneFeature.MICROPHONE -> WebsitePermission.Microphone(
defaultStatus, defaultVisible, defaultEnabled, defaultBlockedByAndroid
)
PhoneFeature.NOTIFICATION -> WebsitePermission.Notification(
defaultStatus, defaultVisible, defaultEnabled, defaultBlockedByAndroid
)
PhoneFeature.AUTOPLAY_AUDIBLE -> WebsitePermission.AutoplayAudible(
defaultStatus, defaultVisible, defaultEnabled, defaultBlockedByAndroid
)
PhoneFeature.AUTOPLAY_INAUDIBLE -> WebsitePermission.AutoplayInaudible(
defaultStatus, defaultVisible, defaultEnabled, defaultBlockedByAndroid
)
}
}

/**
* Navigate to toggle [SitePermissions] for the specified [PhoneFeature]
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* 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.quicksettings

import mozilla.components.lib.state.Action
import org.mozilla.fenix.settings.PhoneFeature

/**
* Parent [Action] for all the [QuickSettingsFragmentState] changes.
*/
sealed class QuickSettingsFragmentAction : Action

/**
* All possible [WebsiteInfoState] changes as result of user / system interactions.
*/
sealed class WebsiteInfoAction : QuickSettingsFragmentAction()

/**
* All possible [WebsitePermissionsState] changes as result of user / system interactions.
*/
sealed class WebsitePermissionAction : QuickSettingsFragmentAction() {
/**
* Change resulting from toggling a specific [WebsitePermission] for the current website.
*
* @param updatedFeature [PhoneFeature] backing a certain [WebsitePermission].
* Allows to easily identify which permission changed
* **Must be the name of one of the properties of [WebsitePermissionsState]**.
* @param updatedStatus [String] the new [WebsitePermission#status] which will be shown to the user.
* @param updatedEnabledStatus [Boolean] the new [WebsitePermission#enabled] which will be shown to the user.
*/
class TogglePermission(
val updatedFeature: PhoneFeature,
val updatedStatus: String,
val updatedEnabledStatus: Boolean
) : WebsitePermissionAction()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/* 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.quicksettings

/**
* Parent Reducer for all [QuickSettingsFragmentState]s of all Views shown in this Fragment.
*/
fun quickSettingsFragmentReducer(
state: QuickSettingsFragmentState,
action: QuickSettingsFragmentAction
): QuickSettingsFragmentState {
return when (action) {
is WebsiteInfoAction -> {
// There is no possible action that can change this View's state while it is displayed to the user.
// Every time the View is recreated it starts with a fresh state. This is the only way to display
// something different.
state
}
is WebsitePermissionAction -> state.copy(
websitePermissionsState = WebsitePermissionsStateReducer.reduce(
state.websitePermissionsState,
action
)
)
}
}

object WebsitePermissionsStateReducer {
/**
* Handles creating a new [WebsitePermissionsState] based on the specific [WebsitePermissionAction]
*/
fun reduce(
state: WebsitePermissionsState,
action: WebsitePermissionAction
): WebsitePermissionsState {
return when (action) {
is WebsitePermissionAction.TogglePermission -> {
val key = action.updatedFeature
val newWebsitePermission = state.getValue(key).copy(
status = action.updatedStatus,
isEnabled = action.updatedEnabledStatus
)

state + Pair(key, newWebsitePermission)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/* 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.quicksettings

import androidx.annotation.ColorRes
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import mozilla.components.lib.state.State
import org.mozilla.fenix.R
import org.mozilla.fenix.settings.PhoneFeature

/**
* [State] containing all data displayed to the user by this Fragment.
*
* Partitioned further to contain mutiple states for each standalone View this Fragment holds.
*/
data class QuickSettingsFragmentState(
val webInfoState: WebsiteInfoState,
val websitePermissionsState: WebsitePermissionsState
) : State

/**
* [State] to be rendered by [WebsiteInfoView] indicating whether the connection is secure or not.
*
* @param websiteUrl [String] the URL of the current web page.
* @param websiteTitle [String] the title of the current web page.
* @param websiteSecurityUiValues UI values to represent the security of the website.
*/
data class WebsiteInfoState(
val websiteUrl: String,
val websiteTitle: String,
val websiteSecurityUiValues: WebsiteSecurityUiValues,
val certificateName: String
) : State

enum class WebsiteSecurityUiValues(
@StringRes val securityInfoRes: Int,
@DrawableRes val iconRes: Int,
@ColorRes val iconTintRes: Int
) {
SECURE(
R.string.quick_settings_sheet_secure_connection,
R.drawable.mozac_ic_lock,
R.color.photonGreen50
),
INSECURE(
R.string.quick_settings_sheet_insecure_connection,
R.drawable.mozac_ic_globe,
R.color.photonRed50
)
}

/**
* [State] to be rendered by [WebsitePermissionsView] displaying all explicitly allowed or blocked
* website permissions.
*/
typealias WebsitePermissionsState = Map<PhoneFeature, WebsitePermission>

/**
* Wrapper over a website permission encompassing all it's needed state to be rendered on the screen.
*
* Contains a limited number of implementations because there is a known, finite number of permissions
* we need to display to the user.
*
* @property status The *allowed* / *blocked* permission status to be shown to the user.
* @property isVisible Whether this permission should be shown to the user.
* @property isEnabled Visual indication about whether this permission is *enabled* / *disabled*
* @property isBlockedByAndroid Whether the corresponding *dangerous* Android permission is granted
* for the app by the user or not.
*/
data class WebsitePermission(
val phoneFeature: PhoneFeature,
val status: String,
val isVisible: Boolean,
val isEnabled: Boolean,
val isBlockedByAndroid: Boolean
)

0 comments on commit a8d3159

Please sign in to comment.