]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/commitdiff
Enable searching of the logcat. https://redmine.stoutner.com/issues/381
authorSoren Stoutner <soren@stoutner.com>
Mon, 8 Apr 2024 23:33:52 +0000 (16:33 -0700)
committerSoren Stoutner <soren@stoutner.com>
Mon, 8 Apr 2024 23:33:52 +0000 (16:33 -0700)
21 files changed:
app/build.gradle
app/src/main/java/com/stoutner/privacybrowser/activities/LogcatActivity.kt
app/src/main/java/com/stoutner/privacybrowser/activities/MainWebViewActivity.kt
app/src/main/java/com/stoutner/privacybrowser/views/NestedScrollWebView.kt
app/src/main/res/drawable/search.xml
app/src/main/res/drawable/search_blue.xml [new file with mode: 0644]
app/src/main/res/layout/logcat_bottom_appbar.xml
app/src/main/res/layout/logcat_top_appbar.xml
app/src/main/res/layout/main_framelayout_bottom_appbar.xml
app/src/main/res/layout/main_framelayout_top_appbar.xml
app/src/main/res/menu/logcat_options_menu.xml
app/src/main/res/values-de/strings.xml
app/src/main/res/values-fr/strings.xml
app/src/main/res/values-night-v27/styles.xml
app/src/main/res/values-night/styles.xml
app/src/main/res/values-v27/styles.xml
app/src/main/res/values/attrs.xml
app/src/main/res/values/strings.xml
app/src/main/res/values/styles.xml
app/src/main/res/xml/preferences.xml
build.gradle

index 861e916570756a33453f03e52749e526ea041033..900ddf9bc86073aabd2bb6ec82f085d53fd08d88 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2016-2024 Soren Stoutner <soren@stoutner.com>.
  *
- * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
+ * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
  *
  * Privacy Browser Android is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index c12c74ecb4302c403067724b84ddcf35ec77c011..214ebf2149aaa6d9bf931ce3d6bec7f1b256b181 100644 (file)
@@ -24,12 +24,20 @@ import android.content.ClipboardManager
 import android.os.Build
 import android.os.Bundle
 import android.provider.OpenableColumns
+import android.text.Editable
+import android.text.TextWatcher
 import android.util.Base64
 import android.util.TypedValue
+import android.view.KeyEvent
 import android.view.Menu
 import android.view.MenuItem
+import android.view.View
 import android.view.WindowManager
+import android.view.inputmethod.InputMethodManager
 import android.webkit.WebView
+import android.widget.EditText
+import android.widget.LinearLayout
+import android.widget.TextView
 
 import androidx.activity.result.contract.ActivityResultContracts
 import androidx.appcompat.app.AppCompatActivity
