diff --git a/app/src/main/java/com/duckduckgo/app/privacy/ui/WebsitesAdapter.kt b/app/src/main/java/com/duckduckgo/app/privacy/ui/WebsitesAdapter.kt
index 30a0bc2cc770..03547d2c1569 100644
--- a/app/src/main/java/com/duckduckgo/app/privacy/ui/WebsitesAdapter.kt
+++ b/app/src/main/java/com/duckduckgo/app/privacy/ui/WebsitesAdapter.kt
@@ -32,7 +32,6 @@ import com.duckduckgo.app.privacy.model.UserWhitelistedDomain
import com.duckduckgo.mobile.android.databinding.RowOneLineListItemBinding
import com.duckduckgo.mobile.android.databinding.ViewSectionHeaderBinding
import com.duckduckgo.mobile.android.ui.menu.PopupMenu
-import com.duckduckgo.mobile.android.ui.view.divider.HorizontalDivider
import kotlinx.coroutines.launch
import timber.log.Timber
@@ -46,15 +45,13 @@ class WebsitesAdapter(
const val SITE_ENTRY = 0
const val DESCRIPTION_TYPE = 1
const val EMPTY_STATE_TYPE = 2
- const val DIVIDER_TYPE = 3
- const val SECTION_TITLE_TYPE = 4
+ const val SECTION_TITLE_TYPE = 3
const val EMPTY_HINT_ITEM_SIZE = 1
}
private val sortedHeaderElements = listOf(
DESCRIPTION_TYPE,
- DIVIDER_TYPE,
SECTION_TITLE_TYPE,
)
@@ -106,9 +103,6 @@ class WebsitesAdapter(
binding.websiteDescription.setText(R.string.whitelistExplanation)
WebsiteViewHolder.SimpleViewHolder(binding.root)
}
- DIVIDER_TYPE -> {
- WebsiteViewHolder.SimpleViewHolder(HorizontalDivider(parent.context))
- }
SECTION_TITLE_TYPE -> {
val binding = ViewSectionHeaderBinding.inflate(inflater, parent, false)
binding.sectionHeader.setText(R.string.settingsPrivacyProtectionWhitelist)
diff --git a/app/src/main/java/com/duckduckgo/app/privacy/ui/WhitelistActivity.kt b/app/src/main/java/com/duckduckgo/app/privacy/ui/WhitelistActivity.kt
index d7916976a083..c2ce0a38a7c1 100644
--- a/app/src/main/java/com/duckduckgo/app/privacy/ui/WhitelistActivity.kt
+++ b/app/src/main/java/com/duckduckgo/app/privacy/ui/WhitelistActivity.kt
@@ -22,17 +22,19 @@ import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
-import androidx.appcompat.app.AlertDialog
import com.duckduckgo.anvil.annotations.InjectWith
import com.duckduckgo.app.browser.R
import com.duckduckgo.app.browser.databinding.ActivityWhitelistBinding
-import com.duckduckgo.app.browser.databinding.EditWhitelistBinding
+import com.duckduckgo.app.browser.databinding.DialogEditWhitelistBinding
import com.duckduckgo.app.browser.favicon.FaviconManager
import com.duckduckgo.app.global.DuckDuckGoActivity
import com.duckduckgo.app.global.extensions.html
import com.duckduckgo.app.privacy.model.UserWhitelistedDomain
import com.duckduckgo.app.privacy.ui.WhitelistViewModel.Command.*
import com.duckduckgo.di.scopes.ActivityScope
+import com.duckduckgo.mobile.android.ui.view.dialog.CustomAlertDialogBuilder
+import com.duckduckgo.mobile.android.ui.view.dialog.TextAlertDialogBuilder
+import com.duckduckgo.mobile.android.ui.view.dialog.TextAlertDialogBuilder.EventListener
import com.duckduckgo.mobile.android.ui.viewbinding.viewBinding
import javax.inject.Inject
@@ -43,10 +45,7 @@ class WhitelistActivity : DuckDuckGoActivity() {
lateinit var faviconManager: FaviconManager
private lateinit var adapter: WebsitesAdapter
-
private val binding: ActivityWhitelistBinding by viewBinding()
-
- private var dialog: AlertDialog? = null
private val viewModel: WhitelistViewModel by bindViewModel()
private val toolbar
@@ -107,64 +106,62 @@ class WhitelistActivity : DuckDuckGoActivity() {
}
private fun showAddDialog() {
- val dialogBinding = EditWhitelistBinding.inflate(layoutInflater)
- val addDialog = AlertDialog.Builder(this).apply {
- setTitle(R.string.dialogAddTitle)
- setView(dialogBinding.root)
- setPositiveButton(R.string.dialogSaveAction) { _, _ ->
- val newText = dialogBinding.textInput.text.toString()
- viewModel.onEntryAdded(UserWhitelistedDomain(newText))
- }
- setNegativeButton(android.R.string.no) { _, _ -> }
- }.create()
-
- dialog?.dismiss()
- dialog = addDialog
- addDialog.show()
+ val inputBinding = DialogEditWhitelistBinding.inflate(layoutInflater)
+ CustomAlertDialogBuilder(this)
+ .setTitle(R.string.dialogAddTitle)
+ .setPositiveButton(R.string.dialogSave)
+ .setNegativeButton(R.string.cancel)
+ .setView(inputBinding)
+ .addEventListener(
+ object : CustomAlertDialogBuilder.EventListener() {
+ override fun onPositiveButtonClicked() {
+ val newText = inputBinding.customDialogTextInput.text
+ viewModel.onEntryAdded(UserWhitelistedDomain(newText))
+ }
+ },
+ )
+ .show()
}
private fun showEditDialog(entry: UserWhitelistedDomain) {
- val dialogBinding = EditWhitelistBinding.inflate(layoutInflater)
- val editDialog = AlertDialog.Builder(this).apply {
- setTitle(R.string.dialogEditTitle)
- setView(dialogBinding.root)
- setPositiveButton(R.string.dialogSaveAction) { _, _ ->
- val newText = dialogBinding.textInput.text.toString()
- viewModel.onEntryEdited(entry, UserWhitelistedDomain(newText))
- }
- setNegativeButton(android.R.string.no) { _, _ -> }
- }.create()
-
- dialog?.dismiss()
- dialog = editDialog
- editDialog.show()
-
- dialogBinding.textInput.setText(entry.domain)
- dialogBinding.textInput.setSelection(entry.domain.length)
+ val inputBinding = DialogEditWhitelistBinding.inflate(layoutInflater)
+ inputBinding.customDialogTextInput.text = entry.domain
+ CustomAlertDialogBuilder(this)
+ .setTitle(R.string.dialogEditTitle)
+ .setPositiveButton(R.string.dialogSave)
+ .setNegativeButton(R.string.cancel)
+ .setView(inputBinding)
+ .addEventListener(
+ object : CustomAlertDialogBuilder.EventListener() {
+ override fun onPositiveButtonClicked() {
+ val newText = inputBinding.customDialogTextInput.text
+ viewModel.onEntryEdited(entry, UserWhitelistedDomain(newText))
+ }
+ },
+ )
+ .show()
}
private fun showDeleteDialog(entry: UserWhitelistedDomain) {
- val deleteDialog = AlertDialog.Builder(this).apply {
- setTitle(R.string.dialogConfirmTitle)
- setMessage(getString(R.string.whitelistEntryDeleteConfirmMessage, entry.domain).html(this.context))
- setPositiveButton(android.R.string.yes) { _, _ -> viewModel.onEntryDeleted(entry) }
- setNegativeButton(android.R.string.no) { _, _ -> }
- }.create()
-
- dialog?.dismiss()
- dialog = deleteDialog
- deleteDialog.show()
+ TextAlertDialogBuilder(this)
+ .setTitle(R.string.dialogConfirmTitle)
+ .setMessage(getString(R.string.whitelistEntryDeleteConfirmMessage, entry.domain).html(this))
+ .setPositiveButton(android.R.string.yes)
+ .setNegativeButton(android.R.string.no)
+ .addEventListener(
+ object : EventListener() {
+ override fun onPositiveButtonClicked() {
+ viewModel.onEntryDeleted(entry)
+ }
+ },
+ )
+ .show()
}
private fun showWhitelistFormatError() {
Toast.makeText(this, R.string.whitelistFormatError, Toast.LENGTH_LONG).show()
}
- override fun onDestroy() {
- dialog?.dismiss()
- super.onDestroy()
- }
-
companion object {
fun intent(context: Context): Intent {
return Intent(context, WhitelistActivity::class.java)
diff --git a/app/src/main/res/layout/dialog_edit_whitelist.xml b/app/src/main/res/layout/dialog_edit_whitelist.xml
new file mode 100644
index 000000000000..7b3fb86fcebf
--- /dev/null
+++ b/app/src/main/res/layout/dialog_edit_whitelist.xml
@@ -0,0 +1,24 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/edit_whitelist.xml b/app/src/main/res/layout/edit_whitelist.xml
deleted file mode 100644
index 0b374fcfae44..000000000000
--- a/app/src/main/res/layout/edit_whitelist.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_fireproof_website_empty_hint.xml b/app/src/main/res/layout/view_fireproof_website_empty_hint.xml
index adfae272373a..7eb40f4390e1 100644
--- a/app/src/main/res/layout/view_fireproof_website_empty_hint.xml
+++ b/app/src/main/res/layout/view_fireproof_website_empty_hint.xml
@@ -18,10 +18,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingStart="@dimen/keyline_4"
- android:paddingTop="@dimen/keyline_5"
- android:paddingEnd="@dimen/keyline_4"
- android:paddingBottom="@dimen/keyline_5">
+ android:padding="@dimen/keyline_4">
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_list_item_empty_hint.xml b/app/src/main/res/layout/view_list_item_empty_hint.xml
index f64690fea347..d94cb065c785 100644
--- a/app/src/main/res/layout/view_list_item_empty_hint.xml
+++ b/app/src/main/res/layout/view_list_item_empty_hint.xml
@@ -14,11 +14,19 @@
~ limitations under the License.
-->
-
\ No newline at end of file
+ android:padding="@dimen/keyline_4">
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_tab_switcher_activity.xml b/app/src/main/res/menu/menu_tab_switcher_activity.xml
index 57b9bfff4b14..e1ddea753a31 100644
--- a/app/src/main/res/menu/menu_tab_switcher_activity.xml
+++ b/app/src/main/res/menu/menu_tab_switcher_activity.xml
@@ -27,7 +27,7 @@
diff --git a/app/src/main/res/menu/whitelist_activity_menu.xml b/app/src/main/res/menu/whitelist_activity_menu.xml
index 925c68b494f6..2b91500c70cc 100644
--- a/app/src/main/res/menu/whitelist_activity_menu.xml
+++ b/app/src/main/res/menu/whitelist_activity_menu.xml
@@ -21,7 +21,7 @@
diff --git a/common-ui/src/main/java/com/duckduckgo/mobile/android/ui/view/dialog/CustomAlertDialogBuilder.kt b/common-ui/src/main/java/com/duckduckgo/mobile/android/ui/view/dialog/CustomAlertDialogBuilder.kt
new file mode 100644
index 000000000000..89aa6324474a
--- /dev/null
+++ b/common-ui/src/main/java/com/duckduckgo/mobile/android/ui/view/dialog/CustomAlertDialogBuilder.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2022 DuckDuckGo
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.duckduckgo.mobile.android.ui.view.dialog
+
+import android.content.Context
+import android.view.LayoutInflater
+import androidx.annotation.StringRes
+import androidx.appcompat.app.AlertDialog
+import androidx.viewbinding.ViewBinding
+import com.duckduckgo.mobile.android.R.style
+import com.duckduckgo.mobile.android.databinding.DialogCustomAlertBinding
+import com.duckduckgo.mobile.android.ui.view.gone
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+
+class CustomAlertDialogBuilder(val context: Context) : DaxAlertDialog {
+
+ abstract class EventListener {
+ open fun onDialogShown() {}
+ open fun onDialogDismissed() {}
+ open fun onPositiveButtonClicked() {}
+ open fun onNegativeButtonClicked() {}
+ }
+
+ internal class DefaultEventListener : EventListener()
+
+ private var dialog: AlertDialog? = null
+ private var customBinding: ViewBinding? = null
+
+ var listener: EventListener = DefaultEventListener()
+ private set
+ var titleText: CharSequence = ""
+ private set
+ var messageText: CharSequence = ""
+ private set
+ var positiveButtonText: CharSequence = ""
+ private set
+ var negativeButtonText: CharSequence = ""
+ private set
+
+ fun setTitle(@StringRes textId: Int): CustomAlertDialogBuilder {
+ titleText = context.getText(textId)
+ return this
+ }
+
+ fun setMessage(@StringRes textId: Int): CustomAlertDialogBuilder {
+ messageText = context.getText(textId)
+ return this
+ }
+
+ fun setTitle(text: CharSequence): CustomAlertDialogBuilder {
+ titleText = text
+ return this
+ }
+
+ fun setMessage(text: CharSequence): CustomAlertDialogBuilder {
+ messageText = text
+ return this
+ }
+
+ fun setPositiveButton(@StringRes textId: Int): CustomAlertDialogBuilder {
+ positiveButtonText = context.getText(textId)
+ return this
+ }
+
+ fun setNegativeButton(@StringRes textId: Int): CustomAlertDialogBuilder {
+ negativeButtonText = context.getText(textId)
+ return this
+ }
+
+ fun addEventListener(eventListener: EventListener): CustomAlertDialogBuilder {
+ listener = eventListener
+ return this
+ }
+
+ fun setView(binding: ViewBinding): CustomAlertDialogBuilder {
+ customBinding = binding
+ return this
+ }
+
+ override fun build(): DaxAlertDialog {
+ val binding: DialogCustomAlertBinding = DialogCustomAlertBinding.inflate(LayoutInflater.from(context))
+ binding.customDialogContent.addView(customBinding?.root)
+
+ val dialogBuilder = MaterialAlertDialogBuilder(context, style.Widget_DuckDuckGo_Dialog)
+ .setView(binding.root)
+ .apply {
+ setCancelable(false)
+ setOnDismissListener { listener.onDialogDismissed() }
+ }
+ dialog = dialogBuilder.create()
+ setViews(binding, dialog!!)
+
+ return this
+ }
+
+ override fun show() {
+ if (dialog == null) {
+ build()
+ }
+ dialog?.show()
+ listener.onDialogShown()
+ }
+
+ override fun dismiss() {
+ dialog?.dismiss()
+ }
+
+ private fun setViews(
+ binding: DialogCustomAlertBinding,
+ dialog: AlertDialog,
+ ) {
+ binding.customDialogTitle.text = titleText
+
+ if (messageText.isEmpty()) {
+ binding.customDialogMessage.gone()
+ } else {
+ binding.customDialogMessage.text = messageText
+ }
+
+ if (positiveButtonText.isEmpty()) {
+ binding.customDialogPositiveButton.gone()
+ } else {
+ binding.customDialogPositiveButton.text = positiveButtonText
+ binding.customDialogPositiveButton.setOnClickListener {
+ listener.onPositiveButtonClicked()
+ dialog.dismiss()
+ }
+ }
+
+ if (negativeButtonText.isEmpty()) {
+ binding.customDialogNegativeButton.gone()
+ } else {
+ binding.customDialogNegativeButton.text = negativeButtonText
+ binding.customDialogNegativeButton.setOnClickListener {
+ listener.onNegativeButtonClicked()
+ dialog.dismiss()
+ }
+ }
+ }
+}
diff --git a/app/src/main/res/drawable/ic_add.xml b/common-ui/src/main/res/drawable/ic_add_24.xml
similarity index 67%
rename from app/src/main/res/drawable/ic_add.xml
rename to common-ui/src/main/res/drawable/ic_add_24.xml
index ece870200492..e06fe79003fa 100644
--- a/app/src/main/res/drawable/ic_add.xml
+++ b/common-ui/src/main/res/drawable/ic_add_24.xml
@@ -1,5 +1,5 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/common-ui/src/main/res/layout/view_dax_text_input.xml b/common-ui/src/main/res/layout/view_dax_text_input.xml
index ff13c838c9f7..8e70e2442a40 100644
--- a/common-ui/src/main/res/layout/view_dax_text_input.xml
+++ b/common-ui/src/main/res/layout/view_dax_text_input.xml
@@ -33,7 +33,8 @@
android:id="@+id/internal_edit_text"
style="@style/Typography.DuckDuckGo.Body1"
android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
+ android:layout_height="wrap_content"
+ android:textColor="?attr/daxColorPrimaryText" />
@@ -45,9 +46,9 @@
android:layout_marginEnd="@dimen/outlinedTextPasswordEndMarginWithEndIcon"
android:foregroundGravity="center_vertical"
android:visibility="gone"
+ app:backgroundTint="?attr/daxColorPrimaryIcon"
app:layout_constraintBottom_toBottomOf="@+id/internal_input_layout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/internal_input_layout"
- app:srcCompat="@drawable/ic_password_show"
- app:backgroundTint="?attr/daxColorPrimaryIcon"/>
+ app:srcCompat="@drawable/ic_password_show" />
\ No newline at end of file
diff --git a/common-ui/src/main/res/layout/view_section_header.xml b/common-ui/src/main/res/layout/view_section_header.xml
index b849b54e1468..4f100171c0e9 100644
--- a/common-ui/src/main/res/layout/view_section_header.xml
+++ b/common-ui/src/main/res/layout/view_section_header.xml
@@ -1,5 +1,4 @@
-
-
-
\ No newline at end of file
+ android:layout_height="wrap_content" />
\ No newline at end of file
diff --git a/common-ui/src/main/res/values/design-system-theming.xml b/common-ui/src/main/res/values/design-system-theming.xml
index e7b83d6c46b1..afd91a7426a4 100644
--- a/common-ui/src/main/res/values/design-system-theming.xml
+++ b/common-ui/src/main/res/values/design-system-theming.xml
@@ -76,7 +76,7 @@
- @style/Widget.DuckDuckGo.AutoCompleteTextView
- @style/AlertDialogTheme
- @style/AlertDialogTheme
- - @style/AlertDialogTheme
+ - @style/Widget.DuckDuckGo.Dialog
- @style/Widget.DuckDuckGo.DaxButton.TextButton.Primary
- @style/Widget.DuckDuckGo.DaxButton.Secondary
- @style/Widget.DuckDuckGo.DaxButton.Ghost