]> gitweb.stoutner.com Git - PrivacyBrowserAndroid.git/blobdiff - app/src/main/java/com/stoutner/privacybrowser/activities/ViewSourceActivity.kt
Unify URL syntax highlighting. https://redmine.stoutner.com/issues/704
[PrivacyBrowserAndroid.git] / app / src / main / java / com / stoutner / privacybrowser / activities / ViewSourceActivity.kt
index 691ff17fc1f7f75d97c5a252c45a3445877ccfa0..514e3095a2abd6fb6ae40351354766dc3e045806 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2017-2022 Soren Stoutner <soren@stoutner.com>.
+ * Copyright 2017-2022 Soren Stoutner <soren@stoutner.com>.
  *
  * This file is part of Privacy Browser Android <https://www.stoutner.com/privacy-browser-android>.
  *
 
 package com.stoutner.privacybrowser.activities
 
-import android.content.res.Configuration
 import android.os.Build
 import android.os.Bundle
 import android.text.SpannableStringBuilder
-import android.text.Spanned
 import android.text.style.ForegroundColorSpan
 import android.util.TypedValue
 import android.view.KeyEvent
@@ -53,6 +51,7 @@ import com.stoutner.privacybrowser.dialogs.AboutViewSourceDialog
 import com.stoutner.privacybrowser.dialogs.UntrustedSslCertificateDialog
 import com.stoutner.privacybrowser.dialogs.UntrustedSslCertificateDialog.UntrustedSslCertificateListener
 import com.stoutner.privacybrowser.helpers.ProxyHelper
+import com.stoutner.privacybrowser.helpers.UrlHelper
 import com.stoutner.privacybrowser.viewmodelfactories.WebViewSourceFactory
 import com.stoutner.privacybrowser.viewmodels.WebViewSource
 
@@ -139,26 +138,13 @@ class ViewSourceActivity: AppCompatActivity(), UntrustedSslCertificateListener {
         // Populate the URL text box.
         urlEditText.setText(currentUrl)
 
-        // Initialize the gray foreground color spans for highlighting the URLs.  The deprecated `getColor()` must be used until the minimum API >= 23.
-        @Suppress("DEPRECATION")
-        initialGrayColorSpan = ForegroundColorSpan(resources.getColor(R.color.gray_500))
-        @Suppress("DEPRECATION")
-        finalGrayColorSpan = ForegroundColorSpan(resources.getColor(R.color.gray_500))
-
-        // Get the current theme status.
-        val currentThemeStatus = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
-
-        // Set the red color span according to the theme.  The deprecated `getColor()` must be used until the minimum API >= 23.
-        redColorSpan = if (currentThemeStatus == Configuration.UI_MODE_NIGHT_NO) {
-            @Suppress("DEPRECATION")
-            ForegroundColorSpan(resources.getColor(R.color.red_a700))
-        } else {
-            @Suppress("DEPRECATION")
-            ForegroundColorSpan(resources.getColor(R.color.red_900))
-        }
+        // Initialize the gray foreground color spans for highlighting the URLs.
+        initialGrayColorSpan = ForegroundColorSpan(getColor(R.color.gray_500))
+        finalGrayColorSpan = ForegroundColorSpan(getColor(R.color.gray_500))
+        redColorSpan = ForegroundColorSpan(getColor(R.color.red_text))
 
         // Apply text highlighting to the URL.
-        highlightUrlText()
+        UrlHelper.highlightSyntax(urlEditText, initialGrayColorSpan, finalGrayColorSpan, redColorSpan)
 
         // Get a handle for the input method manager, which is used to hide the keyboard.
         val inputMethodManager = (getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager)
@@ -178,7 +164,7 @@ class ViewSourceActivity: AppCompatActivity(), UntrustedSslCertificateListener {
                 urlEditText.setSelection(0)
 
                 // Reapply the highlighting.
-                highlightUrlText()
+                UrlHelper.highlightSyntax(urlEditText, initialGrayColorSpan, finalGrayColorSpan, redColorSpan)
             }
         }
 
