From 4433cc4c14e50341b9fd4025676080b0853d809e Mon Sep 17 00:00:00 2001 From: Soren Stoutner Date: Mon, 28 Oct 2024 17:16:23 -0700 Subject: [PATCH] Add an option to delete all domain settings at once. https://redmine.stoutner.com/issues/1085 --- .../activities/DomainsActivity.kt | 273 +++++++++++++----- .../activities/ViewHeadersActivity.kt | 2 +- .../dialogs/AboutViewHeadersDialog.kt | 2 +- .../privacybrowser/dialogs/AddDomainDialog.kt | 4 +- .../dialogs/DeleteAllDomainsDialog.kt | 90 ++++++ .../helpers/DomainsDatabaseHelper.kt | 16 +- .../main/res/menu/domains_options_menu.xml | 8 +- app/src/main/res/values-ru/strings.xml | 6 +- app/src/main/res/values-tr/strings.xml | 4 +- app/src/main/res/values/strings.xml | 3 + 10 files changed, 326 insertions(+), 82 deletions(-) create mode 100644 app/src/main/java/com/stoutner/privacybrowser/dialogs/DeleteAllDomainsDialog.kt diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.kt b/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.kt index 47ffe90f..f3b854e4 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/DomainsActivity.kt @@ -14,7 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Privacy Browser Android. If not, see . + * along with Privacy Browser Android. If not, see . */ package com.stoutner.privacybrowser.activities @@ -55,7 +55,7 @@ import com.google.android.material.snackbar.Snackbar import com.stoutner.privacybrowser.R import com.stoutner.privacybrowser.dialogs.AddDomainDialog -import com.stoutner.privacybrowser.dialogs.AddDomainDialog.AddDomainListener +import com.stoutner.privacybrowser.dialogs.DeleteAllDomainsDialog import com.stoutner.privacybrowser.fragments.DomainSettingsFragment import com.stoutner.privacybrowser.fragments.DomainsListFragment import com.stoutner.privacybrowser.helpers.DOMAIN_NAME @@ -82,11 +82,12 @@ private const val DOMAIN_SETTINGS_DISPLAYED = "domain_settings_displayed" private const val DOMAIN_SETTINGS_SCROLL_Y = "domain_settings_scroll_y" private const val LISTVIEW_POSITION = "listview_position" -class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragment.DismissSnackbarInterface, DomainsListFragment.SaveDomainSettingsInterface { +class DomainsActivity : AppCompatActivity(), AddDomainDialog.AddDomainListener, DeleteAllDomainsDialog.DeleteAllDomainSettingsListener, DomainsListFragment.DismissSnackbarInterface, + DomainsListFragment.SaveDomainSettingsInterface { + companion object { // Define the public variables. var currentDomainDatabaseId = 0 // Used in `DomainsListFragment`. - var deleteMenuItemEnabled = true var dismissingSnackbar = false // Used in `DomainsListFragment`. var domainsListViewPosition = 0 // Used in `DomainsListFragment`. var sslEndDateLong: Long = 0 // Used in `DomainsSettingsFragment`. @@ -119,6 +120,8 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragm private var closeActivityAfterDismissingSnackbar = false private var closeOnBack = false private var deletedDomainPosition = 0 + private var deleteMenuItemEnabled = true + private var deleteAllMenuItemEnabled = true private var domainSettingsDatabaseIdBeforeRestart = 0 private var domainSettingsDisplayedBeforeRestart = false private var domainSettingsScrollY = 0 @@ -274,22 +277,35 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragm // Inflate the menu. menuInflater.inflate(R.menu.domains_options_menu, menu) - // Get a handle for the delete menu item. + // Get a handle for the menu items. val deleteMenuItem = menu.findItem(R.id.delete_domain) + val deleteAllMenuItem = menu.findItem(R.id.delete_all) // Get the domain settings fragment. val domainSettingsFragment = supportFragmentManager.findFragmentByTag(DOMAIN_SETTINGS_FRAGMENT_TAG) // Update the visibility of the delete menu item. - if (twoPanedMode) // The device is in two-paned mode and a domain is selected. + if (twoPanedMode) { // The device is in two-paned mode. + // Show both menu items. deleteMenuItem.isVisible = true - else if ((domainSettingsFragment != null) && domainSettingsFragment.isVisible) // The device is in single-paned mode and the domain settings fragment is visible. + deleteAllMenuItem.isVisible = true + } else if ((domainSettingsFragment != null) && domainSettingsFragment.isVisible) { // The device is in single-paned mode and the domain settings fragment is visible. + // Show the delete menu item. deleteMenuItem.isVisible = true - else // The device is in two-paned mode but no domain is selected (like after deleting a domain) or the device is in single-paned mode and the domains list is visible. + + // Hide the delete all menu item. + deleteAllMenuItem.isVisible = false + } else { // The device is in single-paned mode and the domains list is visible. + // Hide the delete menu item. deleteMenuItem.isVisible = false + // Show the delete all menu item. + deleteAllMenuItem.isVisible = true + } + // Update the status of the delete menu item. deleteMenuItem.isEnabled = deleteMenuItemEnabled + deleteAllMenuItem.isEnabled = deleteAllMenuItemEnabled } override fun onMenuItemSelected(menuItem: MenuItem): Boolean { @@ -371,9 +387,6 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragm // Store the deleted domain position, which is needed if undo is selected in the snackbar. deletedDomainPosition = domainsListView!!.checkedItemPosition - // Disable the delete menu item. - deleteMenuItemEnabled = false - // Get a handle for the domain settings fragment. val domainSettingsFragment = supportFragmentManager.findFragmentById(R.id.domain_settings_fragment_container)!! @@ -385,10 +398,6 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragm // Disable the delete menu item. deleteMenuItemEnabled = false - - // Invalidate the options menu. - invalidateMenu() - } else { // Single-paned mode. // Instantiate a new domains list fragment. val domainsListFragment = DomainsListFragment() @@ -405,24 +414,8 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragm // Get a cursor that does not show the domain to be deleted. val domainsPendingDeleteCursor = domainsDatabaseHelper.getDomainNameCursorOrderedByDomainExcept(databaseIdToDelete) - // Setup the domains pending delete cursor adapter. - val domainsPendingDeleteCursorAdapter: CursorAdapter = object : CursorAdapter(applicationContext, domainsPendingDeleteCursor, false) { - override fun newView(context: Context, cursor: Cursor, parent: ViewGroup): View { - // Inflate the individual item layout. - return layoutInflater.inflate(R.layout.domain_name_linearlayout, parent, false) - } - - override fun bindView(view: View, context: Context, cursor: Cursor) { - // Get the domain name string. - val domainNameString = cursor.getString(cursor.getColumnIndexOrThrow(DOMAIN_NAME)) - - // Get a handle for the domain name text view. - val domainNameTextView = view.findViewById(R.id.domain_name_textview) - - // Display the domain name. - domainNameTextView.text = domainNameString - } - } + // Populate the domains pending delete cursor adapter. + val domainsPendingDeleteCursorAdapter = populateDomainsCursorAdapter(domainsPendingDeleteCursor) // Update the handle for the current domains list view. domainsListView = findViewById(R.id.domains_listview) @@ -430,6 +423,12 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragm // Update the list view. domainsListView!!.adapter = domainsPendingDeleteCursorAdapter + // Disable the delete all menu item if no domains are displayed. + deleteAllMenuItemEnabled = (domainsPendingDeleteCursor.count > 0) + + // Invalidate the options menu. + invalidateMenu() + // Display a snackbar. undoDeleteSnackbar = Snackbar.make(domainsListView!!, R.string.domain_deleted, Snackbar.LENGTH_LONG) .setAction(R.string.undo) {} // Do nothing because everything will be handled by `onDismissed()` below. @@ -440,7 +439,7 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragm // Create an arguments bundle. val argumentsBundle = Bundle() - // Store the domains settings in the arguments bundle. + // Store the domain settings in the arguments bundle. argumentsBundle.putInt(DomainSettingsFragment.DATABASE_ID, databaseIdToDelete) argumentsBundle.putInt(DomainSettingsFragment.SCROLL_Y, domainSettingsScrollY) @@ -451,28 +450,12 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragm domainSettingsFragment.arguments = argumentsBundle // Display the correct fragments. - if (twoPanedMode) { // The device in in two-paned mode. + if (twoPanedMode) { // The device is in two-paned mode. // Get a cursor with the current contents of the domains database. val undoDeleteDomainsCursor = domainsDatabaseHelper.domainNameCursorOrderedByDomain - // Setup the domains cursor adapter. - val undoDeleteDomainsCursorAdapter: CursorAdapter = object : CursorAdapter(applicationContext, undoDeleteDomainsCursor, false) { - override fun newView(context: Context, cursor: Cursor, parent: ViewGroup): View { - // Inflate the individual item layout. - return layoutInflater.inflate(R.layout.domain_name_linearlayout, parent, false) - } - - override fun bindView(view: View, context: Context, cursor: Cursor) { - /// Get the domain name string. - val domainNameString = cursor.getString(cursor.getColumnIndexOrThrow(DOMAIN_NAME)) - - // Get a handle for the domain name text view. - val domainNameTextView = view.findViewById(R.id.domain_name_textview) - - // Display the domain name. - domainNameTextView.text = domainNameString - } - } + // Populate the undo delete domains cursor adapter. + val undoDeleteDomainsCursorAdapter = populateDomainsCursorAdapter(undoDeleteDomainsCursor) // Update the domains list view. domainsListView!!.adapter = undoDeleteDomainsCursorAdapter @@ -480,14 +463,15 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragm // Select the previously deleted domain in the list view. domainsListView!!.setItemChecked(deletedDomainPosition, true) - // Enable the delete menu item. + // Enable the menu items. deleteMenuItemEnabled = true + deleteAllMenuItemEnabled = true // Display the domain settings fragment. supportFragmentManager.commitNow { replace(R.id.domain_settings_fragment_container, domainSettingsFragment, DOMAIN_SETTINGS_FRAGMENT_TAG) } - } else { // The device in in one-paned mode. + } else { // The device is in one-paned mode. // Hide the add domain floating action button. addDomainFAB.hide() @@ -529,6 +513,17 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragm undoDeleteSnackbar!!.show() } } + + R.id.delete_all -> { // Delete all. + // Instantiate the delete all domains dialog fragment. + val deleteAllDomainsDialogFragment = DeleteAllDomainsDialog() + + // Show the delete all domains alert dialog. + deleteAllDomainsDialogFragment.show(supportFragmentManager, getString(R.string.delete_all)) + + // Consume the event. + return true + } } // Consume the event. @@ -735,6 +730,130 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragm } } + override fun deleteAllDomainSettings() { + // Reset close-on-back, which otherwise can cause errors if the system attempts to save settings for a domain that no longer exists. + closeOnBack = false + + // Store a copy of the currently selected domain database ID because it could change while the snackbar is displayed. + val currentlySelectedDatabaseId = currentDomainDatabaseId + + // Store the domains list view scroll position. + val domainsListViewFirstVisiblePosition = domainsListView!!.firstVisiblePosition + + // Update the fragments and menu items. + if (twoPanedMode) { // Two-paned mode. + // Store the deleted domain position, which is needed if undo is selected in the snackbar. + deletedDomainPosition = domainsListView!!.checkedItemPosition + + // Get a handle for the domain settings fragment. + val domainSettingsFragment = supportFragmentManager.findFragmentById(R.id.domain_settings_fragment_container)!! + + // Get a handle for the domain settings fragment view. + val domainSettingsFragmentView = domainSettingsFragment.requireView() + + // Hide the domain settings fragment. + domainSettingsFragmentView.visibility = View.INVISIBLE + + // Disable the delete menu item. + deleteMenuItemEnabled = false + } + + // Disable the delete all menu item. + deleteAllMenuItemEnabled = false + + // Invalidate the options menu. + invalidateMenu() + + // Create an empty cursor + val emptyCursor = domainsDatabaseHelper.getCursorForId(-1) + + // Populate the empty cursor adapter. + val emptyCursorAdapter = populateDomainsCursorAdapter(emptyCursor) + + // Update the handle for the current domains list view. + domainsListView = findViewById(R.id.domains_listview) + + // Update the list view. + domainsListView!!.adapter = emptyCursorAdapter + + // Get a handle for the activity (used in an inner class below). + val activity: Activity = this + + // Display a snackbar. + undoDeleteSnackbar = Snackbar.make(domainsListView!!, R.string.all_domains_deleted, Snackbar.LENGTH_LONG) + .setAction(R.string.undo) {} // Do nothing because everything will be handled by `onDismissed()` below. + .addCallback(object : Snackbar.Callback() { + override fun onDismissed(snackbar: Snackbar, event: Int) { + //Run commands based on the event. + if (event == DISMISS_EVENT_ACTION) { // The user pushed the `Undo` button. + // Get a cursor with the current contents of the domains database. + val undoDeleteDomainsCursor = domainsDatabaseHelper.domainNameCursorOrderedByDomain + + // Populate the undo delete domains cursor adapter. + val undoDeleteDomainsCursorAdapter = populateDomainsCursorAdapter(undoDeleteDomainsCursor) + + // Update the domains list view. + domainsListView!!.adapter = undoDeleteDomainsCursorAdapter + + // Redisplay the domain settings in two-paned mode. + if (twoPanedMode) { + // Create an arguments bundle. + val argumentsBundle = Bundle() + + // Store the domain settings in the arguments bundle. + argumentsBundle.putInt(DomainSettingsFragment.DATABASE_ID, currentlySelectedDatabaseId) + argumentsBundle.putInt(DomainSettingsFragment.SCROLL_Y, domainSettingsScrollY) + + // Instantiate a new domain settings fragment. + val domainSettingsFragment = DomainSettingsFragment() + + // Add the arguments bundle to the domain settings fragment. + domainSettingsFragment.arguments = argumentsBundle + + // Select the previously selected domain in the list view. + domainsListView!!.setItemChecked(deletedDomainPosition, true) + + // Display the domain settings fragment. + supportFragmentManager.commitNow { + replace(R.id.domain_settings_fragment_container, domainSettingsFragment, DOMAIN_SETTINGS_FRAGMENT_TAG) + } + + // Enable the delete menu item. + deleteMenuItemEnabled = true + } + + // Restore the domains list view scroll position. + domainsListView!!.setSelection(domainsListViewFirstVisiblePosition) + + // Enable the delete all menu item. + deleteAllMenuItemEnabled = true + + // Update the options menu. + invalidateMenu() + } else { // The snackbar was dismissed without the undo button being pushed. + // Delete all the domains. + val rowsDeleted = domainsDatabaseHelper.deleteAllDomains() + + // Reset the dismissing snackbar option. + // The rows deleted should always be greater than 0, but in all cases they should be greater than -1. + // This has the effect of tricking the compiler into waiting until after the delete finishes to reenable the delete menu item, + // because the compiler (probably) can't tell that the response will never be less than -1, so it doesn't compile out the delay. + if (rowsDeleted > -1) { + // Reset the dismissing snackbar tracker. + dismissingSnackbar = false + } + + // Close the activity if back was pressed. + if (closeActivityAfterDismissingSnackbar) + NavUtils.navigateUpFromSameTask(activity) + } + } + }) + + // Show the Snackbar. + undoDeleteSnackbar!!.show() + } + override fun saveDomainSettings(view: View) { // Get handles for the domain settings. val domainNameEditText = view.findViewById(R.id.domain_settings_name_edittext) @@ -821,11 +940,8 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragm domainsDatabaseHelper.updatePinnedIpAddresses(currentDomainDatabaseId, currentIpAddresses!!) } - private fun populateDomainsListView(highlightedDomainDatabaseId: Int, domainsListViewPosition: Int) { - // Get a cursor with the current contents of the domains database. - val domainsCursor = domainsDatabaseHelper.domainNameCursorOrderedByDomain - - // Setup the domains cursor adapter. + private fun populateDomainsCursorAdapter(domainsCursor: Cursor) :CursorAdapter { + // Populate the domains cursor adapter. val domainsCursorAdapter: CursorAdapter = object : CursorAdapter(applicationContext, domainsCursor, false) { override fun newView(context: Context, cursor: Cursor, parent: ViewGroup): View { // Inflate the individual item layout. @@ -833,17 +949,28 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragm } override fun bindView(view: View, context: Context, cursor: Cursor) { + /// Get the domain name string. + val domainNameString = cursor.getString(cursor.getColumnIndexOrThrow(DOMAIN_NAME)) + // Get a handle for the domain name text view. val domainNameTextView = view.findViewById(R.id.domain_name_textview) - // Get the domain name string. - val domainNameString = cursor.getString(cursor.getColumnIndexOrThrow(DOMAIN_NAME)) - - // Set the domain name. + // Display the domain name. domainNameTextView.text = domainNameString } } + // Return the domains cursor adapter. + return domainsCursorAdapter + } + + private fun populateDomainsListView(highlightedDomainDatabaseId: Int, domainsListViewPosition: Int) { + // Get a cursor with the current contents of the domains database. + val domainsCursor = domainsDatabaseHelper.domainNameCursorOrderedByDomain + + // Populate the domains cursor adapter. + val domainsCursorAdapter = populateDomainsCursorAdapter(domainsCursor) + // get a handle for the current domains listview. domainsListView = findViewById(R.id.domains_listview) @@ -898,18 +1025,20 @@ class DomainsActivity : AppCompatActivity(), AddDomainListener, DomainsListFragm replace(R.id.domain_settings_fragment_container, domainSettingsFragment, DOMAIN_SETTINGS_FRAGMENT_TAG) } - // Enable the delete options menu item. + // Enable the menu items. deleteMenuItemEnabled = true - - // Update the options menu. - invalidateMenu() + deleteAllMenuItemEnabled = true } else if (twoPanedMode) { // Two-paned mode is enabled but there are no domains. - // Disable the delete menu item. + // Disable the menu items. deleteMenuItemEnabled = false - - // Update the options menu. - invalidateMenu() + deleteAllMenuItemEnabled = false + } else { // Single-paned mode is enabled and the domains list is displayed. + // Set the delete all menu item status according to the number of domains. + deleteAllMenuItemEnabled = (domainsCursor.count > 0) } + + // Update the options menu. + invalidateMenu() } override fun dismissSnackbar() { diff --git a/app/src/main/java/com/stoutner/privacybrowser/activities/ViewHeadersActivity.kt b/app/src/main/java/com/stoutner/privacybrowser/activities/ViewHeadersActivity.kt index 8e72b596..77b3aef5 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/activities/ViewHeadersActivity.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/activities/ViewHeadersActivity.kt @@ -14,7 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Privacy Browser Android. If not, see . + * along with Privacy Browser Android. If not, see . */ package com.stoutner.privacybrowser.activities diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/AboutViewHeadersDialog.kt b/app/src/main/java/com/stoutner/privacybrowser/dialogs/AboutViewHeadersDialog.kt index f88da7b0..a03a7faa 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/AboutViewHeadersDialog.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/AboutViewHeadersDialog.kt @@ -14,7 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Privacy Browser Android. If not, see . + * along with Privacy Browser Android. If not, see . */ package com.stoutner.privacybrowser.dialogs diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/AddDomainDialog.kt b/app/src/main/java/com/stoutner/privacybrowser/dialogs/AddDomainDialog.kt index be5af10b..be337f60 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/dialogs/AddDomainDialog.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/AddDomainDialog.kt @@ -1,7 +1,7 @@ /* * Copyright 2017-2024 Soren Stoutner . * - * This file is part of Privacy Browser Android . + * This file is part of Privacy Browser Android . * * Privacy Browser Android is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -14,7 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Privacy Browser Android. If not, see . + * along with Privacy Browser Android. If not, see . */ package com.stoutner.privacybrowser.dialogs diff --git a/app/src/main/java/com/stoutner/privacybrowser/dialogs/DeleteAllDomainsDialog.kt b/app/src/main/java/com/stoutner/privacybrowser/dialogs/DeleteAllDomainsDialog.kt new file mode 100644 index 00000000..93a6f19c --- /dev/null +++ b/app/src/main/java/com/stoutner/privacybrowser/dialogs/DeleteAllDomainsDialog.kt @@ -0,0 +1,90 @@ +/* + * Copyright 2018-2024 Soren Stoutner . + * + * This file is part of Privacy Browser Android . + * + * Privacy Browser Android is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Privacy Browser Android is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Privacy Browser Android. If not, see . + */ + +package com.stoutner.privacybrowser.dialogs + +import android.app.Dialog +import android.content.Context +import android.content.DialogInterface +import android.os.Bundle +import android.view.WindowManager + +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.DialogFragment +import androidx.preference.PreferenceManager + +import com.stoutner.privacybrowser.R + +class DeleteAllDomainsDialog : DialogFragment() { + // Declare the class variables + private lateinit var deleteAllDomainSettingsListener: DeleteAllDomainSettingsListener + + // The public interface is used to send information back to the parent activity. + interface DeleteAllDomainSettingsListener { + fun deleteAllDomainSettings() + } + + override fun onAttach(context: Context) { + // Run the default commands. + super.onAttach(context) + + // Get a handle for the delete all domain settings listener from the launching context. + deleteAllDomainSettingsListener = context as DeleteAllDomainSettingsListener + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + // Use a builder to create the alert dialog. + val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog) + + // Set the icon according to the theme. + dialogBuilder.setIcon(R.drawable.delete) + + // Set the title. + dialogBuilder.setTitle(R.string.delete_all) + + // Set the text. + dialogBuilder.setMessage(R.string.delete_all_domain_settings) + + // Set the negative button. Using `null` as the listener closes the dialog without doing anything else. + dialogBuilder.setNegativeButton(R.string.cancel, null) + + // Set the positive button. + dialogBuilder.setPositiveButton(R.string.delete, { _: DialogInterface, _: Int -> + // Delete all the domain settings. + deleteAllDomainSettingsListener.deleteAllDomainSettings() + }) + + // Create an alert dialog from the alert dialog builder. + val alertDialog = dialogBuilder.create() + + // Get a handle for the shared preferences. + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()) + + // Get the screenshot preference. + val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false) + + // Disable screenshots if not allowed. + if (!allowScreenshots) { + alertDialog.window!!.addFlags(WindowManager.LayoutParams.FLAG_SECURE) + } + + // Return the alert dialog. + return alertDialog + } +} diff --git a/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.kt b/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.kt index 38ce8992..4ff21848 100644 --- a/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.kt +++ b/app/src/main/java/com/stoutner/privacybrowser/helpers/DomainsDatabaseHelper.kt @@ -14,7 +14,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with Privacy Browser Android. If not, see . + * along with Privacy Browser Android. If not, see . */ package com.stoutner.privacybrowser.helpers @@ -532,6 +532,20 @@ class DomainsDatabaseHelper(private val appContext: Context) : SQLiteOpenHelper( domainsDatabase.close() } + fun deleteAllDomains() : Int { + // Get a writable database handle. + val domainsDatabase = this.writableDatabase + + // Delete the row for the specified database ID. + val rowsDeleted = domainsDatabase.delete(DOMAINS_TABLE, "", null) + + // Close the database handle. + domainsDatabase.close() + + // Return the delete status. + return rowsDeleted + } + fun deleteDomain(databaseId: Int) : Int { // Get a writable database handle. val domainsDatabase = this.writableDatabase diff --git a/app/src/main/res/menu/domains_options_menu.xml b/app/src/main/res/menu/domains_options_menu.xml index 37427c85..1bb6d20d 100644 --- a/app/src/main/res/menu/domains_options_menu.xml +++ b/app/src/main/res/menu/domains_options_menu.xml @@ -16,7 +16,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with Privacy Browser Android. If not, see . --> + along with Privacy Browser Android. If not, see . --> + + diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index ab040d02..ed71aba3 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -3,7 +3,7 @@ + along with Privacy Browser Android. If not, see . --> @@ -275,6 +275,8 @@ выбраны:\u0020 %1$d Вверх Вниз + Переместить вверх + Переместить вниз Изменить Удалить Выбрать все diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 45658be0..358bf367 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -3,7 +3,7 @@ + along with Privacy Browser Android. If not, see . --> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ca05c276..20b18f86 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -357,8 +357,11 @@ Add Domain Domain name already exists Add + Delete All + Delete all domain settings? Domain name Domain deleted + All domains deleted *. may be prepended to a domain to include all subdomains (eg. *.stoutner.com) System default -- 2.45.2