1
0
Fork 0
fenix/app/src/main/java/org/mozilla/fenix/settings/quicksettings/QuickSettingsSheetDialogFra...

289 lines
12 KiB
Kotlin
Raw Normal View History

/* 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.app.Dialog
import android.content.Context
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.Gravity.BOTTOM
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.appcompat.view.ContextThemeWrapper
import androidx.core.widget.NestedScrollView
2019-05-16 22:55:13 +02:00
import androidx.navigation.fragment.NavHostFragment.findNavController
import com.google.android.material.bottomsheet.BottomSheetDialog
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import mozilla.components.browser.session.Session
import mozilla.components.feature.sitepermissions.SitePermissions
import mozilla.components.support.ktx.kotlin.toUri
import org.mozilla.fenix.FenixViewModelProvider
2019-04-26 20:45:24 +02:00
import org.mozilla.fenix.HomeActivity
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.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable
import org.mozilla.fenix.mvi.getManagedEmitter
import org.mozilla.fenix.settings.PhoneFeature
import java.net.MalformedURLException
import java.net.URL
import kotlin.coroutines.CoroutineContext
private const val REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS = 4
@SuppressWarnings("TooManyFunctions")
class QuickSettingsSheetDialogFragment : AppCompatDialogFragment(), CoroutineScope {
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 lateinit var job: Job
private var sitePermissions: SitePermissions? = null
override val coroutineContext: CoroutineContext get() = Dispatchers.IO + job
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
job = Job()
}
2019-04-26 20:45:24 +02:00
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
sitePermissions = QuickSettingsSheetDialogFragmentArgs.fromBundle(safeArguments).sitePermissions
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
)
)
)
}
)
return rootView
}
private fun inflateRootView(container: ViewGroup? = null): View {
2019-04-26 20:45:24 +02:00
val contextThemeWrapper = ContextThemeWrapper(
activity,
(activity as HomeActivity).themeManager.currentThemeResource
)
return LayoutInflater.from(contextThemeWrapper).inflate(
2019-04-26 20:45:24 +02:00
R.layout.fragment_quick_settings_dialog_sheet,
container,
false
)
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val customDialog = if (promptGravity == BOTTOM) {
return BottomSheetDialog(requireContext(), this.theme)
} else {
Dialog(requireContext())
}
return customDialog.applyCustomizationsForTopDialog(inflateRootView())
}
private fun Dialog.applyCustomizationsForTopDialog(rootView: View): Dialog {
addContentView(
rootView,
LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT
)
)
window?.apply {
setGravity(promptGravity)
setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
// This must be called after addContentView, or it won't fully fill to the edge.
setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
}
return this
}
2019-04-26 20:45:24 +02:00
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))
}
}
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
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 = try {
URL(url).host
} catch (e: MalformedURLException) {
url
}
launch {
if (!ExceptionDomains.load(context).contains(host)) {
ExceptionDomains.add(context, host)
} else {
ExceptionDomains.remove(context, listOf(host))
}
}
}
override fun onResume() {
super.onResume()
getAutoDisposeObservable<QuickSettingsAction>()
.subscribe {
when (it) {
is QuickSettingsAction.SelectBlockedByAndroid -> {
requestPermissions(it.permissions, REQUEST_CODE_QUICK_SETTINGS_PERMISSIONS)
}
is QuickSettingsAction.SelectTrackingProtectionSettings -> {
2019-05-16 22:55:13 +02:00
val directions =
QuickSettingsSheetDialogFragmentDirections
.actionQuickSettingsSheetDialogFragmentToTrackingProtectionFragment()
findNavController(this@QuickSettingsSheetDialogFragment).navigate(directions)
}
is QuickSettingsAction.SelectReportProblem -> {
launch(Dispatchers.Main) {
val reportUrl =
String.format(BrowserFragment.REPORT_SITE_ISSUE_URL, it.url)
requireComponents.useCases.tabsUseCases.addTab.invoke(reportUrl)
}
dismiss()
}
is QuickSettingsAction.ToggleTrackingProtection -> {
val trackingEnabled = it.trackingProtection
context?.let { context: Context -> toggleTrackingProtection(context, url) }
launch(Dispatchers.Main) {
getManagedEmitter<QuickSettingsChange>().onNext(
QuickSettingsChange.Change(
url,
isSecured,
trackingEnabled,
sitePermissions
)
)
requireContext().components.useCases.sessionUseCases.reload.invoke()
}
}
is QuickSettingsAction.TogglePermission -> {
launch {
sitePermissions = quickSettingsComponent.toggleSitePermission(
context = requireContext(),
featurePhone = it.featurePhone,
url = url,
sitePermissions = sitePermissions
)
launch(Dispatchers.Main) {
getManagedEmitter<QuickSettingsChange>()
2019-04-26 20:45:24 +02:00
.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) {
super.onUrlChanged(session, url)
launch {
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) {
super.onTrackerBlockingEnabledChanged(session, blockingEnabled)
getManagedEmitter<QuickSettingsChange>().onNext(
QuickSettingsChange.Change(
session.url,
session.securityInfo.secure,
blockingEnabled,
sitePermissions
)
)
}
override fun onSecurityChanged(session: Session, securityInfo: Session.SecurityInfo) {
super.onSecurityChanged(session, securityInfo)
getManagedEmitter<QuickSettingsChange>().onNext(
QuickSettingsChange.Change(
session.url,
securityInfo.secure,
session.trackerBlockingEnabled,
sitePermissions
)
)
}
}
}