mirror of
https://github.com/oxen-io/session-android.git
synced 2024-12-25 01:07:47 +00:00
Add preview for all states
This commit is contained in:
parent
0b11e182ff
commit
e95c842051
@ -5,20 +5,16 @@ import android.widget.Toast
|
|||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
import androidx.compose.foundation.BorderStroke
|
import androidx.compose.foundation.BorderStroke
|
||||||
import androidx.compose.foundation.ScrollState
|
import androidx.compose.foundation.ScrollState
|
||||||
import androidx.compose.foundation.background
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.heightIn
|
import androidx.compose.foundation.layout.heightIn
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
@ -33,27 +29,22 @@ import androidx.compose.runtime.collectAsState
|
|||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.draw.drawWithContent
|
import androidx.compose.ui.draw.drawWithContent
|
||||||
import androidx.compose.ui.geometry.Offset
|
|
||||||
import androidx.compose.ui.graphics.BlendMode
|
import androidx.compose.ui.graphics.BlendMode
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.CompositingStrategy
|
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.layout.ModifierLocalBeyondBoundsLayout
|
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.TextStyle
|
import androidx.compose.ui.text.TextStyle
|
||||||
import androidx.compose.ui.text.buildAnnotatedString
|
|
||||||
import androidx.compose.ui.text.font.Font
|
|
||||||
import androidx.compose.ui.text.font.FontFamily
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.core.text.HtmlCompat
|
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.lifecycle.repeatOnLifecycle
|
import androidx.lifecycle.repeatOnLifecycle
|
||||||
@ -61,6 +52,8 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import network.loki.messenger.R
|
import network.loki.messenger.R
|
||||||
import network.loki.messenger.databinding.ActivityExpirationSettingsBinding
|
import network.loki.messenger.databinding.ActivityExpirationSettingsBinding
|
||||||
|
import network.loki.messenger.libsession_util.util.ExpiryMode
|
||||||
|
import org.session.libsession.utilities.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity
|
||||||
import org.thoughtcrime.securesms.database.RecipientDatabase
|
import org.thoughtcrime.securesms.database.RecipientDatabase
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||||
@ -279,8 +272,18 @@ fun TitledRadioButton(option: OptionModel) {
|
|||||||
.weight(1f)
|
.weight(1f)
|
||||||
.align(Alignment.CenterVertically)) {
|
.align(Alignment.CenterVertically)) {
|
||||||
Column {
|
Column {
|
||||||
Text(text = option.title())
|
Text(
|
||||||
option.subtitle?.let { Text(text = it()) }
|
text = option.title(),
|
||||||
|
fontSize = 16.sp,
|
||||||
|
modifier = Modifier.alpha(if (option.enabled) 1f else 0.5f)
|
||||||
|
)
|
||||||
|
option.subtitle?.let {
|
||||||
|
Text(
|
||||||
|
text = it(),
|
||||||
|
fontSize = 11.sp,
|
||||||
|
modifier = Modifier.alpha(if (option.enabled) 1f else 0.5f)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RadioButton(
|
RadioButton(
|
||||||
@ -307,6 +310,41 @@ fun OutlineButton(text: String, modifier: Modifier = Modifier, onClick: () -> Un
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Preview(widthDp = 450, heightDp = 700)
|
||||||
|
@Composable
|
||||||
|
fun x(
|
||||||
|
@PreviewParameter(StatePreviewParameterProvider::class) state: State
|
||||||
|
) {
|
||||||
|
PreviewTheme(R.style.Classic_Dark) {
|
||||||
|
DisappearingMessages(
|
||||||
|
UiState(state)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StatePreviewParameterProvider : PreviewParameterProvider<State> {
|
||||||
|
override val values = newConfigValues.filter { it.expiryType != ExpiryType.LEGACY } + newConfigValues.map { it.copy(isNewConfigEnabled = false) }
|
||||||
|
|
||||||
|
private val newConfigValues get() = sequenceOf(
|
||||||
|
// new 1-1
|
||||||
|
State(expiryMode = ExpiryMode.NONE),
|
||||||
|
State(expiryMode = ExpiryMode.Legacy(43200)),
|
||||||
|
State(expiryMode = ExpiryMode.AfterRead(300)),
|
||||||
|
State(expiryMode = ExpiryMode.AfterSend(43200)),
|
||||||
|
// new group non-admin
|
||||||
|
State(isGroup = true, isSelfAdmin = false),
|
||||||
|
State(isGroup = true, isSelfAdmin = false, expiryMode = ExpiryMode.Legacy(43200)),
|
||||||
|
State(isGroup = true, isSelfAdmin = false, expiryMode = ExpiryMode.AfterSend(43200)),
|
||||||
|
// new group admin
|
||||||
|
State(isGroup = true),
|
||||||
|
State(isGroup = true, expiryMode = ExpiryMode.Legacy(43200)),
|
||||||
|
State(isGroup = true, expiryMode = ExpiryMode.AfterSend(43200)),
|
||||||
|
// new note-to-self
|
||||||
|
State(isNoteToSelf = true),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Preview
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun PreviewMessageDetails(
|
fun PreviewMessageDetails(
|
||||||
@ -314,27 +352,8 @@ fun PreviewMessageDetails(
|
|||||||
) {
|
) {
|
||||||
PreviewTheme(themeResId) {
|
PreviewTheme(themeResId) {
|
||||||
DisappearingMessages(
|
DisappearingMessages(
|
||||||
UiState(
|
UiState(State(expiryMode = ExpiryMode.AfterSend(43200))),
|
||||||
cards = listOf(
|
|
||||||
CardModel(GetString(R.string.activity_expiration_settings_delete_type), previewTypeOptions()),
|
|
||||||
CardModel(GetString(R.string.activity_expiration_settings_timer), previewTimeOptions())
|
|
||||||
)
|
|
||||||
),
|
|
||||||
modifier = Modifier.size(400.dp, 600.dp)
|
modifier = Modifier.size(400.dp, 600.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun previewTypeOptions() = listOf(
|
|
||||||
OptionModel(GetString(R.string.expiration_off)),
|
|
||||||
OptionModel(GetString(R.string.expiration_type_disappear_legacy)),
|
|
||||||
OptionModel(GetString(R.string.expiration_type_disappear_after_read)),
|
|
||||||
OptionModel(GetString(R.string.expiration_type_disappear_after_send))
|
|
||||||
)
|
|
||||||
|
|
||||||
fun previewTimeOptions() = listOf(
|
|
||||||
OptionModel(GetString("1 Minute")),
|
|
||||||
OptionModel(GetString("5 Minutes")),
|
|
||||||
OptionModel(GetString("1 Week")),
|
|
||||||
OptionModel(GetString("2 Weeks")),
|
|
||||||
)
|
|
@ -6,7 +6,6 @@ import androidx.lifecycle.ViewModelProvider
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
||||||
import kotlinx.coroutines.channels.Channel
|
import kotlinx.coroutines.channels.Channel
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
@ -21,10 +20,11 @@ import org.session.libsession.messaging.messages.ExpirationConfiguration
|
|||||||
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
import org.session.libsession.messaging.messages.control.ExpirationTimerUpdate
|
||||||
import org.session.libsession.messaging.sending_receiving.MessageSender
|
import org.session.libsession.messaging.sending_receiving.MessageSender
|
||||||
import org.session.libsession.snode.SnodeAPI
|
import org.session.libsession.snode.SnodeAPI
|
||||||
|
import org.session.libsession.utilities.Address
|
||||||
import org.session.libsession.utilities.ExpirationUtil
|
import org.session.libsession.utilities.ExpirationUtil
|
||||||
import org.session.libsession.utilities.SSKEnvironment.MessageExpirationManagerProtocol
|
import org.session.libsession.utilities.SSKEnvironment.MessageExpirationManagerProtocol
|
||||||
import org.session.libsession.utilities.TextSecurePreferences
|
import org.session.libsession.utilities.TextSecurePreferences
|
||||||
import org.session.libsession.utilities.recipients.Recipient
|
import org.thoughtcrime.securesms.conversation.expiration.ExpiryType
|
||||||
import org.thoughtcrime.securesms.database.GroupDatabase
|
import org.thoughtcrime.securesms.database.GroupDatabase
|
||||||
import org.thoughtcrime.securesms.database.Storage
|
import org.thoughtcrime.securesms.database.Storage
|
||||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||||
@ -34,8 +34,38 @@ import kotlin.time.Duration.Companion.days
|
|||||||
import kotlin.time.Duration.Companion.hours
|
import kotlin.time.Duration.Companion.hours
|
||||||
import kotlin.time.Duration.Companion.minutes
|
import kotlin.time.Duration.Companion.minutes
|
||||||
|
|
||||||
|
data class Event(
|
||||||
|
val saveSuccess: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
data class State(
|
||||||
|
val isGroup: Boolean = false,
|
||||||
|
val isSelfAdmin: Boolean = true,
|
||||||
|
val address: Address? = null,
|
||||||
|
val isNoteToSelf: Boolean = false,
|
||||||
|
val expiryMode: ExpiryMode? = ExpiryMode.NONE,
|
||||||
|
val isNewConfigEnabled: Boolean = true,
|
||||||
|
val callbacks: Callbacks = NoOpCallbacks
|
||||||
|
) {
|
||||||
|
val subtitle get() = when {
|
||||||
|
isGroup || isNoteToSelf -> GetString(R.string.activity_expiration_settings_subtitle_sent)
|
||||||
|
else -> GetString(R.string.activity_expiration_settings_subtitle)
|
||||||
|
}
|
||||||
|
val duration get() = expiryMode?.duration
|
||||||
|
val expiryType get() = expiryMode?.type
|
||||||
|
|
||||||
|
val isTimeOptionsEnabled = isNoteToSelf || isSelfAdmin && (isNewConfigEnabled || expiryType == ExpiryType.LEGACY)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Callbacks {
|
||||||
|
fun onSetClick(): Any = Unit
|
||||||
|
fun setType(type: ExpiryType) {}
|
||||||
|
fun setTime(seconds: Long) {}
|
||||||
|
fun setMode(mode: ExpiryMode) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
object NoOpCallbacks: Callbacks
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
class ExpirationSettingsViewModel(
|
class ExpirationSettingsViewModel(
|
||||||
private val threadId: Long,
|
private val threadId: Long,
|
||||||
private val textSecurePreferences: TextSecurePreferences,
|
private val textSecurePreferences: TextSecurePreferences,
|
||||||
@ -43,24 +73,19 @@ class ExpirationSettingsViewModel(
|
|||||||
private val threadDb: ThreadDatabase,
|
private val threadDb: ThreadDatabase,
|
||||||
private val groupDb: GroupDatabase,
|
private val groupDb: GroupDatabase,
|
||||||
private val storage: Storage,
|
private val storage: Storage,
|
||||||
private val isNewConfigEnabled: Boolean
|
isNewConfigEnabled: Boolean
|
||||||
) : ViewModel() {
|
) : ViewModel(), Callbacks {
|
||||||
|
|
||||||
private val _event = Channel<Event>()
|
private val _event = Channel<Event>()
|
||||||
val event = _event.receiveAsFlow()
|
val event = _event.receiveAsFlow()
|
||||||
|
|
||||||
private val _state = MutableStateFlow(State())
|
private val _state = MutableStateFlow(State(
|
||||||
|
isNewConfigEnabled = isNewConfigEnabled,
|
||||||
|
callbacks = this@ExpirationSettingsViewModel
|
||||||
|
))
|
||||||
val state = _state.asStateFlow()
|
val state = _state.asStateFlow()
|
||||||
|
|
||||||
val uiState = _state.map {
|
val uiState = _state.map { UiState(it) }
|
||||||
UiState(
|
|
||||||
cards = listOf(
|
|
||||||
CardModel(GetString(R.string.activity_expiration_settings_delete_type), typeOptions(it)),
|
|
||||||
CardModel(GetString(R.string.activity_expiration_settings_timer), timeOptions(it))
|
|
||||||
),
|
|
||||||
showGroupFooter = it.isGroup
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private var expirationConfig: ExpirationConfiguration? = null
|
private var expirationConfig: ExpirationConfiguration? = null
|
||||||
|
|
||||||
@ -71,101 +96,41 @@ class ExpirationSettingsViewModel(
|
|||||||
val recipient = threadDb.getRecipientForThreadId(threadId)
|
val recipient = threadDb.getRecipientForThreadId(threadId)
|
||||||
val groupInfo = recipient?.takeIf { it.isClosedGroupRecipient }
|
val groupInfo = recipient?.takeIf { it.isClosedGroupRecipient }
|
||||||
?.run { address.toGroupString().let(groupDb::getGroup).orNull() }
|
?.run { address.toGroupString().let(groupDb::getGroup).orNull() }
|
||||||
|
|
||||||
_state.update { state ->
|
_state.update { state ->
|
||||||
state.copy(
|
state.copy(
|
||||||
isGroup = groupInfo != null,
|
isGroup = groupInfo != null,
|
||||||
isSelfAdmin = groupInfo == null || groupInfo.admins.any{ it.serialize() == textSecurePreferences.getLocalNumber() },
|
isSelfAdmin = groupInfo == null || groupInfo.admins.any{ it.serialize() == textSecurePreferences.getLocalNumber() },
|
||||||
recipient = recipient,
|
|
||||||
expiryMode = expiryMode
|
expiryMode = expiryMode
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun typeOption(
|
override fun setType(type: ExpiryType) {
|
||||||
type: ExpiryType,
|
|
||||||
state: State,
|
|
||||||
@StringRes title: Int,
|
|
||||||
@StringRes subtitle: Int? = null,
|
|
||||||
@StringRes contentDescription: Int = title
|
|
||||||
) = OptionModel(GetString(title), subtitle?.let(::GetString), selected = state.expiryType == type) { setType(type) }
|
|
||||||
|
|
||||||
private fun typeOptions(state: State) =
|
|
||||||
if (state.isSelf || state.isGroup) emptyList()
|
|
||||||
else listOf(
|
|
||||||
typeOption(ExpiryType.NONE, state, R.string.expiration_off, contentDescription = R.string.AccessibilityId_disable_disappearing_messages),
|
|
||||||
typeOption(ExpiryType.LEGACY, state, R.string.expiration_type_disappear_legacy, contentDescription = R.string.expiration_type_disappear_legacy_description),
|
|
||||||
typeOption(ExpiryType.AFTER_READ, state, R.string.expiration_type_disappear_after_read, contentDescription = R.string.expiration_type_disappear_after_read_description),
|
|
||||||
typeOption(ExpiryType.AFTER_SEND, state, R.string.expiration_type_disappear_after_send, contentDescription = R.string.expiration_type_disappear_after_send_description),
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun setType(type: ExpiryType) {
|
|
||||||
_state.update { it.copy(expiryMode = type.mode(0)) }
|
_state.update { it.copy(expiryMode = type.mode(0)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setTime(seconds: Long) {
|
override fun setTime(seconds: Long) {
|
||||||
_state.update { it.copy(
|
_state.update { it.copy(
|
||||||
expiryMode = it.expiryType?.mode(seconds)
|
expiryMode = it.expiryType?.mode(seconds)
|
||||||
) }
|
) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setMode(mode: ExpiryMode) {
|
override fun setMode(mode: ExpiryMode) {
|
||||||
_state.update { it.copy(
|
_state.update { it.copy(
|
||||||
expiryMode = mode
|
expiryMode = mode
|
||||||
) }
|
) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun timeOption(seconds: Long, @StringRes id: Int) = OptionModel(GetString(id), selected = false, onClick = { setTime(seconds) })
|
override fun onSetClick() = viewModelScope.launch {
|
||||||
fun timeOption(seconds: Long, title: String, subtitle: String) = OptionModel(GetString(title), GetString(subtitle), selected = false, onClick = { setTime(seconds) })
|
|
||||||
|
|
||||||
// private fun timeOptions(state: State) = timeOptions(state.types.isEmpty(), state.expiryType == ExpiryType.AFTER_SEND)
|
|
||||||
private fun timeOptions(state: State): List<OptionModel> =
|
|
||||||
if (state.isSelf || state.isGroup) timeOptionsOnly(state)
|
|
||||||
else when (state.expiryMode) {
|
|
||||||
is ExpiryMode.Legacy -> afterReadTimes
|
|
||||||
is ExpiryMode.AfterRead -> afterReadTimes
|
|
||||||
is ExpiryMode.AfterSend -> afterSendTimes
|
|
||||||
else -> emptyList()
|
|
||||||
}.map { timeOption(it, state) }
|
|
||||||
|
|
||||||
private val afterReadTimes = listOf(12.hours, 1.days, 7.days, 14.days)
|
|
||||||
private val afterSendTimes = listOf(5.minutes, 1.hours) + afterReadTimes
|
|
||||||
|
|
||||||
private fun timeOptionsOnly(state: State) = listOfNotNull(
|
|
||||||
typeOption(ExpiryType.NONE, state, R.string.arrays__off),
|
|
||||||
noteToSelfOption(1.minutes, state, subtitle = "for testing purposes").takeIf { BuildConfig.DEBUG },
|
|
||||||
) + afterSendTimes.map { noteToSelfOption(it, state) }
|
|
||||||
|
|
||||||
private fun timeOption(
|
|
||||||
duration: Duration,
|
|
||||||
state: State,
|
|
||||||
title: GetString = GetString { ExpirationUtil.getExpirationDisplayValue(it, duration.inWholeSeconds.toInt()) },
|
|
||||||
) = OptionModel(
|
|
||||||
title = title,
|
|
||||||
selected = state.expiryMode?.duration == duration,
|
|
||||||
enabled = state.isSelfAdmin
|
|
||||||
) { setTime(duration.inWholeSeconds) }
|
|
||||||
|
|
||||||
private fun noteToSelfOption(
|
|
||||||
duration: Duration,
|
|
||||||
state: State,
|
|
||||||
title: GetString = GetString { ExpirationUtil.getExpirationDisplayValue(it, duration.inWholeSeconds.toInt()) },
|
|
||||||
subtitle: String? = null
|
|
||||||
) = OptionModel(
|
|
||||||
title = title,
|
|
||||||
subtitle = subtitle?.let(::GetString),
|
|
||||||
selected = state.duration == duration,
|
|
||||||
onClick = { setMode(ExpiryMode.AfterSend(duration.inWholeSeconds)) }
|
|
||||||
)
|
|
||||||
|
|
||||||
fun onSetClick() = viewModelScope.launch {
|
|
||||||
val state = _state.value
|
val state = _state.value
|
||||||
val expiryMode = state.expiryMode ?: ExpiryMode.NONE
|
val expiryMode = state.expiryMode ?: ExpiryMode.NONE
|
||||||
val typeValue = expiryMode.let {
|
val typeValue = expiryMode.let {
|
||||||
if (it is ExpiryMode.Legacy) ExpiryMode.AfterRead(it.expirySeconds)
|
if (it is ExpiryMode.Legacy) ExpiryMode.AfterRead(it.expirySeconds)
|
||||||
else it
|
else it
|
||||||
}
|
}
|
||||||
val address = state.recipient?.address
|
val address = state.address
|
||||||
if (address == null || expirationConfig?.expiryMode == typeValue) {
|
if (address == null || expirationConfig?.expiryMode == typeValue) {
|
||||||
_event.send(Event(false))
|
_event.send(Event(false))
|
||||||
return@launch
|
return@launch
|
||||||
@ -211,36 +176,106 @@ class ExpirationSettingsViewModel(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class Event(
|
|
||||||
val saveSuccess: Boolean
|
|
||||||
)
|
|
||||||
|
|
||||||
data class State(
|
|
||||||
val isGroup: Boolean = false,
|
|
||||||
val isSelfAdmin: Boolean = false,
|
|
||||||
val recipient: Recipient? = null,
|
|
||||||
val expiryMode: ExpiryMode? = null,
|
|
||||||
val types: List<ExpiryType> = emptyList()
|
|
||||||
) {
|
|
||||||
val subtitle get() = when {
|
|
||||||
isGroup || isSelf -> GetString(R.string.activity_expiration_settings_subtitle_sent)
|
|
||||||
else -> GetString(R.string.activity_expiration_settings_subtitle)
|
|
||||||
}
|
|
||||||
val duration get() = expiryMode?.duration
|
|
||||||
val isSelf = recipient?.isLocalNumber == true
|
|
||||||
val expiryType get() = expiryMode?.type
|
|
||||||
}
|
|
||||||
|
|
||||||
data class UiState(
|
data class UiState(
|
||||||
val cards: List<CardModel> = emptyList(),
|
val cards: List<CardModel> = emptyList(),
|
||||||
val showGroupFooter: Boolean = false
|
val showGroupFooter: Boolean = false,
|
||||||
|
val callbacks: Callbacks = NoOpCallbacks
|
||||||
|
) {
|
||||||
|
constructor(state: State): this(
|
||||||
|
cards = listOf(
|
||||||
|
CardModel(GetString(R.string.activity_expiration_settings_delete_type), typeOptions(state)),
|
||||||
|
CardModel(GetString(R.string.activity_expiration_settings_timer), timeOptions(state))
|
||||||
|
),
|
||||||
|
showGroupFooter = state.isGroup && state.isNewConfigEnabled,
|
||||||
|
callbacks = state.callbacks
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
data class CardModel(
|
data class CardModel(
|
||||||
val title: GetString,
|
val title: GetString,
|
||||||
val options: List<OptionModel>
|
val options: List<OptionModel>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun typeOptions(state: State) =
|
||||||
|
if (state.isNoteToSelf || (state.isGroup && state.isNewConfigEnabled)) emptyList()
|
||||||
|
else listOfNotNull(
|
||||||
|
typeOption(
|
||||||
|
ExpiryType.NONE,
|
||||||
|
state,
|
||||||
|
R.string.expiration_off,
|
||||||
|
contentDescription = R.string.AccessibilityId_disable_disappearing_messages,
|
||||||
|
enabled = state.isSelfAdmin
|
||||||
|
),
|
||||||
|
if (!state.isNewConfigEnabled) typeOption(
|
||||||
|
ExpiryType.LEGACY,
|
||||||
|
state,
|
||||||
|
R.string.expiration_type_disappear_legacy,
|
||||||
|
contentDescription = R.string.expiration_type_disappear_legacy_description,
|
||||||
|
enabled = state.isSelfAdmin
|
||||||
|
) else null,
|
||||||
|
if (!state.isGroup) typeOption(
|
||||||
|
ExpiryType.AFTER_READ,
|
||||||
|
state,
|
||||||
|
R.string.expiration_type_disappear_after_read,
|
||||||
|
R.string.expiration_type_disappear_after_read_description,
|
||||||
|
contentDescription = R.string.expiration_type_disappear_after_read_description,
|
||||||
|
enabled = state.isNewConfigEnabled && state.isSelfAdmin
|
||||||
|
) else null,
|
||||||
|
typeOption(
|
||||||
|
ExpiryType.AFTER_SEND,
|
||||||
|
state,
|
||||||
|
R.string.expiration_type_disappear_after_send,
|
||||||
|
R.string.expiration_type_disappear_after_read_description,
|
||||||
|
contentDescription = R.string.expiration_type_disappear_after_send_description,
|
||||||
|
enabled = state.isNewConfigEnabled && state.isSelfAdmin
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun typeOption(
|
||||||
|
type: ExpiryType,
|
||||||
|
state: State,
|
||||||
|
@StringRes title: Int,
|
||||||
|
@StringRes subtitle: Int? = null,
|
||||||
|
@StringRes contentDescription: Int = title,
|
||||||
|
enabled: Boolean = true,
|
||||||
|
onClick: () -> Unit = { state.callbacks.setType(type) }
|
||||||
|
) = OptionModel(
|
||||||
|
GetString(title),
|
||||||
|
subtitle?.let(::GetString),
|
||||||
|
selected = state.expiryType == type,
|
||||||
|
enabled = enabled,
|
||||||
|
onClick = onClick
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun timeOptions(state: State): List<OptionModel> =
|
||||||
|
if (state.isNoteToSelf || (state.isGroup && state.isNewConfigEnabled)) timeOptionsOnly(state)
|
||||||
|
else when (state.expiryMode) {
|
||||||
|
is ExpiryMode.Legacy -> afterReadTimes
|
||||||
|
is ExpiryMode.AfterRead -> afterReadTimes
|
||||||
|
is ExpiryMode.AfterSend -> afterSendTimes
|
||||||
|
else -> emptyList()
|
||||||
|
}.map { timeOption(it, state) }
|
||||||
|
|
||||||
|
private val afterSendTimes = listOf(12.hours, 1.days, 7.days, 14.days)
|
||||||
|
private val afterReadTimes = listOf(5.minutes, 1.hours) + afterSendTimes
|
||||||
|
|
||||||
|
private fun timeOptionsOnly(state: State) = listOfNotNull(
|
||||||
|
typeOption(ExpiryType.NONE, state, R.string.arrays__off, enabled = state.isSelfAdmin),
|
||||||
|
timeOption(1.minutes, state, subtitle = GetString("for testing purposes")).takeIf { BuildConfig.DEBUG },
|
||||||
|
) + afterSendTimes.map { timeOption(it, state) }
|
||||||
|
|
||||||
|
private fun timeOption(
|
||||||
|
duration: Duration,
|
||||||
|
state: State,
|
||||||
|
title: GetString = GetString { ExpirationUtil.getExpirationDisplayValue(it, duration.inWholeSeconds.toInt()) },
|
||||||
|
subtitle: GetString? = null
|
||||||
|
) = OptionModel(
|
||||||
|
title = title,
|
||||||
|
subtitle = subtitle,
|
||||||
|
selected = state.expiryMode?.duration == duration,
|
||||||
|
enabled = state.isTimeOptionsEnabled
|
||||||
|
) { state.callbacks.setTime(duration.inWholeSeconds) }
|
||||||
|
|
||||||
data class OptionModel(
|
data class OptionModel(
|
||||||
val title: GetString,
|
val title: GetString,
|
||||||
val subtitle: GetString? = null,
|
val subtitle: GetString? = null,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user