@@ -274,10 +260,10 @@ class ViewSourceActivity: AppCompatActivity(), UntrustedSslCertificateListener {
         val webViewSourceFactory: ViewModelProvider.Factory = WebViewSourceFactory(currentUrl, userAgent, localeString, proxy, contentResolver, MainWebViewActivity.executorService)
 
         // Instantiate the WebView source view model class.
-        webViewSource = ViewModelProvider(this, webViewSourceFactory).get(WebViewSource::class.java)
+        webViewSource = ViewModelProvider(this, webViewSourceFactory)[WebViewSource::class.java]
 
         // Create a source observer.
-        webViewSource.observeSource().observe(this, { sourceStringArray: Array<SpannableStringBuilder> ->
+        webViewSource.observeSource().observe(this) { sourceStringArray: Array<SpannableStringBuilder> ->
             // Populate the text views.  This can take a long time, and freezes the user interface, if the response body is particularly large.
             requestHeadersTextView.text = sourceStringArray[0]
             responseMessageTextView.text = sourceStringArray[1]
@@ -290,10 +276,10 @@ class ViewSourceActivity: AppCompatActivity(), UntrustedSslCertificateListener {
 
             //Stop the swipe to refresh indicator if it is running
             swipeRefreshLayout.isRefreshing = false
-        })
+        }
 
         // Create an error observer.
-        webViewSource.observeErrors().observe(this, { errorString: String ->
+        webViewSource.observeErrors().observe(this) { errorString: String ->
             // Display an error snackbar if the string is not `""`.
             if (errorString != "") {
                 if (errorString.startsWith("javax.net.ssl.SSLHandshakeException")) {
@@ -307,7 +293,7 @@ class ViewSourceActivity: AppCompatActivity(), UntrustedSslCertificateListener {
                     Snackbar.make(swipeRefreshLayout, errorString, Snackbar.LENGTH_LONG).show()
                 }
             }
-        })
+        }
 
         // Implement swipe to refresh.
         swipeRefreshLayout.setOnRefreshListener {
@@ -391,64 +377,6 @@ class ViewSourceActivity: AppCompatActivity(), UntrustedSslCertificateListener {
         webViewSource.updateSource(urlEditText.text.toString(), true)
     }
 
-    private fun highlightUrlText() {
-        // Get a handle for the URL edit text.
-        val urlEditText = findViewById<EditText>(R.id.url_edittext)
-
-        // Get the URL string.
-        val urlString = urlEditText.text.toString()
-
-        // Highlight the URL according to the protocol.
-        if (urlString.startsWith("file://")) {  // This is a file URL.
-            // De-emphasize only the protocol.
-            urlEditText.text.setSpan(initialGrayColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
-        } else if (urlString.startsWith("content://")) {
-            // De-emphasize only the protocol.
-            urlEditText.text.setSpan(initialGrayColorSpan, 0, 10, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
-        } else {  // This is a web URL.
-            // Get the index of the `/` immediately after the domain name.
-            val endOfDomainName = urlString.indexOf("/", urlString.indexOf("//") + 2)
-
-            // Get the base URL.
-            val baseUrl = if (endOfDomainName > 0) {  // There is at least one character after the base URL.
-                // Get the base URL.
-                urlString.substring(0, endOfDomainName)
-            } else {  // There are no characters after the base URL.
-                // Set the base URL to be the entire URL string.
-                urlString
-            }
-
-            // Get the index of the last `.` in the domain.
-            val lastDotIndex = baseUrl.lastIndexOf(".")
-
-            // Get the index of the penultimate `.` in the domain.
-            val penultimateDotIndex = baseUrl.lastIndexOf(".", lastDotIndex - 1)
-
-            // Markup the beginning of the URL.
-            if (urlString.startsWith("http://")) {  // Highlight the protocol of connections that are not encrypted.
-                urlEditText.text.setSpan(redColorSpan, 0, 7, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
-
-                // De-emphasize subdomains.
-                if (penultimateDotIndex > 0) {  // There is more than one subdomain in the domain name.
-                    urlEditText.text.setSpan(initialGrayColorSpan, 7, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
-                }
-            } else if (urlString.startsWith("https://")) {  // De-emphasize the protocol of connections that are encrypted.
-                if (penultimateDotIndex > 0) {  // There is more than one subdomain in the domain name.
-                    // De-emphasize the protocol and the additional subdomains.
-                    urlEditText.text.setSpan(initialGrayColorSpan, 0, penultimateDotIndex + 1, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
-                } else {  // There is only one subdomain in the domain name.
-                    // De-emphasize only the protocol.
-                    urlEditText.text.setSpan(initialGrayColorSpan, 0, 8, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
-                }
-            }
-
-            // De-emphasize the text after the domain name.
-            if (endOfDomainName > 0) {
-                urlEditText.text.setSpan(finalGrayColorSpan, endOfDomainName, urlString.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE)
-            }
-        }
-    }
-
     private fun updateLayout(urlString: String) {
         if (urlString.startsWith("content://")) {  // This is a content URL.
             // Hide the unused text views.
@@ -472,4 +400,4 @@ class ViewSourceActivity: AppCompatActivity(), UntrustedSslCertificateListener {
             responseBodyTitleTextView.setText(R.string.response_body)
         }
     }
-}
\ No newline at end of file
+}