mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-27 12:05:22 +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-indicators: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-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.SlideDeck
|
||||
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.reactions.ReactionsDialogFragment
|
||||
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.push
|
||||
import org.thoughtcrime.securesms.util.show
|
||||
import org.thoughtcrime.securesms.util.start
|
||||
import org.thoughtcrime.securesms.util.toPx
|
||||
import java.lang.ref.WeakReference
|
||||
import java.util.Locale
|
||||
@ -1602,7 +1603,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
val userPublicKey = textSecurePreferences.getLocalNumber()
|
||||
val isNoteToSelf = (recipient.isContactRecipient && recipient.address.toString() == userPublicKey)
|
||||
if (text.contains(seed) && !isNoteToSelf && !hasPermissionToSendSeed) {
|
||||
startRecoveryPasswordActivity()
|
||||
start<RecoveryPasswordActivity>()
|
||||
}
|
||||
// Create the message
|
||||
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.GlideRequests
|
||||
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.preferences.SettingsActivity
|
||||
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.push
|
||||
import org.thoughtcrime.securesms.util.show
|
||||
import org.thoughtcrime.securesms.util.start
|
||||
import org.thoughtcrime.securesms.util.themeState
|
||||
import java.io.IOException
|
||||
import java.util.Locale
|
||||
@ -374,7 +375,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
stringResource(R.string.continue_2),
|
||||
Modifier.align(Alignment.CenterVertically),
|
||||
contentDescription = GetString(R.string.AccessibilityId_reveal_recovery_phrase_button)
|
||||
) { startRecoveryPasswordActivity() }
|
||||
) { start<RecoveryPasswordActivity>() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,21 @@
|
||||
package org.thoughtcrime.securesms.onboarding.recoverypassword
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Bundle
|
||||
import androidx.activity.viewModels
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
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.foundation.layout.width
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.Card
|
||||
import androidx.compose.material.Icon
|
||||
import androidx.compose.material.MaterialTheme
|
||||
import androidx.compose.material.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@ -30,10 +24,7 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
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.platform.ComposeView
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
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.classicDarkColors
|
||||
import org.thoughtcrime.securesms.ui.colorDestructive
|
||||
import org.thoughtcrime.securesms.ui.components.QrImageCard
|
||||
import org.thoughtcrime.securesms.ui.contentDescription
|
||||
import org.thoughtcrime.securesms.ui.h8
|
||||
import org.thoughtcrime.securesms.ui.small
|
||||
@ -68,7 +60,6 @@ class RecoveryPasswordActivity : BaseActionBarActivity() {
|
||||
setContent {
|
||||
RecoveryPassword(
|
||||
viewModel.seed,
|
||||
viewModel.qrBitmap,
|
||||
{ viewModel.copySeed(context) }
|
||||
) { onHide() }
|
||||
}
|
||||
@ -113,7 +104,6 @@ fun PreviewRecoveryPassword(
|
||||
@Composable
|
||||
fun RecoveryPassword(
|
||||
seed: String = "",
|
||||
qrBitmap: Bitmap? = null,
|
||||
copySeed:() -> Unit = {},
|
||||
onHide:() -> Unit = {}
|
||||
) {
|
||||
@ -124,14 +114,14 @@ fun RecoveryPassword(
|
||||
.verticalScroll(rememberScrollState())
|
||||
.padding(bottom = 16.dp)
|
||||
) {
|
||||
RecoveryPasswordCell(seed, qrBitmap, copySeed)
|
||||
RecoveryPasswordCell(seed, copySeed)
|
||||
HideRecoveryPasswordCell(onHide)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RecoveryPasswordCell(seed: String = "", qrBitmap: Bitmap? = null, copySeed:() -> Unit = {}) {
|
||||
fun RecoveryPasswordCell(seed: String, copySeed:() -> Unit = {}) {
|
||||
val showQr = remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
@ -163,21 +153,15 @@ fun RecoveryPasswordCell(seed: String = "", qrBitmap: Bitmap? = null, copySeed:(
|
||||
)
|
||||
}
|
||||
|
||||
AnimatedVisibility(showQr.value, modifier = Modifier.align(Alignment.CenterHorizontally)) {
|
||||
Card(
|
||||
backgroundColor = LocalExtraColors.current.lightCell,
|
||||
elevation = 0.dp,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterHorizontally)
|
||||
.padding(vertical = 24.dp)
|
||||
) {
|
||||
qrBitmap?.let {
|
||||
QrImage(
|
||||
bitmap = it,
|
||||
contentDescription = "QR code of your recovery password",
|
||||
)
|
||||
}
|
||||
}
|
||||
AnimatedVisibility(
|
||||
showQr.value,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally).padding(vertical = 24.dp)
|
||||
) {
|
||||
QrImageCard(
|
||||
seed,
|
||||
contentDescription = "QR code of your recovery password",
|
||||
icon = R.drawable.session_shield
|
||||
)
|
||||
}
|
||||
|
||||
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 }
|
||||
|
||||
@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) }
|
||||
.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.app.Activity
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.net.Uri
|
||||
import android.os.AsyncTask
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Parcelable
|
||||
import android.util.SparseArray
|
||||
import android.view.ActionMode
|
||||
@ -20,9 +19,38 @@ import android.view.View
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
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.isInvisible
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
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.R
|
||||
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.ProfileContactPhoto
|
||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
||||
import org.session.libsession.snode.OnionRequestAPI
|
||||
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.TextSecurePreferences
|
||||
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.avatar.AvatarSelection
|
||||
import org.thoughtcrime.securesms.components.ProfilePictureView
|
||||
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||
import org.thoughtcrime.securesms.home.PathActivity
|
||||
import org.thoughtcrime.securesms.messagerequests.MessageRequestsActivity
|
||||
import org.thoughtcrime.securesms.mms.GlideApp
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
import org.thoughtcrime.securesms.onboarding.recoverypassword.startRecoveryPasswordActivity
|
||||
import org.thoughtcrime.securesms.onboarding.recoverypassword.RecoveryPasswordActivity
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.preferences.appearance.AppearanceSettingsActivity
|
||||
import org.thoughtcrime.securesms.profiles.ProfileMediaConstraints
|
||||
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.BitmapUtil
|
||||
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
|
||||
@ -61,6 +103,8 @@ import java.io.File
|
||||
import java.security.SecureRandom
|
||||
import javax.inject.Inject
|
||||
|
||||
private const val TAG = "SettingsActivity"
|
||||
|
||||
@AndroidEntryPoint
|
||||
class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
|
||||
@ -69,21 +113,14 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
@Inject
|
||||
lateinit var prefs: TextSecurePreferences
|
||||
|
||||
|
||||
|
||||
private lateinit var binding: ActivitySettingsBinding
|
||||
private var displayNameEditActionMode: ActionMode? = null
|
||||
set(value) { field = value; handleDisplayNameEditActionModeChanged() }
|
||||
private lateinit var glide: GlideRequests
|
||||
private var tempFile: File? = null
|
||||
|
||||
private val hexEncodedPublicKey: String
|
||||
get() {
|
||||
return TextSecurePreferences.getLocalNumber(this)!!
|
||||
}
|
||||
private val hexEncodedPublicKey: String get() = TextSecurePreferences.getLocalNumber(this)!!
|
||||
|
||||
companion object {
|
||||
const val updatedProfileResultCode = 1234
|
||||
private const val SCROLL_STATE = "SCROLL_STATE"
|
||||
}
|
||||
|
||||
@ -92,7 +129,12 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
super.onCreate(savedInstanceState, isReady)
|
||||
binding = ActivitySettingsBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
glide = GlideApp.with(this)
|
||||
|
||||
binding.composeView.setContent {
|
||||
AppTheme {
|
||||
Buttons()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
@ -104,21 +146,6 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
ctnGroupNameSection.setOnClickListener { startActionMode(DisplayNameEditActionModeCallback()) }
|
||||
btnGroupNameDisplay.text = getDisplayName()
|
||||
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})")
|
||||
}
|
||||
}
|
||||
@ -167,30 +194,22 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
@Deprecated("Deprecated in Java")
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode != Activity.RESULT_OK) return
|
||||
when (requestCode) {
|
||||
AvatarSelection.REQUEST_CODE_AVATAR -> {
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
return
|
||||
}
|
||||
val outputFile = Uri.fromFile(File(cacheDir, "cropped"))
|
||||
var inputFile: Uri? = data?.data
|
||||
if (inputFile == null && tempFile != null) {
|
||||
inputFile = Uri.fromFile(tempFile)
|
||||
}
|
||||
val inputFile: Uri? = data?.data ?: tempFile?.let(Uri::fromFile)
|
||||
AvatarSelection.circularCropImage(this, inputFile, outputFile, R.string.CropImageActivity_profile_avatar)
|
||||
}
|
||||
AvatarSelection.REQUEST_CODE_CROP_IMAGE -> {
|
||||
if (resultCode != Activity.RESULT_OK) {
|
||||
return
|
||||
}
|
||||
AsyncTask.execute {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
val profilePictureToBeUploaded = BitmapUtil.createScaledBytes(this@SettingsActivity, AvatarSelection.getResultUri(data), ProfileMediaConstraints()).bitmap
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
launch(Dispatchers.Main) {
|
||||
updateProfile(true, profilePictureToBeUploaded)
|
||||
}
|
||||
} catch (e: BitmapDecodingException) {
|
||||
e.printStackTrace()
|
||||
Log.e(TAG, e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -205,10 +224,10 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
|
||||
// region Updating
|
||||
private fun handleDisplayNameEditActionModeChanged() {
|
||||
val isEditingDisplayName = this.displayNameEditActionMode !== null
|
||||
val isEditingDisplayName = this.displayNameEditActionMode != null
|
||||
|
||||
binding.btnGroupNameDisplay.visibility = if (isEditingDisplayName) View.INVISIBLE else View.VISIBLE
|
||||
binding.displayNameEditText.visibility = if (isEditingDisplayName) View.VISIBLE else View.INVISIBLE
|
||||
binding.btnGroupNameDisplay.isInvisible = isEditingDisplayName
|
||||
binding.displayNameEditText.isInvisible = !isEditingDisplayName
|
||||
|
||||
val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
if (isEditingDisplayName) {
|
||||
@ -255,12 +274,11 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
MessagingModuleConfiguration.shared.storage.clearUserPic()
|
||||
}
|
||||
}
|
||||
val compoundPromise = all(promises)
|
||||
compoundPromise.successUi { // Do this on the UI thread so that it happens before the alwaysUi clause below
|
||||
all(promises) successUi { // Do this on the UI thread so that it happens before the alwaysUi clause below
|
||||
val userConfig = configFactory.user
|
||||
if (isUpdatingProfilePicture) {
|
||||
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)
|
||||
// new config
|
||||
val url = TextSecurePreferences.getProfilePictureURL(this)
|
||||
@ -275,8 +293,7 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
configFactory.persist(userConfig, SnodeAPI.nowWithOffset)
|
||||
}
|
||||
ConfigurationMessageUtilities.forceSyncConfigurationNowIfNeeded(this@SettingsActivity)
|
||||
}
|
||||
compoundPromise.alwaysUi {
|
||||
} alwaysUi {
|
||||
if (displayName != null) {
|
||||
binding.btnGroupNameDisplay.text = displayName
|
||||
}
|
||||
@ -318,23 +335,23 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
title(R.string.activity_settings_set_display_picture)
|
||||
view(R.layout.dialog_change_avatar)
|
||||
button(R.string.activity_settings_upload) { startAvatarSelection() }
|
||||
if (TextSecurePreferences.getProfileAvatarId(context) != 0) {
|
||||
if (prefs.getProfileAvatarId() != 0) {
|
||||
button(R.string.activity_settings_remove) { removeAvatar() }
|
||||
}
|
||||
cancelButton()
|
||||
}.apply {
|
||||
val profilePic = findViewById<ProfilePictureView>(R.id.profile_picture_view)
|
||||
?.also(::setupProfilePictureView)
|
||||
val profilePic = findViewById<ProfilePictureView>(R.id.profile_picture_view)
|
||||
?.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
|
||||
pictureIcon?.isVisible = !photoSet
|
||||
}
|
||||
profilePic?.isVisible = photoSet
|
||||
pictureIcon?.isVisible = !photoSet
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeAvatar() {
|
||||
@ -359,65 +376,21 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
}
|
||||
|
||||
private fun sharePublicKey() {
|
||||
val intent = Intent()
|
||||
intent.action = Intent.ACTION_SEND
|
||||
intent.putExtra(Intent.EXTRA_TEXT, hexEncodedPublicKey)
|
||||
intent.type = "text/plain"
|
||||
val chooser = Intent.createChooser(intent, getString(R.string.share))
|
||||
startActivity(chooser)
|
||||
}
|
||||
|
||||
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)
|
||||
Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
putExtra(Intent.EXTRA_TEXT, hexEncodedPublicKey)
|
||||
type = "text/plain"
|
||||
}.let { Intent.createChooser(it, getString(R.string.share)) }
|
||||
.let(::startActivity)
|
||||
}
|
||||
|
||||
private fun sendInvitation() {
|
||||
val intent = Intent()
|
||||
intent.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 !"
|
||||
intent.putExtra(Intent.EXTRA_TEXT, invitation)
|
||||
intent.type = "text/plain"
|
||||
val chooser = Intent.createChooser(intent, getString(R.string.activity_settings_invite_button_title))
|
||||
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")
|
||||
Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
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 !")
|
||||
type = "text/plain"
|
||||
}.let { Intent.createChooser(it, getString(R.string.activity_settings_invite_button_title)) }
|
||||
.let(::startActivity)
|
||||
}
|
||||
|
||||
// endregion
|
||||
@ -451,4 +424,88 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
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
|
||||
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.BorderStroke
|
||||
import androidx.compose.foundation.Canvas
|
||||
import androidx.compose.foundation.ScrollState
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
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.itemsIndexed
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Button
|
||||
import androidx.compose.material.ButtonColors
|
||||
import androidx.compose.material.ButtonDefaults
|
||||
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.RectangleShape
|
||||
import androidx.compose.ui.graphics.StrokeCap
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.graphics.drawscope.Stroke
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.contentDescription
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
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.sp
|
||||
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.delay
|
||||
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
|
||||
fun ItemButton(
|
||||
text: String,
|
||||
@ -267,24 +312,43 @@ fun ItemButton(
|
||||
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()) {
|
||||
ItemButton(
|
||||
text = text,
|
||||
icon = {
|
||||
Icon(
|
||||
painter = painterResource(id = icon),
|
||||
contentDescription = contentDescription,
|
||||
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),
|
||||
elevation = 0.dp,
|
||||
modifier = Modifier
|
||||
.wrapContentHeight()
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = margin),
|
||||
.wrapContentHeight()
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = margin),
|
||||
) {
|
||||
Box(Modifier.padding(padding)) { content() }
|
||||
}
|
||||
@ -321,14 +385,14 @@ fun <T> TitledRadioButton(option: RadioOption<T>, onClick: () -> Unit) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
modifier = Modifier
|
||||
.runIf(option.enabled) { clickable { if (!option.selected) onClick() } }
|
||||
.heightIn(min = 60.dp)
|
||||
.padding(horizontal = 32.dp)
|
||||
.contentDescription(option.contentDescription)
|
||||
.runIf(option.enabled) { clickable { if (!option.selected) onClick() } }
|
||||
.heightIn(min = 60.dp)
|
||||
.padding(horizontal = 32.dp)
|
||||
.contentDescription(option.contentDescription)
|
||||
) {
|
||||
Column(modifier = Modifier
|
||||
.weight(1f)
|
||||
.align(Alignment.CenterVertically)) {
|
||||
.weight(1f)
|
||||
.align(Alignment.CenterVertically)) {
|
||||
Column {
|
||||
Text(
|
||||
text = option.title(),
|
||||
@ -349,8 +413,8 @@ fun <T> TitledRadioButton(option: RadioOption<T>, onClick: () -> Unit) {
|
||||
onClick = null,
|
||||
enabled = option.enabled,
|
||||
modifier = Modifier
|
||||
.height(26.dp)
|
||||
.align(Alignment.CenterVertically)
|
||||
.height(26.dp)
|
||||
.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) {
|
||||
OutlinedButton(
|
||||
modifier = modifier
|
||||
.size(108.dp, 34.dp)
|
||||
.contentDescription(contentDescription),
|
||||
.size(108.dp, 34.dp)
|
||||
.contentDescription(contentDescription),
|
||||
onClick = onClick,
|
||||
border = BorderStroke(1.dp, LocalExtraColors.current.prominentButtonColor),
|
||||
shape = RoundedCornerShape(50), // = 50% percent
|
||||
@ -396,37 +460,37 @@ fun Modifier.fadingEdges(
|
||||
topEdgeHeight: Dp = 0.dp,
|
||||
bottomEdgeHeight: Dp = 20.dp
|
||||
): Modifier = this.then(
|
||||
Modifier
|
||||
// adding layer fixes issue with blending gradient and content
|
||||
.graphicsLayer { alpha = 0.99F }
|
||||
.drawWithContent {
|
||||
drawContent()
|
||||
Modifier
|
||||
// adding layer fixes issue with blending gradient and content
|
||||
.graphicsLayer { alpha = 0.99F }
|
||||
.drawWithContent {
|
||||
drawContent()
|
||||
|
||||
val topColors = listOf(Color.Transparent, Color.Black)
|
||||
val topStartY = scrollState.value.toFloat()
|
||||
val topGradientHeight = min(topEdgeHeight.toPx(), topStartY)
|
||||
if (topGradientHeight > 0f) drawRect(
|
||||
brush = Brush.verticalGradient(
|
||||
colors = topColors,
|
||||
startY = topStartY,
|
||||
endY = topStartY + topGradientHeight
|
||||
),
|
||||
blendMode = BlendMode.DstIn
|
||||
)
|
||||
val topColors = listOf(Color.Transparent, Color.Black)
|
||||
val topStartY = scrollState.value.toFloat()
|
||||
val topGradientHeight = min(topEdgeHeight.toPx(), topStartY)
|
||||
if (topGradientHeight > 0f) drawRect(
|
||||
brush = Brush.verticalGradient(
|
||||
colors = topColors,
|
||||
startY = topStartY,
|
||||
endY = topStartY + topGradientHeight
|
||||
),
|
||||
blendMode = BlendMode.DstIn
|
||||
)
|
||||
|
||||
val bottomColors = listOf(Color.Black, Color.Transparent)
|
||||
val bottomEndY = size.height - scrollState.maxValue + scrollState.value
|
||||
val bottomGradientHeight =
|
||||
min(bottomEdgeHeight.toPx(), scrollState.maxValue.toFloat() - scrollState.value)
|
||||
if (bottomGradientHeight > 0f) drawRect(
|
||||
brush = Brush.verticalGradient(
|
||||
colors = bottomColors,
|
||||
startY = bottomEndY - bottomGradientHeight,
|
||||
endY = bottomEndY
|
||||
),
|
||||
blendMode = BlendMode.DstIn
|
||||
)
|
||||
}
|
||||
val bottomColors = listOf(Color.Black, Color.Transparent)
|
||||
val bottomEndY = size.height - scrollState.maxValue + scrollState.value
|
||||
val bottomGradientHeight =
|
||||
min(bottomEdgeHeight.toPx(), scrollState.maxValue.toFloat() - scrollState.value)
|
||||
if (bottomGradientHeight > 0f) drawRect(
|
||||
brush = Brush.verticalGradient(
|
||||
colors = bottomColors,
|
||||
startY = bottomEndY - bottomGradientHeight,
|
||||
endY = bottomEndY
|
||||
),
|
||||
blendMode = BlendMode.DstIn
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
@Composable
|
||||
@ -440,16 +504,16 @@ fun Divider() {
|
||||
fun RowScope.Avatar(recipient: Recipient) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.width(60.dp)
|
||||
.align(Alignment.CenterVertically)
|
||||
.width(60.dp)
|
||||
.align(Alignment.CenterVertically)
|
||||
) {
|
||||
AndroidView(
|
||||
factory = {
|
||||
ProfilePictureView(it).apply { update(recipient) }
|
||||
},
|
||||
modifier = Modifier
|
||||
.width(46.dp)
|
||||
.height(46.dp)
|
||||
.width(46.dp)
|
||||
.height(46.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -476,8 +540,8 @@ fun Arc(
|
||||
) {
|
||||
Canvas(
|
||||
modifier = modifier
|
||||
.padding(strokeWidth)
|
||||
.size(186.dp)
|
||||
.padding(strokeWidth)
|
||||
.size(186.dp)
|
||||
) {
|
||||
// Background Line
|
||||
drawArc(
|
||||
@ -506,8 +570,8 @@ fun RowScope.SessionShieldIcon() {
|
||||
painter = painterResource(R.drawable.session_shield),
|
||||
contentDescription = null,
|
||||
modifier = Modifier
|
||||
.align(Alignment.CenterVertically)
|
||||
.wrapContentSize(unbounded = true)
|
||||
.align(Alignment.CenterVertically)
|
||||
.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
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.view.View
|
||||
@ -90,12 +91,17 @@ fun String.getThemeStyle(): Int = when (this) {
|
||||
}
|
||||
|
||||
@StyleRes
|
||||
fun Int.getDefaultAccentColor(): Int =
|
||||
if (this == R.style.Ocean_Dark || this == R.style.Ocean_Light) R.style.PrimaryBlue
|
||||
else R.style.PrimaryGreen
|
||||
fun Int.getDefaultAccentColor(): Int = when (this) {
|
||||
R.style.Ocean_Dark, R.style.Ocean_Light -> R.style.PrimaryBlue
|
||||
else -> R.style.PrimaryGreen
|
||||
}
|
||||
|
||||
data class ThemeState (
|
||||
@StyleRes val theme: Int,
|
||||
@StyleRes val accentStyle: Int,
|
||||
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:contentDescription="@string/AccessibilityId_account_id"
|
||||
tools:text="05987d601943c267879be41830888066c6a024cbdc9a548d06813924bf3372ea78" />
|
||||
|
||||
<LinearLayout
|
||||
|
||||
<androidx.compose.ui.platform.ComposeView
|
||||
android:id="@+id/composeView"
|
||||
android:layout_width="match_parent"
|
||||
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>
|
||||
android:layout_height="wrap_content"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/oxenLogoImageView"
|
||||
|
Loading…
Reference in New Issue
Block a user