2 * Copyright 2017-2024 Soren Stoutner <soren@stoutner.com>.
4 * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
6 * Privacy Browser Android is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Privacy Browser Android is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Privacy Browser Android. If not, see <http://www.gnu.org/licenses/>.
20 package com.stoutner.privacybrowser.dialogs
22 import android.app.Dialog
23 import android.content.Context
24 import android.content.DialogInterface
25 import android.os.Bundle
26 import android.text.Editable
27 import android.text.TextWatcher
28 import android.view.KeyEvent
29 import android.view.View
30 import android.view.WindowManager
31 import android.widget.EditText
32 import android.widget.TextView
34 import androidx.appcompat.app.AlertDialog
35 import androidx.fragment.app.DialogFragment
36 import androidx.preference.PreferenceManager
38 import com.stoutner.privacybrowser.R
39 import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper
41 class AddDomainDialog : DialogFragment() {
42 // Declare the class variables
43 private lateinit var addDomainListener: AddDomainListener
45 // The public interface is used to send information back to the parent activity.
46 interface AddDomainListener {
47 fun addDomain(dialogFragment: DialogFragment)
50 override fun onAttach(context: Context) {
51 // Run the default commands.
52 super.onAttach(context)
54 // Get a handle for the listener from the launching context.
55 addDomainListener = context as AddDomainListener
58 override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
59 // Use an alert dialog builder to create the alert dialog.
60 val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
63 dialogBuilder.setIcon(R.drawable.domains)
66 dialogBuilder.setTitle(R.string.add_domain)
69 dialogBuilder.setView(R.layout.add_domain_dialog)
71 // Set the cancel button listener. Using `null` as the listener closes the dialog without doing anything else.
72 dialogBuilder.setNegativeButton(R.string.cancel, null)
74 // Set the add button listener.
75 dialogBuilder.setPositiveButton(R.string.add) { _: DialogInterface, _: Int ->
76 // Return the dialog fragment to the parent activity on add.
77 addDomainListener.addDomain(this)
80 // Create an alert dialog from the builder.
81 val alertDialog = dialogBuilder.create()
83 // Get a handle for the shared preferences.
84 val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
86 // Get the screenshot preference.
87 val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)
89 // Disable screenshots if not allowed.
90 if (!allowScreenshots) {
91 alertDialog.window!!.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
94 // The alert dialog must be shown before the contents can be modified.
97 // Initialize the domains database helper.
98 val domainsDatabaseHelper = DomainsDatabaseHelper(requireContext())
100 // Get handles for the views in the alert dialog.
101 val addDomainEditText = alertDialog.findViewById<EditText>(R.id.domain_name_edittext)!!
102 val domainNameAlreadyExistsTextView = alertDialog.findViewById<TextView>(R.id.domain_name_already_exists_textview)!!
103 val addButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)
105 // Initially disable the add button.
106 addButton.isEnabled = false
108 // Update the status of the warning text and the add button when the domain name changes.
109 addDomainEditText.addTextChangedListener(object: TextWatcher {
110 override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
114 override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
118 override fun afterTextChanged(editable: Editable) {
119 if (domainsDatabaseHelper.getCursorForDomainName(addDomainEditText.text.toString()).count > 0) { // The domain already exists.
120 // Show the warning text.
121 domainNameAlreadyExistsTextView.visibility = View.VISIBLE
123 // Disable the add button.
124 addButton.isEnabled = false
125 } else { // The domain do not yet exist.
126 // Hide the warning text.
127 domainNameAlreadyExistsTextView.visibility = View.GONE
129 // Enable the add button if the domain name is not empty.
130 addButton.isEnabled = editable.isNotEmpty()
135 // Allow the enter key on the keyboard to create the domain from the add domain edit text.
136 addDomainEditText.setOnKeyListener { _: View, keyCode: Int, keyEvent: KeyEvent ->
137 // Check the key code and event.
138 if (keyCode == KeyEvent.KEYCODE_ENTER && keyEvent.action == KeyEvent.ACTION_DOWN) { // The event is a key-down on the enter key.
139 // Trigger the add domain listener and return the dialog fragment to the parent activity.
140 addDomainListener.addDomain(this)
142 // Manually dismiss the alert dialog.
143 alertDialog.dismiss()
145 // Consume the event.
146 return@setOnKeyListener true
147 } else { // Some other key was pressed.
148 // Do not consume the event.
149 return@setOnKeyListener false
153 // Return the alert dialog.