mirror of
https://github.com/oxen-io/session-android.git
synced 2025-02-18 22:38:26 +00:00
Update settings
This commit is contained in:
parent
85c7a23235
commit
c589bed249
@ -373,6 +373,7 @@ dependencies {
|
|||||||
implementation "com.google.accompanist:accompanist-pager:0.33.1-alpha"
|
implementation "com.google.accompanist:accompanist-pager:0.33.1-alpha"
|
||||||
implementation "com.google.accompanist:accompanist-pager-indicators:0.33.1-alpha"
|
implementation "com.google.accompanist:accompanist-pager-indicators:0.33.1-alpha"
|
||||||
implementation "com.google.accompanist:accompanist-permissions:0.33.1-alpha"
|
implementation "com.google.accompanist:accompanist-permissions:0.33.1-alpha"
|
||||||
|
implementation "com.google.accompanist:accompanist-drawablepainter:0.33.1-alpha"
|
||||||
|
|
||||||
implementation "androidx.camera:camera-camera2:1.3.2"
|
implementation "androidx.camera:camera-camera2:1.3.2"
|
||||||
implementation "androidx.camera:camera-lifecycle:1.3.2"
|
implementation "androidx.camera:camera-lifecycle:1.3.2"
|
||||||
|
@ -161,7 +161,7 @@ import org.thoughtcrime.securesms.mms.MediaConstraints
|
|||||||
import org.thoughtcrime.securesms.mms.Slide
|
import org.thoughtcrime.securesms.mms.Slide
|
||||||
import org.thoughtcrime.securesms.mms.SlideDeck
|
import org.thoughtcrime.securesms.mms.SlideDeck
|
||||||
import org.thoughtcrime.securesms.mms.VideoSlide
|
import org.thoughtcrime.securesms.mms.VideoSlide
|
||||||
import org.thoughtcrime.securesms.onboarding.recoverypassword.startRecoveryPasswordActivity
|
import org.thoughtcrime.securesms.onboarding.recoverypassword.RecoveryPasswordActivity
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions
|
import org.thoughtcrime.securesms.permissions.Permissions
|
||||||
import org.thoughtcrime.securesms.reactions.ReactionsDialogFragment
|
import org.thoughtcrime.securesms.reactions.ReactionsDialogFragment
|
||||||
import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiDialogFragment
|
import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiDialogFragment
|
||||||
@ -176,6 +176,7 @@ import org.thoughtcrime.securesms.util.isScrolledToBottom
|
|||||||
import org.thoughtcrime.securesms.util.isScrolledToWithin30dpOfBottom
|
import org.thoughtcrime.securesms.util.isScrolledToWithin30dpOfBottom
|
||||||
import org.thoughtcrime.securesms.util.push
|
import org.thoughtcrime.securesms.util.push
|
||||||
import org.thoughtcrime.securesms.util.show
|
import org.thoughtcrime.securesms.util.show
|
||||||
|
import org.thoughtcrime.securesms.util.start
|
||||||
import org.thoughtcrime.securesms.util.toPx
|
import org.thoughtcrime.securesms.util.toPx
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@ -1602,7 +1603,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
|||||||
val userPublicKey = textSecurePreferences.getLocalNumber()
|
val userPublicKey = textSecurePreferences.getLocalNumber()
|
||||||
val isNoteToSelf = (recipient.isContactRecipient && recipient.address.toString() == userPublicKey)
|
val isNoteToSelf = (recipient.isContactRecipient && recipient.address.toString() == userPublicKey)
|
||||||
if (text.contains(seed) && !isNoteToSelf && !hasPermissionToSendSeed) {
|
if (text.contains(seed) && !isNoteToSelf && !hasPermissionToSendSeed) {
|
||||||
startRecoveryPasswordActivity()
|
start<RecoveryPasswordActivity>()
|
||||||
}
|
}
|
||||||
// Create the message
|
// Create the message
|
||||||
val message = VisibleMessage().applyExpiryMode(viewModel.threadId)
|
val message = VisibleMessage().applyExpiryMode(viewModel.threadId)
|
||||||
|
@ -92,7 +92,7 @@ import org.thoughtcrime.securesms.messagerequests.MessageRequestsActivity
|
|||||||
import org.thoughtcrime.securesms.mms.GlideApp
|
import org.thoughtcrime.securesms.mms.GlideApp
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||||
import org.thoughtcrime.securesms.notifications.PushRegistry
|
import org.thoughtcrime.securesms.notifications.PushRegistry
|
||||||
import org.thoughtcrime.securesms.onboarding.recoverypassword.startRecoveryPasswordActivity
|
import org.thoughtcrime.securesms.onboarding.recoverypassword.RecoveryPasswordActivity
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions
|
import org.thoughtcrime.securesms.permissions.Permissions
|
||||||
import org.thoughtcrime.securesms.preferences.SettingsActivity
|
import org.thoughtcrime.securesms.preferences.SettingsActivity
|
||||||
import org.thoughtcrime.securesms.showMuteDialog
|
import org.thoughtcrime.securesms.showMuteDialog
|
||||||
@ -111,6 +111,7 @@ import org.thoughtcrime.securesms.util.IP2Country
|
|||||||
import org.thoughtcrime.securesms.util.disableClipping
|
import org.thoughtcrime.securesms.util.disableClipping
|
||||||
import org.thoughtcrime.securesms.util.push
|
import org.thoughtcrime.securesms.util.push
|
||||||
import org.thoughtcrime.securesms.util.show
|
import org.thoughtcrime.securesms.util.show
|
||||||
|
import org.thoughtcrime.securesms.util.start
|
||||||
import org.thoughtcrime.securesms.util.themeState
|
import org.thoughtcrime.securesms.util.themeState
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@ -374,7 +375,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
|||||||
stringResource(R.string.continue_2),
|
stringResource(R.string.continue_2),
|
||||||
Modifier.align(Alignment.CenterVertically),
|
Modifier.align(Alignment.CenterVertically),
|
||||||
contentDescription = GetString(R.string.AccessibilityId_reveal_recovery_phrase_button)
|
contentDescription = GetString(R.string.AccessibilityId_reveal_recovery_phrase_button)
|
||||||
) { startRecoveryPasswordActivity() }
|
) { start<RecoveryPasswordActivity>() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,21 @@
|
|||||||
package org.thoughtcrime.securesms.onboarding.recoverypassword
|
package org.thoughtcrime.securesms.onboarding.recoverypassword
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
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.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
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.layout.width
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.Card
|
|
||||||
import androidx.compose.material.Icon
|
|
||||||
import androidx.compose.material.MaterialTheme
|
import androidx.compose.material.MaterialTheme
|
||||||
import androidx.compose.material.Text
|
import androidx.compose.material.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
@ -30,10 +24,7 @@ import androidx.compose.runtime.mutableStateOf
|
|||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.ColorFilter
|
|
||||||
import androidx.compose.ui.graphics.asImageBitmap
|
|
||||||
import androidx.compose.ui.platform.ComposeView
|
import androidx.compose.ui.platform.ComposeView
|
||||||
import androidx.compose.ui.res.painterResource
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
import androidx.compose.ui.text.font.FontFamily
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
@ -52,6 +43,7 @@ import org.thoughtcrime.securesms.ui.SessionShieldIcon
|
|||||||
import org.thoughtcrime.securesms.ui.ThemeResPreviewParameterProvider
|
import org.thoughtcrime.securesms.ui.ThemeResPreviewParameterProvider
|
||||||
import org.thoughtcrime.securesms.ui.classicDarkColors
|
import org.thoughtcrime.securesms.ui.classicDarkColors
|
||||||
import org.thoughtcrime.securesms.ui.colorDestructive
|
import org.thoughtcrime.securesms.ui.colorDestructive
|
||||||
|
import org.thoughtcrime.securesms.ui.components.QrImageCard
|
||||||
import org.thoughtcrime.securesms.ui.contentDescription
|
import org.thoughtcrime.securesms.ui.contentDescription
|
||||||
import org.thoughtcrime.securesms.ui.h8
|
import org.thoughtcrime.securesms.ui.h8
|
||||||
import org.thoughtcrime.securesms.ui.small
|
import org.thoughtcrime.securesms.ui.small
|
||||||
@ -68,7 +60,6 @@ class RecoveryPasswordActivity : BaseActionBarActivity() {
|
|||||||
setContent {
|
setContent {
|
||||||
RecoveryPassword(
|
RecoveryPassword(
|
||||||
viewModel.seed,
|
viewModel.seed,
|
||||||
viewModel.qrBitmap,
|
|
||||||
{ viewModel.copySeed(context) }
|
{ viewModel.copySeed(context) }
|
||||||
) { onHide() }
|
) { onHide() }
|
||||||
}
|
}
|
||||||
@ -113,7 +104,6 @@ fun PreviewRecoveryPassword(
|
|||||||
@Composable
|
@Composable
|
||||||
fun RecoveryPassword(
|
fun RecoveryPassword(
|
||||||
seed: String = "",
|
seed: String = "",
|
||||||
qrBitmap: Bitmap? = null,
|
|
||||||
copySeed:() -> Unit = {},
|
copySeed:() -> Unit = {},
|
||||||
onHide:() -> Unit = {}
|
onHide:() -> Unit = {}
|
||||||
) {
|
) {
|
||||||
@ -124,14 +114,14 @@ fun RecoveryPassword(
|
|||||||
.verticalScroll(rememberScrollState())
|
.verticalScroll(rememberScrollState())
|
||||||
.padding(bottom = 16.dp)
|
.padding(bottom = 16.dp)
|
||||||
) {
|
) {
|
||||||
RecoveryPasswordCell(seed, qrBitmap, copySeed)
|
RecoveryPasswordCell(seed, copySeed)
|
||||||
HideRecoveryPasswordCell(onHide)
|
HideRecoveryPasswordCell(onHide)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RecoveryPasswordCell(seed: String = "", qrBitmap: Bitmap? = null, copySeed:() -> Unit = {}) {
|
fun RecoveryPasswordCell(seed: String, copySeed:() -> Unit = {}) {
|
||||||
val showQr = remember {
|
val showQr = remember {
|
||||||
mutableStateOf(false)
|
mutableStateOf(false)
|
||||||
}
|
}
|
||||||
@ -163,21 +153,15 @@ fun RecoveryPasswordCell(seed: String = "", qrBitmap: Bitmap? = null, copySeed:(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedVisibility(showQr.value, modifier = Modifier.align(Alignment.CenterHorizontally)) {
|
AnimatedVisibility(
|
||||||
Card(
|
showQr.value,
|
||||||
backgroundColor = LocalExtraColors.current.lightCell,
|
modifier = Modifier.align(Alignment.CenterHorizontally).padding(vertical = 24.dp)
|
||||||
elevation = 0.dp,
|
) {
|
||||||
modifier = Modifier
|
QrImageCard(
|
||||||
.align(Alignment.CenterHorizontally)
|
seed,
|
||||||
.padding(vertical = 24.dp)
|
contentDescription = "QR code of your recovery password",
|
||||||
) {
|
icon = R.drawable.session_shield
|
||||||
qrBitmap?.let {
|
)
|
||||||
QrImage(
|
|
||||||
bitmap = it,
|
|
||||||
contentDescription = "QR code of your recovery password",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedVisibility(!showQr.value) {
|
AnimatedVisibility(!showQr.value) {
|
||||||
@ -205,29 +189,6 @@ fun RecoveryPasswordCell(seed: String = "", qrBitmap: Bitmap? = null, copySeed:(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun QrImage(bitmap: Bitmap, contentDescription: String, icon: Int = R.drawable.session_shield) {
|
|
||||||
Box {
|
|
||||||
Image(
|
|
||||||
bitmap = bitmap.asImageBitmap(),
|
|
||||||
contentDescription = contentDescription,
|
|
||||||
colorFilter = ColorFilter.tint(LocalExtraColors.current.onLightCell)
|
|
||||||
)
|
|
||||||
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(id = icon),
|
|
||||||
contentDescription = "",
|
|
||||||
tint = LocalExtraColors.current.onLightCell,
|
|
||||||
modifier = Modifier
|
|
||||||
.align(Alignment.Center)
|
|
||||||
.width(46.dp)
|
|
||||||
.height(56.dp)
|
|
||||||
.background(color = LocalExtraColors.current.lightCell)
|
|
||||||
.padding(horizontal = 3.dp, vertical = 1.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun MutableState<Boolean>.toggle() { value = !value }
|
private fun MutableState<Boolean>.toggle() { value = !value }
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -247,7 +208,3 @@ fun HideRecoveryPasswordCell(onHide: () -> Unit = {}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Context.startRecoveryPasswordActivity() {
|
|
||||||
Intent(this, RecoveryPasswordActivity::class.java).also(::startActivity)
|
|
||||||
}
|
|
||||||
|
@ -42,13 +42,4 @@ class RecoveryPasswordViewModel @Inject constructor(
|
|||||||
MnemonicCodec { MnemonicUtilities.loadFileContents(application, it) }
|
MnemonicCodec { MnemonicUtilities.loadFileContents(application, it) }
|
||||||
.encode(hexEncodedSeed, MnemonicCodec.Language.Configuration.english)
|
.encode(hexEncodedSeed, MnemonicCodec.Language.Configuration.english)
|
||||||
}
|
}
|
||||||
|
|
||||||
val qrBitmap by lazy {
|
|
||||||
QRCodeUtilities.encode(
|
|
||||||
data = seed,
|
|
||||||
size = toPx(280, application.resources),
|
|
||||||
isInverted = false,
|
|
||||||
hasTransparentBackground = true
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,14 @@ package org.thoughtcrime.securesms.preferences
|
|||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.ClipboardManager
|
import android.content.ClipboardManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.AsyncTask
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
|
||||||
import android.os.Looper
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import android.view.ActionMode
|
import android.view.ActionMode
|
||||||
@ -20,9 +19,38 @@ import android.view.View
|
|||||||
import android.view.inputmethod.EditorInfo
|
import android.view.inputmethod.EditorInfo
|
||||||
import android.view.inputmethod.InputMethodManager
|
import android.view.inputmethod.InputMethodManager
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.Card
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
|
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.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.core.view.isGone
|
import androidx.core.view.isGone
|
||||||
|
import androidx.core.view.isInvisible
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.channels.BufferOverflow
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
import network.loki.messenger.BuildConfig
|
import network.loki.messenger.BuildConfig
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import network.loki.messenger.databinding.ActivitySettingsBinding
|
import network.loki.messenger.databinding.ActivitySettingsBinding
|
||||||
@ -34,23 +62,37 @@ import nl.komponents.kovenant.ui.successUi
|
|||||||
import org.session.libsession.avatars.AvatarHelper
|
import org.session.libsession.avatars.AvatarHelper
|
||||||
import org.session.libsession.avatars.ProfileContactPhoto
|
import org.session.libsession.avatars.ProfileContactPhoto
|
||||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||||
|
import org.session.libsession.snode.OnionRequestAPI
|
||||||
import org.session.libsession.snode.SnodeAPI
|
import org.session.libsession.snode.SnodeAPI
|
||||||
import org.session.libsession.utilities.*
|
import org.session.libsession.utilities.Address
|
||||||
|
import org.session.libsession.utilities.ProfileKeyUtil
|
||||||
|
import org.session.libsession.utilities.ProfilePictureUtilities
|
||||||
import org.session.libsession.utilities.SSKEnvironment.ProfileManagerProtocol
|
import org.session.libsession.utilities.SSKEnvironment.ProfileManagerProtocol
|
||||||
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
import org.session.libsession.utilities.recipients.Recipient
|
import org.session.libsession.utilities.recipients.Recipient
|
||||||
|
import org.session.libsession.utilities.truncateIdForDisplay
|
||||||
|
import org.session.libsignal.utilities.Log
|
||||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||||
import org.thoughtcrime.securesms.avatar.AvatarSelection
|
import org.thoughtcrime.securesms.avatar.AvatarSelection
|
||||||
import org.thoughtcrime.securesms.components.ProfilePictureView
|
import org.thoughtcrime.securesms.components.ProfilePictureView
|
||||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||||
import org.thoughtcrime.securesms.home.PathActivity
|
import org.thoughtcrime.securesms.home.PathActivity
|
||||||
import org.thoughtcrime.securesms.messagerequests.MessageRequestsActivity
|
import org.thoughtcrime.securesms.messagerequests.MessageRequestsActivity
|
||||||
import org.thoughtcrime.securesms.mms.GlideApp
|
import org.thoughtcrime.securesms.onboarding.recoverypassword.RecoveryPasswordActivity
|
||||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
|
||||||
import org.thoughtcrime.securesms.onboarding.recoverypassword.startRecoveryPasswordActivity
|
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions
|
import org.thoughtcrime.securesms.permissions.Permissions
|
||||||
import org.thoughtcrime.securesms.preferences.appearance.AppearanceSettingsActivity
|
import org.thoughtcrime.securesms.preferences.appearance.AppearanceSettingsActivity
|
||||||
import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints
|
import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints
|
||||||
import org.thoughtcrime.securesms.showSessionDialog
|
import org.thoughtcrime.securesms.showSessionDialog
|
||||||
|
import org.thoughtcrime.securesms.ui.AppTheme
|
||||||
|
import org.thoughtcrime.securesms.ui.BorderlessButton
|
||||||
|
import org.thoughtcrime.securesms.ui.Cell
|
||||||
|
import org.thoughtcrime.securesms.ui.Divider
|
||||||
|
import org.thoughtcrime.securesms.ui.ItemButton
|
||||||
|
import org.thoughtcrime.securesms.ui.ItemButtonWithDrawable
|
||||||
|
import org.thoughtcrime.securesms.ui.OutlineButton
|
||||||
|
import org.thoughtcrime.securesms.ui.PreviewTheme
|
||||||
|
import org.thoughtcrime.securesms.ui.ThemeResPreviewParameterProvider
|
||||||
|
import org.thoughtcrime.securesms.ui.destructiveButtonColors
|
||||||
import org.thoughtcrime.securesms.util.BitmapDecodingException
|
import org.thoughtcrime.securesms.util.BitmapDecodingException
|
||||||
import org.thoughtcrime.securesms.util.BitmapUtil
|
import org.thoughtcrime.securesms.util.BitmapUtil
|
||||||
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||||
@ -61,6 +103,8 @@ import java.io.File
|
|||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val TAG = "SettingsActivity"
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||||
|
|
||||||
@ -69,21 +113,14 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
@Inject
|
@Inject
|
||||||
lateinit var prefs: TextSecurePreferences
|
lateinit var prefs: TextSecurePreferences
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private lateinit var binding: ActivitySettingsBinding
|
private lateinit var binding: ActivitySettingsBinding
|
||||||
private var displayNameEditActionMode: ActionMode? = null
|
private var displayNameEditActionMode: ActionMode? = null
|
||||||
set(value) { field = value; handleDisplayNameEditActionModeChanged() }
|
set(value) { field = value; handleDisplayNameEditActionModeChanged() }
|
||||||
private lateinit var glide: GlideRequests
|
|
||||||
private var tempFile: File? = null
|
private var tempFile: File? = null
|
||||||
|
|
||||||
private val hexEncodedPublicKey: String
|
private val hexEncodedPublicKey: String get() = TextSecurePreferences.getLocalNumber(this)!!
|
||||||
get() {
|
|
||||||
return TextSecurePreferences.getLocalNumber(this)!!
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val updatedProfileResultCode = 1234
|
|
||||||
private const val SCROLL_STATE = "SCROLL_STATE"
|
private const val SCROLL_STATE = "SCROLL_STATE"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,7 +129,12 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
super.onCreate(savedInstanceState, isReady)
|
super.onCreate(savedInstanceState, isReady)
|
||||||
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
glide = GlideApp.with(this)
|
|
||||||
|
binding.composeView.setContent {
|
||||||
|
AppTheme {
|
||||||
|
Buttons()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
@ -104,21 +146,6 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
ctnGroupNameSection.setOnClickListener { startActionMode(DisplayNameEditActionModeCallback()) }
|
ctnGroupNameSection.setOnClickListener { startActionMode(DisplayNameEditActionModeCallback()) }
|
||||||
btnGroupNameDisplay.text = getDisplayName()
|
btnGroupNameDisplay.text = getDisplayName()
|
||||||
publicKeyTextView.text = hexEncodedPublicKey
|
publicKeyTextView.text = hexEncodedPublicKey
|
||||||
copyButton.setOnClickListener { copyPublicKey() }
|
|
||||||
shareButton.setOnClickListener { sharePublicKey() }
|
|
||||||
pathButton.setOnClickListener { showPath() }
|
|
||||||
pathContainer.disableClipping()
|
|
||||||
privacyButton.setOnClickListener { showPrivacySettings() }
|
|
||||||
notificationsButton.setOnClickListener { showNotificationSettings() }
|
|
||||||
messageRequestsButton.setOnClickListener { showMessageRequests() }
|
|
||||||
chatsButton.setOnClickListener { showChatSettings() }
|
|
||||||
appearanceButton.setOnClickListener { showAppearanceSettings() }
|
|
||||||
inviteFriendButton.setOnClickListener { sendInvitation() }
|
|
||||||
helpButton.setOnClickListener { showHelp() }
|
|
||||||
passwordDivider.isGone = prefs.getHidePassword()
|
|
||||||
passwordButton.isGone = prefs.getHidePassword()
|
|
||||||
passwordButton.setOnClickListener { showPassword() }
|
|
||||||
clearAllDataButton.setOnClickListener { clearAllData() }
|
|
||||||
versionTextView.text = String.format(getString(R.string.version_s), "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})")
|
versionTextView.text = String.format(getString(R.string.version_s), "${BuildConfig.VERSION_NAME} (${BuildConfig.VERSION_CODE})")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,30 +194,22 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
@Deprecated("Deprecated in Java")
|
@Deprecated("Deprecated in Java")
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
if (resultCode != Activity.RESULT_OK) return
|
||||||
when (requestCode) {
|
when (requestCode) {
|
||||||
AvatarSelection.REQUEST_CODE_AVATAR -> {
|
AvatarSelection.REQUEST_CODE_AVATAR -> {
|
||||||
if (resultCode != Activity.RESULT_OK) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val outputFile = Uri.fromFile(File(cacheDir, "cropped"))
|
val outputFile = Uri.fromFile(File(cacheDir, "cropped"))
|
||||||
var inputFile: Uri? = data?.data
|
val inputFile: Uri? = data?.data ?: tempFile?.let(Uri::fromFile)
|
||||||
if (inputFile == null && tempFile != null) {
|
|
||||||
inputFile = Uri.fromFile(tempFile)
|
|
||||||
}
|
|
||||||
AvatarSelection.circularCropImage(this, inputFile, outputFile, R.string.CropImageActivity_profile_avatar)
|
AvatarSelection.circularCropImage(this, inputFile, outputFile, R.string.CropImageActivity_profile_avatar)
|
||||||
}
|
}
|
||||||
AvatarSelection.REQUEST_CODE_CROP_IMAGE -> {
|
AvatarSelection.REQUEST_CODE_CROP_IMAGE -> {
|
||||||
if (resultCode != Activity.RESULT_OK) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
return
|
|
||||||
}
|
|
||||||
AsyncTask.execute {
|
|
||||||
try {
|
try {
|
||||||
val profilePictureToBeUploaded = BitmapUtil.createScaledBytes(this@SettingsActivity, AvatarSelection.getResultUri(data), ProfileMediaConstraints()).bitmap
|
val profilePictureToBeUploaded = BitmapUtil.createScaledBytes(this@SettingsActivity, AvatarSelection.getResultUri(data), ProfileMediaConstraints()).bitmap
|
||||||
Handler(Looper.getMainLooper()).post {
|
launch(Dispatchers.Main) {
|
||||||
updateProfile(true, profilePictureToBeUploaded)
|
updateProfile(true, profilePictureToBeUploaded)
|
||||||
}
|
}
|
||||||
} catch (e: BitmapDecodingException) {
|
} catch (e: BitmapDecodingException) {
|
||||||
e.printStackTrace()
|
Log.e(TAG, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,10 +224,10 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
|
|
||||||
// region Updating
|
// region Updating
|
||||||
private fun handleDisplayNameEditActionModeChanged() {
|
private fun handleDisplayNameEditActionModeChanged() {
|
||||||
val isEditingDisplayName = this.displayNameEditActionMode !== null
|
val isEditingDisplayName = this.displayNameEditActionMode != null
|
||||||
|
|
||||||
binding.btnGroupNameDisplay.visibility = if (isEditingDisplayName) View.INVISIBLE else View.VISIBLE
|
binding.btnGroupNameDisplay.isInvisible = isEditingDisplayName
|
||||||
binding.displayNameEditText.visibility = if (isEditingDisplayName) View.VISIBLE else View.INVISIBLE
|
binding.displayNameEditText.isInvisible = !isEditingDisplayName
|
||||||
|
|
||||||
val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||||
if (isEditingDisplayName) {
|
if (isEditingDisplayName) {
|
||||||
@ -255,12 +274,11 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
MessagingModuleConfiguration.shared.storage.clearUserPic()
|
MessagingModuleConfiguration.shared.storage.clearUserPic()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val compoundPromise = all(promises)
|
all(promises) successUi { // Do this on the UI thread so that it happens before the alwaysUi clause below
|
||||||
compoundPromise.successUi { // Do this on the UI thread so that it happens before the alwaysUi clause below
|
|
||||||
val userConfig = configFactory.user
|
val userConfig = configFactory.user
|
||||||
if (isUpdatingProfilePicture) {
|
if (isUpdatingProfilePicture) {
|
||||||
AvatarHelper.setAvatar(this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)!!), profilePicture)
|
AvatarHelper.setAvatar(this, Address.fromSerialized(TextSecurePreferences.getLocalNumber(this)!!), profilePicture)
|
||||||
TextSecurePreferences.setProfileAvatarId(this, profilePicture?.let { SecureRandom().nextInt() } ?: 0 )
|
prefs.setProfileAvatarId(profilePicture?.let { SecureRandom().nextInt() } ?: 0 )
|
||||||
ProfileKeyUtil.setEncodedProfileKey(this, encodedProfileKey)
|
ProfileKeyUtil.setEncodedProfileKey(this, encodedProfileKey)
|
||||||
// new config
|
// new config
|
||||||
val url = TextSecurePreferences.getProfilePictureURL(this)
|
val url = TextSecurePreferences.getProfilePictureURL(this)
|
||||||
@ -275,8 +293,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
configFactory.persist(userConfig, SnodeAPI.nowWithOffset)
|
configFactory.persist(userConfig, SnodeAPI.nowWithOffset)
|
||||||
}
|
}
|
||||||
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(this@SettingsActivity)
|
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(this@SettingsActivity)
|
||||||
}
|
} alwaysUi {
|
||||||
compoundPromise.alwaysUi {
|
|
||||||
if (displayName != null) {
|
if (displayName != null) {
|
||||||
binding.btnGroupNameDisplay.text = displayName
|
binding.btnGroupNameDisplay.text = displayName
|
||||||
}
|
}
|
||||||
@ -318,23 +335,23 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
title(R.string.activity_settings_set_display_picture)
|
title(R.string.activity_settings_set_display_picture)
|
||||||
view(R.layout.dialog_change_avatar)
|
view(R.layout.dialog_change_avatar)
|
||||||
button(R.string.activity_settings_upload) { startAvatarSelection() }
|
button(R.string.activity_settings_upload) { startAvatarSelection() }
|
||||||
if (TextSecurePreferences.getProfileAvatarId(context) != 0) {
|
if (prefs.getProfileAvatarId() != 0) {
|
||||||
button(R.string.activity_settings_remove) { removeAvatar() }
|
button(R.string.activity_settings_remove) { removeAvatar() }
|
||||||
}
|
}
|
||||||
cancelButton()
|
cancelButton()
|
||||||
}.apply {
|
}.apply {
|
||||||
val profilePic = findViewById<ProfilePictureView>(R.id.profile_picture_view)
|
val profilePic = findViewById<ProfilePictureView>(R.id.profile_picture_view)
|
||||||
?.also(::setupProfilePictureView)
|
?.also(::setupProfilePictureView)
|
||||||
|
|
||||||
val pictureIcon = findViewById<View>(R.id.ic_pictures)
|
val pictureIcon = findViewById<View>(R.id.ic_pictures)
|
||||||
|
|
||||||
val recipient = Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false)
|
val recipient = Recipient.from(context, Address.fromSerialized(hexEncodedPublicKey), false)
|
||||||
|
|
||||||
val photoSet = (recipient.contactPhoto as ProfileContactPhoto).avatarObject !in setOf("0", "")
|
val photoSet = (recipient.contactPhoto as ProfileContactPhoto).avatarObject !in setOf("0", "")
|
||||||
|
|
||||||
profilePic?.isVisible = photoSet
|
profilePic?.isVisible = photoSet
|
||||||
pictureIcon?.isVisible = !photoSet
|
pictureIcon?.isVisible = !photoSet
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeAvatar() {
|
private fun removeAvatar() {
|
||||||
@ -359,65 +376,21 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun sharePublicKey() {
|
private fun sharePublicKey() {
|
||||||
val intent = Intent()
|
Intent().apply {
|
||||||
intent.action = Intent.ACTION_SEND
|
action = Intent.ACTION_SEND
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, hexEncodedPublicKey)
|
putExtra(Intent.EXTRA_TEXT, hexEncodedPublicKey)
|
||||||
intent.type = "text/plain"
|
type = "text/plain"
|
||||||
val chooser = Intent.createChooser(intent, getString(R.string.share))
|
}.let { Intent.createChooser(it, getString(R.string.share)) }
|
||||||
startActivity(chooser)
|
.let(::startActivity)
|
||||||
}
|
|
||||||
|
|
||||||
private fun showPrivacySettings() {
|
|
||||||
val intent = Intent(this, PrivacySettingsActivity::class.java)
|
|
||||||
push(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showNotificationSettings() {
|
|
||||||
val intent = Intent(this, NotificationSettingsActivity::class.java)
|
|
||||||
push(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showMessageRequests() {
|
|
||||||
val intent = Intent(this, MessageRequestsActivity::class.java)
|
|
||||||
push(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showChatSettings() {
|
|
||||||
val intent = Intent(this, ChatSettingsActivity::class.java)
|
|
||||||
push(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showAppearanceSettings() {
|
|
||||||
val intent = Intent(this, AppearanceSettingsActivity::class.java)
|
|
||||||
push(intent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendInvitation() {
|
private fun sendInvitation() {
|
||||||
val intent = Intent()
|
Intent().apply {
|
||||||
intent.action = Intent.ACTION_SEND
|
action = Intent.ACTION_SEND
|
||||||
val invitation = "Hey, I've been using Session to chat with complete privacy and security. Come join me! Download it at https://getsession.org/. My Session ID is $hexEncodedPublicKey !"
|
putExtra(Intent.EXTRA_TEXT, "Hey, I've been using Session to chat with complete privacy and security. Come join me! Download it at https://getsession.org/. My Session ID is $hexEncodedPublicKey !")
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, invitation)
|
type = "text/plain"
|
||||||
intent.type = "text/plain"
|
}.let { Intent.createChooser(it, getString(R.string.activity_settings_invite_button_title)) }
|
||||||
val chooser = Intent.createChooser(intent, getString(R.string.activity_settings_invite_button_title))
|
.let(::startActivity)
|
||||||
startActivity(chooser)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showHelp() {
|
|
||||||
val intent = Intent(this, HelpSettingsActivity::class.java)
|
|
||||||
push(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showPath() {
|
|
||||||
val intent = Intent(this, PathActivity::class.java)
|
|
||||||
show(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showPassword() {
|
|
||||||
startRecoveryPasswordActivity()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun clearAllData() {
|
|
||||||
ClearAllDataDialog().show(supportFragmentManager, "Clear All Data Dialog")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
@ -451,4 +424,88 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Buttons() {
|
||||||
|
Column {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.padding(horizontal = 24.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
|
) {
|
||||||
|
OutlineButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
onClick = { sharePublicKey() }
|
||||||
|
) { Text(stringResource(R.string.share)) }
|
||||||
|
|
||||||
|
OutlineButton(
|
||||||
|
modifier = Modifier.weight(1f),
|
||||||
|
onClick = { copyPublicKey() },
|
||||||
|
temporaryContent = { Text(stringResource(R.string.copied)) }
|
||||||
|
) {
|
||||||
|
Text(stringResource(R.string.copy))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(24.dp))
|
||||||
|
|
||||||
|
var hasPaths by remember {
|
||||||
|
mutableStateOf(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckPaths { hasPaths = it }
|
||||||
|
|
||||||
|
Cell {
|
||||||
|
Column {
|
||||||
|
ItemButtonWithDrawable(R.string.activity_path_title, icon = if (hasPaths) R.drawable.ic_status else R.drawable.ic_path_yellow) { show<PathActivity>() }
|
||||||
|
Divider()
|
||||||
|
ItemButton(R.string.activity_settings_privacy_button_title, icon = R.drawable.ic_privacy_icon) { show<PrivacySettingsActivity>() }
|
||||||
|
Divider()
|
||||||
|
ItemButton(R.string.activity_settings_notifications_button_title, icon = R.drawable.ic_speaker, contentDescription = R.string.AccessibilityId_notifications) { show<NotificationSettingsActivity>() }
|
||||||
|
Divider()
|
||||||
|
ItemButton(R.string.activity_settings_conversations_button_title, icon = R.drawable.ic_conversations, contentDescription = R.string.AccessibilityId_conversations) { show<ChatSettingsActivity>() }
|
||||||
|
Divider()
|
||||||
|
ItemButton(R.string.activity_settings_message_requests_button_title, icon = R.drawable.ic_message_requests, contentDescription = R.string.AccessibilityId_message_requests) { show<MessageRequestsActivity>() }
|
||||||
|
Divider()
|
||||||
|
ItemButton(R.string.activity_settings_message_appearance_button_title, icon = R.drawable.ic_appearance, contentDescription = R.string.AccessibilityId_appearance) { show<AppearanceSettingsActivity>() }
|
||||||
|
Divider()
|
||||||
|
ItemButton(R.string.activity_settings_invite_button_title, icon = R.drawable.ic_invite_friend, contentDescription = R.string.AccessibilityId_invite_friend) { sendInvitation() }
|
||||||
|
Divider()
|
||||||
|
if (!prefs.getHidePassword()) {
|
||||||
|
ItemButton(R.string.sessionRecoveryPassword, icon = R.drawable.ic_recovery_phrase, contentDescription = R.string.AccessibilityId_recovery_password_menu_item) { show<RecoveryPasswordActivity>() }
|
||||||
|
Divider()
|
||||||
|
}
|
||||||
|
ItemButton(R.string.activity_settings_help_button, icon = R.drawable.ic_help, contentDescription = R.string.AccessibilityId_help) { show<HelpSettingsActivity>() }
|
||||||
|
Divider()
|
||||||
|
ItemButton(R.string.activity_settings_clear_all_data_button_title, colors = destructiveButtonColors(), icon = R.drawable.ic_clear_data, contentDescription = R.string.AccessibilityId_clear_data) { ClearAllDataDialog().show(supportFragmentManager, "Clear All Data Dialog") }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CheckPaths(setHasPaths: (Boolean) -> Unit) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
val manager = LocalBroadcastManager.getInstance(context)
|
||||||
|
|
||||||
|
fun update() {
|
||||||
|
lifecycleScope.launch {
|
||||||
|
val paths = withContext(Dispatchers.IO) { OnionRequestAPI.paths }
|
||||||
|
setHasPaths(paths.isNotEmpty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun addReceiver(action: String): BroadcastReceiver = createReceiver { update() }.also { manager.registerReceiver(it, IntentFilter(action)) }
|
||||||
|
|
||||||
|
val receivers = listOf("buildingPaths", "pathsBuilt").map(::addReceiver)
|
||||||
|
|
||||||
|
DisposableEffect(Unit) {
|
||||||
|
onDispose {
|
||||||
|
receivers.forEach(manager::unregisterReceiver)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createReceiver(update: () -> Unit) = object : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) { update() }
|
||||||
}
|
}
|
@ -1,13 +1,17 @@
|
|||||||
package org.thoughtcrime.securesms.ui
|
package org.thoughtcrime.securesms.ui
|
||||||
|
|
||||||
|
import android.graphics.drawable.BitmapDrawable
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
import androidx.compose.foundation.Canvas
|
import androidx.compose.foundation.Canvas
|
||||||
import androidx.compose.foundation.ScrollState
|
import androidx.compose.foundation.ScrollState
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
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.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.RowScope
|
import androidx.compose.foundation.layout.RowScope
|
||||||
@ -23,6 +27,7 @@ import androidx.compose.foundation.layout.wrapContentSize
|
|||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.Button
|
||||||
import androidx.compose.material.ButtonColors
|
import androidx.compose.material.ButtonColors
|
||||||
import androidx.compose.material.ButtonDefaults
|
import androidx.compose.material.ButtonDefaults
|
||||||
import androidx.compose.material.Card
|
import androidx.compose.material.Card
|
||||||
@ -52,10 +57,12 @@ import androidx.compose.ui.graphics.Brush
|
|||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.RectangleShape
|
import androidx.compose.ui.graphics.RectangleShape
|
||||||
import androidx.compose.ui.graphics.StrokeCap
|
import androidx.compose.ui.graphics.StrokeCap
|
||||||
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.semantics.contentDescription
|
import androidx.compose.ui.semantics.contentDescription
|
||||||
import androidx.compose.ui.semantics.semantics
|
import androidx.compose.ui.semantics.semantics
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
@ -64,6 +71,8 @@ import androidx.compose.ui.unit.TextUnit
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
|
import androidx.core.content.res.ResourcesCompat
|
||||||
|
import com.google.accompanist.drawablepainter.rememberDrawablePainter
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -259,6 +268,42 @@ fun <T> OptionsCard(card: OptionsCard<T>, callbacks: Callbacks<T>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ItemButton(
|
||||||
|
@StringRes textId: Int,
|
||||||
|
@DrawableRes icon: Int,
|
||||||
|
colors: ButtonColors = transparentButtonColors(),
|
||||||
|
@StringRes contentDescription: Int = textId,
|
||||||
|
onClick: () -> Unit
|
||||||
|
) {
|
||||||
|
ItemButton(stringResource(textId), icon, colors, stringResource(contentDescription), onClick)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ItemButtonWithDrawable(
|
||||||
|
@StringRes textId: Int,
|
||||||
|
@DrawableRes icon: Int,
|
||||||
|
colors: ButtonColors = transparentButtonColors(),
|
||||||
|
@StringRes contentDescription: Int = textId,
|
||||||
|
onClick: () -> Unit
|
||||||
|
) {
|
||||||
|
val context = LocalContext.current
|
||||||
|
|
||||||
|
ItemButton(
|
||||||
|
text = stringResource(textId),
|
||||||
|
icon = {
|
||||||
|
Image(
|
||||||
|
painter = rememberDrawablePainter(drawable = context.getDrawable(icon)),
|
||||||
|
contentDescription = stringResource(contentDescription),
|
||||||
|
modifier = Modifier.align(Alignment.Center)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
colors = colors,
|
||||||
|
contentDescription = stringResource(contentDescription),
|
||||||
|
onClick = onClick
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ItemButton(
|
fun ItemButton(
|
||||||
text: String,
|
text: String,
|
||||||
@ -267,24 +312,43 @@ fun ItemButton(
|
|||||||
contentDescription: String = text,
|
contentDescription: String = text,
|
||||||
onClick: () -> Unit
|
onClick: () -> Unit
|
||||||
) {
|
) {
|
||||||
TextButton(
|
ItemButton(
|
||||||
modifier = Modifier
|
text = text,
|
||||||
.fillMaxWidth()
|
icon = {
|
||||||
.height(60.dp),
|
|
||||||
colors = colors,
|
|
||||||
onClick = onClick,
|
|
||||||
shape = RectangleShape,
|
|
||||||
) {
|
|
||||||
Box(modifier = Modifier
|
|
||||||
.width(80.dp)
|
|
||||||
.fillMaxHeight()) {
|
|
||||||
Icon(
|
Icon(
|
||||||
painter = painterResource(id = icon),
|
painter = painterResource(id = icon),
|
||||||
contentDescription = contentDescription,
|
contentDescription = contentDescription,
|
||||||
modifier = Modifier.align(Alignment.Center)
|
modifier = Modifier.align(Alignment.Center)
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
colors = colors,
|
||||||
|
contentDescription = contentDescription,
|
||||||
|
onClick = onClick
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ItemButton(
|
||||||
|
text: String,
|
||||||
|
icon: @Composable BoxScope.() -> Unit,
|
||||||
|
colors: ButtonColors = transparentButtonColors(),
|
||||||
|
contentDescription: String = text,
|
||||||
|
onClick: () -> Unit
|
||||||
|
) {
|
||||||
|
TextButton(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(60.dp),
|
||||||
|
colors = colors,
|
||||||
|
onClick = onClick,
|
||||||
|
shape = RectangleShape,
|
||||||
|
) {
|
||||||
|
Box(modifier = Modifier
|
||||||
|
.width(80.dp)
|
||||||
|
.fillMaxHeight()) {
|
||||||
|
icon()
|
||||||
}
|
}
|
||||||
Text(text, modifier = Modifier.fillMaxWidth())
|
Text(text, modifier = Modifier.fillMaxWidth(), style = MaterialTheme.typography.h8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,9 +372,9 @@ fun CellWithPaddingAndMargin(
|
|||||||
shape = RoundedCornerShape(16.dp),
|
shape = RoundedCornerShape(16.dp),
|
||||||
elevation = 0.dp,
|
elevation = 0.dp,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.wrapContentHeight()
|
.wrapContentHeight()
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = margin),
|
.padding(horizontal = margin),
|
||||||
) {
|
) {
|
||||||
Box(Modifier.padding(padding)) { content() }
|
Box(Modifier.padding(padding)) { content() }
|
||||||
}
|
}
|
||||||
@ -321,14 +385,14 @@ fun <T> TitledRadioButton(option: RadioOption<T>, onClick: () -> Unit) {
|
|||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.runIf(option.enabled) { clickable { if (!option.selected) onClick() } }
|
.runIf(option.enabled) { clickable { if (!option.selected) onClick() } }
|
||||||
.heightIn(min = 60.dp)
|
.heightIn(min = 60.dp)
|
||||||
.padding(horizontal = 32.dp)
|
.padding(horizontal = 32.dp)
|
||||||
.contentDescription(option.contentDescription)
|
.contentDescription(option.contentDescription)
|
||||||
) {
|
) {
|
||||||
Column(modifier = Modifier
|
Column(modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.align(Alignment.CenterVertically)) {
|
.align(Alignment.CenterVertically)) {
|
||||||
Column {
|
Column {
|
||||||
Text(
|
Text(
|
||||||
text = option.title(),
|
text = option.title(),
|
||||||
@ -349,8 +413,8 @@ fun <T> TitledRadioButton(option: RadioOption<T>, onClick: () -> Unit) {
|
|||||||
onClick = null,
|
onClick = null,
|
||||||
enabled = option.enabled,
|
enabled = option.enabled,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.height(26.dp)
|
.height(26.dp)
|
||||||
.align(Alignment.CenterVertically)
|
.align(Alignment.CenterVertically)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -373,8 +437,8 @@ fun Modifier.contentDescription(id: Int?): Modifier {
|
|||||||
fun OutlineButton(text: GetString, contentDescription: GetString? = text, modifier: Modifier = Modifier, onClick: () -> Unit) {
|
fun OutlineButton(text: GetString, contentDescription: GetString? = text, modifier: Modifier = Modifier, onClick: () -> Unit) {
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.size(108.dp, 34.dp)
|
.size(108.dp, 34.dp)
|
||||||
.contentDescription(contentDescription),
|
.contentDescription(contentDescription),
|
||||||
onClick = onClick,
|
onClick = onClick,
|
||||||
border = BorderStroke(1.dp, LocalExtraColors.current.prominentButtonColor),
|
border = BorderStroke(1.dp, LocalExtraColors.current.prominentButtonColor),
|
||||||
shape = RoundedCornerShape(50), // = 50% percent
|
shape = RoundedCornerShape(50), // = 50% percent
|
||||||
@ -396,37 +460,37 @@ fun Modifier.fadingEdges(
|
|||||||
topEdgeHeight: Dp = 0.dp,
|
topEdgeHeight: Dp = 0.dp,
|
||||||
bottomEdgeHeight: Dp = 20.dp
|
bottomEdgeHeight: Dp = 20.dp
|
||||||
): Modifier = this.then(
|
): Modifier = this.then(
|
||||||
Modifier
|
Modifier
|
||||||
// adding layer fixes issue with blending gradient and content
|
// adding layer fixes issue with blending gradient and content
|
||||||
.graphicsLayer { alpha = 0.99F }
|
.graphicsLayer { alpha = 0.99F }
|
||||||
.drawWithContent {
|
.drawWithContent {
|
||||||
drawContent()
|
drawContent()
|
||||||
|
|
||||||
val topColors = listOf(Color.Transparent, Color.Black)
|
val topColors = listOf(Color.Transparent, Color.Black)
|
||||||
val topStartY = scrollState.value.toFloat()
|
val topStartY = scrollState.value.toFloat()
|
||||||
val topGradientHeight = min(topEdgeHeight.toPx(), topStartY)
|
val topGradientHeight = min(topEdgeHeight.toPx(), topStartY)
|
||||||
if (topGradientHeight > 0f) drawRect(
|
if (topGradientHeight > 0f) drawRect(
|
||||||
brush = Brush.verticalGradient(
|
brush = Brush.verticalGradient(
|
||||||
colors = topColors,
|
colors = topColors,
|
||||||
startY = topStartY,
|
startY = topStartY,
|
||||||
endY = topStartY + topGradientHeight
|
endY = topStartY + topGradientHeight
|
||||||
),
|
),
|
||||||
blendMode = BlendMode.DstIn
|
blendMode = BlendMode.DstIn
|
||||||
)
|
)
|
||||||
|
|
||||||
val bottomColors = listOf(Color.Black, Color.Transparent)
|
val bottomColors = listOf(Color.Black, Color.Transparent)
|
||||||
val bottomEndY = size.height - scrollState.maxValue + scrollState.value
|
val bottomEndY = size.height - scrollState.maxValue + scrollState.value
|
||||||
val bottomGradientHeight =
|
val bottomGradientHeight =
|
||||||
min(bottomEdgeHeight.toPx(), scrollState.maxValue.toFloat() - scrollState.value)
|
min(bottomEdgeHeight.toPx(), scrollState.maxValue.toFloat() - scrollState.value)
|
||||||
if (bottomGradientHeight > 0f) drawRect(
|
if (bottomGradientHeight > 0f) drawRect(
|
||||||
brush = Brush.verticalGradient(
|
brush = Brush.verticalGradient(
|
||||||
colors = bottomColors,
|
colors = bottomColors,
|
||||||
startY = bottomEndY - bottomGradientHeight,
|
startY = bottomEndY - bottomGradientHeight,
|
||||||
endY = bottomEndY
|
endY = bottomEndY
|
||||||
),
|
),
|
||||||
blendMode = BlendMode.DstIn
|
blendMode = BlendMode.DstIn
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@ -440,16 +504,16 @@ fun Divider() {
|
|||||||
fun RowScope.Avatar(recipient: Recipient) {
|
fun RowScope.Avatar(recipient: Recipient) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(60.dp)
|
.width(60.dp)
|
||||||
.align(Alignment.CenterVertically)
|
.align(Alignment.CenterVertically)
|
||||||
) {
|
) {
|
||||||
AndroidView(
|
AndroidView(
|
||||||
factory = {
|
factory = {
|
||||||
ProfilePictureView(it).apply { update(recipient) }
|
ProfilePictureView(it).apply { update(recipient) }
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.width(46.dp)
|
.width(46.dp)
|
||||||
.height(46.dp)
|
.height(46.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -476,8 +540,8 @@ fun Arc(
|
|||||||
) {
|
) {
|
||||||
Canvas(
|
Canvas(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.padding(strokeWidth)
|
.padding(strokeWidth)
|
||||||
.size(186.dp)
|
.size(186.dp)
|
||||||
) {
|
) {
|
||||||
// Background Line
|
// Background Line
|
||||||
drawArc(
|
drawArc(
|
||||||
@ -506,8 +570,8 @@ fun RowScope.SessionShieldIcon() {
|
|||||||
painter = painterResource(R.drawable.session_shield),
|
painter = painterResource(R.drawable.session_shield),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.align(Alignment.CenterVertically)
|
.align(Alignment.CenterVertically)
|
||||||
.wrapContentSize(unbounded = true)
|
.wrapContentSize(unbounded = true)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
package org.thoughtcrime.securesms.ui.components
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import androidx.compose.foundation.Image
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material.Card
|
||||||
|
import androidx.compose.material.Icon
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.ColorFilter
|
||||||
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
|
import androidx.compose.ui.res.painterResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import network.loki.messenger.R
|
||||||
|
import org.thoughtcrime.securesms.ui.LocalExtraColors
|
||||||
|
import org.thoughtcrime.securesms.util.QRCodeUtilities
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun QrImageCard(
|
||||||
|
string: String,
|
||||||
|
contentDescription: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
icon: Int = R.drawable.session_shield
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
backgroundColor = LocalExtraColors.current.lightCell,
|
||||||
|
elevation = 0.dp,
|
||||||
|
modifier = modifier
|
||||||
|
) { QrImage(string, contentDescription, icon) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun QrImage(string: String, contentDescription: String, icon: Int = R.drawable.session_shield) {
|
||||||
|
var bitmap: Bitmap? by remember {
|
||||||
|
mutableStateOf(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
LaunchedEffect(string) {
|
||||||
|
scope.launch(Dispatchers.IO) {
|
||||||
|
bitmap = QRCodeUtilities.encode(string, 400)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Box {
|
||||||
|
bitmap?.let {
|
||||||
|
Image(
|
||||||
|
bitmap = it.asImageBitmap(),
|
||||||
|
contentDescription = contentDescription,
|
||||||
|
colorFilter = ColorFilter.tint(LocalExtraColors.current.onLightCell)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = icon),
|
||||||
|
contentDescription = "",
|
||||||
|
tint = LocalExtraColors.current.onLightCell,
|
||||||
|
modifier = Modifier
|
||||||
|
.align(Alignment.Center)
|
||||||
|
.width(46.dp)
|
||||||
|
.height(56.dp)
|
||||||
|
.background(color = LocalExtraColors.current.lightCell)
|
||||||
|
.padding(horizontal = 3.dp, vertical = 1.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package org.thoughtcrime.securesms.util
|
package org.thoughtcrime.securesms.util
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
@ -90,12 +91,17 @@ fun String.getThemeStyle(): Int = when (this) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@StyleRes
|
@StyleRes
|
||||||
fun Int.getDefaultAccentColor(): Int =
|
fun Int.getDefaultAccentColor(): Int = when (this) {
|
||||||
if (this == R.style.Ocean_Dark || this == R.style.Ocean_Light) R.style.PrimaryBlue
|
R.style.Ocean_Dark, R.style.Ocean_Light -> R.style.PrimaryBlue
|
||||||
else R.style.PrimaryGreen
|
else -> R.style.PrimaryGreen
|
||||||
|
}
|
||||||
|
|
||||||
data class ThemeState (
|
data class ThemeState (
|
||||||
@StyleRes val theme: Int,
|
@StyleRes val theme: Int,
|
||||||
@StyleRes val accentStyle: Int,
|
@StyleRes val accentStyle: Int,
|
||||||
val followSystem: Boolean
|
val followSystem: Boolean
|
||||||
)
|
)
|
||||||
|
|
||||||
|
inline fun <reified T: Activity> Context.start() = Intent(this, T::class.java).also(::startActivity)
|
||||||
|
inline fun <reified T: Activity> Activity.show() = Intent(this, T::class.java).also(::startActivity).also { overridePendingTransition(R.anim.slide_from_bottom, R.anim.fade_scale_out) }
|
||||||
|
inline fun <reified T: Activity> Activity.push() = Intent(this, T::class.java).also(::startActivity).also { overridePendingTransition(R.anim.slide_from_right, R.anim.fade_scale_out) }
|
||||||
|
17
app/src/main/res/drawable/ic_path_yellow.xml
Normal file
17
app/src/main/res/drawable/ic_path_yellow.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:width="28dp" android:height="28dp">
|
||||||
|
<shape android:shape="oval">
|
||||||
|
<gradient
|
||||||
|
android:type="radial"
|
||||||
|
android:startColor="#FFCE3A"
|
||||||
|
android:endColor="#00FFCE3A"
|
||||||
|
android:gradientRadius="12dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:top="6dp" android:left="6dp" android:right="6dp" android:bottom="6dp">
|
||||||
|
<shape android:shape="oval">
|
||||||
|
<solid android:color="#FFCE3A"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
17
app/src/main/res/drawable/ic_status.xml
Normal file
17
app/src/main/res/drawable/ic_status.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item android:width="28dp" android:height="28dp">
|
||||||
|
<shape android:shape="oval">
|
||||||
|
<gradient
|
||||||
|
android:type="radial"
|
||||||
|
android:startColor="#31F196"
|
||||||
|
android:endColor="#0031F196"
|
||||||
|
android:gradientRadius="12dp"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item android:top="6dp" android:left="6dp" android:right="6dp" android:bottom="6dp">
|
||||||
|
<shape android:shape="oval">
|
||||||
|
<solid android:color="#31F196"/>
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
</layer-list>
|
@ -88,392 +88,11 @@
|
|||||||
android:textAlignment="center"
|
android:textAlignment="center"
|
||||||
android:contentDescription="@string/AccessibilityId_account_id"
|
android:contentDescription="@string/AccessibilityId_account_id"
|
||||||
tools:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
tools:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.compose.ui.platform.ComposeView
|
||||||
|
android:id="@+id/composeView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"/>
|
||||||
android:layout_marginLeft="@dimen/large_spacing"
|
|
||||||
android:layout_marginTop="@dimen/large_spacing"
|
|
||||||
android:layout_marginRight="@dimen/large_spacing"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
style="@style/Widget.Session.Button.Common.ProminentOutline"
|
|
||||||
android:id="@+id/copyButton"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="@dimen/medium_button_height"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:text="@string/copy" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
style="@style/Widget.Session.Button.Common.ProminentOutline"
|
|
||||||
android:id="@+id/shareButton"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="@dimen/medium_button_height"
|
|
||||||
android:layout_weight="1"
|
|
||||||
android:layout_marginStart="@dimen/medium_spacing"
|
|
||||||
android:text="@string/share" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:background="@drawable/preference_single_no_padding"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/large_spacing"
|
|
||||||
android:layout_marginHorizontal="@dimen/large_spacing"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<!-- Path -->
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/pathButton"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
android:orientation="horizontal"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:paddingHorizontal="@dimen/large_spacing"
|
|
||||||
android:layout_height="@dimen/setting_button_height">
|
|
||||||
<FrameLayout
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:id="@+id/pathContainer"
|
|
||||||
android:layout_width="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_height="@dimen/small_profile_picture_size">
|
|
||||||
<org.thoughtcrime.securesms.home.PathStatusView
|
|
||||||
android:layout_gravity="center"
|
|
||||||
android:layout_width="@dimen/path_status_view_size"
|
|
||||||
android:layout_height="@dimen/path_status_view_size"/>
|
|
||||||
</FrameLayout>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/pathText"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
|
||||||
android:textSize="@dimen/medium_font_size"
|
|
||||||
android:layout_marginHorizontal="@dimen/medium_spacing"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:gravity="center"
|
|
||||||
android:layout_toEndOf="@+id/pathContainer"
|
|
||||||
android:text="@string/activity_path_title" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_marginHorizontal="@dimen/very_large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?colorDividerBackground" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/privacyButton"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
android:paddingHorizontal="@dimen/large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/setting_button_height">
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/privacyContainer"
|
|
||||||
android:layout_width="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_height="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:src="@drawable/ic_privacy_icon"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
app:tint="?android:textColorPrimary" />
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/privacyText"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
|
||||||
android:textSize="@dimen/medium_font_size"
|
|
||||||
android:layout_marginHorizontal="@dimen/medium_spacing"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:gravity="center"
|
|
||||||
android:layout_toEndOf="@+id/privacyContainer"
|
|
||||||
android:text="@string/activity_settings_privacy_button_title" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_marginHorizontal="@dimen/very_large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?colorDividerBackground" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/notificationsButton"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
android:paddingHorizontal="@dimen/large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/setting_button_height"
|
|
||||||
android:contentDescription="@string/AccessibilityId_notifications">
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/notificationsContainer"
|
|
||||||
android:layout_width="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_height="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:src="@drawable/ic_speaker"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
app:tint="?android:textColorPrimary" />
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/notificationsText"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
|
||||||
android:textSize="@dimen/medium_font_size"
|
|
||||||
android:layout_marginHorizontal="@dimen/medium_spacing"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:gravity="center"
|
|
||||||
android:layout_toEndOf="@+id/notificationsContainer"
|
|
||||||
android:text="@string/activity_settings_notifications_button_title"
|
|
||||||
/>
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_marginHorizontal="@dimen/very_large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?colorDividerBackground" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/chatsButton"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
android:paddingHorizontal="@dimen/large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/setting_button_height"
|
|
||||||
android:contentDescription="@string/AccessibilityId_conversations">
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/chatsContainer"
|
|
||||||
android:layout_width="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_height="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:src="@drawable/ic_conversations"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
app:tint="?android:textColorPrimary" />
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/chatsText"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
|
||||||
android:textSize="@dimen/medium_font_size"
|
|
||||||
android:layout_marginHorizontal="@dimen/medium_spacing"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:gravity="center"
|
|
||||||
android:layout_toEndOf="@+id/chatsContainer"
|
|
||||||
android:text="@string/activity_settings_conversations_button_title" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_marginHorizontal="@dimen/very_large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?colorDividerBackground" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/messageRequestsButton"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
android:paddingHorizontal="@dimen/large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/setting_button_height"
|
|
||||||
android:contentDescription="@string/AccessibilityId_message_requests">
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/messageRequestsContainer"
|
|
||||||
android:layout_width="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_height="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:src="@drawable/ic_message_requests"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
app:tint="?android:textColorPrimary" />
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/messageRequestsTexts"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
|
||||||
android:textSize="@dimen/medium_font_size"
|
|
||||||
android:layout_marginHorizontal="@dimen/medium_spacing"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:gravity="center"
|
|
||||||
android:layout_toEndOf="@+id/messageRequestsContainer"
|
|
||||||
android:text="@string/activity_settings_message_requests_button_title" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_marginHorizontal="@dimen/very_large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?colorDividerBackground" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/appearanceButton"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
android:paddingHorizontal="@dimen/large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/setting_button_height"
|
|
||||||
android:contentDescription="@string/AccessibilityId_appearance">
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/appearanceContainer"
|
|
||||||
android:layout_width="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_height="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:src="@drawable/ic_appearance"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
app:tint="?android:textColorPrimary" />
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/appearanceText"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
|
||||||
android:textSize="@dimen/medium_font_size"
|
|
||||||
android:layout_marginHorizontal="@dimen/medium_spacing"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:gravity="center"
|
|
||||||
android:layout_toEndOf="@+id/appearanceContainer"
|
|
||||||
android:text="@string/activity_settings_message_appearance_button_title" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_marginHorizontal="@dimen/very_large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?colorDividerBackground" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/inviteFriendButton"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
android:paddingHorizontal="@dimen/large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/setting_button_height"
|
|
||||||
android:contentDescription="@string/AccessibilityId_invite_friend">
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/inviteFriendContainer"
|
|
||||||
android:layout_width="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_height="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:src="@drawable/ic_invite_friend"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
app:tint="?android:textColorPrimary" />
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/inviteFriendTexts"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
|
||||||
android:textSize="@dimen/medium_font_size"
|
|
||||||
android:layout_marginHorizontal="@dimen/medium_spacing"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:gravity="center"
|
|
||||||
android:layout_toEndOf="@+id/inviteFriendContainer"
|
|
||||||
android:text="@string/activity_settings_invite_button_title" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_marginHorizontal="@dimen/very_large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?colorDividerBackground" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/passwordButton"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
android:paddingHorizontal="@dimen/large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/setting_button_height"
|
|
||||||
android:contentDescription="@string/AccessibilityId_recovery_password_menu_item">
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/passwordContainer"
|
|
||||||
android:layout_width="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_height="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:src="@drawable/ic_recovery_phrase"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
app:tint="?android:textColorPrimary" />
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/seedText"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
|
||||||
android:textSize="@dimen/medium_font_size"
|
|
||||||
android:layout_marginHorizontal="@dimen/medium_spacing"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:gravity="center"
|
|
||||||
android:layout_toEndOf="@+id/passwordContainer"
|
|
||||||
android:text="@string/sessionRecoveryPassword" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:id="@+id/passwordDivider"
|
|
||||||
android:layout_marginHorizontal="@dimen/very_large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?colorDividerBackground" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/helpButton"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
android:paddingHorizontal="@dimen/large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/setting_button_height"
|
|
||||||
android:contentDescription="@string/AccessibilityId_help">
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/helpContainer"
|
|
||||||
android:layout_width="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_height="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:src="@drawable/ic_help"
|
|
||||||
android:scaleType="centerInside"
|
|
||||||
app:tint="?android:textColorPrimary" />
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/helpTexts"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:textColor="?android:textColorPrimary"
|
|
||||||
android:textSize="@dimen/medium_font_size"
|
|
||||||
android:layout_marginHorizontal="@dimen/medium_spacing"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:gravity="center"
|
|
||||||
android:layout_toEndOf="@+id/helpContainer"
|
|
||||||
android:text="@string/activity_settings_help_button" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
<View
|
|
||||||
android:layout_marginHorizontal="@dimen/very_large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="1dp"
|
|
||||||
android:background="?colorDividerBackground" />
|
|
||||||
|
|
||||||
<RelativeLayout
|
|
||||||
android:id="@+id/clearAllDataButton"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
android:paddingHorizontal="@dimen/large_spacing"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/setting_button_height"
|
|
||||||
android:contentDescription="@string/AccessibilityId_clear_data">
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/clearContainer"
|
|
||||||
android:layout_width="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_height="@dimen/small_profile_picture_size"
|
|
||||||
android:layout_alignParentStart="true"
|
|
||||||
android:layout_centerVertical="true"
|
|
||||||
android:src="@drawable/ic_clear_data"
|
|
||||||
android:scaleType="centerInside"/>
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/clearText"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:textColor="@color/destructive"
|
|
||||||
android:textSize="@dimen/medium_font_size"
|
|
||||||
android:layout_marginHorizontal="@dimen/medium_spacing"
|
|
||||||
android:textStyle="bold"
|
|
||||||
android:gravity="center"
|
|
||||||
android:layout_toEndOf="@+id/clearContainer"
|
|
||||||
android:text="@string/activity_settings_clear_all_data_button_title" />
|
|
||||||
</RelativeLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/oxenLogoImageView"
|
android:id="@+id/oxenLogoImageView"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user