@@ -58,11 +66,15 @@ private const val SCROLL_Y = "A"
 
 class LogcatActivity : AppCompatActivity() {
     // Declare the class variables.
+    private lateinit var inputMethodManager: InputMethodManager
     private lateinit var logcatPlainTextStringBuilder: StringBuilder
 
     // Declare the class views.
-    private lateinit var swipeRefreshLayout: SwipeRefreshLayout
     private lateinit var logcatWebView: WebView
+    private lateinit var searchEditText: EditText
+    private lateinit var searchLinearLayout: LinearLayout
+    private lateinit var swipeRefreshLayout: SwipeRefreshLayout
+    private lateinit var toolbar: Toolbar
 
     // Define the save logcat activity result launcher.  It must be defined before `onCreate()` is run or the app will crash.
     private val saveLogcatActivityResultLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { fileUri ->
@@ -105,6 +117,9 @@ class LogcatActivity : AppCompatActivity() {
     }
 
     public override fun onCreate(savedInstanceState: Bundle?) {
+        // Run the default commands.
+        super.onCreate(savedInstanceState)
+
         // Get a handle for the shared preferences.
         val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
 
@@ -116,9 +131,6 @@ class LogcatActivity : AppCompatActivity() {
         if (!allowScreenshots)
             window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
 
-        // Run the default commands.
-        super.onCreate(savedInstanceState)
-
         // Set the content view.
         if (bottomAppBar)
             setContentView(R.layout.logcat_bottom_appbar)
@@ -126,7 +138,10 @@ class LogcatActivity : AppCompatActivity() {
             setContentView(R.layout.logcat_top_appbar)
 
         // Get handles for the views.
-        val toolbar = findViewById<Toolbar>(R.id.toolbar)
+        toolbar = findViewById(R.id.toolbar)
+        val searchCountTextView = findViewById<TextView>(R.id.search_count_textview)
+        searchLinearLayout = findViewById(R.id.search_linearlayout)
+        searchEditText = findViewById(R.id.search_edittext)
         swipeRefreshLayout = findViewById(R.id.swiperefreshlayout)
         logcatWebView = findViewById(R.id.logcat_webview)
 
@@ -160,13 +175,63 @@ class LogcatActivity : AppCompatActivity() {
         // Set the swipe refresh background color.
         swipeRefreshLayout.setProgressBackgroundColorSchemeColor(colorBackgroundInt)
 
+        // Get a handle for the input method manager.
+        inputMethodManager = (getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager)
+
+        // Search for the string on the page whenever a character changes in the search edit text.
+        searchEditText.addTextChangedListener(object : TextWatcher {
+            override fun beforeTextChanged(charSequence: CharSequence, start: Int, count: Int, after: Int) {
+                // Do nothing.
+            }
+
+            override fun onTextChanged(charSequence: CharSequence, start: Int, before: Int, count: Int) {
+                // Do nothing.
+            }
+
+            override fun afterTextChanged(editable: Editable) {
+                // Search for the text in the WebView.
+                logcatWebView.findAllAsync(searchEditText.text.toString())
+            }
+        })
+
+        // Set the `check mark` button for the search edit text keyboard to close the soft keyboard.
+        searchEditText.setOnKeyListener { _: View?, keyCode: Int, keyEvent: KeyEvent ->
+            if ((keyEvent.action == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {  // The `enter` key was pressed.
+                // Search for the text in the WebView.
+                logcatWebView.findAllAsync(searchEditText.text.toString())
+
+                // Hide the soft keyboard.
+                inputMethodManager.hideSoftInputFromWindow(logcatWebView.windowToken, 0)
+
+                // Consume the event.
+                return@setOnKeyListener true
+            } else {  // A different key was pressed.
+                // Do not consume the event.
+                return@setOnKeyListener false
+            }
+        }
+
+        // Update the find on page count.
+        logcatWebView.setFindListener { activeMatchOrdinal, numberOfMatches, isDoneCounting ->
+            if (isDoneCounting && (numberOfMatches == 0)) {  // There are no matches.
+                // Set the search count text view to be `0/0`.
+                searchCountTextView.setText(R.string.zero_of_zero)
+            } else if (isDoneCounting) {  // There are matches.
+                // The active match ordinal is zero-based.
+                val activeMatch = activeMatchOrdinal + 1
+
+                // Build the match string.
+                val matchString = "$activeMatch/$numberOfMatches"
+
+                // Update the search count text view.
+                searchCountTextView.text = matchString
+            }
+        }
+
         // Restore the WebView scroll position if the activity has been restarted.
         if (savedInstanceState != null)
             logcatWebView.scrollY = savedInstanceState.getInt(SCROLL_Y)
 
-        // Allow loading of file:// URLs.
-        logcatWebView.settings.allowFileAccess = true
-
         // Populate the logcat.
         populateLogcat()
     }
@@ -182,6 +247,35 @@ class LogcatActivity : AppCompatActivity() {
     override fun onOptionsItemSelected(menuItem: MenuItem): Boolean {
         // Run the commands that correlate to the selected menu item.
         return when (menuItem.itemId) {
+            R.id.search -> {  // Search was selected.
+                // Set the minimum height of the search linear layout to match the toolbar.
+                searchLinearLayout.minimumHeight = toolbar.height
+
+                // Hide the toolbar.
+                toolbar.visibility = View.GONE
+
+                // Show the search linear layout.
+                searchLinearLayout.visibility = View.VISIBLE
+
+                // Display the keyboard once the UI has quiesced.
+                searchLinearLayout.post {
+                    // Set the focus on the find on page edit text.
+                    searchEditText.requestFocus()
+
+                    // Get a handle for the input method manager.
+                    val inputMethodManager = (getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager)
+
+                    // Display the keyboard.  `0` sets no input flags.
+                    inputMethodManager.showSoftInput(searchEditText, 0)
+                }
+
+                // Resume the WebView timers.  For some reason they get automatically paused, which prevents searching.
+                logcatWebView.resumeTimers()
+
+                // Consume the event.
+                true
+            }
+
             R.id.copy -> {  // Copy was selected.
                 // Get a handle for the clipboard manager.
                 val clipboardManager = getSystemService(CLIPBOARD_SERVICE) as ClipboardManager
@@ -241,6 +335,24 @@ class LogcatActivity : AppCompatActivity() {
         savedInstanceState.putInt(SCROLL_Y, logcatWebView.scrollY)
     }
 
+    // The view parameter cannot be removed because it is called from the layout onClick.
+    fun closeSearch(@Suppress("UNUSED_PARAMETER")view: View?) {
+        // Delete the contents of the search edit text.
+        searchEditText.text = null
+
+        // Clear the highlighted phrases in the logcat WebView.
+        logcatWebView.clearMatches()
+
+        // Hide the search linear layout.
+        searchLinearLayout.visibility = View.GONE
+
+        // Show the toolbar.
+        toolbar.visibility = View.VISIBLE
+
+        // Hide the keyboard.
+        inputMethodManager.hideSoftInputFromWindow(toolbar.windowToken, 0)
+    }
+
     private fun populateLogcat() {
         try {
             // Get the logcat.  `-b all` gets all the buffers (instead of just crash, main, and system).  `-v long` produces more complete information.  `-d` dumps the logcat and exits.
@@ -336,4 +448,16 @@ class LogcatActivity : AppCompatActivity() {
         // Stop the swipe to refresh animation if it is displayed.
         swipeRefreshLayout.isRefreshing = false
     }
+
+    // The view parameter cannot be removed because it is called from the layout onClick.
+    fun searchNext(@Suppress("UNUSED_PARAMETER")view: View?) {
+        // Go to the next highlighted phrase on the page. `true` goes forwards instead of backwards.
+        logcatWebView.findNext(true)
+    }
+
+    // The view parameter cannot be removed because it is called from the layout onClick.
+    fun searchPrevious(@Suppress("UNUSED_PARAMETER")view: View?) {
+        // Go to the previous highlighted phrase on the page.  `false` goes backwards instead of forwards.
+        logcatWebView.findNext(false)
+    }
 }
index 75aa38beaf7139c878410fd0a05f80a4b09fe3e6..042af73dce4f9258440b6da318dcdbfaac7ba25d 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Download cookie code contributed 2017 Hendrik Knackstedt.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
  *
- * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
+ * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
  *
  * Privacy Browser Android is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -278,6 +278,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
     private lateinit var findOnPageLinearLayout: LinearLayout
     private lateinit var fullScreenVideoFrameLayout: FrameLayout
     private lateinit var initialGrayColorSpan: ForegroundColorSpan
+    private lateinit var inputMethodManager: InputMethodManager
     private lateinit var navigationBackMenuItem: MenuItem
     private lateinit var navigationForwardMenuItem: MenuItem
     private lateinit var navigationHistoryMenuItem: MenuItem
@@ -1853,9 +1854,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
                     // Set the focus on the find on page edit text.
                     findOnPageEditText.requestFocus()
 
-                    // Get a handle for the input method manager.
-                    val inputMethodManager = (getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager)
-
                     // Display the keyboard.  `0` sets no input flags.
                     inputMethodManager.showSoftInput(findOnPageEditText, 0)
                 }, 200)
@@ -3859,9 +3857,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
         // Show the toolbar.
         toolbar.visibility = View.VISIBLE
 
-        // Get a handle for the input method manager.
-        val inputMethodManager = (getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager)
-
         // Hide the keyboard.
         inputMethodManager.hideSoftInputFromWindow(toolbar.windowToken, 0)
     }
@@ -4155,7 +4150,7 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
     @SuppressLint("ClickableViewAccessibility")
     private fun initializeApp() {
         // Get a handle for the input method.
-        val inputMethodManager = (getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager)
+        inputMethodManager = (getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager)
 
         // Initialize the color spans for highlighting the URLs.
         initialGrayColorSpan = ForegroundColorSpan(getColor(R.color.gray_500))
@@ -4344,11 +4339,15 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
 
         // Search for the string on the page whenever a character changes in the find on page edit text.
         findOnPageEditText.addTextChangedListener(object : TextWatcher {
-            override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
+            override fun beforeTextChanged(charSequence: CharSequence, start: Int, count: Int, after: Int) {
+                // Do nothing.
+            }
 
-            override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
+            override fun onTextChanged(charSequence: CharSequence, start: Int, before: Int, count: Int) {
+                // Do nothing.
+            }
 
-            override fun afterTextChanged(s: Editable) {
+            override fun afterTextChanged(editable: Editable) {
                 // Search for the text in the WebView if it is not null.  Sometimes on resume after a period of non-use the WebView will be null.
                 currentWebView?.findAllAsync(findOnPageEditText.text.toString())
             }
@@ -4603,9 +4602,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             }
         }
 
-        // Get a handle for the input method manager.
-        val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
-
         // Set the app bar scrolling.
         nestedScrollWebView.isNestedScrollingEnabled = scrollAppBar
 
@@ -6192,9 +6188,6 @@ class MainWebViewActivity : AppCompatActivity(), CreateBookmarkDialog.CreateBook
             // Update the privacy icons.  `true` redraws the icons in the app bar.
             updatePrivacyIcons(true)
 
-            // Get a handle for the input method manager.
-            val inputMethodManager = (getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager)
-
             // Get the current URL.
             val urlString = currentWebView!!.url
 
index 6076950291c304e74fa75d0326913973da8c1984..b5b805d88cd90bdac75776d0cfd808149b05a971 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2019-2024 Soren Stoutner <soren@stoutner.com>.
  *
- * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
+ * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
  *
  * Privacy Browser Android is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
index d95d178b90da2722ba73b3809f709c6b6beabb2b..4c5b7348370c3d12c1e13c5203e360c004893ae1 100644 (file)
@@ -1,4 +1,4 @@
-<!-- This file comes from the Android Material icon set, where it is called `search`.  It is released under the Apache License 2.0. -->
+<!-- This file comes from the Android Material icon set, where it is called `search`.  It is released under the Apache License 2.0 <https://fonts.google.com/icons>. -->
 
 <vector
     xmlns:android="http://schemas.android.com/apk/res/android"
@@ -9,6 +9,6 @@
     android:autoMirrored="true" >
 
     <path
-        android:fillColor="@color/blue_icon"
+        android:fillColor="@color/icon"
         android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
-</vector>
\ No newline at end of file
+</vector>
diff --git a/app/src/main/res/drawable/search_blue.xml b/app/src/main/res/drawable/search_blue.xml
new file mode 100644 (file)
index 0000000..0cb5560
--- /dev/null
@@ -0,0 +1,14 @@
+<!-- This file comes from the Android Material icon set, where it is called `search`.  It is released under the Apache License 2.0 <https://fonts.google.com/icons>. -->
+
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24"
+    android:autoMirrored="true" >
+
+    <path
+        android:fillColor="@color/blue_icon"
+        android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
+</vector>
index cc34fb3cc29875d95949cdea83386e6c57c81a56..1db3a353301721fa33bb6f0340a9b557f0bf1529 100644 (file)
@@ -21,6 +21,7 @@
 <androidx.coordinatorlayout.widget.CoordinatorLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:layout_height="match_parent"
     android:layout_width="match_parent" >
 
                 android:id="@+id/toolbar"
                 android:layout_height="wrap_content"
                 android:layout_width="match_parent" />
+
+            <!-- The search linear layout.  It is initially `visibility="gone"` and is only displayed when requested. -->
+            <LinearLayout
+                android:id="@+id/search_linearlayout"
+                android:layout_height="wrap_content"
+                android:layout_width="match_parent"
+                android:orientation="horizontal"
+                android:visibility="gone" >
+
+                <!-- `android:imeOptions="actionDone"` sets the keyboard to have a `check mark` key instead of a `new line` key. -->
+                <EditText
+                    android:id="@+id/search_edittext"
+                    android:layout_height="wrap_content"
+                    android:layout_width="0dp"
+                    android:layout_weight="1"
+                    android:layout_marginStart="8dp"
+                    android:layout_marginEnd="4dp"
+                    android:hint="@string/search"
+                    android:lines="1"
+                    android:imeOptions="actionDone"
+                    android:inputType="text"
+                    tools:ignore="Autofill" />
+
+                <TextView
+                    android:id="@+id/search_count_textview"
+                    android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:layout_marginStart="4dp"
+                    android:layout_marginEnd="4dp"
+                    android:text="@string/zero_of_zero" />
+
+                <!-- `android:background="?attr/selectableItemBackground"` adds a ripple animation on touch. -->
+                <ImageView
+                    android:id="@+id/search_previous"
+                    android:layout_height="35dp"
+                    android:layout_width="35dp"
+                    android:layout_marginStart="4dp"
+                    android:layout_marginEnd="4dp"
+                    android:layout_gravity="center_vertical"
+                    android:src="@drawable/previous"
+                    android:background="?attr/selectableItemBackground"
+                    android:contentDescription="@string/previous"
+                    android:onClick="searchPrevious"
+                    app:tint="@color/blue_icon" />
+
+                <!-- `android:background="?attr/selectableItemBackground"` adds a ripple animation on touch. -->
+                <ImageView
+                    android:id="@+id/search_next"
+                    android:layout_height="35dp"
+                    android:layout_width="35dp"
+                    android:layout_marginStart="4dp"
+                    android:layout_marginEnd="4dp"
+                    android:layout_gravity="center_vertical"
+                    android:src="@drawable/next"
+                    android:background="?attr/selectableItemBackground"
+                    android:contentDescription="@string/next"
+                    android:onClick="searchNext"
+                    app:tint="@color/blue_icon" />
+
+                <!-- `android:background="?attr/selectableItemBackground"` adds a ripple animation on touch. -->
+                <ImageView
+                    android:id="@+id/close_search"
+                    android:layout_height="35dp"
+                    android:layout_width="35dp"
+                    android:layout_marginStart="4dp"
+                    android:layout_marginEnd="8dp"
+                    android:layout_gravity="center_vertical"
+                    android:src="@drawable/close"
+                    android:background="?attr/selectableItemBackground"
+                    android:contentDescription="@string/close"
+                    android:onClick="closeSearch"
+                    app:tint="@color/blue_icon" />
+            </LinearLayout>
         </com.google.android.material.appbar.AppBarLayout>
     </LinearLayout>
 </androidx.coordinatorlayout.widget.CoordinatorLayout>
index 1eb6a675a47e5810ec30ee34bbc8ec92ba2e3fb4..a11dcd9388909ff70c1c1c789ddc6a638997c69a 100644 (file)
@@ -20,6 +20,8 @@
 
 <androidx.coordinatorlayout.widget.CoordinatorLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
     android:layout_height="match_parent"
     android:layout_width="match_parent" >
 
                 android:id="@+id/toolbar"
                 android:layout_height="wrap_content"
                 android:layout_width="match_parent" />
+
+            <!-- The search linear layout.  It is initially `visibility="gone"` and is only displayed when requested. -->
+            <LinearLayout
+                android:id="@+id/search_linearlayout"
+                android:layout_height="wrap_content"
+                android:layout_width="match_parent"
+                android:orientation="horizontal"
+                android:visibility="gone" >
+
+                <!-- `android:imeOptions="actionDone"` sets the keyboard to have a `check mark` key instead of a `new line` key. -->
+                <EditText
+                    android:id="@+id/search_edittext"
+                    android:layout_height="wrap_content"
+                    android:layout_width="0dp"
+                    android:layout_weight="1"
+                    android:layout_marginStart="8dp"
+                    android:layout_marginEnd="4dp"
+                    android:hint="@string/search"
+                    android:lines="1"
+                    android:imeOptions="actionDone"
+                    android:inputType="text"
+                    tools:ignore="Autofill" />
+
+                <TextView
+                    android:id="@+id/search_count_textview"
+                    android:layout_height="wrap_content"
+                    android:layout_width="wrap_content"
+                    android:layout_marginStart="4dp"
+                    android:layout_marginEnd="4dp"
+                    android:text="@string/zero_of_zero" />
+
+                <!-- `android:background="?attr/selectableItemBackground"` adds a ripple animation on touch. -->
+                <ImageView
+                    android:id="@+id/search_previous"
+                    android:layout_height="35dp"
+                    android:layout_width="35dp"
+                    android:layout_marginStart="4dp"
+                    android:layout_marginEnd="4dp"
+                    android:layout_gravity="center_vertical"
+                    android:src="@drawable/previous"
+                    android:background="?attr/selectableItemBackground"
+                    android:contentDescription="@string/previous"
+                    android:onClick="searchPrevious"
+                    app:tint="@color/blue_icon" />
+
+                <!-- `android:background="?attr/selectableItemBackground"` adds a ripple animation on touch. -->
+                <ImageView
+                    android:id="@+id/search_next"
+                    android:layout_height="35dp"
+                    android:layout_width="35dp"
+                    android:layout_marginStart="4dp"
+                    android:layout_marginEnd="4dp"
+                    android:layout_gravity="center_vertical"
+                    android:src="@drawable/next"
+                    android:background="?attr/selectableItemBackground"
+                    android:contentDescription="@string/next"
+                    android:onClick="searchNext"
+                    app:tint="@color/blue_icon" />
+
+                <!-- `android:background="?attr/selectableItemBackground"` adds a ripple animation on touch. -->
+                <ImageView
+                    android:id="@+id/close_search"
+                    android:layout_height="35dp"
+                    android:layout_width="35dp"
+                    android:layout_marginStart="4dp"
+                    android:layout_marginEnd="8dp"
+                    android:layout_gravity="center_vertical"
+                    android:src="@drawable/close"
+                    android:background="?attr/selectableItemBackground"
+                    android:contentDescription="@string/close"
+                    android:onClick="closeSearch"
+                    app:tint="@color/blue_icon" />
+            </LinearLayout>
         </com.google.android.material.appbar.AppBarLayout>
 
         <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
index 3f9ac8ef2bfa59c547d6092ba554412a95c0fc5c..497a823bd3f4bdc46bd50fa7a0be9e2f0ec3c8b4 100644 (file)
                             android:background="?attr/selectableItemBackground"
                             android:contentDescription="@string/previous"
                             android:onClick="findPreviousOnPage"
-                            app:tint="?attr/findOnPageIconTintColor" />
+                            app:tint="@color/blue_icon" />
 
                         <!-- `android:background="?attr/selectableItemBackground"` adds a ripple animation on touch. -->
                         <ImageView
                             android:background="?attr/selectableItemBackground"
                             android:contentDescription="@string/next"
                             android:onClick="findNextOnPage"
-                            app:tint="?attr/findOnPageIconTintColor" />
+                            app:tint="@color/blue_icon" />
 
                         <!-- `android:background="?attr/selectableItemBackground"` adds a ripple animation on touch. -->
                         <ImageView
                             android:background="?attr/selectableItemBackground"
                             android:contentDescription="@string/close"
                             android:onClick="closeFindOnPage"
-                            app:tint="?attr/findOnPageIconTintColor" />
+                            app:tint="@color/blue_icon" />
                     </LinearLayout>
 
                     <!-- The toolbar. -->
index cd407a29570bd8f3d3990be48e7d4052563b94eb..3b43be9d7ae9da5c6d2c2ff2a85e04695d398735 100644 (file)
@@ -96,7 +96,7 @@
                         android:background="?attr/selectableItemBackground"
                         android:contentDescription="@string/previous"
                         android:onClick="findPreviousOnPage"
-                        app:tint="?attr/findOnPageIconTintColor" />
+                        app:tint="@color/blue_icon" />
 
                     <!-- `android:background="?attr/selectableItemBackground"` adds a ripple animation on touch. -->
                     <ImageView
                         android:background="?attr/selectableItemBackground"
                         android:contentDescription="@string/next"
                         android:onClick="findNextOnPage"
-                        app:tint="?attr/findOnPageIconTintColor" />
+                        app:tint="@color/blue_icon" />
 
                     <!-- `android:background="?attr/selectableItemBackground"` adds a ripple animation on touch. -->
                     <ImageView
                         android:background="?attr/selectableItemBackground"
                         android:contentDescription="@string/close"
                         android:onClick="closeFindOnPage"
-                        app:tint="?attr/findOnPageIconTintColor" />
+                        app:tint="@color/blue_icon" />
                 </LinearLayout>
 
                 <!-- The tab linear layout.  It sets the background to the right of the add tab button. -->
index 26e1d04f28126a6648ce2e81c69374750db39da7..4da479730095e3d633c85b5c4ced5ac8c0a6321c 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 
 <!--
-  Copyright © 2015-2020,2022 Soren Stoutner <soren@stoutner.com>.
+  Copyright 2015-2020, 2022, 2024 Soren Stoutner <soren@stoutner.com>.
 
-  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
+  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
 
   Privacy Browser Android is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto" >
 
+    <item
+        android:id="@+id/search"
+        android:title="@string/search"
+        android:orderInCategory="10"
+        android:icon="@drawable/search"
+        app:showAsAction="ifRoom" />
+
     <item
         android:id="@+id/copy"
         android:title="@string/copy_string"
-        android:orderInCategory="10"
+        android:orderInCategory="20"
         android:icon="@drawable/copy"
         app:showAsAction="always" />
 
     <item
         android:id="@+id/save"
         android:title="@string/save"
-        android:orderInCategory="20"
+        android:orderInCategory="30"
         android:icon="@drawable/save"
         app:showAsAction="ifRoom" />
 
     <item
         android:id="@+id/clear"
         android:title="@string/clear"
-        android:orderInCategory="30"
+        android:orderInCategory="40"
         android:icon="@drawable/close"
         app:showAsAction="ifRoom" />
-</menu>
\ No newline at end of file
+</menu>
index 36f94792eebacd9342560b57af50123597bd637d..f0837f6c407eeb37ced4d346dfea0ed1715876d6 100644 (file)
 
     <!-- Import/Export.  Android removes double spaces, but extra spaces can be manually specified with the Unicode `\u0020` formatting.
       The `%1$*` code inserts variables into the displayed text and should be preserved in translation.  <https://developer.android.com/reference/kotlin/java/util/Formatter> -->
+    <string name="bookmarks_and_settings">Lesezeichen und Einstellungen</string>
+    <string name="sqlite_database_format">SQLite-Datenbank-Format</string>
+    <string name="html_format">HTML-Format</string>
     <string name="encryption">Verschlüsselung</string>
     <string-array name="encryption_type">
         <item>keine</item>
     <string name="decrypt">entschlüsseln</string>
     <string name="privacy_browser_settings_pbs">Privacy Browser Android %1$s Einstellungen - Schema %2$d.pbs</string>
     <string name="privacy_browser_settings_pbs_aes">Privacy Browser Android %1$s Einstellungen - Schema %2$d.pbs.aes</string>
+    <string name="privacy_browser_bookmarks_html">Privacy Browser Lesezeichen.html</string>
     <string name="export_successful">Export erfolgreich.</string>
     <string name="export_failed">Export fehlgeschlagen:\u0020 %1$s</string>
     <string name="import_failed">Import fehlgeschlagen:\u0020 %1$s</string>
+    <string name="bookmarks_imported">%1$d Ordner und Lesezeichen importiert.</string>
+    <string name="bookmarks_exported">%1$d Ordner und Lesezeichen exportiert.</string>
 
     <!-- Logcat.  Android removes double spaces, but extra spaces can be manually specified with the Unicode `\u0020` formatting.
         The `%1$s` code inserts variables into the displayed text and should be preserved in translation.  <https://developer.android.com/reference/kotlin/java/util/Formatter> -->
index ae6d75c1a88164840cd1e1e7e3c7f90658333226..0bc640e2ad53066f6a535d3dc4d856de5d9eb7ae 100644 (file)
@@ -5,7 +5,7 @@
 
   Translation 2019-2024 Kévin L. <kevinliste@framalistes.org>.  Copyright assigned to Soren Stoutner <soren@stoutner.com>.
 
-  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
+  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
 
   Privacy Browser Android is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
     <string name="bytes">octets</string>
     <string name="unknown_size">taille inconnue</string>
     <string name="invalid_url">URL invalide</string>
+    <string name="blob_url_warning">Privacy Browser ne peut actuellement pas télécharger les URL de type blob.</string>
+    <string name="data_url_warning">Le gestionnaire de téléchargement d\'Android ne peut pas gérer les URL de type data.</string>
+    <string name="download_directory">Répertoire de téléchargement</string>
+    <string name="documents">Documents</string>
+    <string name="pictures">Images</string>
+    <string name="music">Musique</string>
     <string name="saving_file">Enregistrement du fichier : %1$d%% - %2$s</string>
     <string name="saving_file_progress">Enregistrement du fichier : %1$s octets - %2$s</string>
     <string name="saving_file_percentage_progress">Enregistrement du fichier : %1$d%% - %2$s octets / %3$s octets - %4$s</string>
     <string name="create_folder">Créer un dossier</string>
     <string name="current_bookmark_icon">Icône actuelle</string>
     <string name="current_folder_icon">Icône actuelle</string>
+    <string name="custom_bookmark_icon">Icône de signet personnalisée</string>
+    <string name="custom_folder_icon">Icône de dossier personnalisée</string>
     <string name="default_folder_icon">Icône par défaut</string>
     <string name="webpage_favorite_icon">Icône de la page web courante</string>
     <string name="bookmark_name">Nom du favori</string>
     <string name="edit_folder">Editer dossier</string>
     <string name="move_to_folder">Déplacer vers dossier</string>
     <string name="move">Déplacer</string>
+    <string name="cannot_use_svg">Un fichier SVG ne peut actuellement pas être utilisé comme icône de signet favorite.</string>
 
     <!-- Bookmarks Contextual App Bar.
         The `%1$d` code inserts variables into the displayed text and should be preserved in translation.  <https://developer.android.com/reference/kotlin/java/util/Formatter> -->
         <string name="open_intents_in_new_tab_summary">Les intentions sont des liens envoyés à partir d\'autres applications.</string>
         <string name="swipe_to_refresh">Glisser pour rafraîchir</string>
         <string name="swipe_to_refresh_summary">Certains sites Web ne fonctionnent pas bien lorsque "Glisser pour rafraîchir" est activé.</string>
+        <string name="download_provider">Fournisseur de téléchargement</string>
+        <string-array name="download_provider_entries">
+            <item>Privacy Browser</item>
+            <item>Gestionnaire de téléchargement d\'Android</item>
+            <item>Application externe</item>
+        </string-array>
+        <string name="download_with_privacy_browser">Privacy Browser - Le téléchargeur intégré de Privacy Browser est simple, mais il a l\'avantage de respecter le proxy et d\'utiliser les cookies (si activés),
+            ainsi que de pouvoir enregistrer les URL de données.</string>
+        <string name="download_with_android_download_manager">Gestionnaire de téléchargement d\'Android - Le gestionnaire de téléchargement d\'Android ne respecte pas les paramètres de proxy du navigateur
+            de confidentialité, mais il a accès aux cookies (ce qui signifie que les fichiers téléchargés à partir de sites nécessitant une connexion fonctionneront probablement).</string>
+        <string name="download_with_external_app">Application externe - Les applications externes ne respectent pas les paramètres de proxy de Privacy Browser et n\'ont pas accès aux cookies
+            (ce qui signifie qu\'il est peu probable que les fichiers téléchargés à partir de sites nécessitant une connexion fonctionnent).</string>
         <string name="scroll_app_bar">Défilement barre d\'applications</string>
         <string name="scroll_app_bar_summary">Faites défiler la barre d\'applications en haut de l\'écran lorsque WebView défile vers le bas.</string>
         <string name="bottom_app_bar">Barre d\'application en bas</string>
index d1e8aaa4acf2bc72762f4df4b25b4b1009649d17..7edb9a6e6300bdaaff64f36b586078f0fbda5d3f 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 
 <!--
-  Copyright 2015-2022 Soren Stoutner <soren@stoutner.com>.
+  Copyright 2015-2022, 2024 Soren Stoutner <soren@stoutner.com>.
 
-  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
+  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
 
   Privacy Browser Android is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -33,7 +33,6 @@
 
         <!-- Tints. -->
         <item name="fabIconTintColor">@color/gray_875</item>
-        <item name="findOnPageIconTintColor">@color/violet_500</item>
         <item name="navigationIconTintColor">@color/violet_500</item>
         <item name="progressTintColor">@color/violet_500</item>
 
index 513f3f2d0afb43e8825ddceac2a3946a36fe30f8..06703b20732d12aa0f0a8822848984ad80f8cf8d 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 
 <!--
-  Copyright 2015-2022 Soren Stoutner <soren@stoutner.com>.
+  Copyright 2015-2022, 2024 Soren Stoutner <soren@stoutner.com>.
 
-  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
+  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
 
   Privacy Browser Android is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -31,7 +31,6 @@
 
         <!-- Tints. -->
         <item name="fabIconTintColor">@color/gray_875</item>
-        <item name="findOnPageIconTintColor">@color/violet_500</item>
         <item name="navigationIconTintColor">@color/violet_500</item>
         <item name="progressTintColor">@color/violet_500</item>
 
index f66d95fe189d349054464d3dcae7872e2d026214..a78f4c7976232dc010bfd984ec3b8a46b0f7ee79 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 
 <!--
-  Copyright 2015-2022 Soren Stoutner <soren@stoutner.com>.
+  Copyright 2015-2022, 2024 Soren Stoutner <soren@stoutner.com>.
 
-  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
+  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
 
   Privacy Browser Android is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -33,7 +33,6 @@
 
         <!-- Tints. -->
         <item name="fabIconTintColor">@color/white</item>
-        <item name="findOnPageIconTintColor">@color/blue_800</item>
         <item name="navigationIconTintColor">@color/blue_800</item>
         <item name="progressTintColor">@color/blue_700</item>
 
index db6a6efa97f2d79f33b2e72197c08e43f17e8d75..ecce2323b72c6e498fde7f5d8c5a32f6b1c0abe8 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 
 <!--
-  Copyright 2017-2022 Soren Stoutner <soren@stoutner.com>.
+  Copyright 2017-2022, 2024 Soren Stoutner <soren@stoutner.com>.
 
-  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
+  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
 
   Privacy Browser Android is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -25,7 +25,6 @@
 
     <!-- Tint Colors. -->
     <attr name="fabIconTintColor" format="color" />
-    <attr name="findOnPageIconTintColor" format="color" />
     <attr name="navigationIconTintColor" format="color" />
     <attr name="progressTintColor" format="color" />
 
index 20a5e9a3b3a7f19f7baf78a3925867d2d50a33f8..845e2c1cdec07814acf8c0a09127a20bbbb5112a 100644 (file)
@@ -3,7 +3,7 @@
 <!--
   Copyright 2015-2024 Soren Stoutner <soren@stoutner.com>.
 
-  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
+  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
 
   Privacy Browser Android is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
index 2fdf9bb5ad28d4c1b448f0edebcd40e46230b45b..470b1a7343fa5c7086f1137d9036d649f92a49f0 100644 (file)
@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 
 <!--
-  Copyright 2015-2022 Soren Stoutner <soren@stoutner.com>.
+  Copyright 2015-2022, 2024 Soren Stoutner <soren@stoutner.com>.
 
-  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
+  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
 
   Privacy Browser Android is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
@@ -31,7 +31,6 @@
 
         <!-- Tints. -->
         <item name="fabIconTintColor">@color/white</item>
-        <item name="findOnPageIconTintColor">@color/blue_800</item>
         <item name="navigationIconTintColor">@color/blue_800</item>
         <item name="progressTintColor">@color/blue_700</item>
 
index 85fb5e8e57d5a1da0fa5a88161a83759696e29f3..d26549635c6e90274de61ee065d0b0e1a8d20b01 100644 (file)
@@ -3,7 +3,7 @@
 <!--
   Copyright 2016-2024 Soren Stoutner <soren@stoutner.com>.
 
-  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
+  This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
 
   Privacy Browser Android is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
             app:entries="@array/search_entries"
             app:entryValues="@array/search_entry_values"
             app:defaultValue="@string/search_default_value"
-            app:icon="@drawable/search" />
+            app:icon="@drawable/search_blue" />
 
         <EditTextPreference
             app:key="@string/search_custom_url_key"
index 2491a84056b932fa455ec3d81447edd9cf4f0a82..c390d1f04c642472463442625862ed71ce4c2fea 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright 2016-2024 Soren Stoutner <soren@stoutner.com>.
  *
- * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
+ * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android/>.
  *
  * Privacy Browser Android is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by