implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0'
implementation "androidx.core:core-ktx:1.3.1"
- implementation 'androidx.drawerlayout:drawerlayout:1.1.0'
+ implementation 'androidx.drawerlayout:drawerlayout:1.1.1'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
implementation 'androidx.viewpager:viewpager:1.0.0'
implementation 'androidx.webkit:webkit:1.3.0'
- // Include the Kotlin standard libraries
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.72"
+ // Include the Kotlin standard libraries. This should be the same version number listed in project build.gradle.
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.10"
// Include the Google material library.
- implementation 'com.google.android.material:material:1.2.0'
+ implementation 'com.google.android.material:material:1.2.1'
// Only compile Firebase ads for the free flavor.
freeImplementation 'com.google.firebase:firebase-ads:19.3.0'
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2015-2019 Soren Stoutner <soren@stoutner.com>.
+
+ Translation 2020 Thiago Nazareno Conceição Silva de Jesus <mochileiro2006-trilhas@yahoo.com.br>. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser 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 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. If not, see <http://www.gnu.org/licenses/>. -->
+
+<resources>
+ <!-- Activities. -->
+ <string name="privacy_browser">Privacy Browser Free</string>
+
+ <!-- Create Home Screen Shortcut Alert Dialog. -->
+ <string name="open_with_privacy_browser">Open with Privacy Browser Free.</string>
+
+ <!-- Ad Consent. -->
+ <string name="ad_consent_text">Privacy Browser Free displays a banner ad on the bottom of the screen.
+ These ads come from Google’s set of commonly used providers and are configured to be non-personalized.
+ \n\nThe standard version of Privacy Browser does not contain app ads.</string>
+ <string name="close_browser">Close Browser</string>
+ <string name="accept_ads">Accept Ads</string>
+</resources>
\ No newline at end of file
<!--
- Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
- Translation 2019 Bernhard G. Keller. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+ Translation 2019-2020 Bernhard G. Keller. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
Translation 2016 Aaron Gerlach <aaron@gerlach.com>. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
<h3>Mitwirkende</h3>
Bernhard G. Keller: Deutsch<br/>
+ <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Thiago Nazareno Conceição Silva de Jesus</a>: Brasilianisches Portugiesisch<br/>
<a href="mailto:kevinliste@framalistes.org">Kévin LE FLOHIC</a>: Französisch<br/>
Francesco Buratti: Italienisch<br/>
Jose A. León: Spanisch
<!--
- Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
- Translation 2019 Bernhard G. Keller. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+ Translation 2019-2020 Bernhard G. Keller. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
Translation 2016 Aaron Gerlach <aaron@gerlach.com>. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
<h3>Mitwirkende</h3>
Bernhard G. Keller: Deutsch<br/>
+ <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Thiago Nazareno Conceição Silva de Jesus</a>: Brasilianisches Portugiesisch<br/>
<a href="mailto:kevinliste@framalistes.org">Kévin LE FLOHIC</a>: Französisch<br/>
Francesco Buratti: Italienisch<br/>
Jose A. León: Spanisch
<!--
- Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
Hendrik Knackstedt
<h3>Translators</h3>
+ <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Thiago Nazareno Conceição Silva de Jesus</a>: Brazilian Portuguese<br/>
<a href="mailto:kevinliste@framalistes.org">Kévin LE FLOHIC</a>: French<br/>
Bernhard G. Keller: German<br/>
Francesco Buratti: Italian<br/>
<!--
- Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
Hendrik Knackstedt
<h3>Translators</h3>
+ <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Thiago Nazareno Conceição Silva de Jesus</a>: Brazilian Portuguese<br/>
<a href="mailto:kevinliste@framalistes.org">Kévin LE FLOHIC</a>: French<br/>
Bernhard G. Keller: German<br/>
Francesco Buratti: Italian<br/>
<!--
- Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
- Translation 2017-2019 Jose A. León. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+ Translation 2017-2020 Jose A. León. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<h3>Traductores</h3>
Jose A. León: Español<br/>
+ <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Thiago Nazareno Conceição Silva de Jesus</a>: Portugués brasileño<br/>
<a href="mailto:kevinliste@framalistes.org">Kévin LE FLOHIC</a>: Francés<br/>
Bernhard G. Keller: Alemán<br/>
Francesco Buratti: Italiano
<!--
- Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
- Translation 2017-2019 Jose A. León. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+ Translation 2017-2020 Jose A. León. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<h3>Traductores</h3>
Jose A. León: Español<br/>
+ <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Thiago Nazareno Conceição Silva de Jesus</a>: Portugués brasileño<br/>
<a href="mailto:kevinliste@framalistes.org">Kévin LE FLOHIC</a>: Francés<br/>
Bernhard G. Keller: Alemán<br/>
Francesco Buratti: Italiano
<!--
- Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
- Translation 2019 Kévin LE FLOHIC <kevinliste@framalistes.org>. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+ Translation 2019-2020 Kévin LE FLOHIC <kevinliste@framalistes.org>. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<body>
<h3>Développeur principal</h3>
- <p>Privacy Browser est principalement développé par <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
+ <p>Privacy Browser est principalement développé par <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
- <h3>Codeurs</h3>
- <a href="mailto:lianergoist@vongriffen.dk">Thomas Jensen</a><br/>
- Hendrik Knackstedt
+ <h3>Codeurs</h3>
+ <a href="mailto:lianergoist@vongriffen.dk">Thomas Jensen</a><br/>
+ Hendrik Knackstedt
- <h3>Traducteurs</h3>
- <a href="mailto:kevinliste@framalistes.org">Kévin LE FLOHIC</a> : Français<br/>
- Bernhard G. Keller : Allemand<br/>
- Francesco Buratti : Italien<br/>
- Jose A. León : Espagnol
+ <h3>Traducteurs</h3>
+ <a href="mailto:kevinliste@framalistes.org">Kévin LE FLOHIC</a> : Français<br/>
+ <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Thiago Nazareno Conceição Silva de Jesus</a>: Brazilian Portuguese<br/>
+ Bernhard G. Keller : Allemand<br/>
+ Francesco Buratti : Italien<br/>
+ Jose A. León : Espagnol
- <h3>Anciens traducteurs</h3>
- Stefan Erhardt: Allemand<br/>
- <a href="mailto:aaron@gerlach.com">Aaron Gerlach</a> : Allemand
+ <h3>Anciens traducteurs</h3>
+ Stefan Erhardt: Allemand<br/>
+ <a href="mailto:aaron@gerlach.com">Aaron Gerlach</a> : Allemand
<br/>
<br/>
- <p>Les contributeurs sont invités à soumettre leurs <a href="https://www.stoutner.com/privacy-browser/contributors/">codes et leurs traductions</a>.</p>
+ <p>Les contributeurs sont invités à soumettre leurs <a href="https://www.stoutner.com/privacy-browser/contributors/">codes et leurs traductions</a>.</p>
</body>
</html>
<!--
- Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
- Translation 2019 Kévin LE FLOHIC <kevinliste@framalistes.org>. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+ Translation 2019-2020 Kévin LE FLOHIC <kevinliste@framalistes.org>. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<body>
<h3>Développeur principal</h3>
- <p>Privacy Browser est principalement développé par <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
+ <p>Privacy Browser est principalement développé par <a href="mailto:soren@stoutner.com">Soren Stoutner</a>.</p>
- <h3>Codeurs</h3>
- <a href="mailto:lianergoist@vongriffen.dk">Thomas Jensen</a><br/>
- Hendrik Knackstedt
+ <h3>Codeurs</h3>
+ <a href="mailto:lianergoist@vongriffen.dk">Thomas Jensen</a><br/>
+ Hendrik Knackstedt
- <h3>Traducteurs</h3>
- <a href="mailto:kevinliste@framalistes.org">Kévin LE FLOHIC</a> : Français<br/>
- Bernhard G. Keller : Allemand<br/>
- Francesco Buratti : Italien<br/>
- Jose A. León : Espagnol
+ <h3>Traducteurs</h3>
+ <a href="mailto:kevinliste@framalistes.org">Kévin LE FLOHIC</a> : Français<br/>
+ <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Thiago Nazareno Conceição Silva de Jesus</a>: Brazilian Portuguese<br/>
+ Bernhard G. Keller : Allemand<br/>
+ Francesco Buratti : Italien<br/>
+ Jose A. León : Espagnol
- <h3>Anciens traducteurs</h3>
- Stefan Erhardt: Allemand<br/>
- <a href="mailto:aaron@gerlach.com">Aaron Gerlach</a> : Allemand
+ <h3>Anciens traducteurs</h3>
+ Stefan Erhardt: Allemand<br/>
+ <a href="mailto:aaron@gerlach.com">Aaron Gerlach</a> : Allemand
<br/>
<br/>
- <p>Les contributeurs sont invités à soumettre leurs <a href="https://www.stoutner.com/privacy-browser/contributors/">codes et leurs traductions</a>.</p>
+ <p>Les contributeurs sont invités à soumettre leurs <a href="https://www.stoutner.com/privacy-browser/contributors/">codes et leurs traductions</a>.</p>
</body>
</html>
<!--
- Copyright © 2017-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2017-2020 Soren Stoutner <soren@stoutner.com>.
- Translation 2017,2019 Francesco Buratti. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+ Translation 2017,2019-2020 Francesco Buratti. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<h3>Traduttori</h3>
Francesco Buratti: Italiano<br/>
+ <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Thiago Nazareno Conceição Silva de Jesus</a>: Portoghese Brasiliano<br/>
<a href="mailto:kevinliste@framalistes.org">Kévin LE FLOHIC</a>: Francese<br/>
Bernhard G. Keller: Tedesco<br/>
Jose A. León: Spagnolo
<!--
- Copyright © 2017-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2017-2020 Soren Stoutner <soren@stoutner.com>.
- Translation 2017,2019 Francesco Buratti. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+ Translation 2017,2019-2020 Francesco Buratti. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<h3>Traduttori</h3>
Francesco Buratti: Italiano<br/>
+ <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Thiago Nazareno Conceição Silva de Jesus</a>: Portoghese Brasiliano<br/>
<a href="mailto:kevinliste@framalistes.org">Kévin LE FLOHIC</a>: Francese<br/>
Bernhard G. Keller: Tedesco<br/>
Jose A. León: Spagnolo
<!--
- Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<h3>Переводчики</h3>
<a href="mailto:kevinliste@framalistes.org">Кевин ЛЕ ФЛОХИК (Kévin LE FLOHIC)</a>: Французский<br/>
+ <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Тьяго Назарено Консейсао Силва де Хесус (Thiago Nazareno Conceição Silva de Jesus)</a>: бразильский португальский<br/>
Bernhard G. Keller: немецкий<br/>
Francesco Buratti: итальянский<br/>
Jose A. León: испанский
<!--
- Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<h3>Переводчики</h3>
<a href="mailto:kevinliste@framalistes.org">Кевин ЛЕ ФЛОХИК (Kévin LE FLOHIC)</a>: Французский<br/>
+ <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Тьяго Назарено Консейсао Силва де Хесус (Thiago Nazareno Conceição Silva de Jesus)</a>: бразильский португальский<br/>
Bernhard G. Keller: немецкий<br/>
Francesco Buratti: итальянский<br/>
Jose A. León: испанский
<!--
- Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
Hendrik Knackstedt
<h3>Çevirmenler</h3>
+ <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Thiago Nazareno Conceição Silva de Jesus</a>: Brazilian Portuguese<br/>
<a href="mailto:kevinliste@framalistes.org">Kévin LE FLOHIC</a>: French<br/>
Bernhard G. Keller: Almanca<br/>
Francesco Buratti: İtalyanca<br/>
<!--
- Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
Hendrik Knackstedt
<h3>Çevirmenler</h3>
+ <a href="mailto:mochileiro2006-trilhas@yahoo.com.br">Thiago Nazareno Conceição Silva de Jesus</a>: Brazilian Portuguese<br/>
<a href="mailto:kevinliste@framalistes.org">Kévin LE FLOHIC</a>: French<br/>
Bernhard G. Keller: Almanca<br/>
Francesco Buratti: İtalyanca<br/>
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
// Get the screenshot preference.
- val allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false)
+ val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)
// Disable screenshots if not allowed.
if (!allowScreenshots) {
import com.stoutner.privacybrowser.R
import com.stoutner.privacybrowser.helpers.DomainsDatabaseHelper
+// Declare the class constants.
+private const val URL_STRING = "url_string"
+
class AddDomainDialog: DialogFragment() {
// The public interface is used to send information back to the parent activity.
interface AddDomainListener {
fun onAddDomain(dialogFragment: DialogFragment)
}
- // The add domain listener is initialized in `onAttach()` and used in `onCreateDialog()`.
+ // Declare the class variables
private lateinit var addDomainListener: AddDomainListener
override fun onAttach(context: Context) {
val argumentsBundle = Bundle()
// Store the URL in the bundle.
- argumentsBundle.putString("url_string", urlString)
+ argumentsBundle.putString(URL_STRING, urlString)
// Create a new instance of the dialog.
val addDomainDialog = AddDomainDialog()
}
}
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
@SuppressLint("InflateParams")
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
// Get the arguments.
val arguments = requireArguments()
// Get the URL from the bundle.
- val urlString = arguments.getString("url_string")
+ val urlString = arguments.getString(URL_STRING)
// Use an alert dialog builder to create the alert dialog.
val dialogBuilder: AlertDialog.Builder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
// Get the screenshot preference.
- val allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false)
+ val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots), false)
// Disable screenshots if not allowed.
if (!allowScreenshots) {
import java.io.ByteArrayOutputStream
+// Declare the class constants.
+private const val URL_STRING = "url_string"
+private const val TITLE = "title"
+private const val FAVORITE_ICON_BYTE_ARRAY = "favorite_icon_byte_array"
+
class CreateBookmarkDialog: DialogFragment() {
// The public interface is used to send information back to the parent activity.
interface CreateBookmarkListener {
fun onCreateBookmark(dialogFragment: DialogFragment, favoriteIconBitmap: Bitmap)
}
- // The create bookmark listener is initialized in `onAttach()` and used in `onCreateDialog()`.
+ // Declare the class variables
private lateinit var createBookmarkListener: CreateBookmarkListener
override fun onAttach(context: Context) {
companion object {
// `@JvmStatic` will no longer be required once all the code has transitioned to Kotlin. Also, the function can then be moved out of a companion object and just become a package-level function.
@JvmStatic
- fun createBookmark(urlString: String, titleString: String, favoriteIconBitmap: Bitmap): CreateBookmarkDialog {
+ fun createBookmark(urlString: String, title: String, favoriteIconBitmap: Bitmap): CreateBookmarkDialog {
// Create a favorite icon byte array output stream.
val favoriteIconByteArrayOutputStream = ByteArrayOutputStream()
val argumentsBundle = Bundle()
// Store the variables in the bundle.
- argumentsBundle.putString("url_string", urlString)
- argumentsBundle.putString("title_string", titleString)
- argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray)
+ argumentsBundle.putString(URL_STRING, urlString)
+ argumentsBundle.putString(TITLE, title)
+ argumentsBundle.putByteArray(FAVORITE_ICON_BYTE_ARRAY, favoriteIconByteArray)
// Create a new instance of the dialog.
val createBookmarkDialog = CreateBookmarkDialog()
}
}
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
@SuppressLint("InflateParams")
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
// Get the arguments.
val arguments = requireArguments()
// Get the contents of the arguments.
- val urlString = arguments.getString("url_string")
- val titleString = arguments.getString("title_string")
- val favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array")!!
+ val urlString = arguments.getString(URL_STRING)
+ val title = arguments.getString(TITLE)
+ val favoriteIconByteArray = arguments.getByteArray(FAVORITE_ICON_BYTE_ARRAY)!!
// Convert the favorite icon byte array to a bitmap.
val favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.size)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
// Get the screenshot preference.
- val allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false)
+ val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)
// Disable screenshots if not allowed.
if (!allowScreenshots) {
val createBookmarkUrlEditText = alertDialog.findViewById<EditText>(R.id.create_bookmark_url_edittext)!!
// Set the initial texts for the edit texts.
- createBookmarkNameEditText.setText(titleString)
+ createBookmarkNameEditText.setText(title)
createBookmarkUrlEditText.setText(urlString)
// Allow the enter key on the keyboard to create the bookmark from the create bookmark name edit text.
import java.io.ByteArrayOutputStream
+// Declare the class constants.
+private const val FAVORITE_ICON_BYTE_ARRAY = "favorite_icon_byte_array"
+
class CreateBookmarkFolderDialog: DialogFragment() {
// The public interface is used to send information back to the parent activity.
interface CreateBookmarkFolderListener {
fun onCreateBookmarkFolder(dialogFragment: DialogFragment, favoriteIconBitmap: Bitmap)
}
- // The create bookmark folder listener is initialized in `onAttach()` and used in `onCreateDialog()`.
+ // Declare the class variables.
private lateinit var createBookmarkFolderListener: CreateBookmarkFolderListener
override fun onAttach(context: Context) {
val argumentsBundle = Bundle()
// Store the favorite icon in the bundle.
- argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray)
+ argumentsBundle.putByteArray(FAVORITE_ICON_BYTE_ARRAY, favoriteIconByteArray)
// Create a new instance of the dialog.
val createBookmarkFolderDialog = CreateBookmarkFolderDialog()
}
}
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
@SuppressLint("InflateParams")
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
// Get the arguments.
val arguments = requireArguments()
// Get the favorite icon byte array.
- val favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array")!!
+ val favoriteIconByteArray = arguments.getByteArray(FAVORITE_ICON_BYTE_ARRAY)!!
// Convert the favorite icon byte array to a bitmap.
val favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.size)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
// Get the screenshot preference.
- val allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false)
+ val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)
// Disable screenshots if not allowed.
if (!allowScreenshots) {
import java.io.ByteArrayOutputStream
+// Declare the class constants.
+private const val SHORTCUT_NAME = "shortcut_name"
+private const val URL_STRING = "url_string"
+private const val FAVORITE_ICON_BYTE_ARRAY = "favorite_icon_byte_array"
+
class CreateHomeScreenShortcutDialog: DialogFragment() {
- // Define the class variables.
+ // Declare the class views.
private lateinit var shortcutNameEditText: EditText
private lateinit var urlEditText: EditText
private lateinit var openWithPrivacyBrowserRadioButton: RadioButton
val argumentsBundle = Bundle()
// Store the variables in the bundle.
- argumentsBundle.putString("shortcut_name", shortcutName)
- argumentsBundle.putString("url_string", urlString)
- argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray)
+ argumentsBundle.putString(SHORTCUT_NAME, shortcutName)
+ argumentsBundle.putString(URL_STRING, urlString)
+ argumentsBundle.putByteArray(FAVORITE_ICON_BYTE_ARRAY, favoriteIconByteArray)
// Create a new instance of the dialog.
val createHomeScreenShortcutDialog = CreateHomeScreenShortcutDialog()
}
}
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
@SuppressLint("InflateParams")
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
// Get the arguments.
val arguments = requireArguments()
- // Get the strings from the arguments.
- val initialShortcutName = arguments.getString("shortcut_name")
- val initialUrlString = arguments.getString("url_string")
-
- // Get the favorite icon byte array.
- val favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array")!!
+ // Get the variables from the arguments.
+ val initialShortcutName = arguments.getString(SHORTCUT_NAME)
+ val initialUrlString = arguments.getString(URL_STRING)
+ val favoriteIconByteArray = arguments.getByteArray(FAVORITE_ICON_BYTE_ARRAY)!!
// Convert the favorite icon byte array to a bitmap.
val favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.size)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
// Get the screenshot preference.
- val allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false)
+ val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)
// Disable screenshots if not allowed.
if (!allowScreenshots) {
import android.view.KeyEvent
import android.view.View
import android.view.WindowManager
-import android.widget.*
+import android.widget.AdapterView
import android.widget.AdapterView.OnItemSelectedListener
+import android.widget.Button
+import android.widget.EditText
+import android.widget.ImageView
+import android.widget.RadioButton
+import android.widget.RadioGroup
+import android.widget.Spinner
+import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
+import androidx.cursoradapter.widget.ResourceCursorAdapter
import androidx.fragment.app.DialogFragment
import androidx.preference.PreferenceManager
import java.io.ByteArrayOutputStream
+// Declare the class constants.
+private const val DATABASE_ID = "database_id"
+private const val FAVORITE_ICON_BYTE_ARRAY = "favorite_icon_byte_array"
+
class EditBookmarkDatabaseViewDialog: DialogFragment() {
// The public interface is used to send information back to the parent activity.
interface EditBookmarkDatabaseViewListener {
fun onSaveBookmark(dialogFragment: DialogFragment, selectedBookmarkDatabaseId: Int, favoriteIconBitmap: Bitmap)
}
- // Define the edit bookmark database view listener.
+ // Declare the class variables.
private lateinit var editBookmarkDatabaseViewListener: EditBookmarkDatabaseViewListener
- // Define the handles for the views that need to be accessed from `updateEditButton()`.
+ // Declare the class views.
private lateinit var newIconRadioButton: RadioButton
private lateinit var nameEditText: EditText
private lateinit var urlEditText: EditText
private lateinit var folderSpinner: Spinner
private lateinit var displayOrderEditText: EditText
- private lateinit var editButton: Button
+ private lateinit var saveButton: Button
override fun onAttach(context: Context) {
// Run the default commands.
val argumentsBundle = Bundle()
// Store the variables in the bundle.
- argumentsBundle.putInt("database_id", databaseId)
- argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray)
+ argumentsBundle.putInt(DATABASE_ID, databaseId)
+ argumentsBundle.putByteArray(FAVORITE_ICON_BYTE_ARRAY, favoriteIconByteArray)
// Create a new instance of the dialog.
val editBookmarkDatabaseViewDialog = EditBookmarkDatabaseViewDialog()
}
}
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
@SuppressLint("InflateParams")
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
// Get the arguments.
val arguments = requireArguments()
- // Get the bookmark database ID from the bundle.
- val bookmarkDatabaseId = arguments.getInt("database_id")
-
- // Get the favorite icon byte array.
- val favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array")!!
+ // Get the variables from the arguments.
+ val bookmarkDatabaseId = arguments.getInt(DATABASE_ID)
+ val favoriteIconByteArray = arguments.getByteArray(FAVORITE_ICON_BYTE_ARRAY)!!
// Convert the favorite icon byte array to a bitmap.
val favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.size)
// Set the view. The parent view is `null` because it will be assigned by the alert dialog.
dialogBuilder.setView(requireActivity().layoutInflater.inflate(R.layout.edit_bookmark_databaseview_dialog, null))
- // Set the listener for the cancel button. Using `null` as the listener closes the dialog without doing anything else.
+ // Set the cancel button listener. Using `null` as the listener closes the dialog without doing anything else.
dialogBuilder.setNegativeButton(R.string.cancel, null)
- // Set the listener for the save button.
+ // Set the save button listener.
dialogBuilder.setPositiveButton(R.string.save) { _: DialogInterface, _: Int ->
// Return the dialog fragment to the parent activity on save.
editBookmarkDatabaseViewListener.onSaveBookmark(this, bookmarkDatabaseId, favoriteIconBitmap)
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
// Get the screenshot preference.
- val allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false)
+ val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)
// Disable screenshots if not allowed.
if (!allowScreenshots) {
urlEditText = alertDialog.findViewById(R.id.edit_bookmark_url_edittext)!!
folderSpinner = alertDialog.findViewById(R.id.edit_bookmark_folder_spinner)!!
displayOrderEditText = alertDialog.findViewById(R.id.edit_bookmark_display_order_edittext)!!
- editButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)
+ saveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)
// Store the current bookmark values.
val currentBookmarkName = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME))
// Populate the display order edit text.
displayOrderEditText.setText(bookmarkCursor.getInt(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER)).toString())
- // Initially disable the edit button.
- editButton.isEnabled = false
+ // Initially disable the save button.
+ saveButton.isEnabled = false
- // Update the edit button if the icon selection changes.
+ // Update the save button if the icon selection changes.
iconRadioGroup.setOnCheckedChangeListener { _: RadioGroup, _: Int ->
- // Update the edit button.
- updateEditButton(currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder)
+ // Update the save button.
+ updateSaveButton(currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder)
}
- // Update the edit button if the bookmark name changes.
+ // Update the save button if the bookmark name changes.
nameEditText.addTextChangedListener(object: TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
// Do nothing.
}
override fun afterTextChanged(s: Editable) {
- // Update the edit button.
- updateEditButton(currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder)
+ // Update the Save button.
+ updateSaveButton(currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder)
}
})
- // Update the edit button if the URL changes.
+ // Update the save button if the URL changes.
urlEditText.addTextChangedListener(object: TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
// Do nothing.
}
override fun afterTextChanged(s: Editable) {
- // Update the edit button.
- updateEditButton(currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder)
+ // Update the save button.
+ updateSaveButton(currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder)
}
})
// Wait to set the on item selected listener until the spinner has been inflated. Otherwise the dialog will crash on restart.
folderSpinner.post {
- // Update the edit button if the folder changes.
- folderSpinner.onItemSelectedListener = object : OnItemSelectedListener {
+ // Update the save button if the folder changes.
+ folderSpinner.onItemSelectedListener = object: OnItemSelectedListener {
override fun onItemSelected(parent: AdapterView<*>, view: View, position: Int, id: Long) {
- // Update the edit button.
- updateEditButton(currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder)
+ // Update the save button.
+ updateSaveButton(currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder)
}
override fun onNothingSelected(parent: AdapterView<*>?) {
}
}
- // Update the edit button if the display order changes.
- displayOrderEditText.addTextChangedListener(object : TextWatcher {
+ // Update the save button if the display order changes.
+ displayOrderEditText.addTextChangedListener(object: TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
// Do nothing.
}
}
override fun afterTextChanged(s: Editable) {
- // Update the edit button.
- updateEditButton(currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder)
+ // Update the save button.
+ updateSaveButton(currentBookmarkName, currentUrl, currentFolderDatabaseId, currentDisplayOrder)
}
})
// Allow the enter key on the keyboard to save the bookmark from the bookmark name edit text.
nameEditText.setOnKeyListener { _: View, keyCode: Int, keyEvent: KeyEvent ->
// Check the key code, event, and button status.
- if (keyEvent.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER && editButton.isEnabled) { // The enter key was pressed and the edit button is enabled.
+ if (keyEvent.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER && saveButton.isEnabled) { // The enter key was pressed and the save button is enabled.
// Trigger the listener and return the dialog fragment to the parent activity.
- editBookmarkDatabaseViewListener.onSaveBookmark(this@EditBookmarkDatabaseViewDialog, bookmarkDatabaseId, favoriteIconBitmap)
+ editBookmarkDatabaseViewListener.onSaveBookmark(this, bookmarkDatabaseId, favoriteIconBitmap)
// Manually dismiss the alert dialog.
alertDialog.dismiss()
// Consume the event.
return@setOnKeyListener true
- } else { // If any other key was pressed, or if the edit button is currently disabled, do not consume the event.
+ } else { // If any other key was pressed, or if the save button is currently disabled, do not consume the event.
return@setOnKeyListener false
}
}
// Allow the enter key on the keyboard to save the bookmark from the URL edit text.
urlEditText.setOnKeyListener { _: View, keyCode: Int, keyEvent: KeyEvent ->
// Check the key code, event, and button status.
- if (keyEvent.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER && editButton.isEnabled) { // The enter key was pressed and the edit button is enabled.
+ if (keyEvent.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER && saveButton.isEnabled) { // The enter key was pressed and the save button is enabled.
// Trigger the listener and return the dialog fragment to the parent activity.
- editBookmarkDatabaseViewListener.onSaveBookmark(this@EditBookmarkDatabaseViewDialog, bookmarkDatabaseId, favoriteIconBitmap)
+ editBookmarkDatabaseViewListener.onSaveBookmark(this, bookmarkDatabaseId, favoriteIconBitmap)
// Manually dismiss the alert dialog.
alertDialog.dismiss()
// Consume the event.
return@setOnKeyListener true
- } else { // If any other key was pressed, or if the edit button is currently disabled, do not consume the event.
+ } else { // If any other key was pressed, or if the save button is currently disabled, do not consume the event.
return@setOnKeyListener false
}
}
// Allow the enter key on the keyboard to save the bookmark from the display order edit text.
displayOrderEditText.setOnKeyListener { _: View, keyCode: Int, keyEvent: KeyEvent ->
// Check the key code, event, and button status.
- if (keyEvent.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER && editButton.isEnabled) { // The enter key was pressed and the edit button is enabled.
+ if (keyEvent.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER && saveButton.isEnabled) { // The enter key was pressed and the save button is enabled.
// Trigger the listener and return the dialog fragment to the parent activity.
- editBookmarkDatabaseViewListener.onSaveBookmark(this@EditBookmarkDatabaseViewDialog, bookmarkDatabaseId, favoriteIconBitmap)
+ editBookmarkDatabaseViewListener.onSaveBookmark(this, bookmarkDatabaseId, favoriteIconBitmap)
// Manually dismiss the alert dialog.
alertDialog.dismiss()
// Consume the event.
return@setOnKeyListener true
- } else { // If any other key was pressed, or if the edit button is currently disabled, do not consume the event.
+ } else { // If any other key was pressed, or if the save button is currently disabled, do not consume the event.
return@setOnKeyListener false
}
}
return alertDialog
}
- private fun updateEditButton(currentBookmarkName: String, currentUrl: String, currentFolderDatabaseId: Int, currentDisplayOrder: Int) {
+ private fun updateSaveButton(currentBookmarkName: String, currentUrl: String, currentFolderDatabaseId: Int, currentDisplayOrder: Int) {
// Get the values from the dialog.
val newName = nameEditText.text.toString()
val newUrl = urlEditText.text.toString()
// Is the display order empty?
val displayOrderNotEmpty = newDisplayOrder.isNotEmpty()
- // Update the enabled status of the edit button.
- editButton.isEnabled = (iconChanged || nameChanged || urlChanged || folderChanged || displayOrderChanged) && displayOrderNotEmpty
+ // Update the enabled status of the save button.
+ saveButton.isEnabled = (iconChanged || nameChanged || urlChanged || folderChanged || displayOrderChanged) && displayOrderNotEmpty
}
}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
- *
- * Privacy Browser 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 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. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.stoutner.privacybrowser.dialogs;
-
-import android.annotation.SuppressLint;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.DialogFragment;
-
-import com.stoutner.privacybrowser.R;
-import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper;
-
-import java.io.ByteArrayOutputStream;
-
-public class EditBookmarkDialog extends DialogFragment {
- // Define the edit bookmark listener.
- private EditBookmarkListener editBookmarkListener;
-
- // The public interface is used to send information back to the parent activity.
- public interface EditBookmarkListener {
- void onSaveBookmark(DialogFragment dialogFragment, int selectedBookmarkDatabaseId, Bitmap favoriteIconBitmap);
- }
-
- public void onAttach(@NonNull Context context) {
- // Run the default commands.
- super.onAttach(context);
-
- // Get a handle for `EditBookmarkListener` from the launching context.
- editBookmarkListener = (EditBookmarkListener) context;
- }
-
- // Store the database ID in the arguments bundle.
- public static EditBookmarkDialog bookmarkDatabaseId(int databaseId, Bitmap favoriteIconBitmap) {
- // Create a favorite icon byte array output stream.
- ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream();
-
- // Convert the favorite icon to a PNG and place it in the byte array output stream. `0` is for lossless compression (the only option for a PNG).
- favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream);
-
- // Convert the byte array output stream to a byte array.
- byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray();
-
- // Create an arguments bundle.
- Bundle argumentsBundle = new Bundle();
-
- // Store the variables in the bundle.
- argumentsBundle.putInt("database_id", databaseId);
- argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray);
-
- // Create a new instance of the dialog.
- EditBookmarkDialog editBookmarkDialog = new EditBookmarkDialog();
-
- // Add the arguments bundle to the dialog.
- editBookmarkDialog.setArguments(argumentsBundle);
-
- // Return the new dialog.
- return editBookmarkDialog;
- }
-
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
- @SuppressLint("InflateParams")
- @Override
- @NonNull
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- // Get the arguments.
- Bundle arguments = getArguments();
-
- // Remove the incorrect lint warning below that the arguments might be null.
- assert arguments != null;
-
- // Store the bookmark database ID in the class variable.
- int selectedBookmarkDatabaseId = arguments.getInt("database_id");
-
- // Get the favorite icon byte array.
- byte[] favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array");
-
- // Remove the incorrect lint warning below that the favorite icon byte array might be null.
- assert favoriteIconByteArray != null;
-
- // Convert the favorite icon byte array to a bitmap.
- Bitmap favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.length);
-
- // Initialize the database helper. The `0` specifies a database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`.
- BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(getContext(), null, null, 0);
-
- // Get a `Cursor` with the selected bookmark and move it to the first position.
- Cursor bookmarkCursor = bookmarksDatabaseHelper.getBookmark(selectedBookmarkDatabaseId);
- bookmarkCursor.moveToFirst();
-
- // Use an alert dialog builder to create the alert dialog.
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog);
-
- // Set the title.
- dialogBuilder.setTitle(R.string.edit_bookmark);
-
- // Remove the incorrect lint warning that `getActivity().getLayoutInflater()` might be null.
- assert getActivity() != null;
-
- // Set the view. The parent view is null because it will be assigned by the alert dialog.
- dialogBuilder.setView(getActivity().getLayoutInflater().inflate(R.layout.edit_bookmark_dialog, null));
-
- // Set the cancel button listener.
- dialogBuilder.setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> {
- // Do nothing. The alert dialog will close automatically.
- });
-
- // Set the save button listener.
- dialogBuilder.setPositiveButton(R.string.save, (DialogInterface dialog, int which) -> {
- // Return the dialog fragment to the parent activity.
- editBookmarkListener.onSaveBookmark(this, selectedBookmarkDatabaseId, favoriteIconBitmap);
- });
-
- // Create an alert dialog from the builder.
- final AlertDialog alertDialog = dialogBuilder.create();
-
- // remove the incorrect lint warning below that `getWindow().addFlags()` might be null.
- assert alertDialog.getWindow() != null;
-
- // Get a handle for the shared preferences.
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
-
- // Get the screenshot preference.
- boolean allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false);
-
- // Disable screenshots if not allowed.
- if (!allowScreenshots) {
- alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
- }
-
- // The alert dialog must be shown before items in the layout can be modified.
- alertDialog.show();
-
- // Get handles for the layout items.
- RadioGroup iconRadioGroup = alertDialog.findViewById(R.id.edit_bookmark_icon_radiogroup);
- ImageView currentIconImageView = alertDialog.findViewById(R.id.edit_bookmark_current_icon);
- ImageView newFavoriteIconImageView = alertDialog.findViewById(R.id.edit_bookmark_webpage_favorite_icon);
- EditText nameEditText = alertDialog.findViewById(R.id.edit_bookmark_name_edittext);
- EditText urlEditText = alertDialog.findViewById(R.id.edit_bookmark_url_edittext);
- Button editButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
-
- // Remove the incorrect lint warnings below that the views might be null.
- assert iconRadioGroup != null;
- assert currentIconImageView != null;
- assert newFavoriteIconImageView != null;
- assert nameEditText != null;
- assert urlEditText != null;
-
- // Get the current favorite icon byte array from the cursor.
- byte[] currentIconByteArray = bookmarkCursor.getBlob(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.FAVORITE_ICON));
-
- // Convert the byte array to a bitmap beginning at the first byte and ending at the last.
- Bitmap currentIconBitmap = BitmapFactory.decodeByteArray(currentIconByteArray, 0, currentIconByteArray.length);
-
- // Display the current icon bitmap.
- currentIconImageView.setImageBitmap(currentIconBitmap);
-
- // Set the new favorite icon bitmap.
- newFavoriteIconImageView.setImageBitmap(favoriteIconBitmap);
-
- // Store the current bookmark name and URL.
- String currentName = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME));
- String currentUrl = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL));
-
- // Populate the edit texts.
- nameEditText.setText(currentName);
- urlEditText.setText(currentUrl);
-
- // Initially disable the edit button.
- editButton.setEnabled(false);
-
- // Update the edit button if the icon selection changes.
- iconRadioGroup.setOnCheckedChangeListener((RadioGroup group, int checkedId) -> {
- // Update the edit button.
- updateEditButton(alertDialog, currentName, currentUrl);
- });
-
- // Update the edit button if the bookmark name changes.
- nameEditText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- // Do nothing.
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- // Do nothing.
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- // Update the edit button.
- updateEditButton(alertDialog, currentName, currentUrl);
- }
- });
-
- // Update the edit button if the URL changes.
- urlEditText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- // Do nothing.
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- // Do nothing.
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- // Update the edit button.
- updateEditButton(alertDialog, currentName, currentUrl);
- }
- });
-
- // Allow the enter key on the keyboard to save the bookmark from the bookmark name edit text.
- nameEditText.setOnKeyListener((View v, int keyCode, KeyEvent event) -> {
- // Save the bookmark if the event is a key-down on the "enter" button.
- if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && editButton.isEnabled()) { // The enter key was pressed and the edit button is enabled.
- // Trigger the `Listener` and return the `DialogFragment` to the parent activity.
- editBookmarkListener.onSaveBookmark(this, selectedBookmarkDatabaseId, favoriteIconBitmap);
-
- // Manually dismiss `alertDialog`.
- alertDialog.dismiss();
-
- // Consume the event.
- return true;
- } else { // If any other key was pressed, or if the edit button is currently disabled, do not consume the event.
- return false;
- }
- });
-
- // Allow the enter key on the keyboard to save the bookmark from the URL edit text.
- urlEditText.setOnKeyListener((View v, int keyCode, KeyEvent event) -> {
- // Save the bookmark if the event is a key-down on the "enter" button.
- if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && editButton.isEnabled()) { // The enter key was pressed and the edit button is enabled.
- // Trigger the `Listener` and return the DialogFragment to the parent activity.
- editBookmarkListener.onSaveBookmark(this, selectedBookmarkDatabaseId, favoriteIconBitmap);
-
- // Manually dismiss the alert dialog.
- alertDialog.dismiss();
-
- // Consume the event.
- return true;
- } else { // If any other key was pressed, or if the edit button is currently disabled, do not consume the event.
- return false;
- }
- });
-
- // Return the alert dialog.
- return alertDialog;
- }
-
- private void updateEditButton(AlertDialog alertdialog, String currentName, String currentUrl) {
- // Get handles for the views.
- EditText nameEditText = alertdialog.findViewById(R.id.edit_bookmark_name_edittext);
- EditText urlEditText = alertdialog.findViewById(R.id.edit_bookmark_url_edittext);
- RadioButton newIconRadioButton = alertdialog.findViewById(R.id.edit_bookmark_webpage_favorite_icon_radiobutton);
- Button editButton = alertdialog.getButton(AlertDialog.BUTTON_POSITIVE);
-
- // Remove the incorrect lint warnings below that the views might be null.
- assert nameEditText != null;
- assert urlEditText != null;
- assert newIconRadioButton != null;
-
- // Get the text from the edit texts.
- String newName = nameEditText.getText().toString();
- String newUrl = urlEditText.getText().toString();
-
- // Has the favorite icon changed?
- boolean iconChanged = newIconRadioButton.isChecked();
-
- // Has the name changed?
- boolean nameChanged = !newName.equals(currentName);
-
- // Has the URL changed?
- boolean urlChanged = !newUrl.equals(currentUrl);
-
- // Update the enabled status of the edit button.
- editButton.setEnabled(iconChanged || nameChanged || urlChanged);
- }
-}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser 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 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. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.stoutner.privacybrowser.dialogs
+
+import android.annotation.SuppressLint
+import android.app.Dialog
+import android.content.Context
+import android.content.DialogInterface
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.KeyEvent
+import android.view.View
+import android.view.WindowManager
+import android.widget.Button
+import android.widget.EditText
+import android.widget.ImageView
+import android.widget.RadioButton
+import android.widget.RadioGroup
+
+import androidx.appcompat.app.AlertDialog
+import androidx.fragment.app.DialogFragment
+import androidx.preference.PreferenceManager
+
+import com.stoutner.privacybrowser.R
+import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper
+
+import java.io.ByteArrayOutputStream
+
+// Declare the class constants.
+private const val DATABASE_ID = "database_id"
+private const val FAVORITE_ICON_BYTE_ARRAY = "favorite_icon_byte_array"
+
+class EditBookmarkDialog: DialogFragment() {
+ // The public interface is used to send information back to the parent activity.
+ interface EditBookmarkListener {
+ fun onSaveBookmark(dialogFragment: DialogFragment, selectedBookmarkDatabaseId: Int, favoriteIconBitmap: Bitmap)
+ }
+
+ // Declare the class variables.
+ private lateinit var editBookmarkListener: EditBookmarkListener
+
+ // Declare the class views.
+ private lateinit var nameEditText: EditText
+ private lateinit var urlEditText: EditText
+ private lateinit var newIconRadioButton: RadioButton
+ private lateinit var saveButton: Button
+
+ override fun onAttach(context: Context) {
+ // Run the default commands.
+ super.onAttach(context)
+
+ // Get a handle for the edit bookmark listener from the launching context.
+ editBookmarkListener = context as EditBookmarkListener
+ }
+
+ companion object {
+ // `@JvmStatic` will no longer be required once all the code has transitioned to Kotlin. Also, the function can then be moved out of a companion object and just become a package-level function.
+ @JvmStatic
+ fun bookmarkDatabaseId(databaseId: Int, favoriteIconBitmap: Bitmap): EditBookmarkDialog {
+ // Create a favorite icon byte array output stream.
+ val favoriteIconByteArrayOutputStream = ByteArrayOutputStream()
+
+ // Convert the favorite icon to a PNG and place it in the byte array output stream. `0` is for lossless compression (the only option for a PNG).
+ favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream)
+
+ // Convert the byte array output stream to a byte array.
+ val favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray()
+
+ // Create an arguments bundle.
+ val argumentsBundle = Bundle()
+
+ // Store the variables in the bundle.
+ argumentsBundle.putInt(DATABASE_ID, databaseId)
+ argumentsBundle.putByteArray(FAVORITE_ICON_BYTE_ARRAY, favoriteIconByteArray)
+
+ // Create a new instance of the dialog.
+ val editBookmarkDialog = EditBookmarkDialog()
+
+ // Add the arguments bundle to the dialog.
+ editBookmarkDialog.arguments = argumentsBundle
+
+ // Return the new dialog.
+ return editBookmarkDialog
+ }
+ }
+
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
+ @SuppressLint("InflateParams")
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ // Get the arguments.
+ val arguments = requireArguments()
+
+ // Get the variables from the arguments.
+ val selectedBookmarkDatabaseId = arguments.getInt(DATABASE_ID)
+ val favoriteIconByteArray = arguments.getByteArray(FAVORITE_ICON_BYTE_ARRAY)!!
+
+ // Convert the favorite icon byte array to a bitmap.
+ val favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.size)
+
+ // Initialize the bookmarks database helper. The `0` specifies a database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`.
+ val bookmarksDatabaseHelper = BookmarksDatabaseHelper(context, null, null, 0)
+
+ // Get a cursor with the selected bookmark.
+ val bookmarkCursor = bookmarksDatabaseHelper.getBookmark(selectedBookmarkDatabaseId)
+
+ // Move the cursor to the first position.
+ bookmarkCursor.moveToFirst()
+
+ // Use an alert dialog builder to create the alert dialog.
+ val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
+
+ // Set the title.
+ dialogBuilder.setTitle(R.string.edit_bookmark)
+
+ // Set the view. The parent view is null because it will be assigned by the alert dialog.
+ dialogBuilder.setView(requireActivity().layoutInflater.inflate(R.layout.edit_bookmark_dialog, null))
+
+ // Set the cancel button listener. Using `null` as the listener closes the dialog without doing anything else.
+ dialogBuilder.setNegativeButton(R.string.cancel, null)
+
+ // Set the save button listener.
+ dialogBuilder.setPositiveButton(R.string.save) { _: DialogInterface?, _: Int ->
+ // Return the dialog fragment to the parent activity.
+ editBookmarkListener.onSaveBookmark(this, selectedBookmarkDatabaseId, favoriteIconBitmap)
+ }
+
+ // Create an alert dialog from the builder.
+ val alertDialog = dialogBuilder.create()
+
+ // Get a handle for the shared preferences.
+ val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
+
+ // 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)
+ }
+
+ // The alert dialog must be shown before items in the layout can be modified.
+ alertDialog.show()
+
+ // Get handles for the layout items.
+ val iconRadioGroup = alertDialog.findViewById<RadioGroup>(R.id.edit_bookmark_icon_radiogroup)!!
+ val currentIconImageView = alertDialog.findViewById<ImageView>(R.id.edit_bookmark_current_icon)!!
+ val newFavoriteIconImageView = alertDialog.findViewById<ImageView>(R.id.edit_bookmark_webpage_favorite_icon)!!
+ newIconRadioButton = alertDialog.findViewById(R.id.edit_bookmark_webpage_favorite_icon_radiobutton)!!
+ nameEditText = alertDialog.findViewById(R.id.edit_bookmark_name_edittext)!!
+ urlEditText = alertDialog.findViewById(R.id.edit_bookmark_url_edittext)!!
+ saveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)
+
+ // Get the current favorite icon byte array from the cursor.
+ val currentIconByteArray = bookmarkCursor.getBlob(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.FAVORITE_ICON))
+
+ // Convert the byte array to a bitmap beginning at the first byte and ending at the last.
+ val currentIconBitmap = BitmapFactory.decodeByteArray(currentIconByteArray, 0, currentIconByteArray.size)
+
+ // Display the current icon bitmap.
+ currentIconImageView.setImageBitmap(currentIconBitmap)
+
+ // Set the new favorite icon bitmap.
+ newFavoriteIconImageView.setImageBitmap(favoriteIconBitmap)
+
+ // Store the current bookmark name and URL.
+ val currentName = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME))
+ val currentUrl = bookmarkCursor.getString(bookmarkCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_URL))
+
+ // Populate the edit texts.
+ nameEditText.setText(currentName)
+ urlEditText.setText(currentUrl)
+
+ // Initially disable the save button.
+ saveButton.isEnabled = false
+
+ // Update the save button if the icon selection changes.
+ iconRadioGroup.setOnCheckedChangeListener { _: RadioGroup?, _: Int ->
+ // Update the save button.
+ updateSaveButton(currentName, currentUrl)
+ }
+
+ // Update the save button if the bookmark name changes.
+ nameEditText.addTextChangedListener(object: TextWatcher {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+ // Do nothing.
+ }
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+ // Do nothing.
+ }
+
+ override fun afterTextChanged(s: Editable) {
+ // Update the save button.
+ updateSaveButton(currentName, currentUrl)
+ }
+ })
+
+ // Update the save button if the URL changes.
+ urlEditText.addTextChangedListener(object: TextWatcher {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+ // Do nothing.
+ }
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+ // Do nothing.
+ }
+
+ override fun afterTextChanged(s: Editable) {
+ // Update the edit button.
+ updateSaveButton(currentName, currentUrl)
+ }
+ })
+
+ // Allow the enter key on the keyboard to save the bookmark from the bookmark name edit text.
+ nameEditText.setOnKeyListener { _: View?, keyCode: Int, event: KeyEvent ->
+ // Check the key code, event, and button status.
+ if (event.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER && saveButton.isEnabled) { // The enter key was pressed and the save button is enabled.
+ // Trigger the listener and return the dialog fragment to the parent activity.
+ editBookmarkListener.onSaveBookmark(this, selectedBookmarkDatabaseId, favoriteIconBitmap)
+
+ // Manually dismiss the alert dialog.
+ alertDialog.dismiss()
+
+ // Consume the event.
+ return@setOnKeyListener true
+ } else { // If any other key was pressed, or if the save button is currently disabled, do not consume the event.
+ return@setOnKeyListener false
+ }
+ }
+
+ // Allow the enter key on the keyboard to save the bookmark from the URL edit text.
+ urlEditText.setOnKeyListener { _: View?, keyCode: Int, event: KeyEvent ->
+ // Check the key code, event, and button status.
+ if (event.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER && saveButton.isEnabled) { // The enter key was pressed and the save button is enabled.
+ // Trigger the listener and return the dialog fragment to the parent activity.
+ editBookmarkListener.onSaveBookmark(this, selectedBookmarkDatabaseId, favoriteIconBitmap)
+
+ // Manually dismiss the alert dialog.
+ alertDialog.dismiss()
+
+ // Consume the event.
+ return@setOnKeyListener true
+ } else { // If any other key was pressed, or if the save button is currently disabled, do not consume the event.
+ return@setOnKeyListener false
+ }
+ }
+
+ // Return the alert dialog.
+ return alertDialog
+ }
+
+ private fun updateSaveButton(currentName: String, currentUrl: String) {
+ // Get the text from the edit texts.
+ val newName = nameEditText.text.toString()
+ val newUrl = urlEditText.text.toString()
+
+ // Has the favorite icon changed?
+ val iconChanged = newIconRadioButton.isChecked
+
+ // Has the name changed?
+ val nameChanged = newName != currentName
+
+ // Has the URL changed?
+ val urlChanged = newUrl != currentUrl
+
+ // Update the enabled status of the save button.
+ saveButton.isEnabled = iconChanged || nameChanged || urlChanged
+ }
+}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
- *
- * Privacy Browser 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 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. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.stoutner.privacybrowser.dialogs;
-
-import android.annotation.SuppressLint;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.database.MatrixCursor;
-import android.database.MergeCursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.AdapterView;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-import android.widget.ResourceCursorAdapter;
-import android.widget.Spinner;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
-import androidx.core.content.ContextCompat;
-import androidx.fragment.app.DialogFragment; // The AndroidX dialog fragment must be used or an error is produced on API <=22.
-
-import com.stoutner.privacybrowser.R;
-import com.stoutner.privacybrowser.activities.BookmarksDatabaseViewActivity;
-import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper;
-
-import java.io.ByteArrayOutputStream;
-
-public class EditBookmarkFolderDatabaseViewDialog extends DialogFragment {
- // Define the edit bookmark folder database view listener.
- private EditBookmarkFolderDatabaseViewListener editBookmarkFolderDatabaseViewListener;
-
-
- // The public interface is used to send information back to the parent activity.
- public interface EditBookmarkFolderDatabaseViewListener {
- void onSaveBookmarkFolder(DialogFragment dialogFragment, int selectedFolderDatabaseId, Bitmap favoriteIconBitmap);
- }
-
- public void onAttach(@NonNull Context context) {
- // Run the default commands.
- super.onAttach(context);
-
- // Get a handle for `EditBookmarkDatabaseViewListener` from the launching context.
- editBookmarkFolderDatabaseViewListener = (EditBookmarkFolderDatabaseViewListener) context;
- }
-
-
- public static EditBookmarkFolderDatabaseViewDialog folderDatabaseId(int databaseId, Bitmap favoriteIconBitmap) {
- // Create a favorite icon byte array output stream.
- ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream();
-
- // Convert the favorite icon to a PNG and place it in the byte array output stream. `0` is for lossless compression (the only option for a PNG).
- favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream);
-
- // Convert the byte array output stream to a byte array.
- byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray();
-
- // Create an arguments bundle.
- Bundle argumentsBundle = new Bundle();
-
- // Store the variables in the bundle.
- argumentsBundle.putInt("database_id", databaseId);
- argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray);
-
- // Create a new instance of the dialog.
- EditBookmarkFolderDatabaseViewDialog editBookmarkFolderDatabaseViewDialog = new EditBookmarkFolderDatabaseViewDialog();
-
- // Add the arguments bundle to the dialog.
- editBookmarkFolderDatabaseViewDialog.setArguments(argumentsBundle);
-
- // Return the new dialog.
- return editBookmarkFolderDatabaseViewDialog;
- }
-
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
- @SuppressLint("InflateParams")
- @Override
- @NonNull
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- // Get the arguments.
- Bundle arguments = getArguments();
-
- // Remove the incorrect lint warning below that the arguments might be null.
- assert arguments != null;
-
- // Get the bookmark database ID from the bundle.
- int folderDatabaseId = getArguments().getInt("database_id");
-
- // Get the favorite icon byte array.
- byte[] favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array");
-
- // Remove the incorrect lint warning below that the favorite icon byte array might be null.
- assert favoriteIconByteArray != null;
-
- // Convert the favorite icon byte array to a bitmap.
- Bitmap favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.length);
-
- // Initialize the database helper. The `0` specifies a database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`.
- BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(getContext(), null, null, 0);
-
- // Get a `Cursor` with the selected bookmark and move it to the first position.
- Cursor folderCursor = bookmarksDatabaseHelper.getBookmark(folderDatabaseId);
- folderCursor.moveToFirst();
-
- // Use an alert dialog builder to create the alert dialog.
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog);
-
- // Set the title.
- dialogBuilder.setTitle(R.string.edit_folder);
-
- // Remove the incorrect lint warning that `getActivity()` might be null.
- assert getActivity() != null;
-
- // Set the view. The parent view is `null` because it will be assigned by `AlertDialog`.
- dialogBuilder.setView(getActivity().getLayoutInflater().inflate(R.layout.edit_bookmark_folder_databaseview_dialog, null));
-
- // Set the listener for the negative button.
- dialogBuilder.setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> {
- // Do nothing. The `AlertDialog` will close automatically.
- });
-
- // Set the listener fo the positive button.
- dialogBuilder.setPositiveButton(R.string.save, (DialogInterface dialog, int which) -> {
- // Return the `DialogFragment` to the parent activity on save.
- editBookmarkFolderDatabaseViewListener.onSaveBookmarkFolder(this, folderDatabaseId, favoriteIconBitmap);
- });
-
- // Create an alert dialog from the alert dialog builder.
- final AlertDialog alertDialog = dialogBuilder.create();
-
- // Remove the warning below that `getWindow()` might be null.
- assert alertDialog.getWindow() != null;
-
- // Get a handle for the shared preferences.
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
-
- // Get the screenshot preference.
- boolean allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false);
-
- // Disable screenshots if not allowed.
- if (!allowScreenshots) {
- alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
- }
-
- // The alert dialog must be shown before items in the layout can be modified.
- alertDialog.show();
-
- // Get handles for the layout items.
- TextView databaseIdTextView = alertDialog.findViewById(R.id.edit_folder_database_id_textview);
- RadioGroup iconRadioGroup = alertDialog.findViewById(R.id.edit_folder_icon_radiogroup);
- ImageView currentIconImageView = alertDialog.findViewById(R.id.edit_folder_current_icon_imageview);
- ImageView newFavoriteIconImageView = alertDialog.findViewById(R.id.edit_folder_webpage_favorite_icon_imageview);
- EditText nameEditText = alertDialog.findViewById(R.id.edit_folder_name_edittext);
- Spinner folderSpinner = alertDialog.findViewById(R.id.edit_folder_parent_folder_spinner);
- EditText displayOrderEditText = alertDialog.findViewById(R.id.edit_folder_display_order_edittext);
- Button editButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
-
- // Remove the incorrect lint warnings below that the views might be null.
- assert databaseIdTextView != null;
- assert iconRadioGroup != null;
- assert currentIconImageView != null;
- assert newFavoriteIconImageView != null;
- assert nameEditText != null;
- assert folderSpinner != null;
- assert displayOrderEditText != null;
-
- // Store the current folder values.
- String currentFolderName = folderCursor.getString(folderCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME));
- int currentDisplayOrder = folderCursor.getInt(folderCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER));
- String parentFolder = folderCursor.getString(folderCursor.getColumnIndex(BookmarksDatabaseHelper.PARENT_FOLDER));
-
- // Set the database ID.
- databaseIdTextView.setText(String.valueOf(folderCursor.getInt(folderCursor.getColumnIndex(BookmarksDatabaseHelper._ID))));
-
- // Get the current favorite icon byte array from the `Cursor`.
- byte[] currentIconByteArray = folderCursor.getBlob(folderCursor.getColumnIndex(BookmarksDatabaseHelper.FAVORITE_ICON));
-
- // Convert the byte array to a `Bitmap` beginning at the first byte and ending at the last.
- Bitmap currentIconBitmap = BitmapFactory.decodeByteArray(currentIconByteArray, 0, currentIconByteArray.length);
-
- // Display the current icon bitmap in `edit_bookmark_current_icon`.
- currentIconImageView.setImageBitmap(currentIconBitmap);
-
- // Set the new favorite icon bitmap.
- newFavoriteIconImageView.setImageBitmap(favoriteIconBitmap);
-
- // Populate the folder name edit text.
- nameEditText.setText(currentFolderName);
-
- // Setup a matrix cursor for "Home Folder".
- String[] matrixCursorColumnNames = {BookmarksDatabaseHelper._ID, BookmarksDatabaseHelper.BOOKMARK_NAME};
- MatrixCursor matrixCursor = new MatrixCursor(matrixCursorColumnNames);
- matrixCursor.addRow(new Object[]{BookmarksDatabaseViewActivity.HOME_FOLDER_DATABASE_ID, getString(R.string.home_folder)});
-
- // Add all subfolders of the current folder to the list of folders not to display.
- String exceptFolders = getStringOfSubfolders(currentFolderName, bookmarksDatabaseHelper);
-
- Log.i("Folders", "String of Folders Not To Display: " + exceptFolders);
-
- // Get a cursor with the list of all the folders.
- Cursor foldersCursor = bookmarksDatabaseHelper.getFoldersExcept(exceptFolders);
-
- // Combine the matrix cursor and the folders cursor.
- MergeCursor foldersMergeCursor = new MergeCursor(new Cursor[]{matrixCursor, foldersCursor});
-
- // Remove the incorrect lint warning that `getContext()` might be null.
- assert getContext() != null;
-
- // Create a resource cursor adapter for the spinner.
- ResourceCursorAdapter foldersCursorAdapter = new ResourceCursorAdapter(getContext(), R.layout.databaseview_spinner_item, foldersMergeCursor, 0) {
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- // Get handles for the spinner views.
- ImageView spinnerItemImageView = view.findViewById(R.id.spinner_item_imageview);
- TextView spinnerItemTextView = view.findViewById(R.id.spinner_item_textview);
-
- // Set the folder icon according to the type.
- if (foldersMergeCursor.getPosition() == 0) { // Set the `Home Folder` icon.
- // Set the gray folder image. `ContextCompat` must be used until the minimum API >= 21.
- spinnerItemImageView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.folder_gray));
- } else { // Set a user folder icon.
- // Get the folder icon byte array.
- byte[] folderIconByteArray = cursor.getBlob(cursor.getColumnIndex(BookmarksDatabaseHelper.FAVORITE_ICON));
-
- // Convert the byte array to a bitmap beginning at the first byte and ending at the last.
- Bitmap folderIconBitmap = BitmapFactory.decodeByteArray(folderIconByteArray, 0, folderIconByteArray.length);
-
- // Set the folder icon.
- spinnerItemImageView.setImageBitmap(folderIconBitmap);
- }
-
- // Set the text view to display the folder name.
- spinnerItemTextView.setText(cursor.getString(cursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME)));
- }
- };
-
- // Set the `ResourceCursorAdapter` drop drown view resource.
- foldersCursorAdapter.setDropDownViewResource(R.layout.databaseview_spinner_dropdown_items);
-
- // Set the adapter for the folder `Spinner`.
- folderSpinner.setAdapter(foldersCursorAdapter);
-
- // Select the current folder in the `Spinner` if the bookmark isn't in the "Home Folder".
- if (!parentFolder.equals("")) {
- // Get the database ID of the parent folder.
- int parentFolderDatabaseId = bookmarksDatabaseHelper.getFolderDatabaseId(folderCursor.getString(folderCursor.getColumnIndex(BookmarksDatabaseHelper.PARENT_FOLDER)));
-
- // Initialize `parentFolderPosition` and the iteration variable.
- int parentFolderPosition = 0;
- int i = 0;
-
- // Find the parent folder position in folders `ResourceCursorAdapter`.
- do {
- if (foldersCursorAdapter.getItemId(i) == parentFolderDatabaseId) {
- // Store the current position for the parent folder.
- parentFolderPosition = i;
- } else {
- // Try the next entry.
- i++;
- }
- // Stop when the parent folder position is found or all the items in the `ResourceCursorAdapter` have been checked.
- } while ((parentFolderPosition == 0) && (i < foldersCursorAdapter.getCount()));
-
- // Select the parent folder in the `Spinner`.
- folderSpinner.setSelection(parentFolderPosition);
- }
-
- // Store the current folder database ID.
- int currentParentFolderDatabaseId = (int) folderSpinner.getSelectedItemId();
-
- // Populate the display order `EditText`.
- displayOrderEditText.setText(String.valueOf(folderCursor.getInt(folderCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER))));
-
- // Initially disable the edit button.
- editButton.setEnabled(false);
-
- // Update the edit button if the icon selection changes.
- iconRadioGroup.setOnCheckedChangeListener((group, checkedId) -> {
- // Update the edit button.
- updateEditButton(alertDialog, bookmarksDatabaseHelper, currentFolderName, currentParentFolderDatabaseId, currentDisplayOrder);
- });
-
- // Update the edit button if the bookmark name changes.
- nameEditText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- // Do nothing.
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- // Do nothing.
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- // Update the edit button.
- updateEditButton(alertDialog, bookmarksDatabaseHelper, currentFolderName, currentParentFolderDatabaseId, currentDisplayOrder);
- }
- });
-
- // Update the edit button if the folder changes.
- folderSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
- @Override
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
- // Update the edit button.
- updateEditButton(alertDialog, bookmarksDatabaseHelper, currentFolderName, currentParentFolderDatabaseId, currentDisplayOrder);
- }
-
- @Override
- public void onNothingSelected(AdapterView<?> parent) {
-
- }
- });
-
- // Update the edit button if the display order changes.
- displayOrderEditText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- // Do nothing.
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- // Do nothing.
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- // Update the edit button.
- updateEditButton(alertDialog, bookmarksDatabaseHelper, currentFolderName, currentParentFolderDatabaseId, currentDisplayOrder);
- }
- });
-
- // Allow the `enter` key on the keyboard to save the bookmark from the bookmark name `EditText`.
- nameEditText.setOnKeyListener((View v, int keyCode, KeyEvent event) -> {
- // Save the bookmark if the event is a key-down on the "enter" button.
- if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && editButton.isEnabled()) { // The enter key was pressed and the edit button is enabled.
- // Trigger the `Listener` and return the `DialogFragment` to the parent activity.
- editBookmarkFolderDatabaseViewListener.onSaveBookmarkFolder(this, folderDatabaseId, favoriteIconBitmap);
-
- // Manually dismiss `alertDialog`.
- alertDialog.dismiss();
-
- // Consume the event.
- return true;
- } else { // If any other key was pressed, or if the edit button is currently disabled, do not consume the event.
- return false;
- }
- });
-
- // Allow the "enter" key on the keyboard to save the bookmark from the display order `EditText`.
- displayOrderEditText.setOnKeyListener((View v, int keyCode, KeyEvent event) -> {
- // Save the bookmark if the event is a key-down on the "enter" button.
- if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && editButton.isEnabled()) { // The enter key was pressed and the edit button is enabled.
- // Trigger the `Listener` and return the `DialogFragment` to the parent activity.
- editBookmarkFolderDatabaseViewListener.onSaveBookmarkFolder(this, folderDatabaseId, favoriteIconBitmap);
-
- // Manually dismiss the `AlertDialog`.
- alertDialog.dismiss();
-
- // Consume the event.
- return true;
- } else { // If any other key was pressed, or if the edit button is currently disabled, do not consume the event.
- return false;
- }
- });
-
- // `onCreateDialog` requires the return of an `AlertDialog`.
- return alertDialog;
- }
-
- private void updateEditButton(AlertDialog alertDialog, BookmarksDatabaseHelper bookmarksDatabaseHelper, String currentFolderName, int currentParentFolderDatabaseId, int currentDisplayOrder) {
- // Get handles for the views.
- EditText nameEditText = alertDialog.findViewById(R.id.edit_folder_name_edittext);
- Spinner folderSpinner = alertDialog.findViewById(R.id.edit_folder_parent_folder_spinner);
- EditText displayOrderEditText = alertDialog.findViewById(R.id.edit_folder_display_order_edittext);
- RadioButton currentIconRadioButton = alertDialog.findViewById(R.id.edit_folder_current_icon_radiobutton);
- Button editButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
-
- // Remove the incorrect lint warning below that the views might be null.
- assert nameEditText != null;
- assert folderSpinner != null;
- assert displayOrderEditText != null;
- assert currentIconRadioButton != null;
-
- // Get the values from the dialog.
- String newFolderName = nameEditText.getText().toString();
- int newParentFolderDatabaseId = (int) folderSpinner.getSelectedItemId();
- String newDisplayOrder = displayOrderEditText.getText().toString();
-
- // Get a cursor for the new folder name if it exists.
- Cursor folderExistsCursor = bookmarksDatabaseHelper.getFolder(newFolderName);
-
- // Is the new folder name empty?
- boolean folderNameNotEmpty = !newFolderName.isEmpty();
-
- // Does the folder name already exist?
- boolean folderNameAlreadyExists = (!newFolderName.equals(currentFolderName) && (folderExistsCursor.getCount() > 0));
-
- // Has the favorite icon changed?
- boolean iconChanged = !currentIconRadioButton.isChecked();
-
- // Has the name been renamed?
- boolean folderRenamed = (!newFolderName.equals(currentFolderName) && !folderNameAlreadyExists);
-
- // Has the folder changed?
- boolean parentFolderChanged = newParentFolderDatabaseId != currentParentFolderDatabaseId;
-
- // Has the display order changed?
- boolean displayOrderChanged = !newDisplayOrder.equals(String.valueOf(currentDisplayOrder));
-
- // Is the display order empty?
- boolean displayOrderNotEmpty = !newDisplayOrder.isEmpty();
-
- // Update the enabled status of the edit button.
- editButton.setEnabled((iconChanged || folderRenamed || parentFolderChanged || displayOrderChanged) && folderNameNotEmpty && displayOrderNotEmpty);
- }
-
- private String getStringOfSubfolders(String folderName, BookmarksDatabaseHelper bookmarksDatabaseHelper) {
- // Get a cursor will all the immediate subfolders.
- Cursor subfoldersCursor = bookmarksDatabaseHelper.getSubfolders(folderName);
-
- // Initialize a string builder to track the folders not to display in the spinner and populate it with the current folder.
- StringBuilder exceptFoldersStringBuilder = new StringBuilder(DatabaseUtils.sqlEscapeString(folderName));
-
- for (int i = 0; i < subfoldersCursor.getCount(); i++) {
- // Move the subfolder cursor to the current item.
- subfoldersCursor.moveToPosition(i);
-
- // Get the name of the subfolder.
- String subfolderName = subfoldersCursor.getString(subfoldersCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME));
-
- // Add a comma to the end of the existing string.
- exceptFoldersStringBuilder.append(",");
-
- // Get the folder name and run the task for any subfolders.
- String subfolderString = getStringOfSubfolders(subfolderName, bookmarksDatabaseHelper);
-
- // Add the folder name to the string builder.
- exceptFoldersStringBuilder.append(subfolderString);
- }
-
- // Return the string of folders.
- return exceptFoldersStringBuilder.toString();
- }
-}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser 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 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. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.stoutner.privacybrowser.dialogs
+
+import android.annotation.SuppressLint
+import android.app.Dialog
+import android.content.Context
+import android.content.DialogInterface
+import android.database.Cursor
+import android.database.DatabaseUtils
+import android.database.MatrixCursor
+import android.database.MergeCursor
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.KeyEvent
+import android.view.View
+import android.view.WindowManager
+import android.widget.*
+import android.widget.AdapterView.OnItemSelectedListener
+
+import androidx.appcompat.app.AlertDialog
+import androidx.core.content.ContextCompat
+import androidx.cursoradapter.widget.ResourceCursorAdapter
+import androidx.fragment.app.DialogFragment
+import androidx.preference.PreferenceManager
+
+import com.stoutner.privacybrowser.R
+import com.stoutner.privacybrowser.activities.BookmarksDatabaseViewActivity
+import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper
+
+import java.io.ByteArrayOutputStream
+
+// Declare the class constants.
+private const val DATABASE_ID = "database_id"
+private const val FAVORITE_ICON_BYTE_ARRAY = "favorite_icon_byte_array"
+
+class EditBookmarkFolderDatabaseViewDialog: DialogFragment() {
+ // The public interface is used to send information back to the parent activity.
+ interface EditBookmarkFolderDatabaseViewListener {
+ fun onSaveBookmarkFolder(dialogFragment: DialogFragment, selectedFolderDatabaseId: Int, favoriteIconBitmap: Bitmap)
+ }
+
+ // Declare the class variables.
+ private lateinit var editBookmarkFolderDatabaseViewListener: EditBookmarkFolderDatabaseViewListener
+
+ // Declare the class views.
+ private lateinit var nameEditText: EditText
+ private lateinit var folderSpinner: Spinner
+ private lateinit var displayOrderEditText: EditText
+ private lateinit var currentIconRadioButton: RadioButton
+ private lateinit var saveButton: Button
+
+ override fun onAttach(context: Context) {
+ // Run the default commands.
+ super.onAttach(context)
+
+ // Get a handle for edit bookmark database view listener from the launching context.
+ editBookmarkFolderDatabaseViewListener = context as EditBookmarkFolderDatabaseViewListener
+ }
+
+ companion object {
+ // `@JvmStatic` will no longer be required once all the code has transitioned to Kotlin. Also, the function can then be moved out of a companion object and just become a package-level function.
+ @JvmStatic
+ fun folderDatabaseId(databaseId: Int, favoriteIconBitmap: Bitmap): EditBookmarkFolderDatabaseViewDialog {
+ // Create a favorite icon byte array output stream.
+ val favoriteIconByteArrayOutputStream = ByteArrayOutputStream()
+
+ // Convert the favorite icon to a PNG and place it in the byte array output stream. `0` is for lossless compression (the only option for a PNG).
+ favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream)
+
+ // Convert the byte array output stream to a byte array.
+ val favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray()
+
+ // Create an arguments bundle.
+ val argumentsBundle = Bundle()
+
+ // Store the variables in the bundle.
+ argumentsBundle.putInt(DATABASE_ID, databaseId)
+ argumentsBundle.putByteArray(FAVORITE_ICON_BYTE_ARRAY, favoriteIconByteArray)
+
+ // Create a new instance of the dialog.
+ val editBookmarkFolderDatabaseViewDialog = EditBookmarkFolderDatabaseViewDialog()
+
+ // Add the arguments bundle to the dialog.
+ editBookmarkFolderDatabaseViewDialog.arguments = argumentsBundle
+
+ // Return the new dialog.
+ return editBookmarkFolderDatabaseViewDialog
+ }
+ }
+
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
+ @SuppressLint("InflateParams")
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ // Get a handle for the arguments.
+ val arguments = requireArguments()
+
+ // Get the variables from the arguments.
+ val folderDatabaseId = arguments.getInt(DATABASE_ID)
+ val favoriteIconByteArray = arguments.getByteArray(FAVORITE_ICON_BYTE_ARRAY)!!
+
+ // Convert the favorite icon byte array to a bitmap.
+ val favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.size)
+
+ // Initialize the bookmarks database helper. The `0` specifies a database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`.
+ val bookmarksDatabaseHelper = BookmarksDatabaseHelper(context, null, null, 0)
+
+ // Get a cursor with the selected bookmark.
+ val folderCursor = bookmarksDatabaseHelper.getBookmark(folderDatabaseId)
+
+ // Move the cursor to the first position.
+ folderCursor.moveToFirst()
+
+ // Use an alert dialog builder to create the alert dialog.
+ val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
+
+ // Set the title.
+ dialogBuilder.setTitle(R.string.edit_folder)
+
+ // Set the view. The parent view is `null` because it will be assigned by the alert dialog.
+ dialogBuilder.setView(requireActivity().layoutInflater.inflate(R.layout.edit_bookmark_folder_databaseview_dialog, null))
+
+ // Set the cancel button listener. Using `null` as the listener closes the dialog without doing anything else.
+ dialogBuilder.setNegativeButton(R.string.cancel, null)
+
+ // Set the save button listener.
+ dialogBuilder.setPositiveButton(R.string.save) { _: DialogInterface?, _: Int ->
+ // Return the dialog fragment to the parent activity.
+ editBookmarkFolderDatabaseViewListener.onSaveBookmarkFolder(this, folderDatabaseId, favoriteIconBitmap)
+ }
+
+ // Create an alert dialog from the alert dialog builder.
+ val alertDialog = dialogBuilder.create()
+
+ // Get a handle for the shared preferences.
+ val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
+
+ // 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)
+ }
+
+ // The alert dialog must be shown before items in the layout can be modified.
+ alertDialog.show()
+
+ // Get handles for the layout items.
+ val databaseIdTextView = alertDialog.findViewById<TextView>(R.id.edit_folder_database_id_textview)!!
+ val iconRadioGroup = alertDialog.findViewById<RadioGroup>(R.id.edit_folder_icon_radiogroup)!!
+ val currentIconImageView = alertDialog.findViewById<ImageView>(R.id.edit_folder_current_icon_imageview)!!
+ val newFavoriteIconImageView = alertDialog.findViewById<ImageView>(R.id.edit_folder_webpage_favorite_icon_imageview)!!
+ currentIconRadioButton = alertDialog.findViewById(R.id.edit_folder_current_icon_radiobutton)!!
+ nameEditText = alertDialog.findViewById(R.id.edit_folder_name_edittext)!!
+ folderSpinner = alertDialog.findViewById(R.id.edit_folder_parent_folder_spinner)!!
+ displayOrderEditText = alertDialog.findViewById(R.id.edit_folder_display_order_edittext)!!
+ saveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)
+
+ // Store the current folder values.
+ val currentFolderName = folderCursor.getString(folderCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME))
+ val currentDisplayOrder = folderCursor.getInt(folderCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER))
+ val parentFolder = folderCursor.getString(folderCursor.getColumnIndex(BookmarksDatabaseHelper.PARENT_FOLDER))
+
+ // Populate the database ID text view.
+ databaseIdTextView.text = folderCursor.getInt(folderCursor.getColumnIndex(BookmarksDatabaseHelper._ID)).toString()
+
+ // Get the current favorite icon byte array from the cursor.
+ val currentIconByteArray = folderCursor.getBlob(folderCursor.getColumnIndex(BookmarksDatabaseHelper.FAVORITE_ICON))
+
+ // Convert the byte array to a bitmap beginning at the first byte and ending at the last.
+ val currentIconBitmap = BitmapFactory.decodeByteArray(currentIconByteArray, 0, currentIconByteArray.size)
+
+ // Populate the current icon image view.
+ currentIconImageView.setImageBitmap(currentIconBitmap)
+
+ // Populate the new favorite icon image view.
+ newFavoriteIconImageView.setImageBitmap(favoriteIconBitmap)
+
+ // Populate the folder name edit text.
+ nameEditText.setText(currentFolderName)
+
+ // Define an array of matrix cursor column names.
+ val matrixCursorColumnNames = arrayOf(BookmarksDatabaseHelper._ID, BookmarksDatabaseHelper.BOOKMARK_NAME)
+
+ // Create a matrix cursor.
+ val matrixCursor = MatrixCursor(matrixCursorColumnNames)
+
+ // Add `Home Folder` to the matrix cursor.
+ matrixCursor.addRow(arrayOf(BookmarksDatabaseViewActivity.HOME_FOLDER_DATABASE_ID, getString(R.string.home_folder)))
+
+ // Get a string of the current folder and all subfolders.
+ val currentAndSubfolderString = getStringOfSubfolders(currentFolderName, bookmarksDatabaseHelper)
+
+ // Get a cursor with the list of all the folders.
+ val foldersCursor = bookmarksDatabaseHelper.getFoldersExcept(currentAndSubfolderString)
+
+ // Combine the matrix cursor and the folders cursor.
+ val combinedFoldersCursor = MergeCursor(arrayOf(matrixCursor, foldersCursor))
+
+ // Create a resource cursor adapter for the spinner.
+ val foldersCursorAdapter: ResourceCursorAdapter = object: ResourceCursorAdapter(context, R.layout.databaseview_spinner_item, combinedFoldersCursor, 0) {
+ override fun bindView(view: View, context: Context, cursor: Cursor) {
+ // Get handles for the spinner views.
+ val spinnerItemImageView = view.findViewById<ImageView>(R.id.spinner_item_imageview)
+ val spinnerItemTextView = view.findViewById<TextView>(R.id.spinner_item_textview)
+
+ // Set the folder icon according to the type.
+ if (combinedFoldersCursor.position == 0) { // Set the `Home Folder` icon.
+ // Set the gray folder image. `ContextCompat` must be used until the minimum API >= 21.
+ spinnerItemImageView.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.folder_gray))
+ } else { // Set a user folder icon.
+ // Get the folder icon byte array.
+ val folderIconByteArray = cursor.getBlob(cursor.getColumnIndex(BookmarksDatabaseHelper.FAVORITE_ICON))
+
+ // Convert the byte array to a bitmap beginning at the first byte and ending at the last.
+ val folderIconBitmap = BitmapFactory.decodeByteArray(folderIconByteArray, 0, folderIconByteArray.size)
+
+ // Set the folder icon.
+ spinnerItemImageView.setImageBitmap(folderIconBitmap)
+ }
+
+ // Set the text view to display the folder name.
+ spinnerItemTextView.text = cursor.getString(cursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME))
+ }
+ }
+
+ // Set the folders cursor adapter drop drown view resource.
+ foldersCursorAdapter.setDropDownViewResource(R.layout.databaseview_spinner_dropdown_items)
+
+ // Set the adapter for the folder `Spinner`.
+ folderSpinner.adapter = foldersCursorAdapter
+
+ // Select the current folder in the spinner if the bookmark isn't in the "Home Folder".
+ if (parentFolder != "") {
+ // Get the database ID of the parent folder as a long.
+ val parentFolderDatabaseId = bookmarksDatabaseHelper.getFolderDatabaseId(folderCursor.getString(folderCursor.getColumnIndex(BookmarksDatabaseHelper.PARENT_FOLDER))).toLong()
+
+ // Initialize the parent folder position and the iteration variable.
+ var parentFolderPosition = 0
+ var i = 0
+
+ // Find the parent folder position in the folders cursor adapter.
+ do {
+ if (foldersCursorAdapter.getItemId(i) == parentFolderDatabaseId) {
+ // Store the current position for the parent folder.
+ parentFolderPosition = i
+ } else {
+ // Try the next entry.
+ i++
+ }
+ // Stop when the parent folder position is found or all the items in the folders cursor adapter have been checked.
+ } while (parentFolderPosition == 0 && i < foldersCursorAdapter.count)
+
+ // Select the parent folder in the spinner.
+ folderSpinner.setSelection(parentFolderPosition)
+ }
+
+ // Store the current folder database ID.
+ val currentParentFolderDatabaseId = folderSpinner.selectedItemId.toInt()
+
+ // Populate the display order edit text.
+ displayOrderEditText.setText(folderCursor.getInt(folderCursor.getColumnIndex(BookmarksDatabaseHelper.DISPLAY_ORDER)).toString())
+
+ // Initially disable the edit button.
+ saveButton.isEnabled = false
+
+ // Update the save button if the icon selection changes.
+ iconRadioGroup.setOnCheckedChangeListener { _: RadioGroup?, _: Int ->
+ // Update the save button.
+ updateSaveButton(bookmarksDatabaseHelper, currentFolderName, currentParentFolderDatabaseId, currentDisplayOrder)
+ }
+
+ // Update the save button if the bookmark name changes.
+ nameEditText.addTextChangedListener(object: TextWatcher {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+ // Do nothing.
+ }
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+ // Do nothing.
+ }
+
+ override fun afterTextChanged(s: Editable) {
+ // Update the save button.
+ updateSaveButton(bookmarksDatabaseHelper, currentFolderName, currentParentFolderDatabaseId, currentDisplayOrder)
+ }
+ })
+
+ // Update the save button if the folder changes.
+ folderSpinner.onItemSelectedListener = object: OnItemSelectedListener {
+ override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {
+ // Update the save button.
+ updateSaveButton(bookmarksDatabaseHelper, currentFolderName, currentParentFolderDatabaseId, currentDisplayOrder)
+ }
+
+ override fun onNothingSelected(parent: AdapterView<*>?) {
+ // Do nothing.
+ }
+ }
+
+ // Update the save button if the display order changes.
+ displayOrderEditText.addTextChangedListener(object: TextWatcher {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+ // Do nothing.
+ }
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+ // Do nothing.
+ }
+
+ override fun afterTextChanged(s: Editable) {
+ // Update the save button.
+ updateSaveButton(bookmarksDatabaseHelper, currentFolderName, currentParentFolderDatabaseId, currentDisplayOrder)
+ }
+ })
+
+ // Allow the enter key on the keyboard to save the bookmark from the bookmark name edit text.
+ nameEditText.setOnKeyListener { _: View?, keyCode: Int, event: KeyEvent ->
+ // Check the key code, event, and button status.
+ if (event.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER && saveButton.isEnabled) { // The enter key was pressed and the save button is enabled.
+ // Trigger the listener and return the dialog fragment to the parent activity.
+ editBookmarkFolderDatabaseViewListener.onSaveBookmarkFolder(this, folderDatabaseId, favoriteIconBitmap)
+
+ // Manually dismiss the alert dialog.
+ alertDialog.dismiss()
+
+ // Consume the event.
+ return@setOnKeyListener true
+ } else { // If any other key was pressed, or if the save button is currently disabled, do not consume the event.
+ return@setOnKeyListener false
+ }
+ }
+
+ // Allow the enter key on the keyboard to save the bookmark from the display order edit text.
+ displayOrderEditText.setOnKeyListener { _: View?, keyCode: Int, event: KeyEvent ->
+ // Check the key code, event, and button status.
+ if (event.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER && saveButton.isEnabled) { // The enter key was pressed and the save button is enabled.
+ // Trigger the listener and return the dialog fragment to the parent activity.
+ editBookmarkFolderDatabaseViewListener.onSaveBookmarkFolder(this, folderDatabaseId, favoriteIconBitmap)
+
+ // Manually dismiss the alert dialog.
+ alertDialog.dismiss()
+
+ // Consume the event.
+ return@setOnKeyListener true
+ } else { // If any other key was pressed, or if the save button is currently disabled, do not consume the event.
+ return@setOnKeyListener false
+ }
+ }
+
+ // Return the alert dialog.
+ return alertDialog
+ }
+
+ private fun updateSaveButton(bookmarksDatabaseHelper: BookmarksDatabaseHelper, currentFolderName: String, currentParentFolderDatabaseId: Int, currentDisplayOrder: Int) {
+ // Get the values from the views.
+ val newFolderName = nameEditText.text.toString()
+ val newParentFolderDatabaseId = folderSpinner.selectedItemId.toInt()
+ val newDisplayOrder = displayOrderEditText.text.toString()
+
+ // Get a cursor for the new folder name if it exists.
+ val folderExistsCursor = bookmarksDatabaseHelper.getFolder(newFolderName)
+
+ // Is the new folder name empty?
+ val folderNameNotEmpty = newFolderName.isNotEmpty()
+
+ // Does the folder name already exist?
+ val folderNameAlreadyExists = (newFolderName != currentFolderName) && folderExistsCursor.count > 0
+
+ // Has the favorite icon changed?
+ val iconChanged = !currentIconRadioButton.isChecked
+
+ // Has the folder been renamed?
+ val folderRenamed = (newFolderName != currentFolderName) && !folderNameAlreadyExists
+
+ // Has the parent folder changed?
+ val parentFolderChanged = newParentFolderDatabaseId != currentParentFolderDatabaseId
+
+ // Has the display order changed?
+ val displayOrderChanged = newDisplayOrder != currentDisplayOrder.toString()
+
+ // Is the display order empty?
+ val displayOrderNotEmpty = newDisplayOrder.isNotEmpty()
+
+ // Update the enabled status of the edit button.
+ saveButton.isEnabled = (iconChanged || folderRenamed || parentFolderChanged || displayOrderChanged) && folderNameNotEmpty && displayOrderNotEmpty
+ }
+
+ private fun getStringOfSubfolders(folderName: String, bookmarksDatabaseHelper: BookmarksDatabaseHelper): String {
+ // Get a cursor will all the immediate subfolders.
+ val subfoldersCursor = bookmarksDatabaseHelper.getSubfolders(folderName)
+
+ // Initialize the subfolder string builder and populate it with the current folder.
+ val currentAndSubfolderStringBuilder = StringBuilder(DatabaseUtils.sqlEscapeString(folderName))
+
+ // Populate the subfolder string builder
+ for (i in 0 until subfoldersCursor.count) {
+ // Move the subfolder cursor to the current item.
+ subfoldersCursor.moveToPosition(i)
+
+ // Get the name of the subfolder.
+ val subfolderName = subfoldersCursor.getString(subfoldersCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME))
+
+ // Add a comma to the end of the existing string.
+ currentAndSubfolderStringBuilder.append(",")
+
+ // Get the folder name and run the task for any subfolders.
+ val subfolderString = getStringOfSubfolders(subfolderName, bookmarksDatabaseHelper)
+
+ // Add the folder name to the string builder.
+ currentAndSubfolderStringBuilder.append(subfolderString)
+ }
+
+ // Return the string of folders.
+ return currentAndSubfolderStringBuilder.toString()
+ }
+}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
- *
- * Privacy Browser 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 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. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.stoutner.privacybrowser.dialogs;
-
-import android.annotation.SuppressLint;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.ImageView;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.DialogFragment; // The AndroidX dialog fragment must be used or an error is produced on API <=22.
-
-import com.stoutner.privacybrowser.R;
-import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper;
-
-import java.io.ByteArrayOutputStream;
-
-public class EditBookmarkFolderDialog extends DialogFragment {
- // Instantiate the class variable.
- private EditBookmarkFolderListener editBookmarkFolderListener;
-
- // The public interface is used to send information back to the parent activity.
- public interface EditBookmarkFolderListener {
- void onSaveBookmarkFolder(DialogFragment dialogFragment, int selectedFolderDatabaseId, Bitmap favoriteIconBitmap);
- }
-
- public void onAttach(@NonNull Context context) {
- // Run the default commands.
- super.onAttach(context);
-
- // Get a handle for `EditFolderListener` from the launching context.
- editBookmarkFolderListener = (EditBookmarkFolderListener) context;
- }
-
- // Store the database ID in the arguments bundle.
- public static EditBookmarkFolderDialog folderDatabaseId(int databaseId, Bitmap favoriteIconBitmap) {
- // Create a favorite icon byte array output stream.
- ByteArrayOutputStream favoriteIconByteArrayOutputStream = new ByteArrayOutputStream();
-
- // Convert the favorite icon to a PNG and place it in the byte array output stream. `0` is for lossless compression (the only option for a PNG).
- favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream);
-
- // Convert the byte array output stream to a byte array.
- byte[] favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray();
-
- // Create an arguments bundle
- Bundle argumentsBundle = new Bundle();
-
- // Store the variables in the bundle.
- argumentsBundle.putInt("database_id", databaseId);
- argumentsBundle.putByteArray("favorite_icon_byte_array", favoriteIconByteArray);
-
- // Create a new instance of the dialog.
- EditBookmarkFolderDialog editBookmarkFolderDialog = new EditBookmarkFolderDialog();
-
- // Add the arguments bundle to the dialog.
- editBookmarkFolderDialog.setArguments(argumentsBundle);
-
- // Return the new dialog.
- return editBookmarkFolderDialog;
- }
-
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
- @SuppressLint("InflateParams")
- @Override
- @NonNull
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- // Get the arguments.
- Bundle arguments = getArguments();
-
- // Remove the incorrect lint warning below that the arguments might be null.
- assert arguments != null;
-
- // Store the folder database ID in the class variable.
- int selectedFolderDatabaseId = arguments.getInt("database_id");
-
- // Get the favorite icon byte array.
- byte[] favoriteIconByteArray = arguments.getByteArray("favorite_icon_byte_array");
-
- // Remove the incorrect lint warning below that the favorite icon byte array might be null.
- assert favoriteIconByteArray != null;
-
- // Convert the favorite icon byte array to a bitmap.
- Bitmap favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.length);
-
- // Initialize the database helper. The two `nulls` do not specify the database name or a `CursorFactory`. The `0` specifies a database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`.
- BookmarksDatabaseHelper bookmarksDatabaseHelper = new BookmarksDatabaseHelper(getContext(), null, null, 0);
-
- // Get a cursor with the selected folder and move it to the first position.
- Cursor folderCursor = bookmarksDatabaseHelper.getBookmark(selectedFolderDatabaseId);
- folderCursor.moveToFirst();
-
- // Use an alert dialog builder to create the alert dialog.
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog);
-
- // Set the title.
- dialogBuilder.setTitle(R.string.edit_folder);
-
- // Remove the incorrect lint warning that `getActivity()` might be null.
- assert getActivity() != null;
-
- // Set the view. The parent view is `null` because it will be assigned by `AlertDialog`.
- dialogBuilder.setView(getActivity().getLayoutInflater().inflate(R.layout.edit_bookmark_folder_dialog, null));
-
- // Set the listener for the negative button.
- dialogBuilder.setNegativeButton(R.string.cancel, (DialogInterface dialog, int which) -> {
- // Do nothing. The `AlertDialog` will close automatically.
- });
-
- // Set the listener fo the positive button.
- dialogBuilder.setPositiveButton(R.string.save, (DialogInterface dialog, int which) -> {
- // Return the `DialogFragment` to the parent activity on save.
- editBookmarkFolderListener.onSaveBookmarkFolder(this, selectedFolderDatabaseId, favoriteIconBitmap);
- });
-
- // Create an alert dialog from the alert dialog builder.
- AlertDialog alertDialog = dialogBuilder.create();
-
- // Remove the warning below that `getWindow()` might be null.
- assert alertDialog.getWindow() != null;
-
- // Get a handle for the shared preferences.
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
-
- // Get the screenshot preference.
- boolean allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false);
-
- // Disable screenshots if not allowed.
- if (!allowScreenshots) {
- alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
- }
-
- // The alert dialog must be shown before items in the layout can be modified.
- alertDialog.show();
-
- // Get handles for the views in the alert dialog.
- RadioGroup iconRadioGroup = alertDialog.findViewById(R.id.edit_folder_icon_radio_group);
- RadioButton currentIconRadioButton = alertDialog.findViewById(R.id.edit_folder_current_icon_radiobutton);
- ImageView currentIconImageView = alertDialog.findViewById(R.id.edit_folder_current_icon_imageview);
- ImageView webPageFavoriteIconImageView = alertDialog.findViewById(R.id.edit_folder_web_page_favorite_icon_imageview);
- EditText folderNameEditText = alertDialog.findViewById(R.id.edit_folder_name_edittext);
- Button editButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);
-
- // Remove the incorrect lint warnings below that the views might be null.
- assert iconRadioGroup != null;
- assert currentIconRadioButton != null;
- assert currentIconImageView != null;
- assert webPageFavoriteIconImageView != null;
- assert folderNameEditText != null;
-
- // Initially disable the edit button.
- editButton.setEnabled(false);
-
- // Get the current favorite icon byte array from the Cursor.
- byte[] currentIconByteArray = folderCursor.getBlob(folderCursor.getColumnIndex(BookmarksDatabaseHelper.FAVORITE_ICON));
-
- // Convert the byte array to a bitmap beginning at the first byte and ending at the last.
- Bitmap currentIconBitmap = BitmapFactory.decodeByteArray(currentIconByteArray, 0, currentIconByteArray.length);
-
- // Display the current icon bitmap.
- currentIconImageView.setImageBitmap(currentIconBitmap);
-
- // Set the new favorite icon bitmap.
- webPageFavoriteIconImageView.setImageBitmap(favoriteIconBitmap);
-
- // Get the current folder name.
- String currentFolderName = folderCursor.getString(folderCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME));
-
- // Display the current folder name in `edit_folder_name_edittext`.
- folderNameEditText.setText(currentFolderName);
-
- // Update the status of the edit button when the folder name is changed.
- folderNameEditText.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- // Do nothing.
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- // Do nothing.
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- // Convert the current text to a string.
- String newFolderName = s.toString();
-
- // Get a cursor for the new folder name if it exists.
- Cursor folderExistsCursor = bookmarksDatabaseHelper.getFolder(newFolderName);
-
- // Is the new folder name empty?
- boolean folderNameNotEmpty = !newFolderName.isEmpty();
-
- // Does the folder name already exist?
- boolean folderNameAlreadyExists = (!newFolderName.equals(currentFolderName) && (folderExistsCursor.getCount() > 0));
-
- // Has the folder been renamed?
- boolean folderRenamed = (!newFolderName.equals(currentFolderName) && !folderNameAlreadyExists);
-
- // Has the favorite icon changed?
- boolean iconChanged = (!currentIconRadioButton.isChecked() && !folderNameAlreadyExists);
-
- // Enable the create button if something has been edited and the new folder name is valid.
- editButton.setEnabled(folderNameNotEmpty && (folderRenamed || iconChanged));
- }
- });
-
- // Update the status of the edit button when the icon is changed.
- iconRadioGroup.setOnCheckedChangeListener((RadioGroup group, int checkedId) -> {
- // Get the new folder name.
- String newFolderName = folderNameEditText.getText().toString();
-
- // Get a cursor for the new folder name if it exists.
- Cursor folderExistsCursor = bookmarksDatabaseHelper.getFolder(newFolderName);
-
- // Is the new folder name empty?
- boolean folderNameEmpty = newFolderName.isEmpty();
-
- // Does the folder name already exist?
- boolean folderNameAlreadyExists = (!newFolderName.equals(currentFolderName) && (folderExistsCursor.getCount() > 0));
-
- // Has the folder been renamed?
- boolean folderRenamed = (!newFolderName.equals(currentFolderName) && !folderNameAlreadyExists);
-
- // Has the favorite icon changed?
- boolean iconChanged = (!currentIconRadioButton.isChecked() && !folderNameAlreadyExists);
-
- // Enable the create button if something has been edited and the new folder name is valid.
- editButton.setEnabled(!folderNameEmpty && (folderRenamed || iconChanged));
- });
-
- // Allow the `enter` key on the keyboard to save the bookmark from `edit_bookmark_name_edittext`.
- folderNameEditText.setOnKeyListener((View v, int keyCode, KeyEvent event) -> {
- // If the event is a key-down on the "enter" button, select the PositiveButton `Save`.
- if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER) && editButton.isEnabled()) { // The enter key was pressed and the edit button is enabled.
- // Trigger `editBookmarkListener` and return the DialogFragment to the parent activity.
- editBookmarkFolderListener.onSaveBookmarkFolder(this, selectedFolderDatabaseId, favoriteIconBitmap);
-
- // Manually dismiss the `AlertDialog`.
- alertDialog.dismiss();
-
- // Consume the event.
- return true;
- } else { // If any other key was pressed, or if the edit button is currently disabled, do not consume the event.
- return false;
- }
- });
-
- // `onCreateDialog` requires the return of an `AlertDialog`.
- return alertDialog;
- }
-}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser 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 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. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.stoutner.privacybrowser.dialogs
+
+import android.annotation.SuppressLint
+import android.app.Dialog
+import android.content.Context
+import android.content.DialogInterface
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.os.Bundle
+import android.text.Editable
+import android.text.TextWatcher
+import android.view.KeyEvent
+import android.view.View
+import android.view.WindowManager
+import android.widget.Button
+import android.widget.EditText
+import android.widget.ImageView
+import android.widget.RadioButton
+import android.widget.RadioGroup
+
+import androidx.appcompat.app.AlertDialog
+import androidx.fragment.app.DialogFragment
+import androidx.preference.PreferenceManager
+
+import com.stoutner.privacybrowser.R
+import com.stoutner.privacybrowser.helpers.BookmarksDatabaseHelper
+
+import java.io.ByteArrayOutputStream
+
+// Declare the class constants.
+private const val DATABASE_ID = "database_id"
+private const val FAVORITE_ICON_BYTE_ARRAY = "favorite_icon_byte_array"
+
+class EditBookmarkFolderDialog: DialogFragment() {
+ // The public interface is used to send information back to the parent activity.
+ interface EditBookmarkFolderListener {
+ fun onSaveBookmarkFolder(dialogFragment: DialogFragment?, selectedFolderDatabaseId: Int, favoriteIconBitmap: Bitmap?)
+ }
+
+ // Declare the class variables.
+ private lateinit var editBookmarkFolderListener: EditBookmarkFolderListener
+ private lateinit var bookmarksDatabaseHelper: BookmarksDatabaseHelper
+ private lateinit var currentFolderName: String
+
+ // Declare the class views.
+ private lateinit var currentIconRadioButton: RadioButton
+ private lateinit var folderNameEditText: EditText
+ private lateinit var saveButton: Button
+
+ override fun onAttach(context: Context) {
+ // Run the default commands.
+ super.onAttach(context)
+
+ // Get a handle for the edit bookmark folder listener from the launching context.
+ editBookmarkFolderListener = context as EditBookmarkFolderListener
+ }
+
+ companion object {
+ // `@JvmStatic` will no longer be required once all the code has transitioned to Kotlin. Also, the function can then be moved out of a companion object and just become a package-level function.
+ @JvmStatic
+ fun folderDatabaseId(databaseId: Int, favoriteIconBitmap: Bitmap): EditBookmarkFolderDialog {
+ // Create a favorite icon byte array output stream.
+ val favoriteIconByteArrayOutputStream = ByteArrayOutputStream()
+
+ // Convert the favorite icon to a PNG and place it in the byte array output stream. `0` is for lossless compression (the only option for a PNG).
+ favoriteIconBitmap.compress(Bitmap.CompressFormat.PNG, 0, favoriteIconByteArrayOutputStream)
+
+ // Convert the byte array output stream to a byte array.
+ val favoriteIconByteArray = favoriteIconByteArrayOutputStream.toByteArray()
+
+ // Create an arguments bundle
+ val argumentsBundle = Bundle()
+
+ // Store the variables in the bundle.
+ argumentsBundle.putInt(DATABASE_ID, databaseId)
+ argumentsBundle.putByteArray(FAVORITE_ICON_BYTE_ARRAY, favoriteIconByteArray)
+
+ // Create a new instance of the dialog.
+ val editBookmarkFolderDialog = EditBookmarkFolderDialog()
+
+ // Add the arguments bundle to the dialog.
+ editBookmarkFolderDialog.arguments = argumentsBundle
+
+ // Return the new dialog.
+ return editBookmarkFolderDialog
+ }
+ }
+
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
+ @SuppressLint("InflateParams")
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ // Get a handle for the arguments.
+ val arguments = requireArguments()
+
+ // Get the variables from the arguments.
+ val selectedFolderDatabaseId = arguments.getInt(DATABASE_ID)
+ val favoriteIconByteArray = arguments.getByteArray(FAVORITE_ICON_BYTE_ARRAY)!!
+
+ // Convert the favorite icon byte array to a bitmap.
+ val favoriteIconBitmap = BitmapFactory.decodeByteArray(favoriteIconByteArray, 0, favoriteIconByteArray.size)
+
+ // Initialize the database helper. The `0` specifies a database version, but that is ignored and set instead using a constant in `BookmarksDatabaseHelper`.
+ bookmarksDatabaseHelper = BookmarksDatabaseHelper(context, null, null, 0)
+
+ // Get a cursor with the selected folder.
+ val folderCursor = bookmarksDatabaseHelper.getBookmark(selectedFolderDatabaseId)
+
+ // Move the cursor to the first position.
+ folderCursor.moveToFirst()
+
+ // Use an alert dialog builder to create the alert dialog.
+ val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
+
+ // Set the title.
+ dialogBuilder.setTitle(R.string.edit_folder)
+
+ // Set the view. The parent view is `null` because it will be assigned by `AlertDialog`.
+ dialogBuilder.setView(requireActivity().layoutInflater.inflate(R.layout.edit_bookmark_folder_dialog, null))
+
+ // Set the cancel button listener. Using `null` as the listener closes the dialog without doing anything else.
+ dialogBuilder.setNegativeButton(R.string.cancel, null)
+
+ // Set the save button listener.
+ dialogBuilder.setPositiveButton(R.string.save) { _: DialogInterface?, _: Int ->
+ // Return the dialog fragment to the parent activity on save.
+ editBookmarkFolderListener.onSaveBookmarkFolder(this, selectedFolderDatabaseId, favoriteIconBitmap)
+ }
+
+ // Create an alert dialog from the alert dialog builder.
+ val alertDialog = dialogBuilder.create()
+
+ // Get a handle for the shared preferences.
+ val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
+
+ // 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)
+ }
+
+ // The alert dialog must be shown before items in the layout can be modified.
+ alertDialog.show()
+
+ // Get handles for the views in the alert dialog.
+ val iconRadioGroup = alertDialog.findViewById<RadioGroup>(R.id.edit_folder_icon_radio_group)!!
+ currentIconRadioButton = alertDialog.findViewById(R.id.edit_folder_current_icon_radiobutton)!!
+ val currentIconImageView = alertDialog.findViewById<ImageView>(R.id.edit_folder_current_icon_imageview)!!
+ val webPageFavoriteIconImageView = alertDialog.findViewById<ImageView>(R.id.edit_folder_web_page_favorite_icon_imageview)!!
+ folderNameEditText = alertDialog.findViewById(R.id.edit_folder_name_edittext)!!
+ saveButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE)
+
+ // Get the current favorite icon byte array from the cursor.
+ val currentIconByteArray = folderCursor.getBlob(folderCursor.getColumnIndex(BookmarksDatabaseHelper.FAVORITE_ICON))
+
+ // Convert the byte array to a bitmap beginning at the first byte and ending at the last.
+ val currentIconBitmap = BitmapFactory.decodeByteArray(currentIconByteArray, 0, currentIconByteArray.size)
+
+ // Display the current icon bitmap.
+ currentIconImageView.setImageBitmap(currentIconBitmap)
+
+ // Set the new favorite icon bitmap.
+ webPageFavoriteIconImageView.setImageBitmap(favoriteIconBitmap)
+
+ // Get the current folder name.
+ currentFolderName = folderCursor.getString(folderCursor.getColumnIndex(BookmarksDatabaseHelper.BOOKMARK_NAME))
+
+ // Display the current folder name.
+ folderNameEditText.setText(currentFolderName)
+
+ // Initially disable the save button.
+ saveButton.isEnabled = false
+
+ // Update the status of the save button when the folder name is changed.
+ folderNameEditText.addTextChangedListener(object: TextWatcher {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+ // Do nothing.
+ }
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+ // Do nothing.
+ }
+
+ override fun afterTextChanged(s: Editable) {
+ // Update the save button.
+ updateSaveButton()
+ }
+ })
+
+ // Update the status of the save button when the icon is changed.
+ iconRadioGroup.setOnCheckedChangeListener { _: RadioGroup?, _: Int ->
+ // Update the save button.
+ updateSaveButton()
+ }
+
+ // Allow the enter key on the keyboard to save the bookmark from the edit bookmark name edit text.
+ folderNameEditText.setOnKeyListener { _: View?, keyCode: Int, event: KeyEvent ->
+ // Check the key code, event, and button status.
+ if (event.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER && saveButton.isEnabled) { // The enter key was pressed and the save button is enabled.
+ // Trigger the listener and return the dialog fragment to the parent activity.
+ editBookmarkFolderListener.onSaveBookmarkFolder(this, selectedFolderDatabaseId, favoriteIconBitmap)
+
+ // Manually dismiss the the alert dialog.
+ alertDialog.dismiss()
+
+ // Consume the event.
+ return@setOnKeyListener true
+ } else { // If any other key was pressed, or if the save button is currently disabled, do not consume the event.
+ return@setOnKeyListener false
+ }
+ }
+
+ // Return the alert dialog.
+ return alertDialog
+ }
+
+ private fun updateSaveButton() {
+ // Get the new folder name.
+ val newFolderName = folderNameEditText.text.toString()
+
+ // Get a cursor for the new folder name if it exists.
+ val folderExistsCursor = bookmarksDatabaseHelper.getFolder(newFolderName)
+
+ // Is the new folder name empty?
+ val folderNameEmpty = newFolderName.isEmpty()
+
+ // Does the folder name already exist?
+ val folderNameAlreadyExists = (newFolderName != currentFolderName) && folderExistsCursor.count > 0
+
+ // Has the folder been renamed?
+ val folderRenamed = (newFolderName != currentFolderName) && !folderNameAlreadyExists
+
+ // Has the favorite icon changed?
+ val iconChanged = !currentIconRadioButton.isChecked && !folderNameAlreadyExists
+
+ // Enable the save button if something has been edited and the new folder name is valid.
+ saveButton.isEnabled = !folderNameEmpty && (folderRenamed || iconChanged)
+ }
+}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright © 2019-2020 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
- *
- * Privacy Browser 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 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. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.stoutner.privacybrowser.dialogs;
-
-import android.annotation.SuppressLint;
-import android.app.Activity;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.SharedPreferences;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.EditText;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.DialogFragment;
-import androidx.preference.PreferenceManager;
-
-import com.stoutner.privacybrowser.R;
-
-public class FontSizeDialog extends DialogFragment {
- // Define the update font size listener.
- private UpdateFontSizeListener updateFontSizeListener;
-
- // The public interface is used to send information back to the parent activity.
- public interface UpdateFontSizeListener {
- void onApplyNewFontSize(DialogFragment dialogFragment);
- }
-
- @Override
- public void onAttach(@NonNull Context context) {
- // Run the default commands.
- super.onAttach(context);
-
- // Get a handle for the update font size listener from the launching context.
- updateFontSizeListener = (UpdateFontSizeListener) context;
- }
-
- public static FontSizeDialog displayDialog(int fontSize) {
- // Create an arguments bundle.
- Bundle argumentsBundle = new Bundle();
-
- // Store the font size in the bundle.
- argumentsBundle.putInt("font_size", fontSize);
-
- // Create a new instance of the dialog.
- FontSizeDialog fontSizeDialog = new FontSizeDialog();
-
- // Add the bundle to the dialog.
- fontSizeDialog.setArguments(argumentsBundle);
-
- // Return the new dialog.
- return fontSizeDialog;
- }
-
- // `@SuppressLing("InflateParams")` removes the warning about using null as the parent view group when inflating the alert dialog.
- @SuppressLint("InflateParams")
- @Override
- @NonNull
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- // Get a handle for the activity and the context.
- Activity activity = getActivity();
- Context context = getContext();
-
- // Remove the incorrect lint warnings below that the activity and context might be null.
- assert activity != null;
- assert context != null;
-
- // Get the arguments.
- Bundle arguments = getArguments();
-
- // Remove the incorrect lint warning below that `getInt()` might be null.
- assert arguments != null;
-
- // Get the current font size.
- int currentFontSize = arguments.getInt("font_size");
-
- // Use a builder to create the alert dialog.
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context, R.style.PrivacyBrowserAlertDialog);
-
- // Get the current theme status.
- int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
-
- // Set the icon according to the theme.
- if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
- dialogBuilder.setIcon(R.drawable.font_size_night);
- } else {
- dialogBuilder.setIcon(R.drawable.font_size_day);
- }
-
- // Set the title.
- dialogBuilder.setTitle(R.string.font_size);
-
- // Set the view. The parent view is null because it will be assigned by the alert dialog.
- dialogBuilder.setView(activity.getLayoutInflater().inflate(R.layout.font_size_dialog, null));
-
- // Set the close button listener. Using `null` as the listener closes the dialog without doing anything else.
- dialogBuilder.setNegativeButton(R.string.close, null);
-
- // Set the apply button listener.
- dialogBuilder.setPositiveButton(R.string.apply, (DialogInterface dialog, int which) -> {
- // Return the dialog fragment to the parent activity.
- updateFontSizeListener.onApplyNewFontSize(this);
- });
-
- // Create an alert dialog from the builder.
- AlertDialog alertDialog = dialogBuilder.create();
-
- // Get the alert dialog window.
- Window dialogWindow = alertDialog.getWindow();
-
- // Remove the incorrect lint warning below that the dialog window might be null.
- assert dialogWindow != null;
-
- // Get a handle for the shared preferences.
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
-
- // Get the screenshot preferences.
- boolean allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false);
-
- // Disable screenshots if not allowed.
- if (!allowScreenshots) {
- dialogWindow.addFlags(WindowManager.LayoutParams.FLAG_SECURE);
- }
-
- // Display the keyboard.
- dialogWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
-
- // The alert dialog must be shown before items in the layout can be modified.
- alertDialog.show();
-
- // Get a handle for the font size edit text.
- EditText fontSizeEditText = alertDialog.findViewById(R.id.font_size_edittext);
-
- // Remove the incorrect lint warning below that the edit text might be null.
- assert fontSizeEditText != null;
-
- // Display the current font size.
- fontSizeEditText.setText(String.valueOf(currentFontSize));
-
- // Request focus on the font size edit text.
- fontSizeEditText.requestFocus();
-
- // Set the enter key on the keyboard to update the font size.
- fontSizeEditText.setOnKeyListener((View view, int keyCode, KeyEvent keyEvent) -> {
- // If the key event is a key-down on the `enter` key apply the new font size.
- if ((keyEvent.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) { // The enter key was pressed.
- // Trigger the update font size listener and return the dialog fragment to the parent activity.
- updateFontSizeListener.onApplyNewFontSize((this));
-
- // Manually dismiss the alert dialog.
- alertDialog.dismiss();
-
- //Consume the event.
- return true;
- } else { // If any other key was pressed do not consume the event.
- return false;
- }
- });
-
- // Return the alert dialog.
- return alertDialog;
- }
-}
--- /dev/null
+/*
+ * Copyright © 2019-2020 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser 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 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. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.stoutner.privacybrowser.dialogs
+
+import android.annotation.SuppressLint
+import android.app.Dialog
+import android.content.Context
+import android.content.DialogInterface
+import android.content.res.Configuration
+import android.os.Bundle
+import android.view.KeyEvent
+import android.view.View
+import android.view.WindowManager
+import android.widget.EditText
+
+import androidx.appcompat.app.AlertDialog
+import androidx.fragment.app.DialogFragment
+import androidx.preference.PreferenceManager
+
+import com.stoutner.privacybrowser.R
+
+// Declare the class constants.
+private const val FONT_SIZE = "font_size"
+
+class FontSizeDialog: DialogFragment() {
+ // The public interface is used to send information back to the parent activity.
+ interface UpdateFontSizeListener {
+ fun onApplyNewFontSize(dialogFragment: DialogFragment?)
+ }
+
+ // Declare the class variables.
+ private lateinit var updateFontSizeListener: UpdateFontSizeListener
+
+ override fun onAttach(context: Context) {
+ // Run the default commands.
+ super.onAttach(context)
+
+ // Get a handle for the update font size listener from the launching context.
+ updateFontSizeListener = context as UpdateFontSizeListener
+ }
+
+ companion object {
+ // `@JvmStatic` will no longer be required once all the code has transitioned to Kotlin. Also, the function can then be moved out of a companion object and just become a package-level function.
+ @JvmStatic
+ fun displayDialog(fontSize: Int): FontSizeDialog {
+ // Create an arguments bundle.
+ val argumentsBundle = Bundle()
+
+ // Store the font size in the bundle.
+ argumentsBundle.putInt(FONT_SIZE, fontSize)
+
+ // Create a new instance of the dialog.
+ val fontSizeDialog = FontSizeDialog()
+
+ // Add the bundle to the dialog.
+ fontSizeDialog.arguments = argumentsBundle
+
+ // Return the new dialog.
+ return fontSizeDialog
+ }
+ }
+
+ // `@SuppressLint("InflateParams")` removes the warning about using null as the parent view group when inflating the alert dialog.
+ @SuppressLint("InflateParams")
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ // Get the current font size from the arguments.
+ val currentFontSize = requireArguments().getInt(FONT_SIZE)
+
+ // Use a builder to create the alert dialog.
+ val dialogBuilder = AlertDialog.Builder(requireContext(), R.style.PrivacyBrowserAlertDialog)
+
+ // Get the current theme status.
+ val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
+
+ // Set the icon according to the theme.
+ if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
+ dialogBuilder.setIcon(R.drawable.font_size_day)
+ } else {
+ dialogBuilder.setIcon(R.drawable.font_size_night)
+ }
+
+ // Set the title.
+ dialogBuilder.setTitle(R.string.font_size)
+
+ // Set the view. The parent view is null because it will be assigned by the alert dialog.
+ dialogBuilder.setView(requireActivity().layoutInflater.inflate(R.layout.font_size_dialog, null))
+
+ // Set the close button listener. Using `null` as the listener closes the dialog without doing anything else.
+ dialogBuilder.setNegativeButton(R.string.close, null)
+
+ // Set the apply button listener.
+ dialogBuilder.setPositiveButton(R.string.apply) { _: DialogInterface?, _: Int ->
+ // Return the dialog fragment to the parent activity.
+ updateFontSizeListener.onApplyNewFontSize(this)
+ }
+
+ // Create an alert dialog from the builder.
+ val alertDialog = dialogBuilder.create()
+
+ // Get the alert dialog window.
+ val dialogWindow = alertDialog.window!!
+
+ // Get a handle for the shared preferences.
+ val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
+
+ // Get the screenshot preferences.
+ val allowScreenshots = sharedPreferences.getBoolean(getString(R.string.allow_screenshots_key), false)
+
+ // Disable screenshots if not allowed.
+ if (!allowScreenshots) {
+ dialogWindow.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
+ }
+
+ // Display the keyboard.
+ dialogWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
+
+ // The alert dialog must be shown before items in the layout can be modified.
+ alertDialog.show()
+
+ // Get a handle for the font size edit text.
+ val fontSizeEditText = alertDialog.findViewById<EditText>(R.id.font_size_edittext)!!
+
+ // Display the current font size.
+ fontSizeEditText.setText(currentFontSize.toString())
+
+ // Request focus on the font size edit text.
+ fontSizeEditText.requestFocus()
+
+ // Set the enter key on the keyboard to update the font size.
+ fontSizeEditText.setOnKeyListener { _: View?, keyCode: Int, keyEvent: KeyEvent ->
+ // Check the key code, event, and button status.
+ if (keyEvent.action == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_ENTER) { // The enter key was pressed.
+ // Trigger the update font size listener and return the dialog fragment to the parent activity.
+ updateFontSizeListener.onApplyNewFontSize(this)
+
+ // Manually dismiss the alert dialog.
+ alertDialog.dismiss()
+
+ //Consume the event.
+ return@setOnKeyListener true
+ } else { // If any other key was pressed do not consume the event.
+ return@setOnKeyListener false
+ }
+ }
+
+ // Return the alert dialog.
+ return alertDialog
+ }
+}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright © 2017-2020 Soren Stoutner <soren@stoutner.com>.
- *
- * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
- *
- * Privacy Browser 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 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. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package com.stoutner.privacybrowser.dialogs;
-
-import android.annotation.SuppressLint;
-import android.app.Dialog;
-import android.content.DialogInterface;
-import android.content.SharedPreferences;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
-import android.text.style.ForegroundColorSpan;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.webkit.HttpAuthHandler;
-import android.widget.EditText;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
-import androidx.fragment.app.DialogFragment;
-
-import com.stoutner.privacybrowser.R;
-import com.stoutner.privacybrowser.activities.MainWebViewActivity;
-import com.stoutner.privacybrowser.fragments.WebViewTabFragment;
-import com.stoutner.privacybrowser.views.NestedScrollWebView;
-
-public class HttpAuthenticationDialog extends DialogFragment{
- // Define the class variables.
- private EditText usernameEditText;
- private EditText passwordEditText;
-
- public static HttpAuthenticationDialog displayDialog(String host, String realm, long webViewFragmentId) {
- // Create an arguments bundle.
- Bundle argumentsBundle = new Bundle();
-
- // Store the variables in the bundle.
- argumentsBundle.putString("host", host);
- argumentsBundle.putString("realm", realm);
- argumentsBundle.putLong("webview_fragment_id", webViewFragmentId);
-
- // Create a new instance of the HTTP authentication dialog.
- HttpAuthenticationDialog thisHttpAuthenticationDialog = new HttpAuthenticationDialog();
-
- // Add the arguments bundle to the new dialog.
- thisHttpAuthenticationDialog.setArguments(argumentsBundle);
-
- // Return the new dialog.
- return thisHttpAuthenticationDialog;
- }
-
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
- @SuppressLint("InflateParams")
- @Override
- @NonNull
- public Dialog onCreateDialog(Bundle savedInstanceState) {
- // Get a handle for the arguments.
- Bundle arguments = getArguments();
-
- // Remove the incorrect lint warning below that arguments might be null.
- assert arguments != null;
-
- // Get the variables from the bundle.
- String httpAuthHost = arguments.getString("host");
- String httpAuthRealm = arguments.getString("realm");
- long webViewFragmentId = arguments.getLong("webview_fragment_id");
-
- // Get the current position of this WebView fragment.
- int webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(webViewFragmentId);
-
- // Get the WebView tab fragment.
- WebViewTabFragment webViewTabFragment = MainWebViewActivity.webViewPagerAdapter.getPageFragment(webViewPosition);
-
- // Get the fragment view.
- View fragmentView = webViewTabFragment.getView();
-
- // Remove the incorrect lint warning below that the fragment view might be null.
- assert fragmentView != null;
-
- // Get a handle for the current WebView.
- NestedScrollWebView nestedScrollWebView = fragmentView.findViewById(R.id.nestedscroll_webview);
-
- // Get a handle for the HTTP authentication handler.
- HttpAuthHandler httpAuthHandler = nestedScrollWebView.getHttpAuthHandler();
-
- // Remove the incorrect lint warning that `getActivity()` might be null.
- assert getActivity() != null;
-
- // Get the activity's layout inflater.
- LayoutInflater layoutInflater = getActivity().getLayoutInflater();
-
- // Use an alert dialog builder to create the alert dialog.
- AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getActivity(), R.style.PrivacyBrowserAlertDialog);
-
- // Get the current theme status.
- int currentThemeStatus = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
-
- // Set the icon according to the theme.
- if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
- dialogBuilder.setIcon(R.drawable.lock_night);
- } else {
- dialogBuilder.setIcon(R.drawable.lock_day);
- }
-
- // Set the title.
- dialogBuilder.setTitle(R.string.http_authentication);
-
- // Set the layout. The parent view is `null` because it will be assigned by `AlertDialog`.
- dialogBuilder.setView(layoutInflater.inflate(R.layout.http_authentication_dialog, null));
-
- // Setup the close button.
- dialogBuilder.setNegativeButton(R.string.close, (DialogInterface dialog, int which) -> {
- // Cancel the HTTP authentication request.
- httpAuthHandler.cancel();
-
- // Reset the HTTP authentication handler.
- nestedScrollWebView.resetHttpAuthHandler();
- });
-
- // Setup the proceed button.
- dialogBuilder.setPositiveButton(R.string.proceed, (DialogInterface dialog, int which) -> {
- // Send the login information
- login(httpAuthHandler);
-
- // Reset the HTTP authentication handler.
- nestedScrollWebView.resetHttpAuthHandler();
- });
-
- // Create an alert dialog from the alert dialog builder.
- final AlertDialog alertDialog = dialogBuilder.create();
-
- // Get the alert dialog window.
- Window dialogWindow = alertDialog.getWindow();
-
- // Remove the incorrect lint warning below that the dialog window might be null.
- assert dialogWindow != null;
-
- // Get a handle for the shared preferences.
- SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
-
- // Get the screenshot preference.
- boolean allowScreenshots = sharedPreferences.getBoolean("allow_screenshots", false);
-
- // Disable screenshots if not allowed.
- if (!allowScreenshots) {
- alertDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
- }
-
- // Display the keyboard.
- dialogWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
-
- // The alert dialog needs to be shown before the contents can be modified.
- alertDialog.show();
-
- // Get handles for the views.
- TextView realmTextView = alertDialog.findViewById(R.id.http_authentication_realm);
- TextView hostTextView = alertDialog.findViewById(R.id.http_authentication_host);
- usernameEditText = alertDialog.findViewById(R.id.http_authentication_username);
- passwordEditText = alertDialog.findViewById(R.id.http_authentication_password);
-
- // Remove the incorrect lint warnings below that the views might be null.
- assert realmTextView != null;
- assert hostTextView != null;
-
- // Set the realm text.
- realmTextView.setText(httpAuthRealm);
-
- // Set the realm text color according to the theme. The deprecated `getResources()` must be used until API >= 23.
- if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
- realmTextView.setTextColor(getResources().getColor(R.color.gray_300));
- } else {
- realmTextView.setTextColor(getResources().getColor(R.color.black));
- }
-
- // Initialize the host label and the `SpannableStringBuilder`.
- String hostLabel = getString(R.string.host) + " ";
- SpannableStringBuilder hostStringBuilder = new SpannableStringBuilder(hostLabel + httpAuthHost);
-
- // Create a blue `ForegroundColorSpan`.
- ForegroundColorSpan blueColorSpan;
-
- // Set the blue color span according to the theme. The deprecated `getResources()` must be used until API >= 23.
- if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
- blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.violet_500));
- } else {
- blueColorSpan = new ForegroundColorSpan(getResources().getColor(R.color.blue_700));
- }
-
- // Setup the span to display the host name in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
- hostStringBuilder.setSpan(blueColorSpan, hostLabel.length(), hostStringBuilder.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
-
- // Set the host text.
- hostTextView.setText(hostStringBuilder);
-
- // Allow the `enter` key on the keyboard to trigger `onHttpAuthenticationProceed` from `usernameEditText`.
- usernameEditText.setOnKeyListener((View view, int keyCode, KeyEvent event) -> {
- // If the event is a key-down on the `enter` key, call `onHttpAuthenticationProceed()`.
- if ((keyCode == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) {
- // Send the login information.
- login(httpAuthHandler);
-
- // Manually dismiss the alert dialog.
- alertDialog.dismiss();
-
- // Consume the event.
- return true;
- } else { // If any other key was pressed, do not consume the event.
- return false;
- }
- });
-
- // Allow the `enter` key on the keyboard to trigger `onHttpAuthenticationProceed()` from `passwordEditText`.
- passwordEditText.setOnKeyListener((View view, int keyCode, KeyEvent event) -> {
- // If the event is a key-down on the `enter` key, call `onHttpAuthenticationProceed()`.
- if ((keyCode == KeyEvent.KEYCODE_ENTER) && (event.getAction() == KeyEvent.ACTION_DOWN)) {
- // Send the login information.
- login(httpAuthHandler);
-
- // Manually dismiss the alert dialog.
- alertDialog.dismiss();
-
- // Consume the event.
- return true;
- } else { // If any other key was pressed, do not consume the event.
- return false;
- }
- });
-
- // Return the alert dialog.
- return alertDialog;
- }
-
- private void login(HttpAuthHandler httpAuthHandler) {
- // Send the login information.
- httpAuthHandler.proceed(usernameEditText.getText().toString(), passwordEditText.getText().toString());
- }
-}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright © 2017-2020 Soren Stoutner <soren@stoutner.com>.
+ *
+ * This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+ *
+ * Privacy Browser 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 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. If not, see <http://www.gnu.org/licenses/>.
+ */
+package com.stoutner.privacybrowser.dialogs
+
+import android.annotation.SuppressLint
+import android.app.Dialog
+import android.content.DialogInterface
+import android.content.res.Configuration
+import android.os.Bundle
+import android.text.SpannableStringBuilder
+import android.text.Spanned
+import android.text.style.ForegroundColorSpan
+import android.view.KeyEvent
+import android.view.View
+import android.view.WindowManager
+import android.webkit.HttpAuthHandler
+import android.widget.EditText
+import android.widget.TextView
+
+import androidx.appcompat.app.AlertDialog
+import androidx.fragment.app.DialogFragment
+import androidx.preference.PreferenceManager
+
+import com.stoutner.privacybrowser.R
+import com.stoutner.privacybrowser.activities.MainWebViewActivity
+import com.stoutner.privacybrowser.views.NestedScrollWebView
+
+// Declare the class constants.
+private const val HOST = "host"
+private const val REALM = "realm"
+private const val WEBVIEW_FRAGMENT_ID = "webview_fragment_id"
+
+class HttpAuthenticationDialog: DialogFragment() {
+ // Define the class variables.
+ private var dismissDialog: Boolean = false
+
+ // Define the class views.
+ private lateinit var usernameEditText: EditText
+ private lateinit var passwordEditText: EditText
+
+ companion object {
+ // `@JvmStatic` will no longer be required once all the code has transitioned to Kotlin. Also, the function can then be moved out of a companion object and just become a package-level function.
+ @JvmStatic
+ fun displayDialog(host: String, realm: String, webViewFragmentId: Long): HttpAuthenticationDialog {
+ // Create an arguments bundle.
+ val argumentsBundle = Bundle()
+
+ // Store the variables in the bundle.
+ argumentsBundle.putString(HOST, host)
+ argumentsBundle.putString(REALM, realm)
+ argumentsBundle.putLong(WEBVIEW_FRAGMENT_ID, webViewFragmentId)
+
+ // Create a new instance of the HTTP authentication dialog.
+ val httpAuthenticationDialog = HttpAuthenticationDialog()
+
+ // Add the arguments bundle to the dialog.
+ httpAuthenticationDialog.arguments = argumentsBundle
+
+ // Return the new dialog.
+ return httpAuthenticationDialog
+ }
+ }
+
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
+ @SuppressLint("InflateParams")
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
+ // Get a handle for the arguments.
+ val arguments = requireArguments()
+
+ // Get the variables from the bundle.
+ val httpAuthHost = arguments.getString(HOST)
+ val httpAuthRealm = arguments.getString(REALM)
+ val webViewFragmentId = arguments.getLong(WEBVIEW_FRAGMENT_ID)
+
+ // Try to populate the alert dialog.
+ try { // Getting the WebView tab fragment will fail if Privacy Browser has been restarted.
+ // Get the current position of this WebView fragment.
+ val webViewPosition = MainWebViewActivity.webViewPagerAdapter.getPositionForId(webViewFragmentId)
+
+ // Get the WebView tab fragment.
+ val webViewTabFragment = MainWebViewActivity.webViewPagerAdapter.getPageFragment(webViewPosition)
+
+ // Get the fragment view.
+ val fragmentView = webViewTabFragment.requireView()
+
+ // Get a handle for the current WebView.
+ val nestedScrollWebView = fragmentView.findViewById<NestedScrollWebView>(R.id.nestedscroll_webview)
+
+ // Get a handle for the HTTP authentication handler.
+ val httpAuthHandler = nestedScrollWebView.httpAuthHandler
+
+ // Use an alert dialog builder to create the alert dialog.
+ val dialogBuilder = AlertDialog.Builder(requireActivity(), R.style.PrivacyBrowserAlertDialog)
+
+ // Get the current theme status.
+ val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
+
+ // Set the icon according to the theme.
+ if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
+ dialogBuilder.setIcon(R.drawable.lock_day)
+ } else {
+
+ dialogBuilder.setIcon(R.drawable.lock_night)
+ }
+
+ // Set the title.
+ dialogBuilder.setTitle(R.string.http_authentication)
+
+ // Get the activity's layout inflater.
+ val layoutInflater = requireActivity().layoutInflater
+
+ // Set the layout. The parent view is `null` because it will be assigned by the alert dialog.
+ dialogBuilder.setView(layoutInflater.inflate(R.layout.http_authentication_dialog, null))
+
+ // Set the close button listener.
+ dialogBuilder.setNegativeButton(R.string.close) { _: DialogInterface?, _: Int ->
+ // Cancel the HTTP authentication request.
+ httpAuthHandler.cancel()
+
+ // Reset the HTTP authentication handler.
+ nestedScrollWebView.resetHttpAuthHandler()
+ }// Set the proceed button listener.
+ dialogBuilder.setPositiveButton(R.string.proceed) { _: DialogInterface?, _: Int ->
+ // Send the login information
+ login(httpAuthHandler)
+
+ // Reset the HTTP authentication handler.
+ nestedScrollWebView.resetHttpAuthHandler()
+ }
+
+ // Create an alert dialog from the alert dialog builder.
+ val alertDialog = dialogBuilder.create()
+
+ // Get the alert dialog window.
+ val dialogWindow = alertDialog.window!!
+
+ // Get a handle for the shared preferences.
+ val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
+
+ // 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)
+ }
+
+ // Display the keyboard.
+ dialogWindow.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE)
+
+ // The alert dialog needs to be shown before the contents can be modified.
+ alertDialog.show()
+
+ // Get handles for the views.
+ val realmTextView = alertDialog.findViewById<TextView>(R.id.http_authentication_realm)!!
+ val hostTextView = alertDialog.findViewById<TextView>(R.id.http_authentication_host)!!
+ usernameEditText = alertDialog.findViewById(R.id.http_authentication_username)!!
+ passwordEditText = alertDialog.findViewById(R.id.http_authentication_password)!!
+
+ // Set the realm text.
+ realmTextView.text = httpAuthRealm
+
+ // Initialize the host label and the spannable string builder.
+ val hostLabel = getString(R.string.host) + " "
+ val hostStringBuilder = SpannableStringBuilder(hostLabel + httpAuthHost)
+
+ // Create a blue foreground color span.
+ val blueColorSpan: ForegroundColorSpan
+
+ // Set the blue color span according to the theme. The deprecated `getColor()` must be used until API >= 23.
+ blueColorSpan = if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
+ @Suppress("DEPRECATION")
+ ForegroundColorSpan(resources.getColor(R.color.blue_700))
+ } else {
+ @Suppress("DEPRECATION")
+ ForegroundColorSpan(resources.getColor(R.color.violet_500))
+ }
+
+ // Setup the span to display the host name in blue. `SPAN_INCLUSIVE_INCLUSIVE` allows the span to grow in either direction.
+ hostStringBuilder.setSpan(blueColorSpan, hostLabel.length, hostStringBuilder.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
+
+ // Set the host text.
+ hostTextView.text = hostStringBuilder
+
+ // Allow the enter key on the keyboard to send the login information from the username edit text.
+ usernameEditText.setOnKeyListener { _: View?, keyCode: Int, event: KeyEvent ->
+ // Check the key code and event.
+ if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN) { // The enter key was pressed.
+ // Send the login information.
+ login(httpAuthHandler)
+
+ // Manually dismiss the alert dialog.
+ alertDialog.dismiss()
+
+ // Consume the event.
+ return@setOnKeyListener true
+ } else { // If any other key was pressed, do not consume the event.
+ return@setOnKeyListener false
+ }
+ }
+
+ // Allow the enter key on the keyboard to send the login information from the password edit text.
+ passwordEditText.setOnKeyListener { _: View?, keyCode: Int, event: KeyEvent ->
+ // Check the key code and event.
+ if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN) { // The enter key was pressed.
+ // Send the login information.
+ login(httpAuthHandler)
+
+ // Manually dismiss the alert dialog.
+ alertDialog.dismiss()
+
+ // Consume the event.
+ return@setOnKeyListener true
+ } else { // If any other key was pressed, do not consume the event.
+ return@setOnKeyListener false
+ }
+ }
+
+ // Return the alert dialog.
+ return alertDialog
+ } catch (exception: Exception) { // Privacy Browser was restarted and the HTTP auth handler no longer exists.
+ // Use an alert dialog builder to create an empty alert dialog.
+ val dialogBuilder = AlertDialog.Builder(requireActivity(), R.style.PrivacyBrowserAlertDialog)
+
+ // Create an empty alert dialog from the alert dialog builder.
+ val alertDialog = dialogBuilder.create()
+
+ // Set the flag to dismiss the dialog as soon as it is resumed.
+ dismissDialog = true
+
+ // Return the alert dialog.
+ return alertDialog
+ }
+ }
+
+ override fun onResume() {
+ // Run the default command.
+ super.onResume()
+
+ // Dismiss the alert dialog if the activity was restarted and the HTTP auth handler no longer exists.
+ if (dismissDialog) {
+ dialog!!.dismiss()
+ }
+ }
+
+ private fun login(httpAuthHandler: HttpAuthHandler) {
+ // Send the login information.
+ httpAuthHandler.proceed(usernameEditText.text.toString(), passwordEditText.text.toString())
+ }
+}
\ No newline at end of file
moveToFolderListener = (MoveToFolderListener) context;
}
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
@SuppressLint("InflateParams")
@Override
@NonNull
return pinnedMismatchDialog;
}
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
@SuppressLint("InflateParams")
@Override
@NonNull
saveLogcatListener = (SaveLogcatListener) context;
}
- // `@SuppressLing("InflateParams")` removes the warning about using null as the parent view group when inflating the alert dialog.
+ // `@SuppressLint("InflateParams")` removes the warning about using null as the parent view group when inflating the alert dialog.
@SuppressLint("InflateParams")
@Override
@NonNull
return thisSslCertificateErrorDialog;
}
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
@SuppressLint("InflateParams")
@Override
@NonNull
@Override
@NonNull
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
@SuppressLint("InflateParams")
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Get the activity's layout inflater.
@Override
@NonNull
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the `AlertDialog`.
@SuppressLint("InflateParams")
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Remove the incorrect lint warning that `getInt()` might be null.
return viewSslCertificateDialog;
}
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
@SuppressLint("InflateParams")
@Override
@NonNull
import com.stoutner.privacybrowser.R;
public class WaitingForProxyDialog extends DialogFragment {
- // `@SuppressLing("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
+ // `@SuppressLint("InflateParams")` removes the warning about using `null` as the parent view group when inflating the alert dialog.
@SuppressLint("InflateParams")
@Override
@NonNull
final ForegroundColorSpan redColorSpan;
final ForegroundColorSpan blueColorSpan;
- // Set the color spans according to the theme. The deprecated `resources` must be used until the minimum API >= 23.
+ // Set the color spans according to the theme. The deprecated `getColor()` must be used until the minimum API >= 23.
if (currentThemeStatus == Configuration.UI_MODE_NIGHT_YES) {
redColorSpan = new ForegroundColorSpan(resources.getColor(R.color.red_900));
blueColorSpan = new ForegroundColorSpan(resources.getColor(R.color.violet_500));
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<!-- Setting `android:focusable` and `android:focusableInTouchMode` prevent `edit_bookmark_display_order_edittext` from being autoselected. -->
<LinearLayout
- xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical"
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright © 2016-2017,2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2017,2019-2020 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<LinearLayout
- xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical" >
</RadioGroup>
</LinearLayout>
- <!-- The `TextInputLayout` makes the `android:hint` float above the `EditText`. -->
+ <!-- The `TextInputLayout` makes the `android:hint` float above the edit text. -->
<com.google.android.material.textfield.TextInputLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp" >
- <!-- `android:imeOptions="actionGo"` sets the keyboard to have a `go` key instead of a `new line` key. `android:inputType="textUri"` disables spell check in the `EditText`. -->
+ <!-- `android:imeOptions="actionGo"` sets the keyboard to have a `go` key instead of a `new line` key. `android:inputType="textUri"` disables spell check in the edit text. -->
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_bookmark_name_edittext"
android:layout_height="wrap_content"
android:selectAllOnFocus="true" />
</com.google.android.material.textfield.TextInputLayout>
- <!-- The `TextInputLayout` makes the `android:hint` float above the `EditText`. -->
+ <!-- The `TextInputLayout` makes the `android:hint` float above the edit text. -->
<com.google.android.material.textfield.TextInputLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp" >
- <!-- `android:imeOptions="actionGo"` sets the keyboard to have a `go` key instead of a `new line` key. `android:inputType="textUri"` disables spell check in the `EditText`. -->
+ <!-- `android:imeOptions="actionGo"` sets the keyboard to have a `go` key instead of a `new line` key. `android:inputType="textUri"` disables spell check in the edit text. -->
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edit_bookmark_url_edittext"
android:layout_height="wrap_content"
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright © 2016-2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2020 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<!-- Setting `android:focusable` and `android:focusableInTouchMode` prevent `edit_bookmark_display_order_edittext` from being autoselected. -->
<LinearLayout
- xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical"
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright © 2016-2017,2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2016-2017,2019-2020 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content"
android:layout_width="match_parent" >
<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical" >
<?xml version="1.0" encoding="utf-8"?>
<!--
- Copyright © 2017,2019 Soren Stoutner <soren@stoutner.com>.
+ Copyright © 2017,2019-2020 Soren Stoutner <soren@stoutner.com>.
This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
android:layout_marginTop="12dp"
android:layout_gravity="center_horizontal"
android:textSize="26sp"
- android:textStyle="bold" />
+ android:textStyle="bold"
+ android:textColor="?android:textColorPrimary" />
<TextView
android:id="@+id/http_authentication_host"
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright © 2015-2020 Soren Stoutner <soren@stoutner.com>.
+
+ Translation 2020 Thiago Nazareno Conceição Silva de Jesus <mochileiro2006-trilhas@yahoo.com.br>. Copyright assigned to Soren Stoutner <soren@stoutner.com>.
+
+ This file is part of Privacy Browser <https://www.stoutner.com/privacy-browser>.
+
+ Privacy Browser 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 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. If not, see <http://www.gnu.org/licenses/>. -->
+
+<resources>
+ <!-- Activities. -->
+ <string name="privacy_browser">Navegador Privado</string>
+ <string name="short_name">Privado</string>
+ <!-- For translations, `android_asset_path` should be the localization abbreviation. For example, Spanish is `es`. This should not be translated unless the Guide and About sections are localized. -->
+ <!-- <string name="android_asset_path">pt-br</string> -->
+
+ <!-- MainWebView. -->
+ <string name="privacy_mode">Modo Privado</string>
+ <string name="javascript_enabled">JavaScript ativado</string>
+ <string name="javascript_disabled">JavaScript desativado</string>
+ <string name="first_party_cookies_enabled">Cookies primários habilitados</string>
+ <string name="first_party_cookies_disabled">Cookies primários desabilitados</string>
+ <string name="third_party_cookies_enabled">Cookies de terceiros habilitados</string>
+ <string name="third_party_cookies_disabled">Cookies de terceiros desabilitados</string>
+ <string name="dom_storage_enabled">Armazenamento DOM ativado</string>
+ <string name="dom_storage_disabled">Armazenamento DOM desativado</string>
+ <string name="form_data_enabled">Dados de formulário habilitados</string> <!-- The form data strings can be removed once the minimum API >= 26. -->
+ <string name="form_data_disabled">Dados de formulário desabilitados</string> <!-- The form data strings can be removed once the minimum API >= 26. -->
+ <string name="cookies_deleted">Cookies excluídos</string>
+ <string name="dom_storage_deleted">Armazenamento DOM excluído</string>
+ <string name="form_data_deleted">Dados do formulário excluídos</string>
+ <string name="open_navigation_drawer">Abrir a caixa de navegação</string>
+ <string name="close_navigation_drawer">Fechar a caixa de navegação</string>
+ <string name="unrecognized_url">URL desconhecida:</string>
+ <string name="add_tab">Adicionar aba</string>
+ <string name="close_tab">Fechar aba</string>
+ <string name="new_tab">Nova aba</string>
+ <string name="loading">Carregando...</string>
+ <string name="error">Erro:</string>
+ <string name="apply">Aplicar</string>
+
+ <!-- Loading Blocklists. -->
+ <string name="loading_easylist">Carregando EasyList</string>
+ <string name="loading_easyprivacy">Carregando EasyPrivacy</string>
+ <string name="loading_fanboys_annoyance_list">Carregando Fanboy’s Annoyance List</string>
+ <string name="loading_fanboys_social_blocking_list">Carregando Fanboy’s Social Blocking List</string>
+ <string name="loading_ultralist">Carregando UltraList</string>
+ <string name="loading_ultraprivacy">Carregando UltraPrivacy</string>
+
+ <!-- Custom App Bar. -->
+ <string name="favorite_icon">Ícone dos Favoritos</string>
+ <string name="url_or_search_terms">URL ou termos de pesquisa</string>
+
+ <!-- View SSL Certificate. -->
+ <string name="view_ssl_certificate">Ver certificado SSL</string>
+ <string name="unencrypted_website">Site não criptografado</string>
+ <string name="no_ssl_certificate">A comunicação com este site não é criptografada. Isso permite que terceiros interceptem informações, rastreiem sua navegação e insiram conteúdo malicioso.</string>
+ <string name="ssl_certificate">Certificado SSL</string>
+ <string name="close">Fecha</string>
+ <string name="domain">Domínio</string>
+ <string name="domain_label">Domínio:</string>
+ <string name="ip_addresses">Endereço de IP:</string>
+ <string name="issued_to">Emitido para</string>
+ <string name="issued_by">Emitido por</string>
+ <string name="common_name">Nome Comum:</string>
+ <string name="organization">Organização:</string>
+ <string name="organizational_unit">Unidade da Organização:</string>
+ <string name="valid_dates">Datas Válidas</string>
+ <string name="start_date">Data Inicial:</string>
+ <string name="end_date">Data Final:</string>
+
+ <!-- SSL Certificate Error. -->
+ <string name="ssl_certificate_error">Erro de certificado SSL</string>
+ <string name="proceed">Prosseguir</string>
+ <string name="future_certificate">A data de início do certificado está no futuro</string>
+ <string name="expired_certificate">O certificado expirou</string>
+ <string name="cn_mismatch">O nome comum não corresponde ao nome do host</string>
+ <string name="untrusted">A autoridade de certificação não é confiável</string>
+ <string name="invalid_date">A data do certificado é inválida</string>
+ <string name="invalid_certificate">O certificado é inválido</string>
+ <string name="url">URL</string>
+ <string name="url_label">URL:</string>
+
+ <!-- Pinned Mismatch. -->
+ <string name="pinned_mismatch">Incompatibilidade fixada</string>
+ <string name="update">Atualizar</string>
+ <string name="current">Atual</string>
+ <string name="pinned">Fixada</string>
+
+ <!-- HTTP Authentication. -->
+ <string name="http_authentication">Autenticação HTTP</string>
+ <string name="host">Host:</string>
+ <string name="username">Nome do usuário</string>
+ <string name="password">Senha</string>
+
+ <!-- MainWebViewActivity Navigation Menu. -->
+ <string name="navigation_drawer">Caixa de Navegação</string>
+ <string name="navigation">Navegação</string>
+ <string name="clear_and_exit">Limpar e fechar</string>
+ <string name="home">Início</string>
+ <string name="back">Fim</string>
+ <string name="forward">Avançar</string>
+ <string name="history">Histórico</string>
+ <string name="clear_history">Limpar Histórico</string>
+ <string name="open">Abrir</string>
+ <string name="downloads">Downloads</string>
+ <string name="settings">Configurações</string>
+ <string name="import_export">Importar/Exportar</string>
+ <string name="logcat">Logcat</string>
+ <string name="guide">Guia</string>
+ <string name="about">Sobre</string>
+
+ <!-- MainWebViewActivity Options Menu. -->
+ <string name="javascript">JavaScript</string>
+ <string name="refresh">Atualizar</string>
+ <string name="stop">Parar</string>
+ <string name="first_party_cookies">Cookies primários</string>
+ <string name="third_party_cookies">Cookies de terceiros</string>
+ <string name="dom_storage">Armazenamento DOM</string>
+ <string name="form_data">Dados do formulário</string> <!-- The form data strings can be removed once the minimum API >= 26. -->
+ <string name="clear_data">Limpar dados</string>
+ <string name="clear_cookies">Limpar Cookies</string>
+ <string name="clear_dom_storage">limpar Armazenamento DOM</string>
+ <string name="clear_form_data">Clear Form Data</string> <!-- The form data strings can be removed once the minimum API >= 26. -->
+ <string name="options_fanboys_annoyance_list">Lista de Aborrecimento Fanboy’s</string>
+ <string name="options_fanboys_social_blocking_list">Lista de bloqueio social Fanboy’s</string>
+ <string name="options_block_all_third_party_requests">Bloquear todas as solicitações de terceiros</string>
+ <string name="page">Página</string>
+ <string name="options_user_agent">User Agent</string>
+ <string name="user_agent_privacy_browser">Privacy Browser</string>
+ <string name="user_agent_webview_default">WebView Default</string>
+ <string name="user_agent_firefox_on_android">Firefox para Android</string>
+ <string name="user_agent_chrome_on_android">Chrome para Android</string>
+ <string name="user_agent_safari_on_ios">Safari para iOS</string>
+ <string name="user_agent_firefox_on_linux">Firefox para Linux</string>
+ <string name="user_agent_chromium_on_linux">Chromium para Linux</string>
+ <string name="user_agent_firefox_on_windows">Firefox para Windows</string>
+ <string name="user_agent_chrome_on_windows">Chrome para Windows</string>
+ <string name="user_agent_edge_on_windows">Edge para Windows</string>
+ <string name="user_agent_internet_explorer_on_windows">Internet Explorer para Windows</string>
+ <string name="user_agent_safari_on_macos">Safari para macOS</string>
+ <string name="user_agent_custom">Personalizado</string>
+ <string name="swipe_to_refresh_options_menu">Deslize para atualizar</string>
+ <string name="wide_viewport">Janela ampliada</string>
+ <string name="display_images">Exibir imagens</string>
+ <string name="dark_webview">Dark WebView</string>
+ <string name="font_size">Tamanho da Fonte</string>
+ <string name="find_on_page">Procurar</string>
+ <string name="print">Imprimir</string>
+ <string name="privacy_browser_web_page">Página da Web do Privacy Browser</string>
+ <string name="save">Salvar</string>
+ <string name="save_url">Salvar URL</string>
+ <string name="save_as_archive">Salvar como arquivo</string>
+ <string name="save_as_image">Salvar como imagem</string>
+ <string name="add_to_home_screen">Adicionar à tela inicial</string>
+ <string name="view_source">Ver fonte</string>
+ <string name="share">Compartilhar</string>
+ <string name="share_url">Compartilhar URL</string>
+ <string name="open_with_app">Abrir com aplicativo</string>
+ <string name="open_with_browser">Abrir com navegador</string>
+ <string name="add_domain_settings">Adicionar configurações de domínio</string>
+ <string name="edit_domain_settings">Editar configurações de domínio</string>
+
+ <!-- Context Menus. -->
+ <string name="open_in_new_tab">Abrir em nova aba</string>
+ <string name="open_in_background">Abrir em segundo plano</string>
+ <string name="open_image_in_new_tab">Abra a imagem em uma nova aba</string>
+ <string name="copy_url">Copiar URL</string>
+ <string name="email_address">Endereço de Email</string>
+ <string name="copy_email_address">Copiar Email Address</string>
+ <string name="write_email">Escrever Email</string>
+ <string name="view_image">Visualizar Imagem</string>
+
+ <!-- Find on Page. -->
+ <string name="previous">Anterior</string>
+ <string name="next">Próximo</string>
+
+ <!-- Save. -->
+ <string name="file_name">Nome do Arquivo</string>
+ <string name="save_archive">Salvar Arquivo</string>
+ <string name="save_image">Salvar Imagem</string>
+ <string name="webpage_mht">Pagina_Web.mht</string>
+ <string name="webpage_png">Pagina_Web.png</string>
+ <string name="file">Arquivo</string>
+ <string name="bytes">bytes</string>
+ <string name="unknown_size">tamanho desconhecido</string>
+ <string name="invalid_url">URL inválida</string>
+ <string name="ok">OK</string>
+ <string name="saving_file">Salvando file:</string>
+ <string name="saving_image">Salvando imagem:</string>
+ <string name="file_saved">Arquivo Salvo:</string>
+ <string name="image_saved">Imagem salva.</string>
+ <string name="error_saving_file">Erro ao salvar o arquivo:</string>
+ <string name="error_saving_image">Erro ao salvar a imagem:</string>
+
+ <!-- View Source. -->
+ <string name="request_headers">Solicitar cabeçalhos</string>
+ <string name="response_message">Mensagem de Resposta</string>
+ <string name="response_headers">Cabeçalhos de resposta</string>
+ <string name="response_body">Corpo de Resposta</string>
+ <string name="about_view_source">Sobre Ver Fonte</string>
+ <string name="about_view_source_message">Como o WebView do Android não expõe as informações de origem,
+ uma solicitação separada foi feita usando ferramentas do sistema para reunir as informações exibidas nesta atividade.
+ Pode haver algumas diferenças entre esses dados e aqueles usados pelo WebView na atividade principal. Essa limitação será removida na série 4.x com o lançamento do Privacy WebView.</string>
+
+ <!-- Create Home Screen Shortcut Alert Dialog. -->
+ <string name="create_shortcut">Criar atalho</string>
+ <string name="shortcut_name">Nome do atalho</string>
+ <string name="open_with_default_browser">Abrir com o navegador padrão.</string>
+ <string name="open_with_privacy_browser">Abrir com o Privacy Browser.</string>
+ <string name="cancel">Cancelar</string>
+ <string name="create">Criar</string>
+
+ <!-- Bookmarks. -->
+ <string name="bookmarks">Favoritos</string>
+ <string name="database_view">Visualização do banco de dados</string>
+ <string name="create_bookmark">Criar marcador</string>
+ <string name="create_folder">Criar pasta</string>
+ <string name="current_bookmark_icon">Ícone de favorito atual</string>
+ <string name="current_folder_icon">Ícone da pasta atual</string>
+ <string name="default_folder_icon">Ícone de pasta padrão</string>
+ <string name="web_page_favorite_icon">Ícone favorito da página da web</string>
+ <string name="bookmark_name">Nome do marcador</string>
+ <string name="folder_name">Nome da pasta</string>
+ <string name="bookmark_url">URL do favorito</string>
+ <string name="folder_names_must_be_unique">Os nomes das pastas devem ser únicos</string>
+ <string name="edit_bookmark">Editar favorito</string>
+ <string name="edit_folder">Editar Pasta</string>
+ <string name="move_to_folder">Mover para a pasta</string>
+ <string name="move">Mover</string>
+
+ <!-- Bookmarks Contextual App Bar. -->
+ <string name="selected">Selecionados:</string> <!--This is a plural adjective.-->
+ <string name="move_up">Subir</string>
+ <string name="move_down">Descer</string>
+ <string name="edit">Editar</string>
+ <string name="delete">Apagar</string>
+ <string name="select_all">Selecionar Tudo</string>
+ <string name="bookmarks_deleted">Favoritos excluídos:</string>
+ <string name="undo">Desfazer</string>
+
+ <!-- Bookmarks Database View. -->
+ <string name="bookmarks_database_view">Visualização do banco de dados de favoritos</string>
+ <string name="all_folders">Todas as pastas</string>
+ <string name="home_folder">Pasta Pessoal</string>
+ <string name="sort">Ordenar</string>
+ <string name="sorted_by_database_id">Ordenado por ID de banco de dados.</string>
+ <string name="sorted_by_display_order">Ordenado por ordem de exibição.</string>
+ <string name="database_id">ID de banco de dados:</string>
+ <string name="folder">Pasta:</string>
+ <string name="parent_folder">Pasta Superior:</string>
+ <string name="display_order">Ordem de exibição:</string>
+ <string name="cannot_deselect_bookmark">Um favorito não pode ser desmarcado enquanto a pasta superior estiver selecionada.</string>
+
+ <!-- Requests. -->
+ <string name="requests">Solicitações</string>
+ <string name="request_details">Solicitar Detalhes</string>
+ <string name="disposition">Disposição</string>
+ <string name="all">Tudo</string>
+ <string name="default_label">Padrão</string>
+ <string name="default_allowed">Padrão - Permitido</string>
+ <string name="allowed">Permitido</string>
+ <string name="allowed_plural">Permitido</string>
+ <string name="third_party_plural">Terceiros</string>
+ <string name="third_party_blocked">Terceiros - Bloqueados</string>
+ <string name="blocked">Bloqueado</string>
+ <string name="blocked_plural">Bloqueados</string>
+ <string name="blocklist">Lista de bloqueios</string>
+ <string name="sublist">Sublista</string>
+ <string name="main_whitelist">Lista branca principal</string>
+ <string name="final_whitelist">Lista de permissões final</string>
+ <string name="domain_whitelist">Lista de permissões de domínio</string>
+ <string name="domain_initial_whitelist">Lista de permissões inicial do domínio</string>
+ <string name="domain_final_whitelist">Lista de permissões final de domínio</string>
+ <string name="third_party_whitelist">Lista de permissões de terceiros</string>
+ <string name="third_party_domain_whitelist">Lista de permissões de domínio de terceiros</string>
+ <string name="third_party_domain_initial_whitelist">Lista de permissões inicial de domínio de terceiros</string>
+ <string name="main_blacklist">Lista negra principal</string>
+ <string name="initial_blacklist">Lista negra inicial</string>
+ <string name="final_blacklist">Lista negra final</string>
+ <string name="domain_blacklist">Lista negra de domínio</string>
+ <string name="domain_initial_blacklist">Lista negra inicial do domínio</string>
+ <string name="domain_final_blacklist">Lista negra final do domínio</string>
+ <string name="domain_regular_expression_blacklist">Lista negra de expressões regulares de domínio</string>
+ <string name="third_party_blacklist">Lista negra de terceiros</string>
+ <string name="third_party_initial_blacklist">Lista negra inicial de terceiros</string>
+ <string name="third_party_domain_blacklist">Lista negra de domínios de terceiros</string>
+ <string name="third_party_domain_initial_blacklist">Lista negra inicial de domínios de terceiros</string>
+ <string name="third_party_regular_expression_blacklist">Lista negra de expressões regulares de terceiros</string>
+ <string name="third_party_domain_regular_expression_blacklist">Lista negra de expressões regulares de domínios de terceiros</string>
+ <string name="regular_expression_blacklist">Lista negra de expressões regulares</string>
+ <string name="blocklist_entries">Entradas da lista de bloqueio</string>
+ <string name="blocklist_original_entry">Entrada original da lista de bloqueio</string>
+
+ <!-- Domains. -->
+ <string name="domains">Domínios</string>
+ <string name="domain_settings">Configurações de domínio</string>
+ <string name="add_domain">Adicionar Domínio</string>
+ <string name="domain_name_already_exists">Nome de domínio já existe</string>
+ <string name="add">Adicionar</string>
+ <string name="domain_name">Nome do domínio</string>
+ <string name="domain_deleted">Domínio excluído</string>
+ <string name="domain_name_instructions">*. pode ser anexado a um domínio para incluir todos os subdomínios (e.g. *.stoutner.com)</string>
+ <string-array name="font_size_array">
+ <item>Padrão do Sistema</item>
+ <item>Tamanho de fonte personalizado</item>
+ </string-array>
+ <string-array name="swipe_to_refresh_array">
+ <item>Padrão do Sistema</item>
+ <item>Deslize para atualizar ativado</item>
+ <item>Deslize para atualizar desativado</item>
+ </string-array>
+ <string-array name="webview_theme_array">
+ <item>Padrão do Sistema</item>
+ <item>Tema Claro WebView</item>
+ <item>Tema Escuro WebView</item>
+ </string-array>
+ <string-array name="wide_viewport_array">
+ <item>Padrão do Sistema</item>
+ <item>Janela de visualização ampla ativada</item>
+ <item>Janela de visualização ampla desativada</item>
+ </string-array>
+ <string-array name="display_webpage_images_array">
+ <item>Padrão do Sistema</item>
+ <item>Imagens habilitadas</item>
+ <item>Imagens desabilitadas</item>
+ </string-array>
+ <string name="pinned_ssl_certificate">Certificado SSL fixado</string>
+ <string name="saved_ssl_certificate">Certificado SSL salvo</string>
+ <string name="current_website_ssl_certificate">Certificado SSL do site atual</string>
+ <string name="load_an_encrypted_website">Carregue um site criptografado antes de abrir as configurações de domínio para preencher o certificado SSL do site atual.</string>
+ <string name="pinned_ip_addresses">Endereços IP fixados</string>
+ <string name="saved_ip_addresses">Endereços IP salvos</string>
+ <string name="current_ip_addresses">Endereços IP atuais</string>
+
+ <!-- Import/Export. -->
+ <string name="encryption">Encriptação</string>
+ <string-array name="encryption_type">
+ <item>Nenhum</item>
+ <item>Senha</item>
+ <item>OpenPGP</item>
+ </string-array>
+ <string name="kitkat_password_encryption_message">A criptografia de senha não funciona no Android KitKat.</string>
+ <string name="file_does_not_exist">O arquivo não existe.</string>
+ <string name="file_exists_warning">O arquivo já existe. Se você continuar, ele será sobrescrito.</string>
+ <string name="openkeychain_required">A criptografia OpenPGP requer que o OpenKeychain seja instalado.</string>
+ <string name="openkeychain_import_instructions">O arquivo não criptografado terá que ser importado em uma etapa separada após ser descriptografado.</string>
+ <string name="settings_pbs">Settings.pbs</string>
+ <string name="file_location">Localização do Arquivo</string>
+ <string name="browse">Navegar</string>
+ <string name="export">Exportar</string>
+ <string name="import_button">Importar</string> <!-- `import` is a reserved word and cannot be used as the name. -->
+ <string name="decrypt">Descriptografar</string>
+ <string name="export_successful">Exportação bem sucedida.</string>
+ <string name="export_failed">A exportação falhou:</string>
+ <string name="import_failed">A importação falhou:</string>
+ <string name="storage_permission">Permissão de armazenamento</string>
+ <string name="storage_permission_message">O Privacy Browser precisa de permissão de armazenamento para acessar diretórios públicos.
+ Se for negado, os diretórios do aplicativo ainda podem ser usados.</string>
+ <string name="storage_permission_explanation">O acesso a arquivos em diretórios públicos requer permissão de armazenamento. Caso contrário, apenas os diretórios de aplicativos funcionarão.</string>
+ <string name="cannot_use_location">Este local não pode ser usado porque a permissão de armazenamento não foi concedida.</string>
+
+ <!-- Logcat. -->
+ <string name="copy_string">Cópia</string> <!-- `copy` is a reserved word and should not be used as the name. -->
+ <string name="logcat_copied">Logcat copiado.</string>
+ <string name="clear">Limpar</string>
+ <string name="save_logcat">Salvar logcat</string>
+ <string name="privacy_browser_logcat_txt">Privacy Browser Logcat.txt</string>
+ <string name="file_saved_successfully">Arquivo salvo com sucesso.</string>
+ <string name="save_failed">Falha ao salvar:</string>
+
+ <!-- Guide. -->
+ <string name="overview">Visão geral</string>
+ <string name="local_storage">Armazenamento Local</string>
+ <string name="ssl_certificates">Certificados SSL</string>
+ <string name="proxies">Proxies</string>
+ <string name="tracking_ids">IDs de rastreamento</string>
+
+ <!-- Proxy. -->
+ <string name="orbot_not_installed_title">Orbot Não Instalado</string>
+ <string name="orbot_not_installed_message">O proxy através do Orbot não funcionará a menos que o aplicativo Orbot esteja instalado.</string>
+ <string name="i2p_not_installed_title">I2P Não Instalado</string>
+ <string name="i2p_not_installed_message">O proxy através do I2P não funcionará a menos que o aplicativo I2P esteja instalado.</string>
+ <string name="waiting_for_orbot">Esperando que o Orbot se conecte.</string>
+ <string name="custom_proxy_invalid">O URL do proxy personalizado é inválido.</string>
+ <string name="socks_proxies_do_not_work_on_kitkat">Os proxies SOCKS não funcionam no Android KitKat.</string>
+
+ <!-- About Activity. -->
+ <string name="about_privacy_browser">Sobre o Privacy Browser</string>
+ <string name="version">Versão</string>
+ <string name="version_code">Código da Versão</string>
+ <string name="hardware">Hardware</string>
+ <string name="brand">Marca:</string>
+ <string name="manufacturer">Fabricante:</string>
+ <string name="model">Modelo:</string>
+ <string name="device">Dispositivo:</string>
+ <string name="bootloader">Bootloader:</string>
+ <string name="radio">Radio:</string>
+ <string name="software">Software</string>
+ <string name="android">Android:</string>
+ <string name="api">API</string>
+ <string name="build">Build:</string>
+ <string name="security_patch">Patch de segurança:</string>
+ <string name="webview_provider">Fornecedor WebView:</string>
+ <string name="webview_version">Versão do WebView:</string>
+ <string name="orbot">Orbot:</string>
+ <string name="i2p">I2P:</string>
+ <string name="openkeychain">OpenKeychain:</string>
+ <string name="easylist_label">EasyList:</string>
+ <string name="easyprivacy_label">EasyPrivacy:</string>
+ <string name="fanboy_annoyance_label">Fanboy’s Annoyance List:</string>
+ <string name="fanboy_social_label">Fanboy’s Social Blocking List:</string>
+ <string name="ultralist_label">UltraList:</string>
+ <string name="ultraprivacy_label">UltraPrivacy:</string>
+ <string name="package_signature">Assinatura do Pacote</string>
+ <string name="issuer_dn">DN do emissor:</string>
+ <string name="subject_dn">Assunto DN:</string>
+ <string name="certificate_version">Versão do certificado:</string>
+ <string name="serial_number">Número de série:</string>
+ <string name="signature_algorithm">Algoritmo de Assinatura:</string>
+ <string name="permissions">Permissões</string>
+ <string name="privacy_policy">Política de Privacidade</string>
+ <string name="changelog">Changelog</string>
+ <string name="licenses">Licenças</string>
+ <string name="contributors">Contribuidores</string>
+ <string name="links">Links</string>
+
+ <!-- Preferences. -->
+ <string name="privacy">Privacidade</string>
+ <string name="javascript_preference">JavaScript</string>
+ <string name="javascript_preference_summary">JavaScript permite que sites executem programas (scripts) no dispositivo.</string>
+ <string name="first_party_cookies_preference">Cookies primários</string>
+ <string name="first_party_cookies_preference_summary">Como os cookies primários são uma configuração de nível de aplicativo, quando a guia ativa tem cookies habilitados,
+ todas as solicitações de rede feitas em segundo plano por outras guias também incluirão quaisquer cookies armazenados para seus domínios.
+ O Android KitKat (versão 4.4.x) não diferencia entre cookies primários e de terceiros e os habilitará com esta configuração.</string>
+ <string name="third_party_cookies_preference">Cookies de terceiros</string>
+ <string name="third_party_cookies_summary">Esta configuração requer Android Lollipop (versão 5.0) ou superior. Não tem efeito se os cookies primários estiverem desativados.</string>
+ <string name="dom_storage_preference">Armazenamento DOM</string>
+ <string name="dom_storage_preference_summary">JavaScript deve estar habilitado para que o armazenamento DOM funcione.</string>
+ <string name="save_form_data_preference">Dados do formulário</string> <!-- The form data strings can be removed once the minimum API >= 26. -->
+ <string name="save_form_data_preference_summary">Dados de formulário salvos podem preencher campos automaticamente em sites.</string>
+ <!-- The form data strings can be removed once the minimum API >= 26. -->
+ <string name="user_agent">Mimetizar o Navegador:</string>
+ <string-array name="translated_user_agent_names">
+ <item>Privacy Browser</item>
+ <item>WebView Padrão</item>
+ <item>Firefox para Android</item>
+ <item>Chrome para Android</item>
+ <item>Safari para iOS</item>
+ <item>Firefox para Linux</item>
+ <item>Chromium para Linux</item>
+ <item>Firefox para Windows</item>
+ <item>Chrome para Windows</item>
+ <item>Edge para Windows</item>
+ <item>Internet Explorer para Windows</item>
+ <item>Safari para macOS</item>
+ <item>Personalizado</item>
+ </string-array>
+ <string-array name="translated_domain_settings_user_agent_names"> <!-- The translated names of the user agents with a System Default option for the domains spinner. -->
+ <item>Padrão do Sistema</item>
+ <item>Privacy Browser</item>
+ <item>WebView Padrão</item>
+ <item>Firefox para Android</item>
+ <item>Chrome para Android</item>
+ <item>Safari para iOS</item>
+ <item>Firefox para Linux</item>
+ <item>Chromium para Linux</item>
+ <item>Firefox para Windows</item>
+ <item>Chrome para Windows</item>
+ <item>Edge para Windows</item>
+ <item>Internet Explorer para Windows</item>
+ <item>Safari para macOS</item>
+ <item>Personalizado</item>
+ </string-array>
+ <string name="custom_user_agent">Agente de usuário personalizado</string>
+ <string name="incognito_mode">Modo de navegação anônima</string>
+ <string name="incognito_mode_summary">Limpe o histórico e o cache após o término do carregamento de cada página da web. No modo de navegação anônima,
+ volta para fechar a guia (ou o aplicativo, se houver apenas uma guia).</string>
+ <string name="do_not_track">Não rastreie</string>
+ <string name="do_not_track_summary">Envie \'Não Rastreie\' ao cabeçalho, que sugere educadamente que os servidores da web não rastreiam este navegador.</string>
+ <string name="allow_screenshots">Permitir capturas de tela</string>
+ <string name="allow_screenshots_summary">Permitir capturas de tela, gravação de vídeo e visualização em monitores não seguros. Alterar esta configuração irá reiniciar o Privacy Browser.</string>
+ <string name="blocklists">Blocklists</string>
+ <string name="easylist">EasyList</string>
+ <string name="easylist_summary">Lista principal de bloqueio de anúncios.</string>
+ <string name="easyprivacy">EasyPrivacy</string>
+ <string name="easyprivacy_summary">Lista de bloqueio do rastreador principal.</string>
+ <string name="fanboys_annoyance_list"> Lista de importunação Fanboy’s</string>
+ <string name="fanboys_annoyance_list_summary">Bloqueie popups e links irritantes. Inclui listas de bloqueio social do Fanboy.</string>
+ <string name="fanboys_social_blocking_list">Lista de bloqueio social do Fanboy</string>
+ <string name="fanboys_social_blocking_list_summary">Bloqueia conteúdo de mídia social de terceiros.</string>
+ <string name="ultralist">UltraList</string>
+ <string name="ultralist_summary">O UltraList bloqueia anúncios que EasyList não bloqueia porque fazer isso pode quebrar sites.</string>
+ <string name="ultraprivacy">UltraPrivacy</string>
+ <string name="ultraprivacy_summary">O UltraPrivacy bloqueia rastreadores que o EasyPrivacy não bloqueia, pois isso pode corromper sites.</string>
+ <string name="block_all_third_party_requests">Bloquear todas as solicitações de terceiros</string>
+ <string name="block_all_third_party_requests_summary">Bloquear todas as solicitações de terceiros aumenta a privacidade, mas quebra muitos sites.</string>
+ <string name="url_modification">Modificação de URL</string>
+ <string name="google_analytics">Google Analytics</string>
+ <string name="google_analytics_summary">Remova utm_ e amp; utm_ e qualquer coisa depois deles dos URLs.</string>
+ <string name="facebook_click_ids">IDs de clique do Facebook</string>
+ <string name="facebook_click_ids_summary">Remover “?fbclid=†, “&fbclid=†, “?fbadid=†, e “&fbadid=†e qualquer coisa depois deles a partir de URLs.</string>
+ <string name="twitter_amp_redirects">Redirecionamentos de AMP do Twitter</string>
+ <string name="twitter_amp_redirects_summary">Remover “?amp=1†e qualquer coisa depois de URLs.</string>
+ <string name="search">Search</string>
+ <string-array name="search_entries">
+ <item>Startpage</item>
+ <item>Mojeek</item>
+ <item>DuckDuckGo - JavaScript desativado</item>
+ <item>DuckDuckGo - JavaScript ativado</item>
+ <item>Google</item>
+ <item>Bing</item>
+ <item>Yahoo - JavaScript desativado</item>
+ <item>Yahoo - JavaScript ativado</item>
+ <item>Custom</item>
+ </string-array>
+ <string name="custom_url">URL personalizado</string>
+ <string name="search_custom_url">URL personalizado de pesquisa</string>
+ <string name="proxy">Proxy</string>
+ <string name="proxy_none">Nenhum</string>
+ <string name="proxy_tor">Tor</string>
+ <string name="proxy_i2p">I2P</string>
+ <string name="proxy_custom">Personalizado</string>
+ <string-array name="proxy_entries">
+ <item>Nenhum</item>
+ <item>Tor</item>
+ <item>I2P</item>
+ <item>Personalizado</item>
+ </string-array>
+ <string name="no_proxy_enabled">Nenhum - conecte-se diretamente à Internet.</string>
+ <string name="tor_enabled">Tor - conecte-se por meio do socks://localhost:9050.</string>
+ <string name="tor_enabled_kitkat">Tor - conecte-se por meio de http://localhost:8118.</string>
+ <string name="i2p_enabled">I2P - conecte-se por meio de http://localhost:4444.</string>
+ <string name="custom_proxy">Personalizar proxy</string>
+ <string name="proxy_custom_url">URL de proxy personalizado</string>
+ <string name="full_screen">Tela Cheia</string>
+ <string name="full_screen_browsing_mode">Modo de navegação em tela inteira</string>
+ <string name="full_screen_browsing_mode_summary">Toque duas vezes para alternar o modo de navegação em tela inteira.</string>
+ <string name="hide_app_bar">Ocultar a barra de aplicativos</string>
+ <string name="hide_app_bar_summary">Oculte a barra de aplicativos que contém o URL.</string>
+ <string name="clear_everything">Limpar tudo</string>
+ <!-- The form data part of this string can be removed once the minimum API >= 26. -->
+ <string name="clear_everything_summary">Limpa cookies, armazenamento DOM, dados de formulário e cache do WebView. Em seguida, exclui manualmente todos os diretórios “app_webview” e “cache”.</string>
+ <string name="clear_cookies_preference">Limpar cookies</string>
+ <string name="clear_cookies_summary">Limpa os cookies originais e de terceiros.</string>
+ <string name="clear_dom_storage_preference">Limpar armazenamento DOM</string>
+ <string name="clear_dom_storage_summary">Limpa o armazenamento DOM.</string>
+ <string name="clear_form_data_preference">Limpar dados do formulário</string> <!-- The form data strings can be removed once the minimum API >= 26. -->
+ <string name="clear_form_data_summary">Limpa os dados do formulário.</string> <!-- The form data strings can be removed once the minimum API >= 26. -->
+ <string name="clear_cache">Limpar cache</string>
+ <string name="clear_cache_summary">Limpa o cache do WebView.</string>
+ <string name="general">Geral</string>
+ <string name="homepage">Pagina inicial</string>
+ <string name="download_location">Localização de Download</string>
+ <string-array name="download_location_entries">
+ <item>Automático</item>
+ <item>Diretório do aplicativo</item>
+ <item>Diretório público</item>
+ <item>Personalizado</item>
+ </string-array>
+ <string name="download_custom_location">Localização de Download Personalizada</string>
+ <string name="font_size_preference">Tamanho da Fonte</string>
+ <string name="open_intents_in_new_tab">Abrir conteúdo em uma nova guia</string>
+ <string name="open_intents_in_new_tab_summary">Conteúdos são links enviados de outros aplicativos.</string>
+ <string name="swipe_to_refresh">Deslize para atualizar</string>
+ <string name="swipe_to_refresh_summary">Alguns sites não funcionam bem se deslizar para atualizar estiver habilitado.</string>
+ <string name="scroll_app_bar">Role a barra de aplicativos</string>
+ <string name="scroll_app_bar_summary">Role a barra de aplicativos para fora da parte superior da tela quando o WebView rola para baixo.</string>
+ <string name="display_additional_app_bar_icons">Exibir ícones adicionais da barra de aplicativos</string>
+ <string name="display_additional_app_bar_icons_summary">Exibe ícones na barra de aplicativos para atualizar o WebView e, se houver espaço, para alternar cookies e armazenamento DOM.</string>
+ <string name="app_theme">Tema do aplicativo</string>
+ <string-array name="app_theme_entries">
+ <item>Padrão do Sitema</item>
+ <item>Claro</item>
+ <item>Escuro</item>
+ </string-array>
+ <string name="webview_theme">Tema do WebView</string>
+ <string-array name="webview_theme_entries">
+ <item>Padrão do Sitema</item>
+ <item>Claro</item>
+ <item>Escuro</item>
+ </string-array>
+ <string name="wide_viewport_preference">Janela de visualização ampla</string>
+ <string name="wide_viewport_summary">Usar uma janela de visualização ampla torna o layout de algumas páginas da web mais parecido com o site para desktop.</string>
+ <string name="display_webpage_images">Exibir imagens da página da web</string>
+ <string name="display_webpage_images_summary">Desative para conservar a largura de banda.</string>
+
+ <!-- Ad Control. There are no ads in the standard flavor, but these strings must exist because they are referenced in the code. -->
+ <string name="ad_consent">Consentimento de Anúncio</string>
+</resources>
\ No newline at end of file
<string name="display_webpage_images">Display webpage images</string>
<string name="display_webpage_images_summary">Disable to conserve bandwidth.</string>
+ <!-- Non-translatable preference keys. -->
+ <string name="allow_screenshots_key" translatable="false">allow_screenshots</string>
+
<!-- Non-translatable preference default values. -->
<string name="user_agent_default_value" translatable="false">Privacy Browser</string>
<string name="custom_user_agent_default_value" translatable="false">PrivacyBrowser/1.0</string>
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.1'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.10"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files