Finalising the debug menu

We can now switch environments between mainnet and testnet
This commit is contained in:
ThomasSession 2024-08-26 12:02:46 +10:00
parent 89b3c616d7
commit bc001e3a45
11 changed files with 257 additions and 91 deletions

View File

@ -45,6 +45,7 @@ import org.session.libsession.snode.SnodeModule;
import org.session.libsession.utilities.Address; import org.session.libsession.utilities.Address;
import org.session.libsession.utilities.ConfigFactoryUpdateListener; import org.session.libsession.utilities.ConfigFactoryUpdateListener;
import org.session.libsession.utilities.Device; import org.session.libsession.utilities.Device;
import org.session.libsession.utilities.Environment;
import org.session.libsession.utilities.ProfilePictureUtilities; import org.session.libsession.utilities.ProfilePictureUtilities;
import org.session.libsession.utilities.SSKEnvironment; import org.session.libsession.utilities.SSKEnvironment;
import org.session.libsession.utilities.TextSecurePreferences; import org.session.libsession.utilities.TextSecurePreferences;
@ -237,7 +238,8 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
messageNotifier = new OptimizedMessageNotifier(new DefaultMessageNotifier()); messageNotifier = new OptimizedMessageNotifier(new DefaultMessageNotifier());
broadcaster = new Broadcaster(this); broadcaster = new Broadcaster(this);
LokiAPIDatabase apiDB = getDatabaseComponent().lokiAPIDatabase(); LokiAPIDatabase apiDB = getDatabaseComponent().lokiAPIDatabase();
SnodeModule.Companion.configure(apiDB, broadcaster); boolean useTestNet = textSecurePreferences.getEnvironment() == Environment.TEST_NET;
SnodeModule.Companion.configure(apiDB, broadcaster, useTestNet);
initializeExpiringMessageManager(); initializeExpiringMessageManager();
initializeTypingStatusRepository(); initializeTypingStatusRepository();
initializeTypingStatusSender(); initializeTypingStatusSender();
@ -507,7 +509,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
// Method to clear the local data - returns true on success otherwise false // Method to clear the local data - returns true on success otherwise false
/** /**
* Clear all local profile data and message history then restart the app after a brief delay. * Clear all local profile data and message history.
* @return true on success, false otherwise. * @return true on success, false otherwise.
*/ */
@SuppressLint("ApplySharedPref") @SuppressLint("ApplySharedPref")
@ -519,6 +521,16 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
return false; return false;
} }
configFactory.keyPairChanged(); configFactory.keyPairChanged();
return true;
}
/**
* Clear all local profile data and message history then restart the app after a brief delay.
* @return true on success, false otherwise.
*/
@SuppressLint("ApplySharedPref")
public boolean clearAllDataAndRestart() {
clearAllData();
Util.runOnMain(() -> new Handler().postDelayed(ApplicationContext.this::restartApplication, 200)); Util.runOnMain(() -> new Handler().postDelayed(ApplicationContext.this::restartApplication, 200));
return true; return true;
} }

View File

