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.master
parent
5cca5d7a70
commit
f1f74bc3d6
|
@ -37,25 +37,29 @@ enum class PhoneFeature(val id: Int, val androidPermissionsList: Array<String>)
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("ComplexMethod")
|
||||
fun getActionLabel(
|
||||
context: Context,
|
||||
sitePermissions: SitePermissions? = null,
|
||||
settings: Settings? = null
|
||||
): String {
|
||||
@StringRes val stringRes =
|
||||
when (this) {
|
||||
AUTOPLAY -> {
|
||||
when (getStatus(sitePermissions, settings)) {
|
||||
SitePermissions.Status.BLOCKED -> R.string.preference_option_autoplay_blocked
|
||||
SitePermissions.Status.ALLOWED -> R.string.preference_option_autoplay_allowed
|
||||
else -> R.string.preference_option_autoplay_allowed
|
||||
when (isAndroidPermissionGranted(context)) {
|
||||
false -> R.string.phone_feature_blocked_by_android
|
||||
else -> when (this) {
|
||||
AUTOPLAY -> {
|
||||
when (getStatus(sitePermissions, settings)) {
|
||||
SitePermissions.Status.BLOCKED -> R.string.preference_option_autoplay_blocked
|
||||
SitePermissions.Status.ALLOWED -> R.string.preference_option_autoplay_allowed
|
||||
else -> R.string.preference_option_autoplay_allowed
|
||||
}
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
when (getStatus(sitePermissions, settings)) {
|
||||
SitePermissions.Status.BLOCKED -> R.string.preference_option_phone_feature_blocked
|
||||
SitePermissions.Status.NO_DECISION -> R.string.preference_option_phone_feature_ask_to_allow
|
||||
SitePermissions.Status.ALLOWED -> R.string.preference_option_phone_feature_allowed
|
||||
else -> {
|
||||
when (getStatus(sitePermissions, settings)) {
|
||||
SitePermissions.Status.BLOCKED -> R.string.preference_option_phone_feature_blocked
|
||||
SitePermissions.Status.NO_DECISION -> R.string.preference_option_phone_feature_ask_to_allow
|
||||
SitePermissions.Status.ALLOWED -> R.string.preference_option_phone_feature_allowed
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,9 +5,6 @@
|
|||
package org.mozilla.fenix.settings.quicksettings
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Bundle
|
||||
|
@ -19,75 +16,62 @@ import android.widget.FrameLayout
|
|||
import android.widget.LinearLayout
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
import androidx.appcompat.view.ContextThemeWrapper
|
||||
import androidx.core.net.toUri
|
||||
import androidx.core.widget.NestedScrollView
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.fragment.NavHostFragment.findNavController
|
||||
import androidx.core.view.isVisible
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.android.synthetic.main.fragment_quick_settings_dialog_sheet.view.*
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.browser.session.Session
|
||||
import mozilla.components.feature.sitepermissions.SitePermissions
|
||||
import org.mozilla.fenix.FenixViewModelProvider
|
||||
import kotlinx.coroutines.ObsoleteCoroutinesApi
|
||||
import mozilla.components.lib.state.ext.consumeFrom
|
||||
import org.mozilla.fenix.FeatureFlags
|
||||
import org.mozilla.fenix.HomeActivity
|
||||
import org.mozilla.fenix.IntentReceiverActivity
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.browser.BrowserFragment
|
||||
import org.mozilla.fenix.exceptions.ExceptionDomains
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.ext.requireComponents
|
||||
import org.mozilla.fenix.ext.tryGetHostFromUrl
|
||||
import org.mozilla.fenix.mvi.ActionBusFactory
|
||||
import org.mozilla.fenix.mvi.getAutoDisposeObservable
|
||||
import org.mozilla.fenix.mvi.getManagedEmitter
|
||||
import org.mozilla.fenix.settings.PhoneFeature
|
||||
import org.mozilla.fenix.ext.settings
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
import com.google.android.material.R as MaterialR
|
||||
|
||||
private const val REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS = 4
|
||||
|
||||
@ObsoleteCoroutinesApi
|
||||
@SuppressWarnings("TooManyFunctions")
|
||||
class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() {
|
||||
private lateinit var websiteInfoStore: WebsiteInfoStore
|
||||
private lateinit var websitePermissionsStore: WebsitePermissionsStore
|
||||
private lateinit var websiteTrackingProtectionStore: TrackingProtectionStore
|
||||
private lateinit var websiteInfoView: WebsiteInfoView
|
||||
private lateinit var websitePermissionsView: WebsitePermissionsView
|
||||
private lateinit var websiteTrackingProtectionView: TrackingProtectionView
|
||||
private val safeArguments get() = requireNotNull(arguments)
|
||||
private val sessionId: String by lazy { QuickSettingsSheetDialogFragmentArgs.fromBundle(safeArguments).sessionId }
|
||||
private val url: String by lazy { QuickSettingsSheetDialogFragmentArgs.fromBundle(safeArguments).url }
|
||||
private val isSecured: Boolean by lazy { QuickSettingsSheetDialogFragmentArgs.fromBundle(safeArguments).isSecured }
|
||||
private val isTrackingProtectionOn: Boolean by lazy {
|
||||
QuickSettingsSheetDialogFragmentArgs.fromBundle(safeArguments).isTrackingProtectionOn
|
||||
}
|
||||
private val promptGravity: Int by lazy { QuickSettingsSheetDialogFragmentArgs.fromBundle(safeArguments).gravity }
|
||||
private lateinit var quickSettingsComponent: QuickSettingsComponent
|
||||
|
||||
private var sitePermissions: SitePermissions? = null
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View {
|
||||
sitePermissions = QuickSettingsSheetDialogFragmentArgs.fromBundle(safeArguments).sitePermissions
|
||||
|
||||
val args = QuickSettingsSheetDialogFragmentArgs.fromBundle(safeArguments)
|
||||
val rootView = inflateRootView(container)
|
||||
requireComponents.core.sessionManager.findSessionById(sessionId)?.register(sessionObserver, view = rootView)
|
||||
quickSettingsComponent = QuickSettingsComponent(
|
||||
rootView as NestedScrollView,
|
||||
ActionBusFactory.get(this),
|
||||
FenixViewModelProvider.create(
|
||||
this,
|
||||
QuickSettingsViewModel::class.java
|
||||
) {
|
||||
QuickSettingsViewModel(
|
||||
QuickSettingsState(
|
||||
QuickSettingsState.Mode.Normal(
|
||||
url,
|
||||
isSecured,
|
||||
isTrackingProtectionOn,
|
||||
sitePermissions
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
websitePermissionsStore = WebsitePermissionsStore.createStore(
|
||||
context!!, args.sitePermissions, Settings.getInstance(context!!)
|
||||
)
|
||||
websiteInfoStore = WebsiteInfoStore.createStore(args.url, args.isSecured)
|
||||
|
||||
if (!FeatureFlags.etpCategories) {
|
||||
websiteTrackingProtectionStore =
|
||||
TrackingProtectionStore.createStore(
|
||||
args.url,
|
||||
args.isTrackingProtectionOn,
|
||||
context!!.settings()
|
||||
)
|
||||
websiteTrackingProtectionView =
|
||||
TrackingProtectionView(rootView.trackingProtectionLayout)
|
||||
} else {
|
||||
rootView.trackingProtectionGroup.isVisible = false
|
||||
}
|
||||
|
||||
websiteInfoView = WebsiteInfoView(rootView.websiteInfoLayout)
|
||||
websitePermissionsView = WebsitePermissionsView(rootView.websitePermissionsLayout)
|
||||
|
||||
return rootView
|
||||
}
|
||||
|
||||
|
@ -118,6 +102,17 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
consumeFrom(websiteInfoStore) { websiteInfoView.update(it) }
|
||||
consumeFrom(websitePermissionsStore) { websitePermissionsView.update(it) }
|
||||
if (::websiteTrackingProtectionStore.isInitialized) {
|
||||
consumeFrom(websiteTrackingProtectionStore) { websiteTrackingProtectionView.update(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun Dialog.applyCustomizationsForTopDialog(rootView: View): Dialog {
|
||||
addContentView(
|
||||
rootView,
|
||||
|
@ -135,146 +130,4 @@ class QuickSettingsSheetDialogFragment : AppCompatDialogFragment() {
|
|||
}
|
||||
return this
|
||||
}
|
||||
|
||||
override fun onRequestPermissionsResult(
|
||||
requestCode: Int,
|
||||
permissions: Array<out String>,
|
||||
grantResults: IntArray
|
||||
) {
|
||||
if (arePermissionsGranted(requestCode, grantResults)) {
|
||||
val feature = requireNotNull(PhoneFeature.findFeatureBy(permissions))
|
||||
getManagedEmitter<QuickSettingsChange>()
|
||||
.onNext(QuickSettingsChange.PermissionGranted(feature, sitePermissions))
|
||||
}
|
||||
}
|
||||
|
||||
private fun arePermissionsGranted(requestCode: Int, grantResults: IntArray) =
|
||||
requestCode == REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS && grantResults.all { it == PERMISSION_GRANTED }
|
||||
|
||||
private fun toggleTrackingProtection(context: Context, url: String) {
|
||||
val host = url.tryGetHostFromUrl()
|
||||
lifecycleScope.launch {
|
||||
ExceptionDomains(context).toggle(host)
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalCoroutinesApi
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
getAutoDisposeObservable<QuickSettingsAction>()
|
||||
.subscribe {
|
||||
when (it) {
|
||||
is QuickSettingsAction.SelectBlockedByAndroid -> {
|
||||
requestPermissions(it.permissions, REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS)
|
||||
}
|
||||
is QuickSettingsAction.SelectTrackingProtectionSettings -> {
|
||||
val directions =
|
||||
QuickSettingsSheetDialogFragmentDirections
|
||||
.actionQuickSettingsSheetDialogFragmentToTrackingProtectionFragment()
|
||||
findNavController(this@QuickSettingsSheetDialogFragment).navigate(directions)
|
||||
}
|
||||
is QuickSettingsAction.SelectReportProblem -> {
|
||||
lifecycleScope.launch(Dispatchers.Main) {
|
||||
val reportUrl =
|
||||
String.format(BrowserFragment.REPORT_SITE_ISSUE_URL, it.url)
|
||||
requireComponents.useCases.tabsUseCases.addTab.invoke(reportUrl)
|
||||
val sessionManager = requireComponents.core.sessionManager
|
||||
if (sessionManager.findSessionById(sessionId)?.isCustomTabSession() == true) {
|
||||
val intent = Intent(context, IntentReceiverActivity::class.java)
|
||||
intent.action = Intent.ACTION_VIEW
|
||||
startActivity(intent)
|
||||
}
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
is QuickSettingsAction.ToggleTrackingProtection -> {
|
||||
val trackingEnabled = it.trackingProtection
|
||||
context?.let { context: Context -> toggleTrackingProtection(context, url) }
|
||||
lifecycleScope.launch(Dispatchers.Main) {
|
||||
getManagedEmitter<QuickSettingsChange>().onNext(
|
||||
QuickSettingsChange.Change(
|
||||
url,
|
||||
isSecured,
|
||||
trackingEnabled,
|
||||
sitePermissions
|
||||
)
|
||||
)
|
||||
requireContext().components.useCases.sessionUseCases.reload.invoke()
|
||||
}
|
||||
}
|
||||
is QuickSettingsAction.TogglePermission -> {
|
||||
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
sitePermissions = quickSettingsComponent.toggleSitePermission(
|
||||
context = requireContext(),
|
||||
featurePhone = it.featurePhone,
|
||||
url = url,
|
||||
sitePermissions = sitePermissions
|
||||
)
|
||||
|
||||
launch(Dispatchers.Main) {
|
||||
getManagedEmitter<QuickSettingsChange>()
|
||||
.onNext(
|
||||
QuickSettingsChange.Stored(
|
||||
it.featurePhone,
|
||||
sitePermissions
|
||||
)
|
||||
)
|
||||
|
||||
requireContext().components.useCases.sessionUseCases.reload.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isVisible) {
|
||||
getManagedEmitter<QuickSettingsChange>()
|
||||
.onNext(QuickSettingsChange.PromptRestarted(sitePermissions))
|
||||
}
|
||||
}
|
||||
|
||||
private val sessionObserver = object : Session.Observer {
|
||||
override fun onUrlChanged(session: Session, url: String) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val host = session.url.toUri().host
|
||||
val sitePermissions: SitePermissions? = host?.let {
|
||||
val storage = requireContext().components.core.permissionStorage
|
||||
storage.findSitePermissionsBy(it)
|
||||
}
|
||||
launch(Dispatchers.Main) {
|
||||
getManagedEmitter<QuickSettingsChange>().onNext(
|
||||
QuickSettingsChange.Change(
|
||||
url,
|
||||
session.securityInfo.secure,
|
||||
session.trackerBlockingEnabled,
|
||||
sitePermissions
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onTrackerBlockingEnabledChanged(session: Session, blockingEnabled: Boolean) {
|
||||
getManagedEmitter<QuickSettingsChange>().onNext(
|
||||
QuickSettingsChange.Change(
|
||||
session.url,
|
||||
session.securityInfo.secure,
|
||||
blockingEnabled,
|
||||
sitePermissions
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun onSecurityChanged(session: Session, securityInfo: Session.SecurityInfo) {
|
||||
getManagedEmitter<QuickSettingsChange>().onNext(
|
||||
QuickSettingsChange.Change(
|
||||
session.url,
|
||||
securityInfo.secure,
|
||||
session.trackerBlockingEnabled,
|
||||
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
|
||||
}
|
||||
}
|
|
@ -12,7 +12,6 @@ import androidx.core.net.toUri
|
|||
import androidx.core.view.isGone
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.component_tracking_protection_panel.*
|
||||
import kotlinx.android.synthetic.main.fragment_quick_settings_dialog_sheet.url
|
||||
import kotlinx.android.synthetic.main.switch_with_description.view.*
|
||||
import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes
|
||||
import org.mozilla.fenix.R
|
||||
|
@ -163,11 +162,11 @@ class TrackingProtectionPanelView(
|
|||
}
|
||||
|
||||
private fun bindTrackingProtectionInfo(isTrackingProtectionOn: Boolean) {
|
||||
tracking_protection.switchItemDescription.text =
|
||||
trackingProtectionSwitch.switchItemDescription.text =
|
||||
view.context.getString(if (isTrackingProtectionOn) R.string.etp_panel_on else R.string.etp_panel_off)
|
||||
tracking_protection.switch_widget.isChecked = isTrackingProtectionOn
|
||||
trackingProtectionSwitch.switch_widget.isChecked = isTrackingProtectionOn
|
||||
|
||||
tracking_protection.switch_widget.setOnCheckedChangeListener { _, isChecked ->
|
||||
trackingProtectionSwitch.switch_widget.setOnCheckedChangeListener { _, isChecked ->
|
||||
interactor.trackingProtectionToggled(isChecked)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
<!-- 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"
|
||||
|
||||
<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/panel_wrapper"
|
||||
|
@ -27,7 +29,7 @@
|
|||
tools:text="https://wikipedia.org" />
|
||||
|
||||
<org.mozilla.fenix.trackingprotection.SwitchWithDescription
|
||||
android:id="@+id/tracking_protection"
|
||||
android:id="@+id/trackingProtectionSwitch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/tracking_protection_item_height"
|
||||
|
@ -48,7 +50,7 @@
|
|||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tracking_protection" />
|
||||
app:layout_constraintTop_toBottomOf="@id/trackingProtectionSwitch" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cross_site_tracking"
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
- 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.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<androidx.core.widget.NestedScrollView
|
||||
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:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fillViewport="true">
|
||||
|
@ -17,174 +17,52 @@
|
|||
android:background="?foundation"
|
||||
android:contentDescription="@string/quick_settings_sheet">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/url"
|
||||
style="@style/QuickSettingsText"
|
||||
android:layout_width="0dp"
|
||||
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" />
|
||||
<FrameLayout
|
||||
android:id="@+id/websiteInfoLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toTopOf="@id/trackingProtectionDivider" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/security_info"
|
||||
style="@style/QuickSettingsText.Icon"
|
||||
android:layout_width="0dp"
|
||||
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" />
|
||||
<FrameLayout
|
||||
android:id="@+id/trackingProtectionLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toTopOf="@id/webSitePermissionsDivider" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/websitePermissionsLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<View
|
||||
android:id="@+id/line_divider_security"
|
||||
android:id="@+id/webSitePermissionsDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?neutralFaded"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/security_info" />
|
||||
app:layout_constraintBottom_toTopOf="@id/websitePermissionsLayout" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/tracking_protection_view"
|
||||
<View
|
||||
android:id="@+id/trackingProtectionDivider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?neutralFaded"
|
||||
app:layout_constraintBottom_toTopOf="@id/trackingProtectionLayout" />
|
||||
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/trackingProtectionGroup"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toTopOf="@id/camera_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/line_divider_security">
|
||||
app:constraint_referenced_ids="trackingProtectionLayout,trackingProtectionDivider" />
|
||||
|
||||
<Switch
|
||||
android:id="@+id/tracking_protection"
|
||||
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/tracking_protection_action"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:drawableStart="@drawable/ic_tracking_protection" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tracking_protection_action"
|
||||
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"
|
||||
app:layout_constraintBottom_toTopOf="@id/report_site_issue_action"
|
||||
app:layout_constraintTop_toBottomOf="@id/tracking_protection" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/report_site_issue_action"
|
||||
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_toTopOf="@id/line_divider"
|
||||
app:layout_constraintTop_toBottomOf="@id/tracking_protection_action" />
|
||||
|
||||
|
||||
<View
|
||||
android:id="@+id/line_divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="?neutralFaded"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/camera_icon"
|
||||
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_constraintEnd_toStartOf="@+id/camera_action_label"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tracking_protection_view" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/camera_action_label"
|
||||
style="@style/QuickSettingsText.PermissionItemEnd"
|
||||
<androidx.constraintlayout.widget.Group
|
||||
android:id="@+id/websitePermissionsGroup"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/tracking_protection_view"
|
||||
tools:text="Allowed" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/microphone_icon"
|
||||
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_constraintEnd_toStartOf="@+id/microphone_action_label"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/camera_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/microphone_action_label"
|
||||
style="@style/QuickSettingsText.PermissionItemEnd"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/camera_action_label"
|
||||
tools:text="Blocked by Android" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notification_icon"
|
||||
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_constraintEnd_toStartOf="@+id/notification_action_label"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/microphone_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/notification_action_label"
|
||||
style="@style/QuickSettingsText.PermissionItemEnd"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/microphone_action_label"
|
||||
tools:text="Blocked" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/location_icon"
|
||||
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_constraintEnd_toStartOf="@+id/location_action_label"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/notification_icon" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/location_action_label"
|
||||
style="@style/QuickSettingsText.PermissionItemEnd"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/quicksettings_item_height"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/notification_action_label"
|
||||
tools:text="Blocked" />
|
||||
|
||||
android:layout_height="wrap_content"
|
||||
app:constraint_referenced_ids="websitePermissionsLayout,webSitePermissionsDivider" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
|
|
@ -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