For #4126 - Refactor Views and layouts
Refactored `fragment_quick_settings_dialog_sheet` to now be composed of of FrameLayouts placeholders in which each independent View will inflate itself. Refactored the QuickSettingsUIView and Component to 3 standalone Views with their own lib-state components: Store, State, Actions, Reducer.nightly-build-test
parent
5cca5d7a70
commit
f1f74bc3d6
@ -1,168 +0,0 @@
|
|||||||
/* 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 android.content.Context
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.core.net.toUri
|
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
|
||||||
import org.mozilla.fenix.ext.components
|
|
||||||
import org.mozilla.fenix.ext.settings
|
|
||||||
import org.mozilla.fenix.mvi.Action
|
|
||||||
import org.mozilla.fenix.mvi.ActionBusFactory
|
|
||||||
import org.mozilla.fenix.mvi.Change
|
|
||||||
import org.mozilla.fenix.mvi.UIComponent
|
|
||||||
import org.mozilla.fenix.mvi.UIComponentViewModelBase
|
|
||||||
import org.mozilla.fenix.mvi.UIComponentViewModelProvider
|
|
||||||
import org.mozilla.fenix.mvi.UIView
|
|
||||||
import org.mozilla.fenix.mvi.ViewState
|
|
||||||
import org.mozilla.fenix.settings.PhoneFeature
|
|
||||||
import org.mozilla.fenix.settings.toggle
|
|
||||||
|
|
||||||
class QuickSettingsComponent(
|
|
||||||
private val container: ViewGroup,
|
|
||||||
bus: ActionBusFactory,
|
|
||||||
viewModelProvider: UIComponentViewModelProvider<QuickSettingsState, QuickSettingsChange>
|
|
||||||
) : UIComponent<QuickSettingsState, QuickSettingsAction, QuickSettingsChange>(
|
|
||||||
bus.getManagedEmitter(QuickSettingsAction::class.java),
|
|
||||||
bus.getSafeManagedObservable(QuickSettingsChange::class.java),
|
|
||||||
viewModelProvider
|
|
||||||
) {
|
|
||||||
override fun initView(): UIView<QuickSettingsState, QuickSettingsAction, QuickSettingsChange> {
|
|
||||||
return QuickSettingsUIView(container, actionEmitter, changesObservable, container)
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
bind()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun toggleSitePermission(
|
|
||||||
context: Context,
|
|
||||||
featurePhone: PhoneFeature,
|
|
||||||
url: String,
|
|
||||||
sitePermissions: SitePermissions?
|
|
||||||
): SitePermissions {
|
|
||||||
|
|
||||||
return if (sitePermissions == null) {
|
|
||||||
val settings = context.settings()
|
|
||||||
val origin = requireNotNull(url.toUri().host)
|
|
||||||
var location =
|
|
||||||
settings.getSitePermissionsPhoneFeatureAction(PhoneFeature.LOCATION).toStatus()
|
|
||||||
var camera =
|
|
||||||
settings.getSitePermissionsPhoneFeatureAction(PhoneFeature.CAMERA).toStatus()
|
|
||||||
var microphone =
|
|
||||||
settings.getSitePermissionsPhoneFeatureAction(PhoneFeature.MICROPHONE).toStatus()
|
|
||||||
var notification =
|
|
||||||
settings.getSitePermissionsPhoneFeatureAction(PhoneFeature.NOTIFICATION).toStatus()
|
|
||||||
|
|
||||||
when (featurePhone) {
|
|
||||||
PhoneFeature.CAMERA -> camera = camera.toggle()
|
|
||||||
PhoneFeature.LOCATION -> location = location.toggle()
|
|
||||||
PhoneFeature.MICROPHONE -> microphone = microphone.toggle()
|
|
||||||
PhoneFeature.NOTIFICATION -> notification = notification.toggle()
|
|
||||||
PhoneFeature.AUTOPLAY -> { // not supported by GV or A-C yet
|
|
||||||
}
|
|
||||||
}
|
|
||||||
context.components.core.permissionStorage
|
|
||||||
.addSitePermissionException(origin, location, notification, microphone, camera)
|
|
||||||
} else {
|
|
||||||
val updatedSitePermissions = sitePermissions.toggle(featurePhone)
|
|
||||||
context.components.core.permissionStorage.updateSitePermissions(updatedSitePermissions)
|
|
||||||
updatedSitePermissions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class QuickSettingsState(val mode: Mode) : ViewState {
|
|
||||||
sealed class Mode {
|
|
||||||
data class Normal(
|
|
||||||
val url: String,
|
|
||||||
val isSecured: Boolean,
|
|
||||||
val isTrackingProtectionOn: Boolean,
|
|
||||||
val sitePermissions: SitePermissions?
|
|
||||||
) : Mode()
|
|
||||||
|
|
||||||
data class ActionLabelUpdated(
|
|
||||||
val phoneFeature: PhoneFeature,
|
|
||||||
val sitePermissions: SitePermissions?
|
|
||||||
) :
|
|
||||||
Mode()
|
|
||||||
|
|
||||||
data class CheckPendingFeatureBlockedByAndroid(val sitePermissions: SitePermissions?) :
|
|
||||||
Mode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class QuickSettingsAction : Action {
|
|
||||||
data class SelectReportProblem(val url: String) : QuickSettingsAction()
|
|
||||||
object SelectTrackingProtectionSettings : QuickSettingsAction()
|
|
||||||
data class ToggleTrackingProtection(val trackingProtection: Boolean) : QuickSettingsAction()
|
|
||||||
data class SelectBlockedByAndroid(val permissions: Array<String>) : QuickSettingsAction()
|
|
||||||
data class TogglePermission(val featurePhone: PhoneFeature) : QuickSettingsAction()
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed class QuickSettingsChange : Change {
|
|
||||||
data class Change(
|
|
||||||
val url: String,
|
|
||||||
val isSecured: Boolean,
|
|
||||||
val isTrackingProtectionOn: Boolean,
|
|
||||||
val sitePermissions: SitePermissions?
|
|
||||||
) : QuickSettingsChange()
|
|
||||||
|
|
||||||
data class PermissionGranted(
|
|
||||||
val phoneFeature: PhoneFeature,
|
|
||||||
val sitePermissions: SitePermissions?
|
|
||||||
) :
|
|
||||||
QuickSettingsChange()
|
|
||||||
|
|
||||||
data class PromptRestarted(val sitePermissions: SitePermissions?) : QuickSettingsChange()
|
|
||||||
data class Stored(val phoneFeature: PhoneFeature, val sitePermissions: SitePermissions?) :
|
|
||||||
QuickSettingsChange()
|
|
||||||
}
|
|
||||||
|
|
||||||
class QuickSettingsViewModel(
|
|
||||||
initialState: QuickSettingsState
|
|
||||||
) : UIComponentViewModelBase<QuickSettingsState, QuickSettingsChange>(initialState, reducer) {
|
|
||||||
companion object {
|
|
||||||
val reducer: (QuickSettingsState, QuickSettingsChange) -> QuickSettingsState =
|
|
||||||
{ state, change ->
|
|
||||||
when (change) {
|
|
||||||
is QuickSettingsChange.Change -> {
|
|
||||||
state.copy(
|
|
||||||
mode = QuickSettingsState.Mode.Normal(
|
|
||||||
change.url,
|
|
||||||
change.isSecured,
|
|
||||||
change.isTrackingProtectionOn,
|
|
||||||
change.sitePermissions
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is QuickSettingsChange.PermissionGranted -> {
|
|
||||||
state.copy(
|
|
||||||
mode = QuickSettingsState.Mode.ActionLabelUpdated(
|
|
||||||
change.phoneFeature,
|
|
||||||
change.sitePermissions
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is QuickSettingsChange.PromptRestarted -> {
|
|
||||||
state.copy(
|
|
||||||
mode = QuickSettingsState.Mode.CheckPendingFeatureBlockedByAndroid(
|
|
||||||
change.sitePermissions
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is QuickSettingsChange.Stored -> {
|
|
||||||
state.copy(
|
|
||||||
mode = QuickSettingsState.Mode.ActionLabelUpdated(
|
|
||||||
change.phoneFeature,
|
|
||||||
change.sitePermissions
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,185 +0,0 @@
|
|||||||
/* 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 android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.annotation.ColorRes
|
|
||||||
import androidx.annotation.DrawableRes
|
|
||||||
import androidx.annotation.IdRes
|
|
||||||
import androidx.annotation.StringRes
|
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import androidx.core.net.toUri
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import io.reactivex.Observable
|
|
||||||
import io.reactivex.Observer
|
|
||||||
import io.reactivex.functions.Consumer
|
|
||||||
import kotlinx.android.synthetic.main.fragment_quick_settings_dialog_sheet.*
|
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissions.Status.BLOCKED
|
|
||||||
import mozilla.components.feature.sitepermissions.SitePermissions.Status.NO_DECISION
|
|
||||||
import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes
|
|
||||||
import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelativeWithIntrinsicBounds
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.ext.settings
|
|
||||||
import org.mozilla.fenix.mvi.UIView
|
|
||||||
import org.mozilla.fenix.settings.PhoneFeature
|
|
||||||
import org.mozilla.fenix.settings.PhoneFeature.CAMERA
|
|
||||||
import org.mozilla.fenix.settings.PhoneFeature.LOCATION
|
|
||||||
import org.mozilla.fenix.settings.PhoneFeature.MICROPHONE
|
|
||||||
import org.mozilla.fenix.settings.PhoneFeature.NOTIFICATION
|
|
||||||
import org.mozilla.fenix.utils.Settings
|
|
||||||
|
|
||||||
typealias LabelActionPair = Pair<TextView, TextView>
|
|
||||||
|
|
||||||
@Suppress("TooManyFunctions")
|
|
||||||
class QuickSettingsUIView(
|
|
||||||
container: ViewGroup,
|
|
||||||
actionEmitter: Observer<QuickSettingsAction>,
|
|
||||||
changesObservable: Observable<QuickSettingsChange>,
|
|
||||||
override val view: View
|
|
||||||
) : UIView<QuickSettingsState, QuickSettingsAction, QuickSettingsChange>(
|
|
||||||
container, actionEmitter, changesObservable
|
|
||||||
) {
|
|
||||||
private val blockedByAndroidPhoneFeatures = mutableListOf<PhoneFeature>()
|
|
||||||
private inline val context get() = view.context
|
|
||||||
private val settings: Settings = context.settings()
|
|
||||||
private val trackingProtectionSettingView = TrackingProtectionSettingView(view, actionEmitter)
|
|
||||||
private val labelAndActions = mapOf(
|
|
||||||
CAMERA to findLabelActionPair(R.id.camera_icon, R.id.camera_action_label),
|
|
||||||
LOCATION to findLabelActionPair(R.id.location_icon, R.id.location_action_label),
|
|
||||||
MICROPHONE to findLabelActionPair(R.id.microphone_icon, R.id.microphone_action_label),
|
|
||||||
NOTIFICATION to findLabelActionPair(R.id.notification_icon, R.id.notification_action_label)
|
|
||||||
)
|
|
||||||
|
|
||||||
private val blockedByAndroidClickListener = View.OnClickListener {
|
|
||||||
val feature = it.tag as PhoneFeature
|
|
||||||
actionEmitter.onNext(
|
|
||||||
QuickSettingsAction.SelectBlockedByAndroid(feature.androidPermissionsList)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
private val togglePermissionClickListener = View.OnClickListener {
|
|
||||||
val feature = it.tag as PhoneFeature
|
|
||||||
actionEmitter.onNext(
|
|
||||||
QuickSettingsAction.TogglePermission(feature)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun updateView() = Consumer<QuickSettingsState> { state ->
|
|
||||||
when (state.mode) {
|
|
||||||
is QuickSettingsState.Mode.Normal -> {
|
|
||||||
bindUrl(state.mode.url)
|
|
||||||
bindSecurityInfo(state.mode.isSecured)
|
|
||||||
bindReportSiteIssueAction(state.mode.url)
|
|
||||||
trackingProtectionSettingView.bind(state.mode.isTrackingProtectionOn)
|
|
||||||
bindPhoneFeatureItem(CAMERA, state.mode.sitePermissions)
|
|
||||||
bindPhoneFeatureItem(MICROPHONE, state.mode.sitePermissions)
|
|
||||||
bindPhoneFeatureItem(NOTIFICATION, state.mode.sitePermissions)
|
|
||||||
bindPhoneFeatureItem(LOCATION, state.mode.sitePermissions)
|
|
||||||
}
|
|
||||||
is QuickSettingsState.Mode.ActionLabelUpdated -> {
|
|
||||||
bindPhoneFeatureItem(state.mode.phoneFeature, state.mode.sitePermissions)
|
|
||||||
}
|
|
||||||
is QuickSettingsState.Mode.CheckPendingFeatureBlockedByAndroid -> {
|
|
||||||
checkFeaturesBlockedByAndroid(state.mode.sitePermissions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindUrl(url: String) {
|
|
||||||
this.url.text = url.toUri().hostWithoutCommonPrefixes
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindReportSiteIssueAction(url: String) {
|
|
||||||
report_site_issue_action.setOnClickListener {
|
|
||||||
actionEmitter.onNext(
|
|
||||||
QuickSettingsAction.SelectReportProblem(url)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindSecurityInfo(isSecured: Boolean) {
|
|
||||||
@StringRes val stringId: Int
|
|
||||||
@DrawableRes val drawableId: Int
|
|
||||||
@ColorRes val drawableTint: Int
|
|
||||||
|
|
||||||
if (isSecured) {
|
|
||||||
stringId = R.string.quick_settings_sheet_secure_connection
|
|
||||||
drawableId = R.drawable.mozac_ic_lock
|
|
||||||
drawableTint = R.color.photonGreen50
|
|
||||||
} else {
|
|
||||||
stringId = R.string.quick_settings_sheet_insecure_connection
|
|
||||||
drawableId = R.drawable.mozac_ic_broken_lock
|
|
||||||
drawableTint = R.color.photonRed50
|
|
||||||
}
|
|
||||||
|
|
||||||
val icon = context.getDrawable(drawableId)
|
|
||||||
icon?.setTint(ContextCompat.getColor(context, drawableTint))
|
|
||||||
security_info.setText(stringId)
|
|
||||||
security_info.putCompoundDrawablesRelativeWithIntrinsicBounds(start = icon)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindPhoneFeatureItem(phoneFeature: PhoneFeature, sitePermissions: SitePermissions? = null) {
|
|
||||||
val (label, action) = labelAndActions.getValue(phoneFeature)
|
|
||||||
val shouldBeVisible = phoneFeature.shouldBeVisible(sitePermissions)
|
|
||||||
label.isVisible = shouldBeVisible
|
|
||||||
action.isVisible = shouldBeVisible
|
|
||||||
|
|
||||||
if (shouldBeVisible) {
|
|
||||||
if (phoneFeature.isAndroidPermissionGranted(context)) {
|
|
||||||
bindPhoneAction(phoneFeature, sitePermissions)
|
|
||||||
} else {
|
|
||||||
handleBlockedByAndroidAction(phoneFeature)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun PhoneFeature.shouldBeVisible(sitePermissions: SitePermissions?): Boolean {
|
|
||||||
return getStatus(sitePermissions, settings) != NO_DECISION
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun PhoneFeature.isPermissionBlocked(sitePermissions: SitePermissions?): Boolean {
|
|
||||||
return getStatus(sitePermissions, settings) == BLOCKED
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun handleBlockedByAndroidAction(phoneFeature: PhoneFeature) {
|
|
||||||
val (label, action) = labelAndActions.getValue(phoneFeature)
|
|
||||||
|
|
||||||
action.setText(R.string.phone_feature_blocked_by_android)
|
|
||||||
action.tag = phoneFeature
|
|
||||||
action.setOnClickListener(blockedByAndroidClickListener)
|
|
||||||
label.isEnabled = false
|
|
||||||
blockedByAndroidPhoneFeatures.add(phoneFeature)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun bindPhoneAction(phoneFeature: PhoneFeature, sitePermissions: SitePermissions? = null) {
|
|
||||||
val (label, action) = labelAndActions.getValue(phoneFeature)
|
|
||||||
|
|
||||||
action.text = phoneFeature.getActionLabel(
|
|
||||||
context = context,
|
|
||||||
sitePermissions = sitePermissions,
|
|
||||||
settings = settings
|
|
||||||
)
|
|
||||||
|
|
||||||
action.tag = phoneFeature
|
|
||||||
action.setOnClickListener(togglePermissionClickListener)
|
|
||||||
|
|
||||||
label.isEnabled = !phoneFeature.isPermissionBlocked(sitePermissions)
|
|
||||||
blockedByAndroidPhoneFeatures.remove(phoneFeature)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun checkFeaturesBlockedByAndroid(sitePermissions: SitePermissions?) {
|
|
||||||
blockedByAndroidPhoneFeatures.forEach { phoneFeature ->
|
|
||||||
if (phoneFeature.isAndroidPermissionGranted(context)) {
|
|
||||||
bindPhoneAction(phoneFeature, sitePermissions)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun findLabelActionPair(@IdRes labelId: Int, @IdRes actionId: Int): LabelActionPair {
|
|
||||||
return view.findViewById<TextView>(labelId) to view.findViewById(actionId)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,63 +0,0 @@
|
|||||||
/* 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 android.view.View
|
|
||||||
import android.widget.CompoundButton
|
|
||||||
import android.widget.Switch
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.appcompat.content.res.AppCompatResources
|
|
||||||
import androidx.constraintlayout.widget.ConstraintLayout
|
|
||||||
import androidx.core.view.isVisible
|
|
||||||
import io.reactivex.Observer
|
|
||||||
import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelativeWithIntrinsicBounds
|
|
||||||
import org.mozilla.fenix.FeatureFlags
|
|
||||||
import org.mozilla.fenix.R
|
|
||||||
import org.mozilla.fenix.ext.settings
|
|
||||||
|
|
||||||
class TrackingProtectionSettingView(
|
|
||||||
container: View,
|
|
||||||
private val actionEmitter: Observer<QuickSettingsAction>
|
|
||||||
) : View.OnClickListener, CompoundButton.OnCheckedChangeListener {
|
|
||||||
private val trackingProtectionSwitch: Switch = container.findViewById(R.id.tracking_protection)
|
|
||||||
private val trackingProtectionAction: TextView =
|
|
||||||
container.findViewById(R.id.tracking_protection_action)
|
|
||||||
private val trackingProtectionSettingView: ConstraintLayout =
|
|
||||||
container.findViewById(R.id.tracking_protection_view)
|
|
||||||
|
|
||||||
init {
|
|
||||||
trackingProtectionSwitch.putCompoundDrawablesRelativeWithIntrinsicBounds(
|
|
||||||
start = AppCompatResources.getDrawable(
|
|
||||||
container.context,
|
|
||||||
R.drawable.ic_tracking_protection
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun bind(isTrackingProtectionOn: Boolean) {
|
|
||||||
trackingProtectionSettingView.visibility =
|
|
||||||
if (FeatureFlags.etpCategories) View.GONE else View.VISIBLE
|
|
||||||
val globalTPSetting = trackingProtectionSwitch.context.settings().shouldUseTrackingProtection
|
|
||||||
|
|
||||||
trackingProtectionAction.isVisible = !globalTPSetting
|
|
||||||
trackingProtectionAction.setOnClickListener(this)
|
|
||||||
|
|
||||||
trackingProtectionSwitch.isChecked = isTrackingProtectionOn
|
|
||||||
trackingProtectionSwitch.isEnabled = globalTPSetting
|
|
||||||
trackingProtectionSwitch.setOnCheckedChangeListener(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onClick(view: View) {
|
|
||||||
actionEmitter.onNext(
|
|
||||||
QuickSettingsAction.SelectTrackingProtectionSettings
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
|
|
||||||
actionEmitter.onNext(
|
|
||||||
QuickSettingsAction.ToggleTrackingProtection(isChecked)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,51 @@
|
|||||||
|
/* 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 mozilla.components.lib.state.State
|
||||||
|
import mozilla.components.lib.state.Store
|
||||||
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
|
class TrackingProtectionStore(
|
||||||
|
val initialState: TrackingProtectionState
|
||||||
|
) : Store<TrackingProtectionState, TrackingProtectionAction>(
|
||||||
|
initialState, ::trackingProtectionReducer
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
fun createStore(
|
||||||
|
url: String,
|
||||||
|
isTrackingProtectionOn: Boolean,
|
||||||
|
settings: Settings
|
||||||
|
) = TrackingProtectionStore(
|
||||||
|
TrackingProtectionState(
|
||||||
|
websiteUrl = url,
|
||||||
|
isTrackingProtectionEnabledPerApp = settings.shouldUseTrackingProtection,
|
||||||
|
isTrackingProtectionEnabledPerWebsite = isTrackingProtectionOn
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class TrackingProtectionState(
|
||||||
|
val websiteUrl: String,
|
||||||
|
val isTrackingProtectionEnabledPerApp: Boolean,
|
||||||
|
val isTrackingProtectionEnabledPerWebsite: Boolean
|
||||||
|
) : State
|
||||||
|
|
||||||
|
sealed class TrackingProtectionAction : Action {
|
||||||
|
object Stub1 : TrackingProtectionAction()
|
||||||
|
object Stub2 : TrackingProtectionAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun trackingProtectionReducer(
|
||||||
|
state: TrackingProtectionState,
|
||||||
|
action: TrackingProtectionAction
|
||||||
|
): TrackingProtectionState {
|
||||||
|
return when (action) {
|
||||||
|
TrackingProtectionAction.Stub1 -> state
|
||||||
|
TrackingProtectionAction.Stub2 -> state
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/* 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 android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.quicksettings_tracking_protection.*
|
||||||
|
import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelativeWithIntrinsicBounds
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
|
||||||
|
class TrackingProtectionView(
|
||||||
|
override val containerView: ViewGroup
|
||||||
|
) : LayoutContainer {
|
||||||
|
|
||||||
|
val view: View = LayoutInflater.from(containerView.context)
|
||||||
|
.inflate(R.layout.quicksettings_tracking_protection, containerView, true)
|
||||||
|
|
||||||
|
init {
|
||||||
|
trackingProtectionSwitch.putCompoundDrawablesRelativeWithIntrinsicBounds(
|
||||||
|
start = AppCompatResources.getDrawable(
|
||||||
|
containerView.context,
|
||||||
|
R.drawable.ic_tracking_protection
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun update(state: TrackingProtectionState) {
|
||||||
|
trackingProtectionAction.isVisible = !state.isTrackingProtectionEnabledPerApp
|
||||||
|
|
||||||
|
trackingProtectionSwitch.isChecked = state.isTrackingProtectionEnabledPerWebsite
|
||||||
|
trackingProtectionSwitch.isEnabled = state.isTrackingProtectionEnabledPerApp
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
/* 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.Action
|
||||||
|
import mozilla.components.lib.state.State
|
||||||
|
import mozilla.components.lib.state.Store
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
|
||||||
|
class WebsiteInfoStore(
|
||||||
|
initialState: WebsiteInfoState
|
||||||
|
) : Store<WebsiteInfoState, WebsiteInfoAction>(
|
||||||
|
initialState, ::websiteInfoReducer
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
fun createStore(url: String, isSecured: Boolean): WebsiteInfoStore {
|
||||||
|
val (stringRes, iconRes, colorRes) = when (isSecured) {
|
||||||
|
true -> getSecuredWebsiteUiValues()
|
||||||
|
false -> getInsecureWebsiteUiValues()
|
||||||
|
}
|
||||||
|
return WebsiteInfoStore(WebsiteInfoState(url, stringRes, iconRes, colorRes))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class WebsiteInfoState(
|
||||||
|
val url: String,
|
||||||
|
@StringRes val securityInfoRes: Int,
|
||||||
|
@DrawableRes val iconRes: Int,
|
||||||
|
@ColorRes val iconTintRes: Int
|
||||||
|
) : State
|
||||||
|
|
||||||
|
sealed class WebsiteInfoAction : Action {
|
||||||
|
object Stub1 : WebsiteInfoAction()
|
||||||
|
object Stub2 : WebsiteInfoAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun websiteInfoReducer(
|
||||||
|
state: WebsiteInfoState,
|
||||||
|
action: WebsiteInfoAction
|
||||||
|
): WebsiteInfoState {
|
||||||
|
return when (action) {
|
||||||
|
WebsiteInfoAction.Stub1 -> state
|
||||||
|
WebsiteInfoAction.Stub2 -> state
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSecuredWebsiteUiValues() = Triple(
|
||||||
|
R.string.quick_settings_sheet_secure_connection,
|
||||||
|
R.drawable.mozac_ic_lock,
|
||||||
|
R.color.photonGreen50
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun getInsecureWebsiteUiValues() = Triple(
|
||||||
|
R.string.quick_settings_sheet_insecure_connection,
|
||||||
|
R.drawable.mozac_ic_globe,
|
||||||
|
R.color.photonRed50
|
||||||
|
)
|
@ -0,0 +1,46 @@
|
|||||||
|
/* 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 android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.annotation.ColorRes
|
||||||
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.net.toUri
|
||||||
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.quicksettings_website_info.view.*
|
||||||
|
import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes
|
||||||
|
import mozilla.components.support.ktx.android.view.putCompoundDrawablesRelativeWithIntrinsicBounds
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
|
||||||
|
class WebsiteInfoView(
|
||||||
|
override val containerView: ViewGroup
|
||||||
|
) : LayoutContainer {
|
||||||
|
val view: View = LayoutInflater.from(containerView.context)
|
||||||
|
.inflate(R.layout.quicksettings_website_info, containerView, true)
|
||||||
|
|
||||||
|
fun update(state: WebsiteInfoState) {
|
||||||
|
bindUrl(state.url)
|
||||||
|
bindSecurityInfo(state.securityInfoRes, state.iconRes, state.iconTintRes)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindUrl(url: String) {
|
||||||
|
view.url.text = url.toUri().hostWithoutCommonPrefixes
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindSecurityInfo(
|
||||||
|
@StringRes securityInfoRes: Int,
|
||||||
|
@DrawableRes iconRes: Int,
|
||||||
|
@ColorRes iconTintRes: Int
|
||||||
|
) {
|
||||||
|
val icon = view.context.getDrawable(iconRes)
|
||||||
|
icon?.setTint(ContextCompat.getColor(view.context, iconTintRes))
|
||||||
|
view.securityInfo.setText(securityInfoRes)
|
||||||
|
view.securityInfo.putCompoundDrawablesRelativeWithIntrinsicBounds(start = icon)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
/* 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 android.content.Context
|
||||||
|
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||||
|
import mozilla.components.lib.state.Action
|
||||||
|
import mozilla.components.lib.state.State
|
||||||
|
import mozilla.components.lib.state.Store
|
||||||
|
import org.mozilla.fenix.settings.PhoneFeature
|
||||||
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
|
||||||
|
class WebsitePermissionsStore(
|
||||||
|
initialState: WebsitePermissionsState
|
||||||
|
) : Store<WebsitePermissionsState, WebsitePermissionAction>(
|
||||||
|
initialState, ::reducer
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
fun createStore(
|
||||||
|
context: Context,
|
||||||
|
permissions: SitePermissions?,
|
||||||
|
settings: Settings
|
||||||
|
) = WebsitePermissionsStore(
|
||||||
|
WebsitePermissionsState(
|
||||||
|
camera = initWebsitePermission(context, PhoneFeature.CAMERA, permissions, settings),
|
||||||
|
microphone = initWebsitePermission(context, PhoneFeature.MICROPHONE, permissions, settings),
|
||||||
|
notification = initWebsitePermission(context, PhoneFeature.NOTIFICATION, permissions, settings),
|
||||||
|
location = initWebsitePermission(context, PhoneFeature.LOCATION, permissions, settings)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun initWebsitePermission(
|
||||||
|
context: Context,
|
||||||
|
phoneFeature: PhoneFeature,
|
||||||
|
permissions: SitePermissions?,
|
||||||
|
settings: Settings
|
||||||
|
): WebsitePermission {
|
||||||
|
val shouldBeVisible = phoneFeature.shouldBeVisible(permissions, settings)
|
||||||
|
|
||||||
|
return WebsitePermission(
|
||||||
|
name = phoneFeature.name,
|
||||||
|
status = phoneFeature.getActionLabel(context, permissions, settings),
|
||||||
|
visible = shouldBeVisible,
|
||||||
|
enabled = shouldBeVisible &&
|
||||||
|
phoneFeature.isAndroidPermissionGranted(context) &&
|
||||||
|
!phoneFeature.isUserPermissionGranted(permissions, settings)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun PhoneFeature.shouldBeVisible(
|
||||||
|
sitePermissions: SitePermissions?,
|
||||||
|
settings: Settings
|
||||||
|
) = getStatus(sitePermissions, settings) != SitePermissions.Status.NO_DECISION
|
||||||
|
|
||||||
|
private fun PhoneFeature.isUserPermissionGranted(
|
||||||
|
sitePermissions: SitePermissions?,
|
||||||
|
settings: Settings
|
||||||
|
) = getStatus(sitePermissions, settings) == SitePermissions.Status.BLOCKED
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class WebsitePermissionsState(
|
||||||
|
val camera: WebsitePermission,
|
||||||
|
val microphone: WebsitePermission,
|
||||||
|
val notification: WebsitePermission,
|
||||||
|
val location: WebsitePermission
|
||||||
|
) : State
|
||||||
|
|
||||||
|
sealed class WebsitePermissionAction : Action {
|
||||||
|
object Stub1 : WebsitePermissionAction()
|
||||||
|
object Stub2 : WebsitePermissionAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
data class WebsitePermission(
|
||||||
|
val name: String,
|
||||||
|
val status: String,
|
||||||
|
val visible: Boolean,
|
||||||
|
val enabled: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
fun reducer(
|
||||||
|
state: WebsitePermissionsState,
|
||||||
|
action: WebsitePermissionAction
|
||||||
|
): WebsitePermissionsState {
|
||||||
|
return when (action) {
|
||||||
|
WebsitePermissionAction.Stub1 -> state
|
||||||
|
WebsitePermissionAction.Stub2 -> state
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
/* 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 android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
|
||||||
|
class WebsitePermissionsView(
|
||||||
|
override val containerView: ViewGroup
|
||||||
|
) : LayoutContainer {
|
||||||
|
private val context = containerView.context
|
||||||
|
|
||||||
|
val view: View = LayoutInflater.from(context)
|
||||||
|
.inflate(R.layout.quicksettings_permissions, containerView, true)
|
||||||
|
|
||||||
|
fun update(state: WebsitePermissionsState) {
|
||||||
|
bindPermission(state.camera,
|
||||||
|
Pair(view.findViewById(R.id.cameraIcon), view.findViewById(R.id.cameraActionLabel)))
|
||||||
|
bindPermission(state.location,
|
||||||
|
Pair(view.findViewById(R.id.locationIcon), view.findViewById(R.id.locationActionLabel)))
|
||||||
|
bindPermission(state.microphone,
|
||||||
|
Pair(view.findViewById(R.id.microphoneIcon), view.findViewById(R.id.microphoneActionLabel)))
|
||||||
|
bindPermission(state.notification,
|
||||||
|
Pair(view.findViewById(R.id.notificationIcon), view.findViewById(R.id.notificationActionLabel)))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun bindPermission(permissionState: WebsitePermission, permissionViews: Pair<TextView, TextView>) {
|
||||||
|
val (icon, status) = permissionViews
|
||||||
|
|
||||||
|
status.text = permissionState.status
|
||||||
|
status.isEnabled = permissionState.enabled
|
||||||
|
icon.isVisible = permissionState.visible
|
||||||
|
status.isVisible = permissionState.visible
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
<?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/. -->
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
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:id="@+id/permissions_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/cameraActionLabel"
|
||||||
|
style="@style/QuickSettingsText.PermissionItemEnd"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="@dimen/quicksettings_item_height"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/microphoneActionLabel"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/cameraIcon"
|
||||||
|
tools:text="Allowed" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/cameraIcon"
|
||||||
|
style="@style/QuickSettingsText.Icon"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="@dimen/quicksettings_item_height"
|
||||||
|
android:drawableStart="@drawable/ic_camera"
|
||||||
|
android:text="@string/preference_phone_feature_camera"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/microphoneIcon"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/cameraActionLabel"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/microphoneActionLabel"
|
||||||
|
style="@style/QuickSettingsText.PermissionItemEnd"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="@dimen/quicksettings_item_height"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/notificationActionLabel"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/microphoneIcon"
|
||||||
|
tools:text="Blocked by Android" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/microphoneIcon"
|
||||||
|
style="@style/QuickSettingsText.Icon"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="@dimen/quicksettings_item_height"
|
||||||
|
android:drawableStart="@drawable/ic_microphone"
|
||||||
|
android:text="@string/preference_phone_feature_microphone"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/notificationIcon"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/microphoneActionLabel"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/notificationActionLabel"
|
||||||
|
style="@style/QuickSettingsText.PermissionItemEnd"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="@dimen/quicksettings_item_height"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/locationActionLabel"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/notificationIcon"
|
||||||
|
tools:text="Blocked" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/notificationIcon"
|
||||||
|
style="@style/QuickSettingsText.Icon"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="@dimen/quicksettings_item_height"
|
||||||
|
android:drawableStart="@drawable/ic_notifications"
|
||||||
|
android:text="@string/preference_phone_feature_notification"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/locationIcon"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/notificationActionLabel"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/locationActionLabel"
|
||||||
|
style="@style/QuickSettingsText.PermissionItemEnd"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="@dimen/quicksettings_item_height"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/locationIcon"
|
||||||
|
tools:text="Blocked" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/locationIcon"
|
||||||
|
style="@style/QuickSettingsText.Icon"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="@dimen/quicksettings_item_height"
|
||||||
|
android:drawableStart="@drawable/ic_location"
|
||||||
|
android:text="@string/preference_phone_feature_location"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/locationActionLabel"
|
||||||
|
app:layout_constraintStart_toStartOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -0,0 +1,50 @@
|
|||||||
|
<?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/. -->
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
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:id="@+id/tracking_protection_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<Switch
|
||||||
|
android:id="@+id/trackingProtectionSwitch"
|
||||||
|
style="@style/QuickSettingsText.Icon"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/quicksettings_item_height"
|
||||||
|
android:paddingEnd="24dp"
|
||||||
|
android:text="@string/preferences_tracking_protection"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/trackingProtectionAction"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:drawableStart="@drawable/ic_tracking_protection" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/trackingProtectionAction"
|
||||||
|
style="@style/QuickSettingsText.Icon"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/quicksettings_item_height"
|
||||||
|
android:gravity="top"
|
||||||
|
android:paddingStart="48dp"
|
||||||
|
android:paddingEnd="0dp"
|
||||||
|
android:text="@string/preferences_tracking_protection_turned_off_globally"
|
||||||
|
android:textColor="?accentBright"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/reportSiteIssueAction" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/reportSiteIssueAction"
|
||||||
|
style="@style/QuickSettingsText.Icon"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/quicksettings_item_height"
|
||||||
|
android:gravity="top"
|
||||||
|
android:paddingStart="48dp"
|
||||||
|
android:paddingEnd="0dp"
|
||||||
|
android:text="@string/browser_menu_report_issue"
|
||||||
|
android:textColor="?accentUsedOnDarkBackground"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -0,0 +1,36 @@
|
|||||||
|
<?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/. -->
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
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:id="@+id/website_info_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/url"
|
||||||
|
style="@style/QuickSettingsText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/quicksettings_item_height"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="https://wikipedia.org" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/securityInfo"
|
||||||
|
style="@style/QuickSettingsText.Icon"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/quicksettings_item_height"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/url"
|
||||||
|
tools:drawableStart="@drawable/mozac_ic_lock"
|
||||||
|
tools:drawableTint="@color/photonGreen50"
|
||||||
|
tools:text="Secure connection" />
|
||||||
|
</LinearLayout>
|
Loading…
Reference in New Issue