Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Commit

Permalink
Closes #6915: Add addon installation confirmation dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
psymoon committed May 8, 2020
1 parent b1f8371 commit 2782bdc
Show file tree
Hide file tree
Showing 6 changed files with 523 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
/* 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 mozilla.components.feature.addons.ui

import android.annotation.SuppressLint
import android.app.Dialog
import android.content.DialogInterface
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.GradientDrawable
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import androidx.annotation.ColorRes
import androidx.appcompat.app.AppCompatDialogFragment
import androidx.appcompat.widget.AppCompatCheckBox
import androidx.core.content.ContextCompat
import mozilla.components.feature.addons.Addon
import mozilla.components.feature.addons.R

private const val KEY_DIALOG_GRAVITY = "KEY_DIALOG_GRAVITY"
private const val KEY_DIALOG_WIDTH_MATCH_PARENT = "KEY_DIALOG_WIDTH_MATCH_PARENT"
private const val KEY_POSITIVE_BUTTON_BACKGROUND_COLOR = "KEY_POSITIVE_BUTTON_BACKGROUND_COLOR"
private const val KEY_POSITIVE_BUTTON_TEXT_COLOR = "KEY_POSITIVE_BUTTON_TEXT_COLOR"
private const val KEY_POSITIVE_BUTTON_RADIUS = "KEY_POSITIVE_BUTTON_RADIUS"
private const val DEFAULT_VALUE = Int.MAX_VALUE

/**
* A dialog that shows [Addon] installation confirmation.
*/
class AddonInstallationDialogFragment : AppCompatDialogFragment() {

/**
* A lambda called when the allow button is clicked.
*/
var onPositiveButtonClicked: ((Addon, Boolean) -> Unit)? = null

private val safeArguments get() = requireNotNull(arguments)

internal val addon get() = requireNotNull(safeArguments.getParcelable<Addon>(KEY_ADDON))
private var allowPrivateBrowsing: Boolean = false

internal val positiveButtonRadius
get() =
safeArguments.getFloat(KEY_POSITIVE_BUTTON_RADIUS, DEFAULT_VALUE.toFloat())

internal val dialogGravity: Int
get() =
safeArguments.getInt(
KEY_DIALOG_GRAVITY,
DEFAULT_VALUE
)
internal val dialogShouldWidthMatchParent: Boolean
get() =
safeArguments.getBoolean(KEY_DIALOG_WIDTH_MATCH_PARENT)

internal val positiveButtonBackgroundColor
get() =
safeArguments.getInt(
KEY_POSITIVE_BUTTON_BACKGROUND_COLOR,
DEFAULT_VALUE
)

internal val positiveButtonTextColor
get() =
safeArguments.getInt(
KEY_POSITIVE_BUTTON_TEXT_COLOR,
DEFAULT_VALUE
)

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val sheetDialog = Dialog(requireContext())
sheetDialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
sheetDialog.setCanceledOnTouchOutside(true)

val rootView = createContainer()

sheetDialog.setContainerView(rootView)

sheetDialog.window?.apply {
if (dialogGravity != DEFAULT_VALUE) {
setGravity(dialogGravity)
}

if (dialogShouldWidthMatchParent) {
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 sheetDialog
}

override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
onPositiveButtonClicked?.invoke(addon, allowPrivateBrowsing)
}

private fun Dialog.setContainerView(rootView: View) {
if (dialogShouldWidthMatchParent) {
setContentView(rootView)
} else {
addContentView(
rootView,
LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT
)
)
}
}

@SuppressLint("InflateParams")
private fun createContainer(): View {
val rootView = LayoutInflater.from(requireContext()).inflate(
R.layout.mozac_feature_addons_fragment_dialog_addon_installed,
null,
false
)

rootView.findViewById<TextView>(R.id.title).text =
requireContext().getString(
R.string.mozac_feature_addons_installed_dialog_title,
addon.translatedName
)

val allowedInPrivateBrowsing = rootView.findViewById<AppCompatCheckBox>(R.id.allow_in_private_browsing)
allowedInPrivateBrowsing.setOnCheckedChangeListener { _, isChecked ->
allowPrivateBrowsing = isChecked
}

val positiveButton = rootView.findViewById<Button>(R.id.confirm_button)
positiveButton.setOnClickListener {
onPositiveButtonClicked?.invoke(addon, allowPrivateBrowsing)
dismiss()
}

if (positiveButtonBackgroundColor != DEFAULT_VALUE) {
val backgroundTintList =
ContextCompat.getColorStateList(requireContext(), positiveButtonBackgroundColor)
positiveButton.backgroundTintList = backgroundTintList
}

if (positiveButtonTextColor != DEFAULT_VALUE) {
val color = ContextCompat.getColor(requireContext(), positiveButtonTextColor)
positiveButton.setTextColor(color)
}

if (positiveButtonRadius != DEFAULT_VALUE.toFloat()) {
val shape = GradientDrawable()
shape.shape = GradientDrawable.RECTANGLE
shape.setColor(
ContextCompat.getColor(
requireContext(),
positiveButtonBackgroundColor
)
)
shape.cornerRadius = positiveButtonRadius
positiveButton.background = shape
}

return rootView
}

