mirror of
https://github.com/oxen-io/session-android.git
synced 2025-08-11 17:27:42 +00:00
Merge remote-tracking branch 'origin/dev' into closed_groups
# Conflicts: # app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt # app/src/main/java/org/thoughtcrime/securesms/conversation/v2/dialogs/DownloadDialog.kt # app/src/main/java/org/thoughtcrime/securesms/home/HomeActivity.kt # app/src/main/java/org/thoughtcrime/securesms/recoverypassword/RecoveryPasswordActivity.kt
This commit is contained in:
@@ -15,8 +15,8 @@ configurations.configureEach {
|
||||
exclude module: "commons-logging"
|
||||
}
|
||||
|
||||
def canonicalVersionCode = 382
|
||||
def canonicalVersionName = "1.20.0"
|
||||
def canonicalVersionCode = 383
|
||||
def canonicalVersionName = "1.20.1"
|
||||
|
||||
def postFixSize = 10
|
||||
def abiPostFix = ['armeabi-v7a' : 1,
|
||||
@@ -59,7 +59,7 @@ android {
|
||||
|
||||
splits {
|
||||
abi {
|
||||
enable true
|
||||
enable !project.hasProperty('huawei') // huawei builds do not need the split variants
|
||||
reset()
|
||||
include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||
universalApk true
|
||||
@@ -122,6 +122,25 @@ android {
|
||||
}
|
||||
}
|
||||
|
||||
signingConfigs {
|
||||
play {
|
||||
if (project.hasProperty('SESSION_STORE_FILE')) {
|
||||
storeFile file(SESSION_STORE_FILE)
|
||||
storePassword SESSION_STORE_PASSWORD
|
||||
keyAlias SESSION_KEY_ALIAS
|
||||
keyPassword SESSION_KEY_PASSWORD
|
||||
}
|
||||
}
|
||||
huawei {
|
||||
if (project.hasProperty('SESSION_HUAWEI_STORE_FILE')) {
|
||||
storeFile file(SESSION_HUAWEI_STORE_FILE)
|
||||
storePassword SESSION_HUAWEI_STORE_PASSWORD
|
||||
keyAlias SESSION_HUAWEI_KEY_ALIAS
|
||||
keyPassword SESSION_HUAWEI_KEY_PASSWORD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions "distribution"
|
||||
productFlavors {
|
||||
play {
|
||||
@@ -133,6 +152,7 @@ android {
|
||||
buildConfigField "org.session.libsession.utilities.Device", "DEVICE", "org.session.libsession.utilities.Device.ANDROID"
|
||||
buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl"
|
||||
buildConfigField 'String', 'PUSH_KEY_SUFFIX', '\"\"'
|
||||
signingConfig signingConfigs.play
|
||||
}
|
||||
|
||||
huawei {
|
||||
@@ -142,6 +162,7 @@ android {
|
||||
buildConfigField "org.session.libsession.utilities.Device", "DEVICE", "org.session.libsession.utilities.Device.HUAWEI"
|
||||
buildConfigField "String", "NOPLAY_UPDATE_URL", "$ext.websiteUpdateUrl"
|
||||
buildConfigField 'String', 'PUSH_KEY_SUFFIX', '\"_HUAWEI\"'
|
||||
signingConfig signingConfigs.huawei
|
||||
}
|
||||
|
||||
website {
|
||||
@@ -159,8 +180,10 @@ android {
|
||||
def abiName = output.getFilter("ABI") ?: 'universal'
|
||||
def postFix = abiPostFix.get(abiName, 0)
|
||||
|
||||
def flavour = (variant.flavorName == 'huawei') ? "-huawei" : ""
|
||||
|
||||
if (postFix >= postFixSize) throw new AssertionError("postFix is too large")
|
||||
output.outputFileName = output.outputFileName = "session-${variant.versionName}-${abiName}.apk"
|
||||
output.outputFileName = output.outputFileName = "session-${variant.versionName}-${abiName}${flavour}.apk"
|
||||
output.versionCodeOverride = canonicalVersionCode * postFixSize + postFix
|
||||
}
|
||||
}
|
||||
|
@@ -62,7 +62,10 @@ class SessionDialogBuilder(val context: Context) {
|
||||
|
||||
// Main title entry point
|
||||
fun title(text: String?) {
|
||||
text(text, R.style.TextAppearance_Session_Dialog_Title) { setPadding(dp20, 0, dp20, 0) }
|
||||
text(
|
||||
text = text,
|
||||
qaTag = context.getString(R.string.AccessibilityId_modalTitle),
|
||||
style = R.style.TextAppearance_Session_Dialog_Title) { setPadding(dp20, 0, dp20, 0) }
|
||||
}
|
||||
|
||||
// Convenience assessor for title that takes a string resource
|
||||
@@ -74,18 +77,24 @@ class SessionDialogBuilder(val context: Context) {
|
||||
fun text(@StringRes id: Int, style: Int? = null) = text(context.getString(id), style)
|
||||
|
||||
fun text(text: CharSequence?, @StyleRes style: Int? = null) {
|
||||
text(text, style) {
|
||||
text(text = text, style = style) {
|
||||
layoutParams = LinearLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT)
|
||||
.apply { updateMargins(dp40, 0, dp40, 0) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun text(text: CharSequence?, @StyleRes style: Int? = null, modify: TextView.() -> Unit) {
|
||||
private fun text(
|
||||
text: CharSequence?,
|
||||
qaTag: String = context.getString(R.string.AccessibilityId_modalMessage),
|
||||
@StyleRes style: Int? = null,
|
||||
modify: TextView.() -> Unit
|
||||
) {
|
||||
text ?: return
|
||||
TextView(context, null, 0, style ?: R.style.TextAppearance_Session_Dialog_Message)
|
||||
.apply {
|
||||
setText(text)
|
||||
textAlignment = View.TEXT_ALIGNMENT_CENTER
|
||||
contentDescription = qaTag
|
||||
modify()
|
||||
}.let(topView::addView)
|
||||
|
||||
@@ -166,7 +175,7 @@ class SessionDialogBuilder(val context: Context) {
|
||||
textColor?.let{
|
||||
setTextColor(it)
|
||||
}
|
||||
contentDescription = resources.getString(contentDescriptionRes)
|
||||
contentDescription = resources.getString(text) // QA now wants the qa tag to mtch the button's text
|
||||
layoutParams = LinearLayout.LayoutParams(WRAP_CONTENT, dp60, 1f)
|
||||
setOnClickListener {
|
||||
listener.invoke()
|
||||
|
@@ -38,7 +38,6 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.drawToBitmap
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.DialogFragment
|
||||
@@ -60,6 +59,7 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import kotlinx.coroutines.flow.collect
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.collectLatest
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.filter
|
||||
@@ -192,6 +192,7 @@ import org.thoughtcrime.securesms.util.DateUtils
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
import org.thoughtcrime.securesms.util.NetworkUtils
|
||||
import org.thoughtcrime.securesms.util.SaveAttachmentTask
|
||||
import org.thoughtcrime.securesms.util.drawToBitmap
|
||||
import org.thoughtcrime.securesms.util.isScrolledToBottom
|
||||
import org.thoughtcrime.securesms.util.isScrolledToWithin30dpOfBottom
|
||||
import org.thoughtcrime.securesms.util.push
|
||||
@@ -750,9 +751,10 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
private fun restoreDraftIfNeeded() {
|
||||
val mediaURI = intent.data
|
||||
val mediaType = AttachmentManager.MediaType.from(intent.type)
|
||||
val mimeType = MediaUtil.getMimeType(this, mediaURI)
|
||||
if (mediaURI != null && mediaType != null) {
|
||||
if (AttachmentManager.MediaType.IMAGE == mediaType || AttachmentManager.MediaType.GIF == mediaType || AttachmentManager.MediaType.VIDEO == mediaType) {
|
||||
val media = Media(mediaURI, MediaUtil.getMimeType(this, mediaURI)!!, 0, 0, 0, 0, Optional.absent(), Optional.absent())
|
||||
if (mimeType != null && (AttachmentManager.MediaType.IMAGE == mediaType || AttachmentManager.MediaType.GIF == mediaType || AttachmentManager.MediaType.VIDEO == mediaType)) {
|
||||
val media = Media(mediaURI, mimeType, 0, 0, 0, 0, Optional.absent(), Optional.absent())
|
||||
startActivityForResult(MediaSendActivity.buildEditorIntent(this, listOf( media ), viewModel.recipient!!, ""), PICK_FROM_LIBRARY)
|
||||
return
|
||||
} else {
|
||||
@@ -829,7 +831,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
if (shouldShowLegacy) {
|
||||
|
||||
val txt = Phrase.from(applicationContext, R.string.disappearingMessagesLegacy)
|
||||
.put(NAME_KEY, legacyRecipient!!.name)
|
||||
.put(NAME_KEY, legacyRecipient!!.toShortString())
|
||||
.format()
|
||||
binding.outdatedBannerTextView.text = txt
|
||||
}
|
||||
@@ -1248,7 +1250,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
val name = if (recipient.isClosedGroupV2Recipient && invitingAdmin != null) {
|
||||
invitingAdmin.getSearchName()
|
||||
} else {
|
||||
recipient.name
|
||||
recipient.toShortString()
|
||||
}
|
||||
|
||||
showSessionDialog {
|
||||
@@ -1314,7 +1316,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
title(R.string.blockUnblock)
|
||||
text(
|
||||
Phrase.from(context, R.string.blockUnblockName)
|
||||
.put(NAME_KEY, recipient.name)
|
||||
.put(NAME_KEY, recipient.toShortString())
|
||||
.format()
|
||||
)
|
||||
dangerButton(R.string.blockUnblock, R.string.AccessibilityId_unblockConfirm) { viewModel.unblock() }
|
||||
@@ -1793,10 +1795,19 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
binding.inputBar.text = ""
|
||||
binding.inputBar.cancelQuoteDraft()
|
||||
binding.inputBar.cancelLinkPreviewDraft()
|
||||
// Put the message in the database
|
||||
message.id = smsDb.insertMessageOutbox(viewModel.threadId, outgoingTextMessage, false, message.sentTimestamp!!, null, true)
|
||||
// Send it
|
||||
MessageSender.send(message, recipient.address)
|
||||
lifecycleScope.launch(Dispatchers.Default) {
|
||||
// Put the message in the database
|
||||
message.id = smsDb.insertMessageOutbox(
|
||||
viewModel.threadId,
|
||||
outgoingTextMessage,
|
||||
false,
|
||||
message.sentTimestamp!!,
|
||||
null,
|
||||
true
|
||||
)
|
||||
// Send it
|
||||
MessageSender.send(message, recipient.address)
|
||||
}
|
||||
// Send a typing stopped message
|
||||
ApplicationContext.getInstance(this).typingStatusSender.onTypingStopped(viewModel.threadId)
|
||||
return Pair(recipient.address, sentTimestamp)
|
||||
|
@@ -151,14 +151,17 @@ public class ThreadRecord extends DisplayRecord {
|
||||
.format().toString();
|
||||
|
||||
} else if (MmsSmsColumns.Types.isMessageRequestResponse(type)) {
|
||||
if (lastMessage.getRecipient().getAddress().serialize().equals(
|
||||
TextSecurePreferences.getLocalNumber(context))) {
|
||||
return UtilKt.getSubbedCharSequence(
|
||||
context,
|
||||
R.string.messageRequestYouHaveAccepted,
|
||||
new Pair<>(NAME_KEY, getName())
|
||||
);
|
||||
try {
|
||||
if (lastMessage.getRecipient().getAddress().serialize().equals(
|
||||
TextSecurePreferences.getLocalNumber(context))) {
|
||||
return UtilKt.getSubbedCharSequence(
|
||||
context,
|
||||
R.string.messageRequestYouHaveAccepted,
|
||||
new Pair<>(NAME_KEY, getName())
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (Exception e){} // the above can throw a null exception
|
||||
|
||||
return context.getString(R.string.messageRequestsAccepted);
|
||||
} else if (getCount() == 0) {
|
||||
|
@@ -74,12 +74,10 @@ fun DebugMenu(
|
||||
buttons = listOf(
|
||||
DialogButtonModel(
|
||||
text = GetString(R.string.cancel),
|
||||
contentDescription = GetString(R.string.cancel),
|
||||
onClick = { sendCommand(HideEnvironmentWarningDialog) }
|
||||
),
|
||||
DialogButtonModel(
|
||||
text = GetString(R.string.ok),
|
||||
contentDescription = GetString(R.string.ok),
|
||||
onClick = { sendCommand(ChangeEnvironment) }
|
||||
)
|
||||
)
|
||||
|
@@ -66,6 +66,10 @@ import org.thoughtcrime.securesms.home.search.GlobalSearchInputLayout
|
||||
import org.thoughtcrime.securesms.home.search.GlobalSearchResult
|
||||
import org.thoughtcrime.securesms.home.search.GlobalSearchViewModel
|
||||
import org.thoughtcrime.securesms.messagerequests.MessageRequestsActivity
|
||||
import com.bumptech.glide.Glide
|
||||
import com.bumptech.glide.RequestManager
|
||||
import org.session.libsession.utilities.truncateIdForDisplay
|
||||
import org.thoughtcrime.securesms.notifications.PushRegistry
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.preferences.SettingsActivity
|
||||
import org.thoughtcrime.securesms.recoverypassword.RecoveryPasswordActivity
|
||||
@@ -498,7 +502,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
showSessionDialog {
|
||||
title(R.string.block)
|
||||
text(Phrase.from(context, R.string.blockDescription)
|
||||
.put(NAME_KEY, thread.recipient.name)
|
||||
.put(NAME_KEY, thread.recipient.toShortString())
|
||||
.format())
|
||||
dangerButton(R.string.block, R.string.AccessibilityId_blockConfirm) {
|
||||
lifecycleScope.launch(Dispatchers.Default) {
|
||||
@@ -509,7 +513,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
}
|
||||
}
|
||||
// Block confirmation toast added as per SS-64
|
||||
val txt = Phrase.from(context, R.string.blockBlockedUser).put(NAME_KEY, thread.recipient.name).format().toString()
|
||||
val txt = Phrase.from(context, R.string.blockBlockedUser).put(NAME_KEY, thread.recipient.toShortString()).format().toString()
|
||||
Toast.makeText(context, txt, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
cancelButton()
|
||||
@@ -519,7 +523,7 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
private fun unblockConversation(thread: ThreadRecord) {
|
||||
showSessionDialog {
|
||||
title(R.string.blockUnblock)
|
||||
text(Phrase.from(context, R.string.blockUnblockName).put(NAME_KEY, thread.recipient.name).format())
|
||||
text(Phrase.from(context, R.string.blockUnblockName).put(NAME_KEY, thread.recipient.toShortString()).format())
|
||||
dangerButton(R.string.blockUnblock, R.string.AccessibilityId_unblockConfirm) {
|
||||
lifecycleScope.launch(Dispatchers.Default) {
|
||||
storage.setBlocked(listOf(thread.recipient), false)
|
||||
@@ -597,28 +601,40 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
|
||||
var positiveButtonId: Int = R.string.yes
|
||||
var negativeButtonId: Int = R.string.no
|
||||
|
||||
if (recipient.isCommunityRecipient) {
|
||||
title =
|
||||
if (recipient.isCommunityRecipient) getString(R.string.communityLeave) else getString(
|
||||
R.string.groupLeave
|
||||
)
|
||||
message = Phrase.from(this.applicationContext, R.string.groupLeaveDescription)
|
||||
.put(GROUP_NAME_KEY, recipient.name.orEmpty())
|
||||
.format()
|
||||
}
|
||||
// If this is a 1-on-1 conversation
|
||||
else if (recipient.name != null) {
|
||||
title = getString(R.string.conversationsDelete)
|
||||
message = Phrase.from(this.applicationContext, R.string.conversationsDeleteDescription)
|
||||
.put(NAME_KEY, recipient.name)
|
||||
.format()
|
||||
}
|
||||
else {
|
||||
// If not group-related and we don't have a recipient name then this must be our Note to Self conversation
|
||||
title = getString(R.string.clearMessages)
|
||||
message = getString(R.string.clearMessagesNoteToSelfDescription)
|
||||
positiveButtonId = R.string.clear
|
||||
if (recipient.isGroupRecipient) {
|
||||
val group = groupDatabase.getGroup(recipient.address.toString()).orNull()
|
||||
|
||||
// If you are an admin of this group you can delete it
|
||||
if (group != null && group.admins.map { it.toString() }.contains(textSecurePreferences.getLocalNumber())) {
|
||||
title = getString(R.string.groupLeave)
|
||||
message = Phrase.from(this.applicationContext, R.string.groupDeleteDescription)
|
||||
.put(GROUP_NAME_KEY, group.title)
|
||||
.format()
|
||||
} else {
|
||||
// Otherwise this is either a community, or it's a group you're not an admin of
|
||||
title = if (recipient.isCommunityRecipient) getString(R.string.communityLeave) else getString(R.string.groupLeave)
|
||||
message = Phrase.from(this.applicationContext, R.string.groupLeaveDescription)
|
||||
.put(GROUP_NAME_KEY, group.title)
|
||||
.format()
|
||||
}
|
||||
|
||||
positiveButtonId = R.string.leave
|
||||
negativeButtonId = R.string.cancel
|
||||
} else {
|
||||
// If this is a 1-on-1 conversation
|
||||
if (recipient.name != null) {
|
||||
title = getString(R.string.conversationsDelete)
|
||||
message = Phrase.from(this.applicationContext, R.string.conversationsDeleteDescription)
|
||||
.put(NAME_KEY, recipient.toShortString())
|
||||
.format()
|
||||
}
|
||||
else {
|
||||
// If not group-related and we don't have a recipient name then this must be our Note to Self conversation
|
||||
title = getString(R.string.clearMessages)
|
||||
message = getString(R.string.clearMessagesNoteToSelfDescription)
|
||||
positiveButtonId = R.string.clear
|
||||
negativeButtonId = R.string.cancel
|
||||
}
|
||||
}
|
||||
|
||||
showSessionDialog {
|
||||
|
@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.home.search
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.channels.BufferOverflow
|
||||
@@ -13,11 +14,13 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.buffer
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import kotlinx.coroutines.flow.merge
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.plus
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.thoughtcrime.securesms.search.SearchRepository
|
||||
import org.thoughtcrime.securesms.search.model.SearchResult
|
||||
import javax.inject.Inject
|
||||
@@ -38,9 +41,14 @@ class GlobalSearchViewModel @Inject constructor(
|
||||
.buffer(onBufferOverflow = BufferOverflow.DROP_OLDEST)
|
||||
.mapLatest { query ->
|
||||
if (query.trim().isEmpty()) {
|
||||
// searching for 05 as contactDb#getAllContacts was not returning contacts
|
||||
// without a nickname/name who haven't approved us.
|
||||
GlobalSearchResult(query.toString(), searchRepository.queryContacts("05").first.toList())
|
||||
withContext(Dispatchers.Default) {
|
||||
// searching for 05 as contactDb#getAllContacts was not returning contacts
|
||||
// without a nickname/name who haven't approved us.
|
||||
GlobalSearchResult(
|
||||
query.toString(),
|
||||
searchRepository.queryContacts("05").first.toList()
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// User input delay in case we get a new query within a few hundred ms this
|
||||
// coroutine will be cancelled and the expensive query will not be run.
|
||||
|
@@ -231,8 +231,8 @@ private fun SaveAttachmentWarningDialog(
|
||||
title = context.getString(R.string.warning),
|
||||
text = context.resources.getString(R.string.attachmentsWarning),
|
||||
buttons = listOf(
|
||||
DialogButtonModel(GetString(R.string.save), GetString(R.string.AccessibilityId_saveAttachment), color = LocalColors.current.danger, onClick = onAccepted),
|
||||
DialogButtonModel(GetString(android.R.string.cancel), GetString(R.string.AccessibilityId_cancel), dismissOnClick = true)
|
||||
DialogButtonModel(GetString(R.string.save), color = LocalColors.current.danger, onClick = onAccepted),
|
||||
DialogButtonModel(GetString(android.R.string.cancel), dismissOnClick = true)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@@ -92,7 +92,7 @@ class MessageRequestsActivity : PassphraseRequiredActionBarActivity(), Conversat
|
||||
showSessionDialog {
|
||||
title(R.string.block)
|
||||
text(Phrase.from(context, R.string.blockDescription)
|
||||
.put(NAME_KEY, thread.recipient.name)
|
||||
.put(NAME_KEY, thread.recipient.toShortString())
|
||||
.format())
|
||||
dangerButton(R.string.block, R.string.AccessibilityId_blockConfirm) {
|
||||
doBlock()
|
||||
|
@@ -85,12 +85,10 @@ internal fun LandingScreen(
|
||||
buttons = listOf(
|
||||
DialogButtonModel(
|
||||
text = GetString(R.string.onboardingTos),
|
||||
contentDescription = GetString(R.string.AccessibilityId_onboardingTos),
|
||||
onClick = openTerms
|
||||
),
|
||||
DialogButtonModel(
|
||||
text = GetString(R.string.onboardingPrivacy),
|
||||
contentDescription = GetString(R.string.AccessibilityId_onboardingPrivacy),
|
||||
onClick = openPrivacyPolicy
|
||||
)
|
||||
)
|
||||
|
@@ -566,13 +566,11 @@ class SettingsActivity : PassphraseRequiredActionBarActivity() {
|
||||
buttons = listOf(
|
||||
DialogButtonModel(
|
||||
text = GetString(R.string.save),
|
||||
contentDescription = GetString(R.string.AccessibilityId_save),
|
||||
enabled = state is TempAvatar,
|
||||
onClick = saveAvatar
|
||||
),
|
||||
DialogButtonModel(
|
||||
text = GetString(R.string.remove),
|
||||
contentDescription = GetString(R.string.AccessibilityId_remove),
|
||||
color = LocalColors.current.danger,
|
||||
enabled = state is UserAvatar || // can remove is the user has an avatar set
|
||||
(state is TempAvatar && state.hasAvatar),
|
||||
|
@@ -26,7 +26,10 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import network.loki.messenger.R
|
||||
import org.thoughtcrime.securesms.ui.AlertDialog
|
||||
import org.thoughtcrime.securesms.ui.Cell
|
||||
import org.thoughtcrime.securesms.ui.DialogButtonModel
|
||||
import org.thoughtcrime.securesms.ui.GetString
|
||||
import org.thoughtcrime.securesms.ui.SessionShieldIcon
|
||||
import org.thoughtcrime.securesms.ui.components.QrImage
|
||||
import org.thoughtcrime.securesms.ui.components.SlimOutlineButton
|
||||
@@ -45,8 +48,8 @@ import org.thoughtcrime.securesms.ui.theme.monospace
|
||||
internal fun RecoveryPasswordScreen(
|
||||
mnemonic: String,
|
||||
seed: String? = null,
|
||||
copyMnemonic:() -> Unit = {},
|
||||
onHide:() -> Unit = {}
|
||||
confirmHideRecovery: () -> Unit,
|
||||
copyMnemonic:() -> Unit = {}
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(LocalDimensions.current.smallSpacing),
|
||||
@@ -57,7 +60,7 @@ internal fun RecoveryPasswordScreen(
|
||||
.padding(horizontal = LocalDimensions.current.spacing)
|
||||
) {
|
||||
RecoveryPasswordCell(mnemonic, seed, copyMnemonic)
|
||||
HideRecoveryPasswordCell(onHide)
|
||||
HideRecoveryPasswordCell(confirmHideRecovery = confirmHideRecovery)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +154,12 @@ private fun RecoveryPassword(mnemonic: String) {
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun HideRecoveryPasswordCell(onHide: () -> Unit = {}) {
|
||||
private fun HideRecoveryPasswordCell(
|
||||
confirmHideRecovery:() -> Unit
|
||||
) {
|
||||
var showHideRecoveryDialog by remember { mutableStateOf(false) }
|
||||
var showHideRecoveryConfirmationDialog by remember { mutableStateOf(false) }
|
||||
|
||||
Cell {
|
||||
Row(
|
||||
modifier = Modifier.padding(LocalDimensions.current.smallSpacing)
|
||||
@@ -176,10 +184,44 @@ private fun HideRecoveryPasswordCell(onHide: () -> Unit = {}) {
|
||||
.align(Alignment.CenterVertically)
|
||||
.contentDescription(R.string.AccessibilityId_recoveryPasswordHideRecoveryPassword),
|
||||
color = LocalColors.current.danger,
|
||||
onClick = onHide
|
||||
onClick = { showHideRecoveryDialog = true }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// recovery hide dialog
|
||||
if(showHideRecoveryDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showHideRecoveryDialog = false },
|
||||
title = stringResource(R.string.recoveryPasswordHidePermanently),
|
||||
text = stringResource(R.string.recoveryPasswordHidePermanentlyDescription1),
|
||||
buttons = listOf(
|
||||
DialogButtonModel(
|
||||
GetString(R.string.theContinue),
|
||||
color = LocalColors.current.danger,
|
||||
onClick = { showHideRecoveryConfirmationDialog = true }
|
||||
),
|
||||
DialogButtonModel(GetString(android.R.string.cancel))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// recovery hide confirmation dialog
|
||||
if(showHideRecoveryConfirmationDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = { showHideRecoveryConfirmationDialog = false },
|
||||
title = stringResource(R.string.recoveryPasswordHidePermanently),
|
||||
text = stringResource(R.string.recoveryPasswordHidePermanentlyDescription2),
|
||||
buttons = listOf(
|
||||
DialogButtonModel(
|
||||
GetString(R.string.yes),
|
||||
color = LocalColors.current.danger,
|
||||
onClick = confirmHideRecovery
|
||||
),
|
||||
DialogButtonModel(GetString(android.R.string.cancel))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@@ -188,6 +230,9 @@ private fun PreviewRecoveryPasswordScreen(
|
||||
@PreviewParameter(SessionColorsParameterProvider::class) colors: ThemeColors
|
||||
) {
|
||||
PreviewTheme(colors) {
|
||||
RecoveryPasswordScreen(mnemonic = "voyage urban toyed maverick peculiar tuxedo penguin tree grass building listen speak withdraw terminal plane")
|
||||
RecoveryPasswordScreen(
|
||||
mnemonic = "voyage urban toyed maverick peculiar tuxedo penguin tree grass building listen speak withdraw terminal plane",
|
||||
confirmHideRecovery = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -24,33 +24,12 @@ class RecoveryPasswordActivity : BaseActionBarActivity() {
|
||||
RecoveryPasswordScreen(
|
||||
mnemonic = mnemonic,
|
||||
seed = seed,
|
||||
copyMnemonic = viewModel::copyMnemonic,
|
||||
onHide = ::onHide
|
||||
confirmHideRecovery = {
|
||||
viewModel.permanentlyHidePassword()
|
||||
finish()
|
||||
},
|
||||
copyMnemonic = viewModel::copyMnemonic
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onHide() {
|
||||
showSessionDialog {
|
||||
title(R.string.recoveryPasswordHidePermanently)
|
||||
text(R.string.recoveryPasswordHidePermanentlyDescription1)
|
||||
dangerButton(R.string.theContinue, R.string.AccessibilityId_theContinue) { onHideConfirm() }
|
||||
cancelButton()
|
||||
}
|
||||
}
|
||||
|
||||
private fun onHideConfirm() {
|
||||
showSessionDialog {
|
||||
title(R.string.recoveryPasswordHidePermanently)
|
||||
text(R.string.recoveryPasswordHidePermanentlyDescription2)
|
||||
cancelButton()
|
||||
dangerButton(
|
||||
R.string.yes,
|
||||
contentDescriptionRes = R.string.AccessibilityId_recoveryPasswordHidePermanentlyConfirm
|
||||
) {
|
||||
viewModel.permanentlyHidePassword()
|
||||
finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -55,7 +55,6 @@ import org.thoughtcrime.securesms.ui.theme.bold
|
||||
|
||||
class DialogButtonModel(
|
||||
val text: GetString,
|
||||
val contentDescription: GetString = text,
|
||||
val color: Color = Color.Unspecified,
|
||||
val dismissOnClick: Boolean = true,
|
||||
val enabled: Boolean = true,
|
||||
@@ -130,6 +129,7 @@ fun AlertDialog(
|
||||
textAlign = TextAlign.Center,
|
||||
style = LocalType.current.h7,
|
||||
modifier = Modifier.padding(bottom = LocalDimensions.current.xxsSpacing)
|
||||
.qaTag(stringResource(R.string.AccessibilityId_modalTitle))
|
||||
)
|
||||
}
|
||||
text?.let {
|
||||
@@ -152,6 +152,7 @@ fun AlertDialog(
|
||||
textAlign = TextAlign.Center,
|
||||
style = textStyle,
|
||||
modifier = textModifier
|
||||
.qaTag(stringResource(R.string.AccessibilityId_modalMessage))
|
||||
)
|
||||
}
|
||||
content()
|
||||
@@ -163,7 +164,7 @@ fun AlertDialog(
|
||||
text = it.text(),
|
||||
modifier = Modifier
|
||||
.fillMaxHeight()
|
||||
.contentDescription(it.contentDescription())
|
||||
.qaTag(it.text.string())
|
||||
.weight(1f),
|
||||
color = it.color,
|
||||
enabled = it.enabled
|
||||
@@ -201,13 +202,11 @@ fun OpenURLAlertDialog(
|
||||
buttons = listOf(
|
||||
DialogButtonModel(
|
||||
text = GetString(R.string.open),
|
||||
contentDescription = GetString(R.string.AccessibilityId_urlOpenBrowser),
|
||||
color = LocalColors.current.danger,
|
||||
onClick = { context.openUrl(url) }
|
||||
),
|
||||
DialogButtonModel(
|
||||
text = GetString(android.R.string.copyUrl),
|
||||
contentDescription = GetString(R.string.AccessibilityId_copy),
|
||||
onClick = {
|
||||
context.copyURLToClipboard(url)
|
||||
Toast.makeText(context, R.string.copied, Toast.LENGTH_SHORT).show()
|
||||
@@ -297,7 +296,8 @@ fun LoadingDialog(
|
||||
title?.let {
|
||||
Text(
|
||||
it,
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally),
|
||||
modifier = Modifier.align(Alignment.CenterHorizontally)
|
||||
.qaTag(stringResource(R.string.AccessibilityId_modalTitle)),
|
||||
style = LocalType.current.large
|
||||
)
|
||||
}
|
||||
@@ -340,12 +340,10 @@ fun PreviewXCloseDialog() {
|
||||
buttons = listOf(
|
||||
DialogButtonModel(
|
||||
text = GetString(R.string.onboardingTos),
|
||||
contentDescription = GetString(R.string.AccessibilityId_onboardingTos),
|
||||
onClick = {}
|
||||
),
|
||||
DialogButtonModel(
|
||||
text = GetString(R.string.onboardingPrivacy),
|
||||
contentDescription = GetString(R.string.AccessibilityId_onboardingPrivacy),
|
||||
onClick = {}
|
||||
)
|
||||
),
|
||||
|
Reference in New Issue
Block a user