[tor-commits] [Git][tpo/applications/firefox-android][firefox-android-115.2.1-13.5-1] fixup! Add Tor integration and UI

Dan Ballard (@dan) git at gitlab.torproject.org
Wed Apr 17 01:00:20 UTC 2024



Dan Ballard pushed to branch firefox-android-115.2.1-13.5-1 at The Tor Project / Applications / firefox-android


Commits:
2095a229 by clairehurst at 2024-04-17T00:27:30+00:00
fixup! Add Tor integration and UI

- - - - -


4 changed files:

- + fenix/app/src/main/java/org/mozilla/fenix/tor/TorLogsComposeFragment.kt
- − fenix/app/src/main/java/org/mozilla/fenix/tor/TorLogsFragment.kt
- + fenix/app/src/main/java/org/mozilla/fenix/tor/TorLogsViewModel.kt
- fenix/app/src/main/res/navigation/nav_graph.xml


Changes:

=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/TorLogsComposeFragment.kt
=====================================
@@ -0,0 +1,82 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.tor
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.text.selection.DisableSelection
+import androidx.compose.foundation.text.selection.SelectionContainer
+import androidx.compose.foundation.verticalScroll
+import androidx.compose.material.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.Stable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.unit.dp
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
+import mozilla.components.ui.colors.PhotonColors
+
+class TorLogsComposeFragment : Fragment() {
+    private val viewModel: TorLogsViewModel by viewModels()
+
+    override fun onCreateView(
+        inflater: LayoutInflater,
+        container: ViewGroup?,
+        savedInstanceState: Bundle?,
+    ): View {
+        return ComposeView(requireContext()).apply {
+            setContent {
+                SelectionContainer {
+                    Column(
+                        // Column instead of LazyColumn so that you can select all the logs, and not just one "screen" at a time
+                        // The logs won't be too big so loading them all instead of just whats visible shouldn't be a big deal
+                        modifier = Modifier
+                            .fillMaxSize()
+                            .verticalScroll(state = rememberScrollState(), reverseScrolling = true),
+                    ) {
+                        for (log in viewModel.torLogs) {
+                            LogRow(log = log)
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+ at Composable
+ at Stable
+fun LogRow(log: TorLog, modifier: Modifier = Modifier) {
+    Column(
+        modifier
+            .fillMaxWidth()
+            .padding(
+                start = 16.dp,
+                end = 16.dp,
+                bottom = 16.dp,
+            ),
+    ) {
+        DisableSelection {
+            Text(
+                text = log.timestamp.toString(),
+                color = PhotonColors.LightGrey40,
+                modifier = modifier
+                    .padding(bottom = 4.dp),
+            )
+        }
+        Text(
+            text = log.text,
+            color = PhotonColors.LightGrey05,
+        )
+    }
+}


=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/TorLogsFragment.kt deleted
=====================================
@@ -1,81 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-package org.mozilla.fenix.tor
-
-import android.os.Bundle
-import android.text.method.ScrollingMovementMethod
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.fragment.app.Fragment
-import org.mozilla.fenix.R
-import org.mozilla.fenix.components.Components
-import org.mozilla.fenix.databinding.TorBootstrapLoggerBinding
-import org.mozilla.fenix.ext.requireComponents
-import org.mozilla.fenix.tor.view.TorBootstrapLoggerViewHolder
-
-class TorLogsFragment : Fragment(), TorLogs {
-
-    private var entries = mutableListOf<String>()
-    internal var _binding: TorBootstrapLoggerBinding? = null
-    private val binding get() = _binding!!
-
-    private var _components: Components? = null
-    private val components get() = _components!!
-
-    override fun onCreateView(
-        inflater: LayoutInflater,
-        container: ViewGroup?,
-        savedInstanceState: Bundle?,
-    ): View {
-        _binding = TorBootstrapLoggerBinding.inflate(inflater)
-        _components = requireComponents
-
-        components.torController.registerTorLogListener(this)
-
-        val currentEntries = components.torController.logEntries.filter { it.second != null }
-            .filter { !(it.second!!.startsWith("Circuit") && it.first == "ON") }
-            // Keep synchronized with format in onTorStatusUpdate
-            .flatMap { listOf("(${it.first}) '${it.second}'") }
-        val entriesLen = currentEntries.size
-        val subListOffset =
-            if (entriesLen > TorBootstrapLoggerViewHolder.MAX_NEW_ENTRIES) TorBootstrapLoggerViewHolder.MAX_NEW_ENTRIES else entriesLen
-        entries =
-            currentEntries.subList((entriesLen - subListOffset), entriesLen) as MutableList<String>
-        val initLog =
-            "---------------" + getString(R.string.tor_initializing_log) + "---------------"
-        entries.add(0, initLog)
-
-        with(binding.torBootstrapLogEntries) {
-            movementMethod = ScrollingMovementMethod()
-            text = formatLogEntries(entries)
-        }
-
-
-        return binding.root
-    }
-
-    // TODO on destroy unregiuster
-
-    private fun formatLogEntries(entries: List<String>) = entries.joinToString("\n")
-
-    override fun onLog(type: String?, message: String?) {
-        if (message == null || type == null) return
-        if (type == "ON" && type.startsWith("Circuit")) return
-
-        if (entries.size > TorBootstrapLoggerViewHolder.MAX_LINES) {
-            entries = entries.drop(1) as MutableList<String>
-        }
-        entries.add("($type) '$message'")
-
-        binding.torBootstrapLogEntries.text = formatLogEntries(entries)
-    }
-
-    override fun onStop() {
-        super.onStop()
-        components.torController.unregisterTorLogListener(this)
-    }
-
-}


=====================================
fenix/app/src/main/java/org/mozilla/fenix/tor/TorLogsViewModel.kt
=====================================
@@ -0,0 +1,88 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.tor
+
+import android.app.Application
+import android.content.ClipData
+import android.content.ClipboardManager
+import android.content.Context
+import android.os.Build
+import android.widget.Toast
+import androidx.compose.runtime.Stable
+import androidx.lifecycle.AndroidViewModel
+import org.mozilla.fenix.R
+import org.mozilla.fenix.ext.components
+import java.sql.Timestamp
+
+class TorLogsViewModel(application: Application) : AndroidViewModel(application), TorLogs {
+    private val torController = application.components.torController
+    private val clipboardManager =
+        application.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
+
+    val torLogs: MutableList<TorLog> = mutableListOf(
+        TorLog(
+            "---------------" + application.getString(R.string.tor_initializing_log) + "---------------",
+        ),
+    )
+
+    init {
+        setupClipboardListener()
+        torController.registerTorLogListener(this)
+        val currentEntries = torController.logEntries.filter { it.second != null }
+            .filter { !(it.second!!.startsWith("Circuit") && it.first == "ON") }
+            // Keep synchronized with format in onTorStatusUpdate
+            .flatMap { listOf(TorLog("[${it.first}] ${it.second}")) }
+        torLogs.addAll(currentEntries)
+    }
+
+    override fun onLog(type: String?, message: String?) {
+        if (message == null || type == null) return
+        if (type == "ON" && type.startsWith("Circuit")) return
+
+        torLogs.add(TorLog("[$type] $message"))
+    }
+
+    override fun onCleared() {
+        super.onCleared()
+        torController.unregisterTorLogListener(this)
+    }
+
+    private fun setupClipboardListener() {
+        clipboardManager.addPrimaryClipChangedListener {
+            // Only show a toast for Android 12 and lower.
+            // https://developer.android.com/develop/ui/views/touch-and-input/copy-paste#duplicate-notifications
+            if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
+                Toast.makeText(
+                    getApplication<Application>().applicationContext,
+                    getApplication<Application>().getString(R.string.toast_copy_link_to_clipboard), // "Copied to clipboard" already translated
+                    Toast.LENGTH_SHORT,
+                ).show()
+            }
+        }
+    }
+
+    fun copyAllLogsToClipboard() { // TODO add kebab menu in top right corner which includes option to "Copy all logs"
+        clipboardManager.setPrimaryClip(
+            ClipData.newPlainText(
+                "Copied Text",
+                getAllTorLogs(),
+            ),
+        )
+    }
+
+    private fun getAllTorLogs(): String {
+        var ret = ""
+        for (log in torLogs) {
+            ret += log.text + '\n'
+        }
+        return ret
+    }
+}
+
+ at Stable
+data class TorLog(
+    val text: String,
+    val timestamp: Timestamp = Timestamp(System.currentTimeMillis()),
+)


=====================================
fenix/app/src/main/res/navigation/nav_graph.xml
=====================================
@@ -976,8 +976,7 @@
     <fragment
         android:id="@+id/torBridgeConfigFragment"
         android:name="org.mozilla.fenix.settings.TorBridgeConfigFragment"
-        android:label="@string/preferences_tor_network_settings_bridge_config"
-        tools:layout="@layout/fragment_tor_bridge_config" />
+        android:label="@string/preferences_tor_network_settings_bridge_config" />
     <fragment
         android:id="@+id/torBetaConnectionFeaturesFragment"
         android:name="org.mozilla.fenix.tor.TorBetaConnectionFeaturesFragment"
@@ -985,9 +984,8 @@
         tools:layout="@layout/tor_network_settings_beta_connection_features" />
     <fragment
         android:id="@+id/torLogsFragment"
-        android:name="org.mozilla.fenix.tor.TorLogsFragment"
-        android:label="Tor Logs"
-        tools:layout="@layout/tor_bootstrap_logger" />
+        android:name="org.mozilla.fenix.tor.TorLogsComposeFragment"
+        android:label="@string/preferences_tor_logs" />
 
     <fragment
         android:id="@+id/trackingProtectionFragment"



View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/commit/2095a229dde4ebe19313e5ad399ad07fdb360b55

-- 
View it on GitLab: https://gitlab.torproject.org/tpo/applications/firefox-android/-/commit/2095a229dde4ebe19313e5ad399ad07fdb360b55
You're receiving this email because of your account on gitlab.torproject.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.torproject.org/pipermail/tor-commits/attachments/20240417/9e0d5156/attachment-0001.htm>


More information about the tor-commits mailing list