@Suppress("LongParameterList")
companion object {
/**
* Returns a new instance of [AddonInstallationDialogFragment].
* @param addon The addon to show in the dialog.
* @param promptsStyling Styling properties for the dialog.
* @param onPositiveButtonClicked A lambda called when the allow button is clicked.
*/
fun newInstance(
addon: Addon,
promptsStyling: PromptsStyling? = PromptsStyling(
gravity = Gravity.BOTTOM,
shouldWidthMatchParent = true
),
onPositiveButtonClicked: ((Addon, Boolean) -> Unit)? = null
): AddonInstallationDialogFragment {

val fragment = AddonInstallationDialogFragment()
val arguments = fragment.arguments ?: Bundle()

arguments.apply {
putParcelable(KEY_ADDON, addon)

promptsStyling?.gravity?.apply {
putInt(KEY_DIALOG_GRAVITY, this)
}
promptsStyling?.shouldWidthMatchParent?.apply {
putBoolean(KEY_DIALOG_WIDTH_MATCH_PARENT, this)
}
promptsStyling?.positiveButtonBackgroundColor?.apply {
putInt(KEY_POSITIVE_BUTTON_BACKGROUND_COLOR, this)
}

promptsStyling?.positiveButtonTextColor?.apply {
putInt(KEY_POSITIVE_BUTTON_TEXT_COLOR, this)
}
}
fragment.onPositiveButtonClicked = onPositiveButtonClicked
fragment.arguments = arguments
return fragment
}
}

/**
* Styling for the permissions dialog.
*/
data class PromptsStyling(
val gravity: Int,
val shouldWidthMatchParent: Boolean = false,
@ColorRes
val positiveButtonBackgroundColor: Int? = null,
@ColorRes
val positiveButtonTextColor: Int? = null,
val positiveButtonRadius: Float? = null
)
}
Original file line number Diff line number Diff line change
@@ -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/. -->
<RelativeLayout 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="wrap_content"
android:background="?android:windowBackground"
android:orientation="vertical"
tools:ignore="Overdraw">

<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/icon"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentTop="true"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:importantForAccessibility="no"
android:scaleType="center"
app:tint="?android:attr/textColorPrimary"
app:srcCompat="@drawable/mozac_ic_extensions" />

<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@id/icon"
android:layout_alignParentTop="true"
android:layout_marginStart="3dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="11dp"
android:layout_toEndOf="@id/icon"
android:paddingStart="5dp"
android:paddingTop="4dp"
android:paddingEnd="5dp"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp"
tools:text="@string/mozac_feature_addons_installed_dialog_title"
tools:textColor="#000000" />

<TextView
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/title"
android:layout_alignStart="@id/title"
android:layout_marginTop="16dp"
android:paddingStart="5dp"
android:paddingTop="4dp"
android:paddingEnd="5dp"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/mozac_feature_addons_installed_dialog_description" />

<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@+id/description"
android:layout_below="@id/title"
android:layout_marginTop="16dp"
app:tint="?android:attr/textColorPrimary"
app:srcCompat="@drawable/mozac_ic_menu"
/>

<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/allow_in_private_browsing"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/description"
android:layout_alignStart="@id/title"
android:layout_marginTop="16dp"
android:paddingStart="5dp"
android:paddingTop="4dp"
android:paddingEnd="5dp"
android:text="@string/mozac_feature_addons_settings_allow_in_private_browsing" />

<Button
android:id="@+id/confirm_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/allow_in_private_browsing"
android:layout_alignParentEnd="true"
android:layout_marginStart="8dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
android:text="@string/mozac_feature_addons_installed_dialog_okay_button"
android:textAllCaps="false" />

</RelativeLayout>
8 changes: 7 additions & 1 deletion components/feature/addons/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -181,4 +181,10 @@
<string name="mozac_feature_addons_updater_dialog_last_attempt">Last attempt:</string>
<!-- Displayed in the "Status" field for the updater when an add-on has been correctly updated -->
<string name="mozac_feature_addons_updater_dialog_status">Status:</string>
</resources>
<!-- Text shown in he dialog when add-on installation is completed. %1$s is the add-on name. -->
<string name="mozac_feature_addons_installed_dialog_title">%1$s has been added to Firefox</string>
<!-- Text shown in he dialog when add-on installation is completed. %1$s is the add-on name. -->
<string name="mozac_feature_addons_installed_dialog_description">Open it in the menu</string>
<!-- Confirmation button text for the dialog when add-on installation is completed. -->
<string name="mozac_feature_addons_installed_dialog_okay_button">Okay, Got It</string>
</resources>
Loading

0 comments on commit 2782bdc

Please sign in to comment.