mirror of
https://github.com/simplex-chat/simplex-chat.git
synced 2026-07-09 23:11:52 +00:00
conditions modal in settings
This commit is contained in:
+9
-5
@@ -1034,7 +1034,7 @@ object ChatController {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun getUsageConditions(rh: Long?): Triple<UsageConditionsDetail, String?, CR.UsageConditions?>? {
|
||||
suspend fun getUsageConditions(rh: Long?): Triple<UsageConditionsDetail, String?, UsageConditionsDetail?>? {
|
||||
val r = sendCmd(rh, CC.ApiGetUsageConditions())
|
||||
return when (r) {
|
||||
is CR.UsageConditions -> Triple(r.usageConditions, r.conditionsText, r.acceptedConditions)
|
||||
@@ -1056,11 +1056,15 @@ object ChatController {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun acceptConditions(rh: Long?, conditionsId: Long, operatorIds: List<Long>): CR.ServerOperatorConditions? {
|
||||
suspend fun acceptConditions(rh: Long?, conditionsId: Long, operatorIds: List<Long>): ServerOperatorConditionsDetail? {
|
||||
val r = sendCmd(rh, CC.ApiAcceptConditions(conditionsId, operatorIds))
|
||||
return when (r) {
|
||||
is CR.ServerOperatorConditions -> r
|
||||
is CR.ServerOperatorConditions -> r.conditions
|
||||
else -> {
|
||||
AlertManager.shared.showAlertMsg(
|
||||
generalGetString(MR.strings.error_accepting_operator_conditions),
|
||||
"${r.responseType}: ${r.details}"
|
||||
)
|
||||
Log.e(TAG, "acceptConditions bad response: ${r.responseType} ${r.details}")
|
||||
null
|
||||
}
|
||||
@@ -3705,7 +3709,7 @@ data class ServerOperator(
|
||||
val tradeName: String,
|
||||
val legalName: String?,
|
||||
val serverDomains: List<String>,
|
||||
val conditionsAcceptance: ConditionsAcceptance,
|
||||
var conditionsAcceptance: ConditionsAcceptance,
|
||||
var enabled: Boolean,
|
||||
val smpRoles: ServerRoles,
|
||||
val xftpRoles: ServerRoles,
|
||||
@@ -5336,7 +5340,7 @@ sealed class CR {
|
||||
@Serializable @SerialName("serverOperatorConditions") class ServerOperatorConditions(val conditions: ServerOperatorConditionsDetail): CR()
|
||||
@Serializable @SerialName("userServers") class UserServers(val user: UserRef, val userServers: List<UserOperatorServers>): CR()
|
||||
@Serializable @SerialName("userServersValidation") class UserServersValidation(val user: UserRef, val serverErrors: List<UserServersError>): CR()
|
||||
@Serializable @SerialName("usageConditions") class UsageConditions(val usageConditions: UsageConditionsDetail, val conditionsText: String?, val acceptedConditions: UsageConditions?): CR()
|
||||
@Serializable @SerialName("usageConditions") class UsageConditions(val usageConditions: UsageConditionsDetail, val conditionsText: String?, val acceptedConditions: UsageConditionsDetail?): CR()
|
||||
@Serializable @SerialName("chatItemTTL") class ChatItemTTL(val user: UserRef, val chatItemTTL: Long? = null): CR()
|
||||
@Serializable @SerialName("networkConfig") class NetworkConfig(val networkConfig: NetCfg): CR()
|
||||
@Serializable @SerialName("contactInfo") class ContactInfo(val user: UserRef, val contact: Contact, val connectionStats_: ConnectionStats? = null, val customUserProfile: Profile? = null): CR()
|
||||
|
||||
+32
-3
@@ -25,6 +25,7 @@ import androidx.compose.ui.graphics.*
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.model.ChatController.acceptConditions
|
||||
import chat.simplex.common.model.ChatController.appPrefs
|
||||
import chat.simplex.common.model.ChatController.getUserServers
|
||||
import chat.simplex.common.model.ChatController.setUserServers
|
||||
@@ -44,6 +45,8 @@ fun NetworkAndServersView(close: () -> Unit) {
|
||||
val networkUseSocksProxy: MutableState<Boolean> = remember { mutableStateOf(netCfg.useSocksProxy) }
|
||||
val currUserServers = remember { mutableStateOf(emptyList<UserOperatorServers>()) }
|
||||
val userServers = remember { mutableStateOf(emptyList<UserOperatorServers>()) }
|
||||
val serverErrors = remember { mutableStateOf(emptyList<UserServersError>()) }
|
||||
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
val proxyPort = remember { derivedStateOf { appPrefs.networkProxy.state.value.port } }
|
||||
@@ -65,6 +68,7 @@ fun NetworkAndServersView(close: () -> Unit) {
|
||||
onionHosts = remember { mutableStateOf(netCfg.onionHosts) },
|
||||
currUserServers = currUserServers,
|
||||
userServers = userServers,
|
||||
serverErrors = serverErrors,
|
||||
toggleSocksProxy = { enable ->
|
||||
val def = NetCfg.defaults
|
||||
val proxyDef = NetCfg.proxyDefaults
|
||||
@@ -131,6 +135,7 @@ fun NetworkAndServersView(close: () -> Unit) {
|
||||
networkUseSocksProxy: MutableState<Boolean>,
|
||||
onionHosts: MutableState<OnionHosts>,
|
||||
currUserServers: MutableState<List<UserOperatorServers>>,
|
||||
serverErrors: MutableState<List<UserServersError>>,
|
||||
userServers: MutableState<List<UserOperatorServers>>,
|
||||
toggleSocksProxy: (Boolean) -> Unit,
|
||||
) {
|
||||
@@ -160,7 +165,7 @@ fun NetworkAndServersView(close: () -> Unit) {
|
||||
if (!chatModel.desktopNoUserNoRemote) {
|
||||
SectionView(generalGetString(MR.strings.network_preset_servers_title).uppercase()) {
|
||||
userServers.value.forEachIndexed { index, srv ->
|
||||
srv.operator?.let { ServerOperatorRow(index, it, currUserServers, userServers, currentRemoteHost?.remoteHostId) }
|
||||
srv.operator?.let { ServerOperatorRow(index, it, currUserServers, userServers, serverErrors, currentRemoteHost?.remoteHostId) }
|
||||
}
|
||||
}
|
||||
if (conditionsAction != null && anyOperatorEnabled.value) {
|
||||
@@ -610,9 +615,10 @@ private fun ServerOperatorRow(
|
||||
operator: ServerOperator,
|
||||
currUserServers: MutableState<List<UserOperatorServers>>,
|
||||
userServers: MutableState<List<UserOperatorServers>>,
|
||||
serverErrors: MutableState<List<UserServersError>>,
|
||||
rhId: Long?
|
||||
) {
|
||||
SectionItemView({ ModalManager.start.showModalCloseable { _ -> OperatorView(currUserServers, userServers, index, rhId) } }) {
|
||||
SectionItemView({ ModalManager.start.showModalCloseable { _ -> OperatorView(currUserServers, userServers, serverErrors, index, rhId) } }) {
|
||||
Image(
|
||||
painterResource(MR.images.decentralized),
|
||||
operator.tradeName,
|
||||
@@ -713,6 +719,28 @@ fun showUpdateNetworkSettingsDialog(
|
||||
)
|
||||
}
|
||||
|
||||
fun updateOperatorsConditionsAcceptance(usvs: MutableState<List<UserOperatorServers>>, updatedOperators: List<ServerOperator>) {
|
||||
for (i in usvs.value.indices) {
|
||||
val updatedOperator = updatedOperators.firstOrNull { it.operatorId == usvs.value[i].operator?.operatorId } ?: continue
|
||||
usvs.value[i].operator?.conditionsAcceptance = updatedOperator.conditionsAcceptance
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun validateServers(
|
||||
rhId: Long?,
|
||||
userServers: MutableState<List<UserOperatorServers>>,
|
||||
serverErrors: MutableState<List<UserServersError>>
|
||||
) {
|
||||
val userServersToValidate = userServers.value
|
||||
|
||||
try {
|
||||
val errors = chatController.validateServers(rhId, userServersToValidate) ?: return
|
||||
serverErrors.value = errors
|
||||
} catch (ex: Exception) {
|
||||
Log.e(TAG, ex.stackTraceToString())
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewNetworkAndServersLayout() {
|
||||
@@ -723,7 +751,8 @@ fun PreviewNetworkAndServersLayout() {
|
||||
onionHosts = remember { mutableStateOf(OnionHosts.PREFER) },
|
||||
toggleSocksProxy = {},
|
||||
currUserServers = remember { mutableStateOf(emptyList()) },
|
||||
userServers = remember { mutableStateOf(emptyList()) }
|
||||
userServers = remember { mutableStateOf(emptyList()) },
|
||||
serverErrors = remember { mutableStateOf(emptyList()) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+187
-41
@@ -7,36 +7,46 @@ import SectionView
|
||||
import TextIconSpaced
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.*
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.text.intl.Locale
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import chat.simplex.common.model.*
|
||||
import chat.simplex.common.model.ChatController.getUsageConditions
|
||||
import chat.simplex.common.platform.ColumnWithScrollBar
|
||||
import chat.simplex.common.platform.chatModel
|
||||
import chat.simplex.common.platform.*
|
||||
import chat.simplex.common.ui.theme.*
|
||||
import chat.simplex.common.views.helpers.*
|
||||
import chat.simplex.res.MR
|
||||
import dev.icerock.moko.resources.compose.painterResource
|
||||
import dev.icerock.moko.resources.compose.stringResource
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.datetime.*
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.time.format.FormatStyle
|
||||
|
||||
@Composable
|
||||
fun ModalData.OperatorView(currUserServers: MutableState<List<UserOperatorServers>>, userServers: MutableState<List<UserOperatorServers>>, operatorIndex: Int, rhId: Long?) {
|
||||
fun ModalData.OperatorView(
|
||||
currUserServers: MutableState<List<UserOperatorServers>>,
|
||||
userServers: MutableState<List<UserOperatorServers>>,
|
||||
serverErrors: MutableState<List<UserServersError>>,
|
||||
operatorIndex: Int,
|
||||
rhId: Long?
|
||||
) {
|
||||
val testing = remember { mutableStateOf(false) }
|
||||
val operator = remember { userServers.value[operatorIndex].operator_ }
|
||||
|
||||
ColumnWithScrollBar(Modifier.alpha(if (testing.value) 0.6f else 1f)) {
|
||||
AppBarTitle(String.format(stringResource(MR.strings.operator_servers_title), operator.tradeName))
|
||||
OperatorViewLayout(currUserServers, userServers, operatorIndex, rhId)
|
||||
OperatorViewLayout(currUserServers, userServers, serverErrors, operatorIndex, rhId)
|
||||
if (testing.value) {
|
||||
DefaultProgressView(null)
|
||||
}
|
||||
@@ -44,7 +54,13 @@ fun ModalData.OperatorView(currUserServers: MutableState<List<UserOperatorServer
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun OperatorViewLayout(currUserServers: MutableState<List<UserOperatorServers>>, userServers: MutableState<List<UserOperatorServers>>, operatorIndex: Int, rhId: Long?) {
|
||||
fun OperatorViewLayout(
|
||||
currUserServers: MutableState<List<UserOperatorServers>>,
|
||||
userServers: MutableState<List<UserOperatorServers>>,
|
||||
serverErrors: MutableState<List<UserServersError>>,
|
||||
operatorIndex: Int,
|
||||
rhId: Long?
|
||||
) {
|
||||
val operator = remember { userServers.value[operatorIndex].operator_ }
|
||||
|
||||
Column {
|
||||
@@ -61,7 +77,7 @@ fun OperatorViewLayout(currUserServers: MutableState<List<UserOperatorServers>>,
|
||||
TextIconSpaced()
|
||||
Text(operator.tradeName, color = MaterialTheme.colors.onBackground)
|
||||
}
|
||||
UseOperatorToggle(currUserServers = currUserServers, userServers = userServers, operatorIndex = operatorIndex, rhId = rhId)
|
||||
UseOperatorToggle(currUserServers = currUserServers, userServers = userServers, serverErrors = serverErrors, operatorIndex = operatorIndex, rhId = rhId)
|
||||
}
|
||||
if (operator.enabled) {
|
||||
if (userServers.value[operatorIndex].smpServers.filter { !it.deleted }.isNotEmpty()) {
|
||||
@@ -96,6 +112,7 @@ private fun OperatorInfoView(serverOperator: ServerOperator) {
|
||||
private fun UseOperatorToggle(
|
||||
currUserServers: MutableState<List<UserOperatorServers>>,
|
||||
userServers: MutableState<List<UserOperatorServers>>,
|
||||
serverErrors: MutableState<List<UserServersError>>,
|
||||
operatorIndex: Int,
|
||||
rhId: Long?
|
||||
) {
|
||||
@@ -111,22 +128,21 @@ private fun UseOperatorToggle(
|
||||
checked = operator.enabled,
|
||||
onCheckedChange = { enabled ->
|
||||
if (enabled) {
|
||||
when (operator.conditionsAcceptance) {
|
||||
when (val conditionsAcceptance = operator.conditionsAcceptance) {
|
||||
is ConditionsAcceptance.Accepted -> {
|
||||
userServers.value[operatorIndex].operator_.enabled = true
|
||||
}
|
||||
|
||||
is ConditionsAcceptance.Required -> {
|
||||
if (operator.conditionsAcceptance.deadline == null) {
|
||||
val deadline = operator.conditionsAcceptance.deadline
|
||||
// show conditions modal
|
||||
|
||||
ModalManager.start.showModalCloseable { _ ->
|
||||
if (conditionsAcceptance.deadline == null) {
|
||||
ModalManager.start.showModalCloseable { close ->
|
||||
SingleOperatorUsageConditionsView(
|
||||
currUserServers = currUserServers,
|
||||
userServers = userServers,
|
||||
serverErrors = serverErrors,
|
||||
operatorIndex = operatorIndex,
|
||||
rhId = rhId
|
||||
rhId = rhId,
|
||||
close = close
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@@ -146,31 +162,140 @@ private fun UseOperatorToggle(
|
||||
private fun SingleOperatorUsageConditionsView(
|
||||
currUserServers: MutableState<List<UserOperatorServers>>,
|
||||
userServers: MutableState<List<UserOperatorServers>>,
|
||||
serverErrors: MutableState<List<UserServersError>>,
|
||||
operatorIndex: Int,
|
||||
rhId: Long?
|
||||
rhId: Long?,
|
||||
close: () -> Unit
|
||||
) {
|
||||
val operatorsWithConditionsAccepted = remember { chatModel.conditions.value.serverOperators.filter { it.conditionsAcceptance.conditionsAccepted } }
|
||||
val operator = remember { userServers.value[operatorIndex].operator_ }
|
||||
val scope = rememberCoroutineScope()
|
||||
|
||||
ColumnWithScrollBar {
|
||||
AppBarTitle(String.format(stringResource(MR.strings.use_operator_x), operator.tradeName))
|
||||
suspend fun acceptForOperators(rhId: Long?, operatorIds: List<Long>, operatorIndexToEnable: Int, close: () -> Unit) {
|
||||
try {
|
||||
val conditionsId = chatModel.conditions.value.currentConditions.conditionsId
|
||||
val r = chatController.acceptConditions(rhId, conditionsId, operatorIds) ?: return
|
||||
|
||||
if (operator.conditionsAcceptance is ConditionsAcceptance.Accepted) {
|
||||
// In current UI implementation this branch doesn't get shown - as conditions can't be opened from inside operator once accepted
|
||||
ConditionsTextView(rhId)
|
||||
} else if (operatorsWithConditionsAccepted.isNotEmpty()) {
|
||||
//
|
||||
} else {
|
||||
//
|
||||
chatModel.conditions.value = r
|
||||
updateOperatorsConditionsAcceptance(currUserServers, r.serverOperators)
|
||||
updateOperatorsConditionsAcceptance(userServers, r.serverOperators)
|
||||
userServers.value.getOrNull(operatorIndexToEnable)?.operator?.enabled = true
|
||||
validateServers(rhId, userServers, serverErrors)
|
||||
close()
|
||||
} catch (ex: Exception) {
|
||||
Log.e(TAG, ex.stackTraceToString())
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AcceptConditionsButton(close: () -> Unit) {
|
||||
// Opened operator or Other enabled operators with conditions not accepted
|
||||
val operatorIds = chatModel.conditions.value.serverOperators
|
||||
.filter { it.operatorId == operator.id || (it.enabled && !it.conditionsAcceptance.conditionsAccepted) }
|
||||
.map { it.operatorId }
|
||||
|
||||
Column(Modifier.fillMaxWidth().padding(bottom = DEFAULT_PADDING * 2), horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
Button(
|
||||
onClick = {
|
||||
scope.launch {
|
||||
acceptForOperators(rhId = rhId, operatorIds = operatorIds, operatorIndexToEnable = operatorIndex, close)
|
||||
}
|
||||
},
|
||||
shape = CircleShape,
|
||||
contentPadding = PaddingValues(horizontal = DEFAULT_PADDING * 2, vertical = DEFAULT_PADDING),
|
||||
colors = ButtonDefaults.buttonColors(MaterialTheme.colors.primary, disabledBackgroundColor = MaterialTheme.colors.secondary)
|
||||
) {
|
||||
Text(stringResource(MR.strings.accept_conditions), style = MaterialTheme.typography.h2, color = Color.White, fontSize = 18.sp, fontWeight = FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UsageConditionsDestinationView(close: () -> Unit) {
|
||||
ColumnWithScrollBar(modifier = Modifier.fillMaxSize()) {
|
||||
NonScrollableTitle(stringResource(MR.strings.operator_conditions_of_use))
|
||||
Column(modifier = Modifier.weight(1f).padding(end = DEFAULT_PADDING, start = DEFAULT_PADDING, bottom = DEFAULT_PADDING, top = DEFAULT_PADDING)) {
|
||||
ConditionsTextView(rhId)
|
||||
}
|
||||
AcceptConditionsButton(close)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun UsageConditionsNavLinkButton() {
|
||||
Text(
|
||||
stringResource(MR.strings.view_conditions),
|
||||
color = MaterialTheme.colors.primary,
|
||||
modifier = Modifier.clickable {
|
||||
ModalManager.start.showModalCloseable { close ->
|
||||
UsageConditionsDestinationView(close)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
ColumnWithScrollBar(modifier = Modifier.fillMaxSize()) {
|
||||
NonScrollableTitle(String.format(stringResource(MR.strings.use_operator_x), operator.tradeName))
|
||||
if (operator.conditionsAcceptance is ConditionsAcceptance.Accepted) {
|
||||
// In current UI implementation this branch doesn't get shown - as conditions can't be opened from inside operator once accepted
|
||||
Column(modifier = Modifier.weight(1f).padding(end = DEFAULT_PADDING, start = DEFAULT_PADDING, bottom = DEFAULT_PADDING)) {
|
||||
ConditionsTextView(rhId)
|
||||
}
|
||||
} else if (operatorsWithConditionsAccepted.isNotEmpty()) {
|
||||
SectionItemView {
|
||||
Text(String.format(stringResource(MR.strings.operator_conditions_accepted_for_some), operatorsWithConditionsAccepted.joinToString(", ") { it.legalName_ }))
|
||||
}
|
||||
SectionItemView {
|
||||
Text(String.format(stringResource(MR.strings.operator_same_conditions_will_be_applied), operator.legalName_))
|
||||
}
|
||||
ConditionsAppliedToOtherOperatorsText(userServers = userServers.value, operatorIndex = operatorIndex)
|
||||
|
||||
SectionItemView {
|
||||
UsageConditionsNavLinkButton()
|
||||
}
|
||||
Spacer(Modifier.fillMaxWidth().weight(1f))
|
||||
AcceptConditionsButton(close)
|
||||
} else {
|
||||
SectionItemView {
|
||||
Text(String.format(stringResource(MR.strings.operator_in_order_to_use_accept_conditions, operator.legalName_)))
|
||||
}
|
||||
SectionItemView {
|
||||
ConditionsAppliedToOtherOperatorsText(userServers = userServers.value, operatorIndex = operatorIndex)
|
||||
}
|
||||
Column(modifier = Modifier.weight(1f).padding(end = DEFAULT_PADDING, start = DEFAULT_PADDING, bottom = DEFAULT_PADDING)) {
|
||||
ConditionsTextView(rhId)
|
||||
}
|
||||
AcceptConditionsButton(close)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun NonScrollableTitle(title: String) {
|
||||
val titleColor = MaterialTheme.appColors.title
|
||||
val theme = CurrentColors.collectAsState()
|
||||
|
||||
val brush = if (theme.value.base == DefaultTheme.SIMPLEX)
|
||||
Brush.linearGradient(listOf(titleColor.darker(0.2f), titleColor.lighter(0.35f)), Offset(0f, Float.POSITIVE_INFINITY), Offset(Float.POSITIVE_INFINITY, 0f))
|
||||
else // color is not updated when changing themes if I pass null here
|
||||
Brush.linearGradient(listOf(titleColor, titleColor), Offset(0f, Float.POSITIVE_INFINITY), Offset(Float.POSITIVE_INFINITY, 0f))
|
||||
|
||||
Text(
|
||||
title,
|
||||
Modifier
|
||||
.padding(start = DEFAULT_PADDING, top = DEFAULT_PADDING_HALF, end = DEFAULT_PADDING),
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
style = MaterialTheme.typography.h1.copy(brush = brush),
|
||||
color = MaterialTheme.colors.primaryVariant,
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ConditionsTextView(
|
||||
rhId: Long?
|
||||
) {
|
||||
val conditionsData = remember { mutableStateOf<Triple<UsageConditionsDetail, String?, CR.UsageConditions?>?>(null) }
|
||||
val conditionsData = remember { mutableStateOf<Triple<UsageConditionsDetail, String?, UsageConditionsDetail?>?>(null) }
|
||||
val failedToLoad = remember { mutableStateOf(false) }
|
||||
val defaultConditionsLink = "https://github.com/simplex-chat/simplex-chat/blob/stable/PRIVACY.md"
|
||||
val scope = rememberCoroutineScope()
|
||||
@@ -196,21 +321,22 @@ private fun ConditionsTextView(
|
||||
val (usageConditions, conditionsText, _) = conditions
|
||||
|
||||
if (conditionsText != null) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(
|
||||
color = MaterialTheme.colors.secondaryVariant,
|
||||
shape = RoundedCornerShape(12.dp)
|
||||
)
|
||||
.padding(8.dp)
|
||||
) {
|
||||
ColumnWithScrollBar {
|
||||
val scrollState = rememberScrollState()
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.verticalScroll(scrollState)
|
||||
.background(
|
||||
color = MaterialTheme.colors.background.mixWith(MaterialTheme.colors.onBackground, 0.97f),
|
||||
)
|
||||
.padding(8.dp)
|
||||
) {
|
||||
Text(
|
||||
text = conditionsText.trim(),
|
||||
text = conditionsText.trimIndent(),
|
||||
modifier = Modifier.padding(16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val conditionsLink = "https://github.com/simplex-chat/simplex-chat/blob/${usageConditions.conditionsCommit}/PRIVACY.md"
|
||||
ConditionsLinkView(conditionsLink)
|
||||
@@ -224,10 +350,30 @@ private fun ConditionsTextView(
|
||||
|
||||
@Composable
|
||||
private fun ConditionsLinkView(conditionsLink: String) {
|
||||
|
||||
SectionItemView {
|
||||
val uriHandler = LocalUriHandler.current
|
||||
Text(stringResource(MR.strings.operator_conditions_failed_to_load), color = MaterialTheme.colors.onBackground)
|
||||
Text(conditionsLink, color = MaterialTheme.colors.primary, modifier = Modifier.clickable { uriHandler.openUriCatching(conditionsLink) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ConditionsAppliedToOtherOperatorsText(userServers: List<UserOperatorServers>, operatorIndex: Int) {
|
||||
val otherOperatorsToApply = remember {
|
||||
derivedStateOf {
|
||||
chatModel.conditions.value.serverOperators.filter {
|
||||
it.enabled &&
|
||||
!it.conditionsAcceptance.conditionsAccepted &&
|
||||
it.operatorId != userServers[operatorIndex].operator_.operatorId
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (otherOperatorsToApply.value.isNotEmpty()) {
|
||||
SectionItemView {
|
||||
Text(
|
||||
String.format(stringResource(MR.strings.operators_conditions_will_also_apply), otherOperatorsToApply.value.joinToString(", ") { it.legalName_ }),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
<string name="no_media_servers_configured_for_sending">No media & file servers configured for sending.</string>
|
||||
<string name="no_media_servers_configured_for_private_routing">No media & file servers configured for private routing.</string>
|
||||
<string name="for_chat_profile">For chat profile %s:</string>
|
||||
<string name="error_accepting_operator_conditions">Error accepting conditions</string>
|
||||
|
||||
<!-- API Error Responses - SimpleXAPI.kt -->
|
||||
<string name="connection_timeout">Connection timeout</string>
|
||||
@@ -1692,7 +1693,13 @@
|
||||
<string name="operator_use_operator_toggle_description">Use operator</string>
|
||||
<string name="use_operator_x">Use operator %s</string>
|
||||
<string name="operator_conditions_failed_to_load">Current conditions text couldn\'t be loaded, you can review conditions via this link:</string>
|
||||
|
||||
<string name="operator_conditions_accepted_for_some">Conditions are already accepted for following operator(s): %s.</string>
|
||||
<string name="operator_same_conditions_will_be_applied">Same conditions will apply to operator %s.</string>
|
||||
<string name="operators_conditions_will_also_apply">Conditions will also apply for following operator(s) you use: %s.</string>
|
||||
<string name="view_conditions">View conditions</string>
|
||||
<string name="accept_conditions">Accept conditions</string>
|
||||
<string name="operator_conditions_of_use">Conditions of use</string>
|
||||
<string name="operator_in_order_to_use_accept_conditions">In order to use operator %s, accept conditions of use.</string>
|
||||
|
||||
<!-- AdvancedNetworkSettings.kt -->
|
||||
<string name="network_option_tcp_connection">TCP connection</string>
|
||||
|
||||
Reference in New Issue
Block a user