mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-24 16:57:50 +00:00
Feature/debug menu (#1645)
* Reorganised cells * Clipping content * Simplifying Cell and leaving responsibility to modifier and content * Fixing animations Also fixing compose copy that wasn't set up properly... * Debug menu Added a debug menu It can be accessed from the settings page or via an app shortcut (from the app icon) * Finalising the debug menu We can now switch environments between mainnet and testnet * Update app/src/main/java/org/thoughtcrime/securesms/debugmenu/DebugMenu.kt Co-authored-by: AL-Session <160798022+AL-Session@users.noreply.github.com> --------- Co-authored-by: AL-Session <160798022+AL-Session@users.noreply.github.com>
This commit is contained in:
parent
bfbe4a8fd2
commit
1393335121
@ -241,6 +241,7 @@ dependencies {
|
||||
implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion"
|
||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycleVersion"
|
||||
implementation "androidx.lifecycle:lifecycle-process:$lifecycleVersion"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycleVersion"
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
|
||||
implementation "androidx.paging:paging-runtime-ktx:$pagingVersion"
|
||||
implementation 'androidx.activity:activity-ktx:1.5.1'
|
||||
|
@ -136,6 +136,10 @@
|
||||
android:name="org.thoughtcrime.securesms.preferences.SettingsActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:label="@string/activity_settings_title" />
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.debugmenu.DebugActivity"
|
||||
android:screenOrientation="portrait"
|
||||
android:theme="@style/Theme.Session.DayNight.NoActionBar" />
|
||||
<activity
|
||||
android:name="org.thoughtcrime.securesms.home.PathActivity"
|
||||
android:screenOrientation="portrait" />
|
||||
|
@ -27,6 +27,9 @@ import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.pm.ShortcutInfoCompat;
|
||||
import androidx.core.content.pm.ShortcutManagerCompat;
|
||||
import androidx.core.graphics.drawable.IconCompat;
|
||||
import androidx.lifecycle.DefaultLifecycleObserver;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.ProcessLifecycleOwner;
|
||||
@ -42,6 +45,7 @@ import org.session.libsession.snode.SnodeModule;
|
||||
import org.session.libsession.utilities.Address;
|
||||
import org.session.libsession.utilities.ConfigFactoryUpdateListener;
|
||||
import org.session.libsession.utilities.Device;
|
||||
import org.session.libsession.utilities.Environment;
|
||||
import org.session.libsession.utilities.ProfilePictureUtilities;
|
||||
import org.session.libsession.utilities.SSKEnvironment;
|
||||
import org.session.libsession.utilities.TextSecurePreferences;
|
||||
@ -62,6 +66,7 @@ import org.thoughtcrime.securesms.database.LokiAPIDatabase;
|
||||
import org.thoughtcrime.securesms.database.Storage;
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.database.model.EmojiSearchData;
|
||||
import org.thoughtcrime.securesms.debugmenu.DebugActivity;
|
||||
import org.thoughtcrime.securesms.dependencies.AppComponent;
|
||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory;
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
|
||||
@ -107,6 +112,7 @@ import dagger.hilt.EntryPoints;
|
||||
import dagger.hilt.android.HiltAndroidApp;
|
||||
import kotlin.Unit;
|
||||
import network.loki.messenger.BuildConfig;
|
||||
import network.loki.messenger.R;
|
||||
import network.loki.messenger.libsession_util.ConfigBase;
|
||||
import network.loki.messenger.libsession_util.UserProfile;
|
||||
|
||||
@ -232,7 +238,8 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
||||
messageNotifier = new OptimizedMessageNotifier(new DefaultMessageNotifier());
|
||||
broadcaster = new Broadcaster(this);
|
||||
LokiAPIDatabase apiDB = getDatabaseComponent().lokiAPIDatabase();
|
||||
SnodeModule.Companion.configure(apiDB, broadcaster);
|
||||
boolean useTestNet = textSecurePreferences.getEnvironment() == Environment.TEST_NET;
|
||||
SnodeModule.Companion.configure(apiDB, broadcaster, useTestNet);
|
||||
initializeExpiringMessageManager();
|
||||
initializeTypingStatusRepository();
|
||||
initializeTypingStatusSender();
|
||||
@ -248,6 +255,22 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
||||
|
||||
NetworkConstraint networkConstraint = new NetworkConstraint.Factory(this).create();
|
||||
HTTP.INSTANCE.setConnectedToNetwork(networkConstraint::isMet);
|
||||
|
||||
// add our shortcut debug menu if we are not in a release build
|
||||
if (BuildConfig.BUILD_TYPE != "release") {
|
||||
// add the config settings shortcut
|
||||
Intent intent = new Intent(this, DebugActivity.class);
|
||||
intent.setAction(Intent.ACTION_VIEW);
|
||||
|
||||
ShortcutInfoCompat shortcut = new ShortcutInfoCompat.Builder(this, "shortcut_debug_menu")
|
||||
.setShortLabel("Debug Menu")
|
||||
.setLongLabel("Debug Menu")
|
||||
.setIcon(IconCompat.createWithResource(this, R.drawable.ic_settings))
|
||||
.setIntent(intent)
|
||||
.build();
|
||||
|
||||
ShortcutManagerCompat.pushDynamicShortcut(this, shortcut);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -486,7 +509,7 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
||||
// 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.
|
||||
*/
|
||||
@SuppressLint("ApplySharedPref")
|
||||
@ -498,6 +521,16 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
|
||||
return false;
|
||||
}
|
||||
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));
|
||||
return true;
|
||||
}
|
||||
|
@ -2085,7 +2085,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
override fun showMessageDetail(messages: Set<MessageRecord>) {
|
||||
Intent(this, MessageDetailActivity::class.java)
|
||||
.apply { putExtra(MESSAGE_TIMESTAMP, messages.first().timestamp) }
|
||||
.let { handleMessageDetail.launch(it) }
|
||||
.let {
|
||||
handleMessageDetail.launch(it)
|
||||
overridePendingTransition(R.anim.slide_from_right, R.anim.slide_to_left)
|
||||
}
|
||||
|
||||
endActionMode()
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.conversation.v2
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent.ACTION_UP
|
||||
@ -15,6 +16,7 @@ import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.FlowRow
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@ -28,6 +30,7 @@ import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@ -35,6 +38,7 @@ import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
@ -58,23 +62,21 @@ import org.thoughtcrime.securesms.ui.Avatar
|
||||
import org.thoughtcrime.securesms.ui.CarouselNextButton
|
||||
import org.thoughtcrime.securesms.ui.CarouselPrevButton
|
||||
import org.thoughtcrime.securesms.ui.Cell
|
||||
import org.thoughtcrime.securesms.ui.CellNoMargin
|
||||
import org.thoughtcrime.securesms.ui.CellWithPaddingAndMargin
|
||||
import org.thoughtcrime.securesms.ui.Divider
|
||||
import org.thoughtcrime.securesms.ui.GetString
|
||||
import org.thoughtcrime.securesms.ui.HorizontalPagerIndicator
|
||||
import org.thoughtcrime.securesms.ui.LargeItemButton
|
||||
import org.thoughtcrime.securesms.ui.TitledText
|
||||
import org.thoughtcrime.securesms.ui.setComposeContent
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalColors
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalType
|
||||
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
|
||||
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
|
||||
import org.thoughtcrime.securesms.ui.TitledText
|
||||
import org.thoughtcrime.securesms.ui.theme.ThemeColors
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalColors
|
||||
import org.thoughtcrime.securesms.ui.theme.blackAlpha40
|
||||
import org.thoughtcrime.securesms.ui.theme.dangerButtonColors
|
||||
import org.thoughtcrime.securesms.ui.setComposeContent
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalType
|
||||
import org.thoughtcrime.securesms.ui.theme.bold
|
||||
import org.thoughtcrime.securesms.ui.theme.dangerButtonColors
|
||||
import org.thoughtcrime.securesms.ui.theme.monospace
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -191,8 +193,11 @@ fun CellMetadata(
|
||||
) {
|
||||
state.apply {
|
||||
if (listOfNotNull(sent, received, error, senderInfo).isEmpty()) return
|
||||
CellWithPaddingAndMargin {
|
||||
Column(verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing)) {
|
||||
Cell(modifier = Modifier.padding(horizontal = LocalDimensions.current.spacing)) {
|
||||
Column(
|
||||
modifier = Modifier.padding(LocalDimensions.current.spacing),
|
||||
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing)
|
||||
) {
|
||||
TitledText(sent)
|
||||
TitledText(received)
|
||||
TitledErrorText(error)
|
||||
@ -215,7 +220,7 @@ fun CellButtons(
|
||||
onResend: (() -> Unit)? = null,
|
||||
onDelete: () -> Unit = {},
|
||||
) {
|
||||
Cell {
|
||||
Cell(modifier = Modifier.padding(horizontal = LocalDimensions.current.spacing)) {
|
||||
Column {
|
||||
onReply?.let {
|
||||
LargeItemButton(
|
||||
@ -254,8 +259,11 @@ fun Carousel(attachments: List<Attachment>, onClick: (Int) -> Unit) {
|
||||
Row {
|
||||
CarouselPrevButton(pagerState)
|
||||
Box(modifier = Modifier.weight(1f)) {
|
||||
CellCarousel(pagerState, attachments, onClick)
|
||||
HorizontalPagerIndicator(pagerState)
|
||||
CarouselPager(pagerState, attachments, onClick)
|
||||
HorizontalPagerIndicator(
|
||||
pagerState = pagerState,
|
||||
modifier = Modifier.padding(bottom = LocalDimensions.current.xxsSpacing)
|
||||
)
|
||||
ExpandButton(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomEnd)
|
||||
@ -273,12 +281,15 @@ fun Carousel(attachments: List<Attachment>, onClick: (Int) -> Unit) {
|
||||
ExperimentalGlideComposeApi::class
|
||||
)
|
||||
@Composable
|
||||
private fun CellCarousel(
|
||||
private fun CarouselPager(
|
||||
pagerState: PagerState,
|
||||
attachments: List<Attachment>,
|
||||
onClick: (Int) -> Unit
|
||||
) {
|
||||
CellNoMargin {
|
||||
Cell(
|
||||
modifier = Modifier
|
||||
.clip(MaterialTheme.shapes.small)
|
||||
) {
|
||||
HorizontalPager(state = pagerState) { i ->
|
||||
GlideImage(
|
||||
contentScale = ContentScale.Crop,
|
||||
@ -317,6 +328,33 @@ fun PreviewMessageDetails(
|
||||
PreviewTheme(colors) {
|
||||
MessageDetails(
|
||||
state = MessageDetailsState(
|
||||
imageAttachments = listOf(
|
||||
Attachment(
|
||||
fileDetails = listOf(
|
||||
TitledText(R.string.message_details_header__file_id, "Screen Shot 2023-07-06 at 11.35.50 am.png")
|
||||
),
|
||||
fileName = "Screen Shot 2023-07-06 at 11.35.50 am.png",
|
||||
uri = Uri.parse(""),
|
||||
hasImage = true
|
||||
),
|
||||
Attachment(
|
||||
fileDetails = listOf(
|
||||
TitledText(R.string.message_details_header__file_id, "Screen Shot 2023-07-06 at 11.35.50 am.png")
|
||||
),
|
||||
fileName = "Screen Shot 2023-07-06 at 11.35.50 am.png",
|
||||
uri = Uri.parse(""),
|
||||
hasImage = true
|
||||
),
|
||||
Attachment(
|
||||
fileDetails = listOf(
|
||||
TitledText(R.string.message_details_header__file_id, "Screen Shot 2023-07-06 at 11.35.50 am.png")
|
||||
),
|
||||
fileName = "Screen Shot 2023-07-06 at 11.35.50 am.png",
|
||||
uri = Uri.parse(""),
|
||||
hasImage = true
|
||||
)
|
||||
|
||||
),
|
||||
nonImageAttachmentFileDetails = listOf(
|
||||
TitledText(R.string.message_details_header__file_id, "Screen Shot 2023-07-06 at 11.35.50 am.png"),
|
||||
TitledText(R.string.message_details_header__file_type, "image/png"),
|
||||
@ -337,7 +375,7 @@ fun PreviewMessageDetails(
|
||||
fun FileDetails(fileDetails: List<TitledText>) {
|
||||
if (fileDetails.isEmpty()) return
|
||||
|
||||
Cell {
|
||||
Cell(modifier = Modifier.padding(horizontal = LocalDimensions.current.spacing)) {
|
||||
FlowRow(
|
||||
modifier = Modifier.padding(horizontal = LocalDimensions.current.xsSpacing, vertical = LocalDimensions.current.spacing),
|
||||
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing)
|
||||
|
@ -0,0 +1,21 @@
|
||||
package org.thoughtcrime.securesms.debugmenu
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.thoughtcrime.securesms.ui.setComposeContent
|
||||
|
||||
|
||||
@AndroidEntryPoint
|
||||
class DebugActivity : AppCompatActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
setComposeContent {
|
||||
DebugMenuScreen(
|
||||
onClose = { finish() }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,172 @@
|
||||
package org.thoughtcrime.securesms.debugmenu
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
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.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
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.DialogButtonModel
|
||||
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.DropDown
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalColors
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalType
|
||||
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
|
||||
import org.thoughtcrime.securesms.ui.theme.bold
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun DebugMenu(
|
||||
uiState: DebugMenuViewModel.UIState,
|
||||
sendCommand: (DebugMenuViewModel.Commands) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
onClose: () -> Unit
|
||||
){
|
||||
val snackbarHostState = remember { SnackbarHostState() }
|
||||
|
||||
Scaffold(
|
||||
modifier = modifier.fillMaxSize(),
|
||||
snackbarHost = {
|
||||
SnackbarHost(hostState = snackbarHostState)
|
||||
}
|
||||
) { 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, // don't 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(
|
||||
modifier = Modifier
|
||||
.padding(contentPadding)
|
||||
.fillMaxSize()
|
||||
.background(color = LocalColors.current.background)
|
||||
) {
|
||||
// App bar
|
||||
BackAppBar(title = "Debug Menu", onBack = onClose)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = LocalDimensions.current.spacing)
|
||||
.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
// Info pane
|
||||
DebugCell("App Info") {
|
||||
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))
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun ColumnScope.DebugCell(
|
||||
title: String,
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
Spacer(modifier = Modifier.height(LocalDimensions.current.smallSpacing))
|
||||
|
||||
Cell {
|
||||
Column(
|
||||
modifier = modifier.padding(LocalDimensions.current.spacing)
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
style = LocalType.current.large.bold()
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.height(LocalDimensions.current.xsSpacing))
|
||||
|
||||
content()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewDebugMenu(){
|
||||
PreviewTheme {
|
||||
DebugMenu(
|
||||
uiState = DebugMenuViewModel.UIState(
|
||||
currentEnvironment = "Development",
|
||||
environments = listOf("Development", "Production"),
|
||||
snackMessage = null,
|
||||
showEnvironmentWarningDialog = false,
|
||||
showEnvironmentLoadingDialog = false
|
||||
),
|
||||
sendCommand = {},
|
||||
onClose = {}
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.thoughtcrime.securesms.debugmenu
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
|
||||
@Composable
|
||||
fun DebugMenuScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
debugMenuViewModel: DebugMenuViewModel = viewModel(),
|
||||
onClose: () -> Unit
|
||||
) {
|
||||
val uiState by debugMenuViewModel.uiState.collectAsState()
|
||||
|
||||
DebugMenu(
|
||||
modifier = modifier,
|
||||
uiState = uiState,
|
||||
sendCommand = debugMenuViewModel::onCommand,
|
||||
onClose = onClose
|
||||
)
|
||||
}
|
@ -0,0 +1,115 @@
|
||||
package org.thoughtcrime.securesms.debugmenu
|
||||
|
||||
import android.app.Application
|
||||
import android.widget.Toast
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers.Main
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
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.snode.SnodeAPI
|
||||
import org.session.libsession.utilities.TextSecurePreferences
|
||||
import org.session.libsignal.utilities.Log
|
||||
import org.thoughtcrime.securesms.ApplicationContext
|
||||
import org.session.libsession.utilities.Environment
|
||||
import org.thoughtcrime.securesms.dependencies.DatabaseComponent
|
||||
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class DebugMenuViewModel @Inject constructor(
|
||||
private val application: Application,
|
||||
private val textSecurePreferences: TextSecurePreferences
|
||||
) : ViewModel() {
|
||||
private val TAG = "DebugMenu"
|
||||
|
||||
private val _uiState = MutableStateFlow(
|
||||
UIState(
|
||||
currentEnvironment = textSecurePreferences.getEnvironment().label,
|
||||
environments = Environment.entries.map { it.label },
|
||||
snackMessage = null,
|
||||
showEnvironmentWarningDialog = false,
|
||||
showEnvironmentLoadingDialog = false
|
||||
)
|
||||
)
|
||||
val uiState: StateFlow<UIState>
|
||||
get() = _uiState
|
||||
|
||||
private var temporaryEnv: Environment? = null
|
||||
|
||||
fun onCommand(command: Commands) {
|
||||
when (command) {
|
||||
is Commands.ChangeEnvironment -> changeEnvironment()
|
||||
|
||||
is Commands.HideEnvironmentWarningDialog -> _uiState.value =
|
||||
_uiState.value.copy(showEnvironmentWarningDialog = false)
|
||||
|
||||
is Commands.ShowEnvironmentWarningDialog ->
|
||||
showEnvironmentWarningDialog(command.environment)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showEnvironmentWarningDialog(environment: String) {
|
||||
if(environment == _uiState.value.currentEnvironment) 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
|
||||
_uiState.value = _uiState.value.copy(
|
||||
showEnvironmentWarningDialog = false,
|
||||
showEnvironmentLoadingDialog = true
|
||||
)
|
||||
|
||||
// clear remote and local data, then restart the app
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(application).get()
|
||||
} catch (e: Exception) {
|
||||
// we can ignore fails here as we might be switching environments before the user gets a public key
|
||||
}
|
||||
ApplicationContext.getInstance(application).clearAllData().let { success ->
|
||||
if(success){
|
||||
// save the environment
|
||||
textSecurePreferences.setEnvironment(env)
|
||||
delay(500)
|
||||
ApplicationContext.getInstance(application).restartApplication()
|
||||
} else {
|
||||
_uiState.value = _uiState.value.copy(
|
||||
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(
|
||||
val currentEnvironment: String,
|
||||
val environments: List<String>,
|
||||
val snackMessage: String?,
|
||||
val showEnvironmentWarningDialog: Boolean,
|
||||
val showEnvironmentLoadingDialog: Boolean
|
||||
)
|
||||
|
||||
sealed class Commands {
|
||||
object ChangeEnvironment : Commands()
|
||||
data class ShowEnvironmentWarningDialog(val environment: String) : Commands()
|
||||
object HideEnvironmentWarningDialog : Commands()
|
||||
}
|
||||
}
|
@ -45,7 +45,7 @@ internal fun MessageNotificationsScreen(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
CircularProgressIndicator(LocalColors.current.primary)
|
||||
CircularProgressIndicator(color = LocalColors.current.primary)
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -72,7 +72,7 @@ internal class MessageNotificationsViewModel(
|
||||
_uiStates.update { it.copy(clearData = true) }
|
||||
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
ApplicationContext.getInstance(application).clearAllData()
|
||||
ApplicationContext.getInstance(application).clearAllDataAndRestart()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ class ClearAllDataDialog : DialogFragment() {
|
||||
}
|
||||
return
|
||||
}
|
||||
ApplicationContext.getInstance(context).clearAllData().let { success ->
|
||||
ApplicationContext.getInstance(context).clearAllDataAndRestart().let { success ->
|
||||
withContext(Main) {
|
||||
if (success) {
|
||||
dismiss()
|
||||
@ -162,7 +162,7 @@ class ClearAllDataDialog : DialogFragment() {
|
||||
}
|
||||
else if (deletionResultMap.values.all { it }) {
|
||||
// ..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() }
|
||||
}
|
||||
}
|
||||
|
@ -68,6 +68,7 @@ import org.session.libsignal.utilities.Util.SECURE_RANDOM
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||
import org.thoughtcrime.securesms.avatar.AvatarSelection
|
||||
import org.thoughtcrime.securesms.components.ProfilePictureView
|
||||
import org.thoughtcrime.securesms.debugmenu.DebugActivity
|
||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||
import org.thoughtcrime.securesms.home.PathActivity
|
||||
import org.thoughtcrime.securesms.messagerequests.MessageRequestsActivity
|
||||
@ -91,7 +92,6 @@ import org.thoughtcrime.securesms.util.BitmapUtil
|
||||
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||
import org.thoughtcrime.securesms.util.NetworkUtils
|
||||
import org.thoughtcrime.securesms.util.push
|
||||
import org.thoughtcrime.securesms.util.show
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -162,6 +162,9 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
super.onCreate(savedInstanceState, isReady)
|
||||
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
|
||||
// set the toolbar icon to a close icon
|
||||
supportActionBar?.setHomeAsUpIndicator(R.drawable.ic_baseline_close_24)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
@ -174,7 +177,8 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
btnGroupNameDisplay.text = getDisplayName()
|
||||
publicKeyTextView.text = hexEncodedPublicKey
|
||||
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 {
|
||||
@ -182,6 +186,11 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun finish() {
|
||||
super.finish()
|
||||
overridePendingTransition(R.anim.fade_scale_in, R.anim.slide_to_bottom)
|
||||
}
|
||||
|
||||
private fun getDisplayName(): String =
|
||||
TextSecurePreferences.getProfileName(this) ?: truncateIdForDisplay(hexEncodedPublicKey)
|
||||
|
||||
@ -473,10 +482,12 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
|
||||
@Composable
|
||||
fun Buttons() {
|
||||
Column {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = LocalDimensions.current.spacing)
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = LocalDimensions.current.spacing)
|
||||
.padding(top = LocalDimensions.current.xxsSpacing),
|
||||
horizontalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing),
|
||||
) {
|
||||
@ -498,27 +509,33 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
|
||||
Cell {
|
||||
Column {
|
||||
// add the debug menu in non release builds
|
||||
if (BuildConfig.BUILD_TYPE != "release") {
|
||||
LargeItemButton(R.string.activity_settings_debug_button_title, R.drawable.ic_settings) { push<DebugActivity>() }
|
||||
Divider()
|
||||
}
|
||||
|
||||
Crossfade(if (hasPaths) R.drawable.ic_status else R.drawable.ic_path_yellow, label = "path") {
|
||||
LargeItemButtonWithDrawable(R.string.activity_path_title, it) { show<PathActivity>() }
|
||||
LargeItemButtonWithDrawable(R.string.activity_path_title, it) { push<PathActivity>() }
|
||||
}
|
||||
Divider()
|
||||
LargeItemButton(R.string.activity_settings_privacy_button_title, R.drawable.ic_privacy_icon) { show<PrivacySettingsActivity>() }
|
||||
LargeItemButton(R.string.activity_settings_privacy_button_title, R.drawable.ic_privacy_icon) { push<PrivacySettingsActivity>() }
|
||||
Divider()
|
||||
LargeItemButton(R.string.activity_settings_notifications_button_title, R.drawable.ic_speaker, Modifier.contentDescription(R.string.AccessibilityId_notifications)) { show<NotificationSettingsActivity>() }
|
||||
LargeItemButton(R.string.activity_settings_notifications_button_title, R.drawable.ic_speaker, Modifier.contentDescription(R.string.AccessibilityId_notifications)) { push<NotificationSettingsActivity>() }
|
||||
Divider()
|
||||
LargeItemButton(R.string.activity_settings_conversations_button_title, R.drawable.ic_conversations, Modifier.contentDescription(R.string.AccessibilityId_conversations)) { show<ChatSettingsActivity>() }
|
||||
LargeItemButton(R.string.activity_settings_conversations_button_title, R.drawable.ic_conversations, Modifier.contentDescription(R.string.AccessibilityId_conversations)) { push<ChatSettingsActivity>() }
|
||||
Divider()
|
||||
LargeItemButton(R.string.activity_settings_message_requests_button_title, R.drawable.ic_message_requests, Modifier.contentDescription(R.string.AccessibilityId_message_requests)) { show<MessageRequestsActivity>() }
|
||||
LargeItemButton(R.string.activity_settings_message_requests_button_title, R.drawable.ic_message_requests, Modifier.contentDescription(R.string.AccessibilityId_message_requests)) { push<MessageRequestsActivity>() }
|
||||
Divider()
|
||||
LargeItemButton(R.string.activity_settings_message_appearance_button_title, R.drawable.ic_appearance, Modifier.contentDescription(R.string.AccessibilityId_appearance)) { show<AppearanceSettingsActivity>() }
|
||||
LargeItemButton(R.string.activity_settings_message_appearance_button_title, R.drawable.ic_appearance, Modifier.contentDescription(R.string.AccessibilityId_appearance)) { push<AppearanceSettingsActivity>() }
|
||||
Divider()
|
||||
LargeItemButton(R.string.activity_settings_invite_button_title, R.drawable.ic_invite_friend, Modifier.contentDescription(R.string.AccessibilityId_invite_friend)) { sendInvitationToUseSession() }
|
||||
Divider()
|
||||
if (!prefs.getHidePassword()) {
|
||||
LargeItemButton(R.string.sessionRecoveryPassword, R.drawable.ic_shield_outline, Modifier.contentDescription(R.string.AccessibilityId_recovery_password_menu_item)) { show<RecoveryPasswordActivity>() }
|
||||
LargeItemButton(R.string.sessionRecoveryPassword, R.drawable.ic_shield_outline, Modifier.contentDescription(R.string.AccessibilityId_recovery_password_menu_item)) { push<RecoveryPasswordActivity>() }
|
||||
Divider()
|
||||
}
|
||||
LargeItemButton(R.string.activity_settings_help_button, R.drawable.ic_help, Modifier.contentDescription(R.string.AccessibilityId_help)) { show<HelpSettingsActivity>() }
|
||||
LargeItemButton(R.string.activity_settings_help_button, R.drawable.ic_help, Modifier.contentDescription(R.string.AccessibilityId_help)) { push<HelpSettingsActivity>() }
|
||||
Divider()
|
||||
LargeItemButton(R.string.activity_settings_clear_all_data_button_title, R.drawable.ic_delete, Modifier.contentDescription(R.string.AccessibilityId_clear_data), dangerButtonColors()) { ClearAllDataDialog().show(supportFragmentManager, "Clear All Data Dialog") }
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.recoverypassword
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
@ -25,19 +26,19 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.ui.CellWithPaddingAndMargin
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
|
||||
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
|
||||
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
|
||||
import org.thoughtcrime.securesms.ui.Cell
|
||||
import org.thoughtcrime.securesms.ui.SessionShieldIcon
|
||||
import org.thoughtcrime.securesms.ui.theme.ThemeColors
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalColors
|
||||
import org.thoughtcrime.securesms.ui.components.QrImage
|
||||
import org.thoughtcrime.securesms.ui.components.SlimOutlineButton
|
||||
import org.thoughtcrime.securesms.ui.components.SlimOutlineCopyButton
|
||||
import org.thoughtcrime.securesms.ui.components.border
|
||||
import org.thoughtcrime.securesms.ui.contentDescription
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalColors
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalDimensions
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalType
|
||||
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
|
||||
import org.thoughtcrime.securesms.ui.theme.SessionColorsParameterProvider
|
||||
import org.thoughtcrime.securesms.ui.theme.ThemeColors
|
||||
import org.thoughtcrime.securesms.ui.theme.monospace
|
||||
|
||||
@Composable
|
||||
@ -53,6 +54,7 @@ internal fun RecoveryPasswordScreen(
|
||||
.contentDescription(R.string.AccessibilityId_recovery_password)
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(bottom = LocalDimensions.current.smallSpacing)
|
||||
.padding(horizontal = LocalDimensions.current.spacing)
|
||||
) {
|
||||
RecoveryPasswordCell(mnemonic, seed, copyMnemonic)
|
||||
HideRecoveryPasswordCell(onHide)
|
||||
@ -69,8 +71,10 @@ private fun RecoveryPasswordCell(
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
CellWithPaddingAndMargin {
|
||||
Column {
|
||||
Cell {
|
||||
Column(
|
||||
modifier = Modifier.padding(LocalDimensions.current.smallSpacing)
|
||||
) {
|
||||
Row {
|
||||
Text(
|
||||
stringResource(R.string.sessionRecoveryPassword),
|
||||
@ -148,8 +152,10 @@ private fun RecoveryPassword(mnemonic: String) {
|
||||
|
||||
@Composable
|
||||
private fun HideRecoveryPasswordCell(onHide: () -> Unit = {}) {
|
||||
CellWithPaddingAndMargin {
|
||||
Row {
|
||||
Cell {
|
||||
Row(
|
||||
modifier = Modifier.padding(LocalDimensions.current.smallSpacing)
|
||||
) {
|
||||
Column(
|
||||
Modifier.weight(1f)
|
||||
) {
|
||||
|
@ -3,13 +3,16 @@ package org.thoughtcrime.securesms.ui
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.IntrinsicSize
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.BasicAlertDialog
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
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.unit.dp
|
||||
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.LocalDimensions
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalType
|
||||
@ -48,6 +52,7 @@ class DialogButtonModel(
|
||||
@Composable
|
||||
fun AlertDialog(
|
||||
onDismissRequest: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
title: String? = null,
|
||||
text: String? = null,
|
||||
buttons: List<DialogButtonModel>? = null,
|
||||
@ -55,18 +60,10 @@ fun AlertDialog(
|
||||
content: @Composable () -> Unit = {}
|
||||
) {
|
||||
BasicAlertDialog(
|
||||
modifier = modifier,
|
||||
onDismissRequest = onDismissRequest,
|
||||
content = {
|
||||
Box(
|
||||
modifier = Modifier.background(
|
||||
color = LocalColors.current.backgroundSecondary,
|
||||
shape = MaterialTheme.shapes.small)
|
||||
.border(
|
||||
width = 1.dp,
|
||||
color = LocalColors.current.borders,
|
||||
shape = MaterialTheme.shapes.small)
|
||||
|
||||
) {
|
||||
DialogBg {
|
||||
// only show the 'x' button is required
|
||||
if (showCloseButton) {
|
||||
IconButton(
|
||||
@ -133,7 +130,7 @@ fun AlertDialog(
|
||||
@Composable
|
||||
fun DialogButton(
|
||||
text: String,
|
||||
modifier: Modifier,
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = Color.Unspecified,
|
||||
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
|
||||
@Composable
|
||||
fun PreviewSimpleDialog() {
|
||||
@ -200,3 +253,13 @@ fun PreviewXCloseDialog() {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewLoadingDialog() {
|
||||
PreviewTheme {
|
||||
LoadingDialog(
|
||||
title = stringResource(R.string.warning)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
@ -42,14 +43,17 @@ import kotlin.math.sign
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun BoxScope.HorizontalPagerIndicator(pagerState: PagerState) {
|
||||
if (pagerState.pageCount >= 2) Box(
|
||||
modifier = Modifier
|
||||
.background(color = blackAlpha40, shape = pillShape)
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(LocalDimensions.current.xxsSpacing)
|
||||
) {
|
||||
Box(modifier = Modifier.padding(LocalDimensions.current.xxsSpacing)) {
|
||||
fun BoxScope.HorizontalPagerIndicator(
|
||||
pagerState: PagerState,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
if (pagerState.pageCount >= 2){
|
||||
Box(
|
||||
modifier = modifier
|
||||
.background(color = blackAlpha40, shape = pillShape)
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(LocalDimensions.current.xxsSpacing)
|
||||
) {
|
||||
ClickableHorizontalPagerIndicator(
|
||||
pagerState = pagerState,
|
||||
pageCount = pagerState.pageCount
|
||||
|
@ -12,6 +12,7 @@ import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@ -105,7 +106,7 @@ fun <T> OptionsCard(card: OptionsCardData<T>, callbacks: Callbacks<T>) {
|
||||
|
||||
Spacer(modifier = Modifier.height(LocalDimensions.current.xsSpacing))
|
||||
|
||||
CellNoMargin {
|
||||
Cell {
|
||||
LazyColumn(
|
||||
modifier = Modifier.heightIn(max = 5000.dp)
|
||||
) {
|
||||
@ -257,32 +258,19 @@ fun PrewviewItemButton() {
|
||||
|
||||
@Composable
|
||||
fun Cell(
|
||||
padding: Dp = 0.dp,
|
||||
margin: Dp = LocalDimensions.current.spacing,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
CellWithPaddingAndMargin(padding, margin) { content() }
|
||||
}
|
||||
@Composable
|
||||
fun CellNoMargin(content: @Composable () -> Unit) {
|
||||
CellWithPaddingAndMargin(padding = 0.dp, margin = 0.dp) { content() }
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun CellWithPaddingAndMargin(
|
||||
padding: Dp = LocalDimensions.current.spacing,
|
||||
margin: Dp = LocalDimensions.current.spacing,
|
||||
modifier: Modifier = Modifier,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = margin)
|
||||
.background(color = LocalColors.current.backgroundSecondary,
|
||||
shape = MaterialTheme.shapes.small)
|
||||
modifier = modifier
|
||||
.background(
|
||||
color = LocalColors.current.backgroundSecondary,
|
||||
shape = MaterialTheme.shapes.small
|
||||
)
|
||||
.wrapContentHeight()
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
Box(Modifier.padding(padding)) { content() }
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,18 +8,24 @@ import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
@Composable
|
||||
fun CircularProgressIndicator(color: Color = LocalContentColor.current) {
|
||||
fun CircularProgressIndicator(
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = LocalContentColor.current
|
||||
) {
|
||||
androidx.compose.material3.CircularProgressIndicator(
|
||||
modifier = Modifier.size(40.dp),
|
||||
modifier = modifier.size(40.dp),
|
||||
color = color,
|
||||
strokeWidth = 2.dp
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SmallCircularProgressIndicator(color: Color = LocalContentColor.current) {
|
||||
fun SmallCircularProgressIndicator(
|
||||
modifier: Modifier = Modifier,
|
||||
color: Color = LocalContentColor.current
|
||||
) {
|
||||
androidx.compose.material3.CircularProgressIndicator(
|
||||
modifier = Modifier.size(20.dp),
|
||||
modifier = modifier.size(20.dp),
|
||||
color = color,
|
||||
strokeWidth = 2.dp
|
||||
)
|
||||
|
@ -0,0 +1,109 @@
|
||||
package org.thoughtcrime.securesms.ui.components
|
||||
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.ExposedDropdownMenuDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.MenuDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalColors
|
||||
import org.thoughtcrime.securesms.ui.theme.LocalType
|
||||
import org.thoughtcrime.securesms.ui.theme.PreviewTheme
|
||||
import org.thoughtcrime.securesms.ui.theme.bold
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun DropDown(
|
||||
modifier: Modifier = Modifier,
|
||||
selectedText: String,
|
||||
values: List<String>,
|
||||
onValueSelected: (String) -> Unit
|
||||
) {
|
||||
var expanded by remember { mutableStateOf(false) }
|
||||
|
||||
ExposedDropdownMenuBox(
|
||||
modifier = modifier,
|
||||
expanded = expanded,
|
||||
onExpandedChange = {
|
||||
expanded = !expanded
|
||||
}
|
||||
) {
|
||||
TextField(
|
||||
value = selectedText,
|
||||
onValueChange = {},
|
||||
readOnly = true,
|
||||
trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
|
||||
modifier = Modifier
|
||||
.menuAnchor()
|
||||
.border(
|
||||
1.dp,
|
||||
color = LocalColors.current.borders,
|
||||
shape = MaterialTheme.shapes.medium
|
||||
),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
colors = ExposedDropdownMenuDefaults.textFieldColors(
|
||||
focusedContainerColor = LocalColors.current.backgroundSecondary,
|
||||
unfocusedContainerColor = LocalColors.current.backgroundSecondary,
|
||||
disabledIndicatorColor = Color.Transparent,
|
||||
errorIndicatorColor = Color.Transparent,
|
||||
focusedIndicatorColor = Color.Transparent,
|
||||
unfocusedIndicatorColor = Color.Transparent,
|
||||
disabledTrailingIconColor = LocalColors.current.primary,
|
||||
errorTrailingIconColor = LocalColors.current.primary,
|
||||
focusedTrailingIconColor = LocalColors.current.primary,
|
||||
unfocusedTrailingIconColor = LocalColors.current.primary,
|
||||
disabledTextColor = LocalColors.current.text,
|
||||
errorTextColor = LocalColors.current.text,
|
||||
focusedTextColor = LocalColors.current.text,
|
||||
unfocusedTextColor = LocalColors.current.text
|
||||
),
|
||||
textStyle = LocalType.current.base.bold()
|
||||
)
|
||||
|
||||
ExposedDropdownMenu(
|
||||
expanded = expanded,
|
||||
onDismissRequest = { expanded = false }
|
||||
) {
|
||||
values.forEach { item ->
|
||||
DropdownMenuItem(
|
||||
text = {
|
||||
Text(
|
||||
text = item,
|
||||
style = LocalType.current.base
|
||||
)
|
||||
},
|
||||
colors = MenuDefaults.itemColors(
|
||||
textColor = LocalColors.current.text
|
||||
),
|
||||
onClick = {
|
||||
expanded = false
|
||||
onValueSelected(item)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewDropDown() {
|
||||
PreviewTheme {
|
||||
DropDown(
|
||||
selectedText = "Hello",
|
||||
values = listOf("First Item", "Second Item", "Third Item"),
|
||||
onValueSelected = {})
|
||||
}
|
||||
}
|
@ -8,11 +8,11 @@ import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.sp
|
||||
|
||||
|
||||
fun TextStyle.bold() = TextStyle.Default.copy(
|
||||
fun TextStyle.bold() = copy(
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
|
||||
fun TextStyle.monospace() = TextStyle.Default.copy(
|
||||
fun TextStyle.monospace() = copy(
|
||||
fontFamily = FontFamily.Monospace
|
||||
)
|
||||
|
||||
|
@ -53,7 +53,7 @@ fun AppCompatActivity.push(intent: Intent, isForResult: Boolean = false) {
|
||||
} else {
|
||||
startActivity(intent)
|
||||
}
|
||||
overridePendingTransition(R.anim.slide_from_right, R.anim.fade_scale_out)
|
||||
overridePendingTransition(R.anim.slide_from_right, R.anim.slide_to_left)
|
||||
}
|
||||
|
||||
fun AppCompatActivity.show(intent: Intent, isForResult: Boolean = false) {
|
||||
@ -108,5 +108,5 @@ data class ThemeState (
|
||||
)
|
||||
|
||||
inline fun <reified T: Activity> Activity.show() = Intent(this, T::class.java).also(::startActivity).let { overridePendingTransition(R.anim.slide_from_bottom, R.anim.fade_scale_out) }
|
||||
inline fun <reified T: Activity> Activity.push(modify: Intent.() -> Unit = {}) = Intent(this, T::class.java).also(modify).also(::startActivity).let { overridePendingTransition(R.anim.slide_from_right, R.anim.fade_scale_out) }
|
||||
inline fun <reified T: Activity> Activity.push(modify: Intent.() -> Unit = {}) = Intent(this, T::class.java).also(modify).also(::startActivity).let { overridePendingTransition(R.anim.slide_from_right, R.anim.slide_to_left) }
|
||||
inline fun <reified T: Activity> Context.start(modify: Intent.() -> Unit = {}) = Intent(this, T::class.java).also(modify).apply { addFlags(FLAG_ACTIVITY_SINGLE_TOP) }.let(::startActivity)
|
||||
|
21
app/src/main/res/anim/fade_scale_in.xml
Normal file
21
app/src/main/res/anim/fade_scale_in.xml
Normal file
@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<set
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:anim/decelerate_interpolator">
|
||||
|
||||
<scale
|
||||
android:duration="250"
|
||||
android:fromXScale="0.85"
|
||||
android:fromYScale="0.85"
|
||||
android:toXScale="1.0"
|
||||
android:toYScale="1.0"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%" />
|
||||
|
||||
<alpha
|
||||
android:duration="250"
|
||||
android:fromAlpha="0.6"
|
||||
android:toAlpha="1" />
|
||||
|
||||
</set>
|
11
app/src/main/res/anim/slide_to_bottom.xml
Normal file
11
app/src/main/res/anim/slide_to_bottom.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<set
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:anim/decelerate_interpolator">
|
||||
|
||||
<translate
|
||||
android:duration="250"
|
||||
android:fromYDelta="0%"
|
||||
android:toYDelta="100%" />
|
||||
|
||||
</set>
|
12
app/src/main/res/drawable/ic_settings.xml
Normal file
12
app/src/main/res/drawable/ic_settings.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="50"
|
||||
android:viewportHeight="50">
|
||||
<path
|
||||
android:pathData="M25,15.916C19.991,15.916 15.916,19.991 15.916,25C15.916,30.009 19.991,34.084 25,34.084C30.009,34.084 34.084,30.009 34.084,25C34.084,19.991 30.009,15.916 25,15.916ZM25,31.813C21.243,31.813 18.187,28.757 18.187,25C18.187,21.243 21.243,18.187 25,18.187C28.757,18.187 31.813,21.243 31.813,25C31.813,28.757 28.757,31.813 25,31.813Z"
|
||||
android:fillColor="#000000"/>
|
||||
<path
|
||||
android:pathData="M43.106,20.673L40.185,20.038C39.931,19.261 39.617,18.502 39.245,17.772L40.862,15.257C41.151,14.807 41.088,14.217 40.71,13.84L36.16,9.29C35.783,8.913 35.193,8.849 34.743,9.138L32.228,10.755C31.498,10.383 30.739,10.069 29.962,9.815L29.327,6.894C29.213,6.372 28.751,6 28.217,6H21.783C21.249,6 20.787,6.372 20.673,6.894L20.038,9.815C19.261,10.069 18.502,10.383 17.772,10.755L15.257,9.138C14.807,8.849 14.217,8.913 13.84,9.29L9.29,13.84C8.913,14.217 8.849,14.807 9.138,15.257L10.755,17.772C10.383,18.502 10.069,19.261 9.815,20.038L6.894,20.673C6.372,20.787 6,21.249 6,21.783V28.217C6,28.751 6.372,29.213 6.894,29.327L9.815,29.962C10.069,30.739 10.383,31.498 10.755,32.228L9.138,34.743C8.849,35.193 8.913,35.783 9.29,36.16L13.84,40.71C14.217,41.088 14.807,41.151 15.257,40.862L17.772,39.245C18.502,39.617 19.261,39.931 20.038,40.185L20.673,43.106C20.787,43.628 21.249,44 21.783,44H28.217C28.751,44 29.213,43.628 29.327,43.106L29.962,40.185C30.739,39.931 31.498,39.617 32.228,39.245L34.743,40.862C35.193,41.151 35.783,41.088 36.16,40.71L40.71,36.16C41.088,35.783 41.151,35.193 40.862,34.743L39.245,32.228C39.617,31.498 39.931,30.739 40.185,29.962L43.106,29.327C43.628,29.213 44,28.751 44,28.217V21.783C44,21.249 43.628,20.787 43.106,20.673ZM41.729,27.302L39.051,27.884C38.64,27.974 38.312,28.283 38.199,28.689C37.904,29.744 37.481,30.765 36.94,31.723C36.734,32.089 36.746,32.541 36.974,32.895L38.457,35.201L35.202,38.457L32.895,36.974C32.541,36.746 32.089,36.734 31.723,36.94C30.765,37.481 29.744,37.904 28.689,38.199C28.283,38.312 27.974,38.64 27.884,39.051L27.302,41.729H22.698L22.116,39.051C22.026,38.64 21.717,38.312 21.311,38.199C20.256,37.904 19.235,37.481 18.277,36.94C17.911,36.734 17.459,36.747 17.105,36.974L14.799,38.457L11.543,35.201L13.026,32.895C13.254,32.541 13.267,32.089 13.06,31.723C12.519,30.765 12.096,29.744 11.802,28.689C11.689,28.283 11.361,27.974 10.949,27.884L8.271,27.302V22.698L10.949,22.116C11.36,22.026 11.689,21.717 11.802,21.311C12.096,20.256 12.519,19.235 13.059,18.277C13.267,17.911 13.254,17.459 13.026,17.105L11.543,14.799L14.798,11.543L17.105,13.026C17.459,13.254 17.911,13.267 18.277,13.059C19.235,12.519 20.256,12.096 21.311,11.802C21.717,11.689 22.026,11.36 22.116,10.949L22.698,8.271H27.302L27.884,10.949C27.974,11.36 28.283,11.689 28.689,11.802C29.744,12.096 30.765,12.519 31.723,13.059C32.089,13.267 32.541,13.253 32.895,13.026L35.201,11.543L38.457,14.799L36.974,17.105C36.746,17.459 36.733,17.911 36.94,18.277C37.481,19.235 37.904,20.256 38.199,21.311C38.312,21.717 38.639,22.026 39.051,22.116L41.729,22.698V27.302Z"
|
||||
android:fillColor="#000000"/>
|
||||
</vector>
|
@ -787,6 +787,7 @@
|
||||
<string name="activity_settings_display_name_edit_text_hint">Enter a display name</string>
|
||||
<string name="activity_settings_display_name_missing_error">Please pick a display name</string>
|
||||
<string name="activity_settings_display_name_too_long_error">Please pick a shorter display name</string>
|
||||
<string name="activity_settings_debug_button_title">Debug Menu</string>
|
||||
<string name="activity_settings_privacy_button_title">Privacy</string>
|
||||
<string name="activity_settings_notifications_button_title">Notifications</string>
|
||||
<string name="activity_settings_message_requests_button_title">Message Requests</string>
|
||||
|
@ -2,7 +2,6 @@
|
||||
|
||||
package org.session.libsession.snode
|
||||
|
||||
import android.os.Build
|
||||
import com.goterl.lazysodium.exceptions.SodiumException
|
||||
import com.goterl.lazysodium.interfaces.GenericHash
|
||||
import com.goterl.lazysodium.interfaces.PwHash
|
||||
@ -76,9 +75,7 @@ object SnodeAPI {
|
||||
// Use port 4433 to enforce pinned certificates
|
||||
private val seedNodePort = 4443
|
||||
|
||||
private const val useTestnet = false
|
||||
|
||||
private val seedNodePool = if (useTestnet) setOf(
|
||||
private val seedNodePool = if (SnodeModule.shared.useTestNet) setOf(
|
||||
"http://public.loki.foundation:38157"
|
||||
) else setOf(
|
||||
"https://seed1.getsession.org:$seedNodePort",
|
||||
|
@ -3,16 +3,18 @@ package org.session.libsession.snode
|
||||
import org.session.libsignal.database.LokiAPIDatabaseProtocol
|
||||
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 {
|
||||
lateinit var shared: SnodeModule
|
||||
|
||||
val isInitialized: Boolean get() = Companion::shared.isInitialized
|
||||
|
||||
fun configure(storage: LokiAPIDatabaseProtocol, broadcaster: Broadcaster) {
|
||||
fun configure(storage: LokiAPIDatabaseProtocol, broadcaster: Broadcaster, useTestNet: Boolean) {
|
||||
if (isInitialized) { return }
|
||||
shared = SnodeModule(storage, broadcaster)
|
||||
shared = SnodeModule(storage, broadcaster, useTestNet)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package org.session.libsession.utilities
|
||||
|
||||
enum class Environment(val label: String) {
|
||||
MAIN_NET("Mainnet"), TEST_NET("Testnet")
|
||||
}
|
@ -18,6 +18,7 @@ import org.session.libsession.utilities.TextSecurePreferences.Companion.AUTOPLAY
|
||||
import org.session.libsession.utilities.TextSecurePreferences.Companion.CALL_NOTIFICATIONS_ENABLED
|
||||
import org.session.libsession.utilities.TextSecurePreferences.Companion.CLASSIC_DARK
|
||||
import org.session.libsession.utilities.TextSecurePreferences.Companion.CLASSIC_LIGHT
|
||||
import org.session.libsession.utilities.TextSecurePreferences.Companion.ENVIRONMENT
|
||||
import org.session.libsession.utilities.TextSecurePreferences.Companion.FOLLOW_SYSTEM_SETTINGS
|
||||
import org.session.libsession.utilities.TextSecurePreferences.Companion.HIDE_PASSWORD
|
||||
import org.session.libsession.utilities.TextSecurePreferences.Companion.LAST_VACUUM_TIME
|
||||
@ -190,6 +191,8 @@ interface TextSecurePreferences {
|
||||
fun setHidePassword(value: Boolean)
|
||||
fun getLastVersionCheck(): Long
|
||||
fun setLastVersionCheck()
|
||||
fun getEnvironment(): Environment
|
||||
fun setEnvironment(value: Environment)
|
||||
|
||||
companion object {
|
||||
val TAG = TextSecurePreferences::class.simpleName
|
||||
@ -277,6 +280,7 @@ interface TextSecurePreferences {
|
||||
const val FINGERPRINT_KEY_GENERATED = "fingerprint_key_generated"
|
||||
const val SELECTED_ACCENT_COLOR = "selected_accent_color"
|
||||
const val LAST_VERSION_CHECK = "pref_last_version_check"
|
||||
const val ENVIRONMENT = "debug_environment"
|
||||
|
||||
const val HAS_RECEIVED_LEGACY_CONFIG = "has_received_legacy_config"
|
||||
const val HAS_FORCED_NEW_CONFIG = "has_forced_new_config"
|
||||
@ -1554,6 +1558,17 @@ class AppTextSecurePreferences @Inject constructor(
|
||||
setLongPreference(LAST_VERSION_CHECK, System.currentTimeMillis())
|
||||
}
|
||||
|
||||
override fun getEnvironment(): Environment {
|
||||
val environment = getStringPreference(ENVIRONMENT, null)
|
||||
return if (environment != null) {
|
||||
Environment.valueOf(environment)
|
||||
} else Environment.MAIN_NET
|
||||
}
|
||||
|
||||
override fun setEnvironment(value: Environment) {
|
||||
setStringPreference(ENVIRONMENT, value.name)
|
||||
}
|
||||
|
||||
override fun setShownCallNotification(): Boolean {
|
||||
val previousValue = getBooleanPreference(SHOWN_CALL_NOTIFICATION, false)
|
||||
if (previousValue) return false
|
||||
|
Loading…
x
Reference in New Issue
Block a user