@ -1,33 +1,37 @@
package org.thoughtcrime.securesms.debugmenu package org.thoughtcrime.securesms.debugmenu
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import network.loki.messenger.BuildConfig import network.loki.messenger.BuildConfig
import network.loki.messenger.R
import org.thoughtcrime.securesms.debugmenu.DebugMenuViewModel.Commands.ChangeEnvironment
import org.thoughtcrime.securesms.debugmenu.DebugMenuViewModel.Commands.HideEnvironmentWarningDialog
import org.thoughtcrime.securesms.debugmenu.DebugMenuViewModel.Commands.ShowEnvironmentWarningDialog
import org.thoughtcrime.securesms.ui.AlertDialog
import org.thoughtcrime.securesms.ui.Cell import org.thoughtcrime.securesms.ui.Cell
import org.thoughtcrime.securesms.ui.components.AppBarCloseIcon import org.thoughtcrime.securesms.ui.DialogButtonModel
import org.thoughtcrime.securesms.ui.components.AppBarText import org.thoughtcrime.securesms.ui.GetString
import org.thoughtcrime.securesms.ui.LoadingDialog
import org.thoughtcrime.securesms.ui.components.BackAppBar import org.thoughtcrime.securesms.ui.components.BackAppBar
import org.thoughtcrime.securesms.ui.components.DropDown import org.thoughtcrime.securesms.ui.components.DropDown
import org.thoughtcrime.securesms.ui.components.appBarColors
import org.thoughtcrime.securesms.ui.theme.LocalColors import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalType import org.thoughtcrime.securesms.ui.theme.LocalType
@ -42,37 +46,84 @@ fun DebugMenu(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onClose: () -> Unit onClose: () -> Unit
){ ){
Column( val snackbarHostState = remember { SnackbarHostState() }
modifier = modifier
.fillMaxSize() Scaffold(
.background(color = LocalColors.current.background) modifier = modifier.fillMaxSize(),
) { snackbarHost = {
// App bar SnackbarHost(hostState = snackbarHostState)
BackAppBar(title = "Debug Menu", onBack = onClose) }
) { contentPadding ->
// display a snackbar when required
LaunchedEffect(uiState.snackMessage) {
if(!uiState.snackMessage.isNullOrEmpty()){
snackbarHostState.showSnackbar(uiState.snackMessage)
}
}
// Alert dialogs
if (uiState.showEnvironmentWarningDialog) {
AlertDialog(
onDismissRequest = { sendCommand(HideEnvironmentWarningDialog) },
title = "Are you sure you want to switch environments?",
text = "Changing this setting will result in all conversations and Snode data being cleared...",
showCloseButton = false, // display the 'x' button
buttons = listOf(
DialogButtonModel(
text = GetString(R.string.cancel),
contentDescription = GetString(R.string.cancel),
onClick = { sendCommand(HideEnvironmentWarningDialog) }
),
DialogButtonModel(
text = GetString(R.string.ok),
contentDescription = GetString(R.string.ok),
onClick = { sendCommand(ChangeEnvironment) }
)
)
)
}
if (uiState.showEnvironmentLoadingDialog) {
LoadingDialog(title = "Changing Environment...")
}
Column( Column(
modifier = Modifier modifier = Modifier
.padding(horizontal = LocalDimensions.current.spacing) .padding(contentPadding)
.verticalScroll(rememberScrollState()) .fillMaxSize()
.background(color = LocalColors.current.background)
) { ) {
// Info pane // App bar
DebugCell("App Info"){ BackAppBar(title = "Debug Menu", onBack = onClose)
Text(
text = "Version: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE} - ${BuildConfig.GIT_HASH.take(6)})",
style = LocalType.current.base
)
}
// Environment Column(
DebugCell("Environment"){ modifier = Modifier
DropDown( .padding(horizontal = LocalDimensions.current.spacing)
modifier = Modifier.fillMaxWidth(0.6f), .verticalScroll(rememberScrollState())
selectedText = uiState.currentEnvironment, ) {
values = uiState.environments, // Info pane
onValueSelected = { DebugCell("App Info") {
sendCommand(DebugMenuViewModel.Commands.ChangeEnvironment(it)) Text(
} text = "Version: ${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE} - ${
) BuildConfig.GIT_HASH.take(
6
)
})",
style = LocalType.current.base
)
}
// Environment
DebugCell("Environment") {
DropDown(
modifier = Modifier.fillMaxWidth(0.6f),
selectedText = uiState.currentEnvironment,
values = uiState.environments,
onValueSelected = {
sendCommand(ShowEnvironmentWarningDialog(it))
}
)
}
} }
} }
} }
@ -109,7 +160,10 @@ fun PreviewDebugMenu(){
DebugMenu( DebugMenu(
uiState = DebugMenuViewModel.UIState( uiState = DebugMenuViewModel.UIState(
currentEnvironment = "Development", currentEnvironment = "Development",
environments = listOf("Development", "Production") environments = listOf("Development", "Production"),
snackMessage = null,
showEnvironmentWarningDialog = false,
showEnvironmentLoadingDialog = false
), ),
sendCommand = {}, sendCommand = {},
onClose = {} onClose = {}

View File

@ -1,12 +1,17 @@
package org.thoughtcrime.securesms.debugmenu package org.thoughtcrime.securesms.debugmenu
import android.app.Application import android.app.Application
import android.widget.Toast
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import network.loki.messenger.R
import org.session.libsession.messaging.open_groups.OpenGroupApi import org.session.libsession.messaging.open_groups.OpenGroupApi
import org.session.libsession.snode.SnodeAPI import org.session.libsession.snode.SnodeAPI
import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.TextSecurePreferences
@ -14,6 +19,7 @@ import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.ApplicationContext
import org.session.libsession.utilities.Environment import org.session.libsession.utilities.Environment
import org.thoughtcrime.securesms.dependencies.DatabaseComponent import org.thoughtcrime.securesms.dependencies.DatabaseComponent
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
@ -26,59 +32,84 @@ class DebugMenuViewModel @Inject constructor(
private val _uiState = MutableStateFlow( private val _uiState = MutableStateFlow(
UIState( UIState(
currentEnvironment = textSecurePreferences.getEnvironment().label, currentEnvironment = textSecurePreferences.getEnvironment().label,
environments = Environment.entries.map { it.label } environments = Environment.entries.map { it.label },
snackMessage = null,
showEnvironmentWarningDialog = false,
showEnvironmentLoadingDialog = false
) )
) )
val uiState: StateFlow<UIState> val uiState: StateFlow<UIState>
get() = _uiState get() = _uiState
private var temporaryEnv: Environment? = null
fun onCommand(command: Commands) { fun onCommand(command: Commands) {
when (command) { when (command) {
is Commands.ChangeEnvironment -> changeEnvironment(command.environment) is Commands.ChangeEnvironment -> changeEnvironment()
is Commands.HideEnvironmentWarningDialog -> _uiState.value =
_uiState.value.copy(showEnvironmentWarningDialog = false)
is Commands.ShowEnvironmentWarningDialog ->
showEnvironmentWarningDialog(command.environment)
} }
} }
private fun changeEnvironment(environment: String) { private fun showEnvironmentWarningDialog(environment: String) {
if(environment == _uiState.value.currentEnvironment) return if(environment == _uiState.value.currentEnvironment) return
val env = Environment.entries.firstOrNull { it.label == environment } ?: return val env = Environment.entries.firstOrNull { it.label == environment } ?: return
temporaryEnv = env
_uiState.value = _uiState.value.copy(showEnvironmentWarningDialog = true)
}
private fun changeEnvironment() {
val env = temporaryEnv ?: return
// show a loading state // show a loading state
_uiState.value = _uiState.value.copy(
showEnvironmentWarningDialog = false,
showEnvironmentLoadingDialog = true
)
// clear remote and local data, then restart the app // clear remote and local data, then restart the app
viewModelScope.launch { viewModelScope.launch {
val deletionResultMap: Map<String, Boolean>? = try { try {
val openGroups = ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(application).get()
DatabaseComponent.get(application).lokiThreadDatabase().getAllOpenGroups()
openGroups.map { it.value.server }.toSet().forEach { server ->
OpenGroupApi.deleteAllInboxMessages(server).get()
}
SnodeAPI.deleteAllMessages().get()
} catch (e: Exception) { } catch (e: Exception) {
Log.e( // we can ignore fails here as we might be switching environments before the user gets a public key
TAG, "Failed to delete network message from debug menu", e
)
null
} }
ApplicationContext.getInstance(application).clearAllData().let { success ->
// If the network data deletion was successful proceed to delete the local data as well. if(success){
if (deletionResultMap?.values?.all { it } == true) { // save the environment
// save the environment textSecurePreferences.setEnvironment(env)
textSecurePreferences.setEnvironment(env) delay(500)
ApplicationContext.getInstance(application).restartApplication()
// clear local data and restart } else {
ApplicationContext.getInstance(application).clearAllData() _uiState.value = _uiState.value.copy(
} else { // the remote deletion failed, show an error showEnvironmentWarningDialog = false,
showEnvironmentLoadingDialog = false
)
Log.e(TAG, "Failed to force sync when deleting data")
_uiState.value = _uiState.value.copy(snackMessage = "Sorry, something went wrong...")
return@launch
}
} }
} }
} }
data class UIState( data class UIState(
val currentEnvironment: String, val currentEnvironment: String,
val environments: List<String> val environments: List<String>,
val snackMessage: String?,
val showEnvironmentWarningDialog: Boolean,
val showEnvironmentLoadingDialog: Boolean
) )
sealed class Commands { sealed class Commands {
data class ChangeEnvironment(val environment: String) : Commands() object ChangeEnvironment : Commands()
data class ShowEnvironmentWarningDialog(val environment: String) : Commands()
object HideEnvironmentWarningDialog : Commands()
} }
} }

View File

@ -45,7 +45,7 @@ internal fun MessageNotificationsScreen(
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
CircularProgressIndicator(LocalColors.current.primary) CircularProgressIndicator(color = LocalColors.current.primary)
} }
return return

View File

@ -72,7 +72,7 @@ internal class MessageNotificationsViewModel(
_uiStates.update { it.copy(clearData = true) } _uiStates.update { it.copy(clearData = true) }
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
ApplicationContext.getInstance(application).clearAllData() ApplicationContext.getInstance(application).clearAllDataAndRestart()
} }
} }

View File

@ -125,7 +125,7 @@ class ClearAllDataDialog : DialogFragment() {
} }
return return
} }
ApplicationContext.getInstance(context).clearAllData().let { success -> ApplicationContext.getInstance(context).clearAllDataAndRestart().let { success ->
withContext(Main) { withContext(Main) {
if (success) { if (success) {
dismiss() dismiss()
@ -162,7 +162,7 @@ class ClearAllDataDialog : DialogFragment() {
} }
else if (deletionResultMap.values.all { it }) { else if (deletionResultMap.values.all { it }) {
// ..otherwise if the network data deletion was successful proceed to delete the local data as well. // ..otherwise if the network data deletion was successful proceed to delete the local data as well.
ApplicationContext.getInstance(context).clearAllData() ApplicationContext.getInstance(context).clearAllDataAndRestart()
withContext(Main) { dismiss() } withContext(Main) { dismiss() }
} }
} }

View File

@ -177,7 +177,8 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
btnGroupNameDisplay.text = getDisplayName() btnGroupNameDisplay.text = getDisplayName()
publicKeyTextView.text = hexEncodedPublicKey publicKeyTextView.text = hexEncodedPublicKey
val gitCommitFirstSixChars = BuildConfig.GIT_HASH.take(6) val gitCommitFirstSixChars = BuildConfig.GIT_HASH.take(6)
versionTextView.text = String.format(getString(R.string.version_s), "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE} - $gitCommitFirstSixChars)") val environment: String = if(BuildConfig.BUILD_TYPE == "release") "" else " - ${prefs.getEnvironment().label}"
versionTextView.text = String.format(getString(R.string.version_s), "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE} - $gitCommitFirstSixChars) $environment")
} }
binding.composeView.setThemedContent { binding.composeView.setThemedContent {

View File

@ -3,13 +3,16 @@ package org.thoughtcrime.securesms.ui
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.BoxScope
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.BasicAlertDialog import androidx.compose.material3.BasicAlertDialog
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@ -29,6 +32,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import network.loki.messenger.R import network.loki.messenger.R
import org.thoughtcrime.securesms.ui.components.CircularProgressIndicator
import org.thoughtcrime.securesms.ui.theme.LocalColors import org.thoughtcrime.securesms.ui.theme.LocalColors
import org.thoughtcrime.securesms.ui.theme.LocalDimensions import org.thoughtcrime.securesms.ui.theme.LocalDimensions
import org.thoughtcrime.securesms.ui.theme.LocalType import org.thoughtcrime.securesms.ui.theme.LocalType
@ -48,6 +52,7 @@ class DialogButtonModel(
@Composable @Composable
fun AlertDialog( fun AlertDialog(
onDismissRequest: () -> Unit, onDismissRequest: () -> Unit,
modifier: Modifier = Modifier,
title: String? = null, title: String? = null,
text: String? = null, text: String? = null,
buttons: List<DialogButtonModel>? = null, buttons: List<DialogButtonModel>? = null,
@ -55,18 +60,10 @@ fun AlertDialog(
content: @Composable () -> Unit = {} content: @Composable () -> Unit = {}
) { ) {
BasicAlertDialog( BasicAlertDialog(
modifier = modifier,
onDismissRequest = onDismissRequest, onDismissRequest = onDismissRequest,
content = { content = {
Box( DialogBg {
modifier = Modifier.background(
color = LocalColors.current.backgroundSecondary,
shape = MaterialTheme.shapes.small)
.border(
width = 1.dp,
color = LocalColors.current.borders,
shape = MaterialTheme.shapes.small)
) {
// only show the 'x' button is required // only show the 'x' button is required
if (showCloseButton) { if (showCloseButton) {
IconButton( IconButton(
@ -133,7 +130,7 @@ fun AlertDialog(
@Composable @Composable
fun DialogButton( fun DialogButton(
text: String, text: String,
modifier: Modifier, modifier: Modifier = Modifier,
color: Color = Color.Unspecified, color: Color = Color.Unspecified,
onClick: () -> Unit onClick: () -> Unit
) { ) {
@ -154,6 +151,62 @@ fun DialogButton(
} }
} }
@Composable
fun DialogBg(
content: @Composable BoxScope.() -> Unit
){
Box(
modifier = Modifier
.background(
color = LocalColors.current.backgroundSecondary,
shape = MaterialTheme.shapes.small
)
.border(
width = 1.dp,
color = LocalColors.current.borders,
shape = MaterialTheme.shapes.small
)
) {
content()
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun LoadingDialog(
modifier: Modifier = Modifier,
title: String? = null,
){
BasicAlertDialog(
modifier = modifier,
onDismissRequest = {},
content = {
DialogBg {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(LocalDimensions.current.spacing)
) {
CircularProgressIndicator(
modifier = Modifier.align(Alignment.CenterHorizontally)
)
Spacer(modifier = Modifier.height(LocalDimensions.current.spacing))
title?.let {
Text(
it,
modifier = Modifier.align(Alignment.CenterHorizontally),
style = LocalType.current.large
)
}
}
}
}
)
}
@Preview @Preview
@Composable @Composable
fun PreviewSimpleDialog() { fun PreviewSimpleDialog() {
@ -200,3 +253,13 @@ fun PreviewXCloseDialog() {
) )
} }
} }
@Preview
@Composable
fun PreviewLoadingDialog() {
PreviewTheme {
LoadingDialog(
title = stringResource(R.string.warning)
)
}
}

View File

@ -8,18 +8,24 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@Composable @Composable
fun CircularProgressIndicator(color: Color = LocalContentColor.current) { fun CircularProgressIndicator(
modifier: Modifier = Modifier,
color: Color = LocalContentColor.current
) {
androidx.compose.material3.CircularProgressIndicator( androidx.compose.material3.CircularProgressIndicator(
modifier = Modifier.size(40.dp), modifier = modifier.size(40.dp),
color = color, color = color,
strokeWidth = 2.dp strokeWidth = 2.dp
) )
} }
@Composable @Composable
fun SmallCircularProgressIndicator(color: Color = LocalContentColor.current) { fun SmallCircularProgressIndicator(
modifier: Modifier = Modifier,
color: Color = LocalContentColor.current
) {
androidx.compose.material3.CircularProgressIndicator( androidx.compose.material3.CircularProgressIndicator(
modifier = Modifier.size(20.dp), modifier = modifier.size(20.dp),
color = color, color = color,
strokeWidth = 2.dp strokeWidth = 2.dp
) )

View File

@ -2,7 +2,6 @@
package org.session.libsession.snode package org.session.libsession.snode
import android.os.Build
import com.goterl.lazysodium.exceptions.SodiumException import com.goterl.lazysodium.exceptions.SodiumException
import com.goterl.lazysodium.interfaces.GenericHash import com.goterl.lazysodium.interfaces.GenericHash
import com.goterl.lazysodium.interfaces.PwHash import com.goterl.lazysodium.interfaces.PwHash
@ -76,9 +75,7 @@ object SnodeAPI {
// Use port 4433 to enforce pinned certificates // Use port 4433 to enforce pinned certificates
private val seedNodePort = 4443 private val seedNodePort = 4443
private const val useTestnet = false private val seedNodePool = if (SnodeModule.shared.useTestNet) setOf(
private val seedNodePool = if (useTestnet) setOf(
"http://public.loki.foundation:38157" "http://public.loki.foundation:38157"
) else setOf( ) else setOf(
"https://seed1.getsession.org:$seedNodePort", "https://seed1.getsession.org:$seedNodePort",

View File

@ -3,16 +3,18 @@ package org.session.libsession.snode
import org.session.libsignal.database.LokiAPIDatabaseProtocol import org.session.libsignal.database.LokiAPIDatabaseProtocol
import org.session.libsignal.utilities.Broadcaster import org.session.libsignal.utilities.Broadcaster
class SnodeModule(val storage: LokiAPIDatabaseProtocol, val broadcaster: Broadcaster) { class SnodeModule(
val storage: LokiAPIDatabaseProtocol, val broadcaster: Broadcaster, val useTestNet: Boolean
) {
companion object { companion object {
lateinit var shared: SnodeModule lateinit var shared: SnodeModule
val isInitialized: Boolean get() = Companion::shared.isInitialized val isInitialized: Boolean get() = Companion::shared.isInitialized
fun configure(storage: LokiAPIDatabaseProtocol, broadcaster: Broadcaster) { fun configure(storage: LokiAPIDatabaseProtocol, broadcaster: Broadcaster, useTestNet: Boolean) {
if (isInitialized) { return } if (isInitialized) { return }
shared = SnodeModule(storage, broadcaster) shared = SnodeModule(storage, broadcaster, useTestNet)
} }
} }
} }