ui: updated conditions (#5700)

* ios: updated conditions ui

* view

* kotlin

* show Updated conditions via review button

* same for android

---------

Co-authored-by: Evgeny Poberezkin <evgeny@poberezkin.com>
This commit is contained in:
spaced4ndy 2025-03-03 20:26:05 +04:00 committed by GitHub
parent 3d076a89e7
commit 27bf19c2b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 119 additions and 23 deletions

View file

@ -303,7 +303,8 @@ struct ContentView: View {
case .updatedConditions:
UsageConditionsView(
currUserServers: Binding.constant([]),
userServers: Binding.constant([])
userServers: Binding.constant([]),
updated: true
)
.modifier(ThemedBackground(grouped: true))
.task { await setConditionsNotified_() }

View file

@ -163,7 +163,8 @@ struct ChooseServerOperators: View {
case .showConditions:
UsageConditionsView(
currUserServers: Binding.constant([]),
userServers: Binding.constant([])
userServers: Binding.constant([]),
updated: false
)
.modifier(ThemedBackground(grouped: true))
}

View file

@ -647,7 +647,8 @@ struct WhatsNewView: View {
case .showConditions:
UsageConditionsView(
currUserServers: Binding.constant([]),
userServers: Binding.constant([])
userServers: Binding.constant([]),
updated: true
)
.modifier(ThemedBackground(grouped: true))
}

View file

@ -20,11 +20,11 @@ private enum NetworkAlert: Identifiable {
}
private enum NetworkAndServersSheet: Identifiable {
case showConditions
case showConditions(updated: Bool)
var id: String {
switch self {
case .showConditions: return "showConditions"
case let .showConditions(updated): return "showConditions \(updated)"
}
}
}
@ -169,10 +169,11 @@ struct NetworkAndServers: View {
}
.sheet(item: $sheetItem) { item in
switch item {
case .showConditions:
case let .showConditions(updated):
UsageConditionsView(
currUserServers: $ss.servers.currUserServers,
userServers: $ss.servers.userServers
userServers: $ss.servers.userServers,
updated: updated
)
.modifier(ThemedBackground(grouped: true))
}
@ -218,7 +219,8 @@ struct NetworkAndServers: View {
private func conditionsButton(_ conditionsAction: UsageConditionsAction) -> some View {
Button {
sheetItem = .showConditions
let updated = if case .review = conditionsAction { true } else { false }
sheetItem = .showConditions(updated: updated)
} label: {
switch conditionsAction {
case .review:
@ -235,13 +237,18 @@ struct UsageConditionsView: View {
@EnvironmentObject var theme: AppTheme
@Binding var currUserServers: [UserOperatorServers]
@Binding var userServers: [UserOperatorServers]
var updated: Bool
var body: some View {
VStack(alignment: .leading, spacing: 20) {
HStack {
Text("Conditions of use").font(.largeTitle).bold()
Spacer()
conditionsLinkButton()
if updated {
Text("Updated conditions").font(.largeTitle).bold()
} else {
Text("Conditions of use").font(.largeTitle).bold()
Spacer()
conditionsLinkButton()
}
}
.padding(.top)
.padding(.top)
@ -265,6 +272,12 @@ struct UsageConditionsView: View {
.multilineTextAlignment(.center)
.frame(maxWidth: .infinity, alignment: .center)
.padding(.horizontal, 32)
if updated {
conditionsDiffButton(.footnote)
}
} else if updated {
conditionsDiffButton()
.padding(.top)
}
}
.padding(.bottom)
@ -312,6 +325,19 @@ struct UsageConditionsView: View {
}
}
}
@ViewBuilder private func conditionsDiffButton(_ font: Font? = nil) -> some View {
let commit = ChatModel.shared.conditions.currentConditions.conditionsCommit
if let commitUrl = URL(string: "https://github.com/simplex-chat/simplex-chat/commit/\(commit)") {
Link(destination: commitUrl) {
HStack {
Text("Open changes")
Image(systemName: "arrow.up.right.circle")
}
.font(font)
}
}
}
}
func validateServers_(_ userServers: Binding<[UserOperatorServers]>, _ serverErrors: Binding<[UserServersError]>) {

View file

@ -145,7 +145,13 @@ fun ChatListView(chatModel: ChatModel, userPickerState: MutableStateFlow<Animate
Log.d(TAG, "UsageConditionsView setConditionsNotified error: ${e.message}")
}
}
UsageConditionsView(userServers = mutableStateOf(emptyList()), currUserServers = mutableStateOf(emptyList()), close = close, rhId = rhId)
UsageConditionsView(
userServers = mutableStateOf(emptyList()),
currUserServers = mutableStateOf(emptyList()),
updated = true,
close = close,
rhId = rhId
)
}
}
}

View file

@ -94,6 +94,7 @@ fun ModalData.ChooseServerOperators(
UsageConditionsView(
currUserServers = remember { mutableStateOf(emptyList()) },
userServers = remember { mutableStateOf(emptyList()) },
updated = false,
close = close,
rhId = null,
)

View file

@ -14,6 +14,7 @@ import dev.icerock.moko.resources.compose.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import chat.simplex.common.model.ChatController.appPrefs
@ -160,15 +161,29 @@ fun ModalData.WhatsNewView(updatedConditions: Boolean = false, viaSettings: Bool
}
if (updatedConditions) {
Text(
stringResource(MR.strings.view_updated_conditions),
color = MaterialTheme.colors.primary,
modifier = Modifier.clickable {
modalManager.showModalCloseable {
close -> UsageConditionsView(userServers = mutableStateOf(emptyList()), currUserServers = mutableStateOf(emptyList()), close = close, rhId = rhId)
Row(
modifier = Modifier
.clip(shape = CircleShape)
.clickable {
modalManager.showModalCloseable { close ->
UsageConditionsView(
userServers = mutableStateOf(emptyList()),
currUserServers = mutableStateOf(emptyList()),
updated = true,
close = close,
rhId = rhId
)
}
}
}
)
.padding(horizontal = 6.dp, vertical = 4.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Text(
stringResource(MR.strings.view_updated_conditions),
color = MaterialTheme.colors.primary
)
}
}
if (!viaSettings) {

View file

@ -22,8 +22,12 @@ import androidx.compose.ui.text.*
import androidx.compose.ui.text.input.*
import androidx.compose.desktop.ui.tooling.preview.Preview
import androidx.compose.foundation.Image
import androidx.compose.foundation.clickable
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.*
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.*
import chat.simplex.common.model.*
@ -180,7 +184,15 @@ fun ModalData.NetworkAndServersView(closeNetworkAndServers: () -> Unit) {
@Composable
fun ConditionsButton(conditionsAction: UsageConditionsAction, rhId: Long?) {
SectionItemView(
click = { ModalManager.start.showModalCloseable(endButtons = { ConditionsLinkButton() }) { close -> UsageConditionsView(currUserServers, userServers, close, rhId) } },
click = { ModalManager.start.showModalCloseable(endButtons = { ConditionsLinkButton() }) { close ->
UsageConditionsView(
currUserServers,
userServers,
updated = conditionsAction is UsageConditionsAction.Review,
close,
rhId
)
} },
) {
Text(
stringResource(if (conditionsAction is UsageConditionsAction.Review) MR.strings.operator_review_conditions else MR.strings.operator_conditions_accepted),
@ -700,6 +712,7 @@ private fun UnsavedChangesIndicator() {
fun UsageConditionsView(
currUserServers: MutableState<List<UserOperatorServers>>,
userServers: MutableState<List<UserOperatorServers>>,
updated: Boolean,
close: () -> Unit,
rhId: Long?
) {
@ -733,8 +746,35 @@ fun UsageConditionsView(
}
}
@Composable
fun ConditionsDiffButton() {
val uriHandler = LocalUriHandler.current
val commit = chatModel.conditions.value.currentConditions.conditionsCommit
Column (
modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally
) {
Row(
modifier = Modifier
.clip(shape = CircleShape)
.clickable {
val commitUrl = "https://github.com/simplex-chat/simplex-chat/commit/$commit"
uriHandler.openUriCatching(commitUrl)
}
.padding(horizontal = 6.dp, vertical = 4.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.Center
) {
Text(stringResource(MR.strings.operator_open_changes), color = MaterialTheme.colors.primary)
Spacer(Modifier.width(8.dp))
Icon(painterResource(MR.images.ic_outbound), contentDescription = null, tint = MaterialTheme.colors.primary)
}
}
}
ColumnWithScrollBar(modifier = Modifier.fillMaxSize().padding(horizontal = DEFAULT_PADDING)) {
AppBarTitle(stringResource(MR.strings.operator_conditions_of_use), enableAlphaChanges = false, withPadding = false, bottomPadding = DEFAULT_PADDING)
val title = if (updated) MR.strings.operator_updated_conditions else MR.strings.operator_conditions_of_use
AppBarTitle(stringResource(title), enableAlphaChanges = false, withPadding = false, bottomPadding = DEFAULT_PADDING)
when (val conditionsAction = chatModel.conditions.value.conditionsAction) {
is UsageConditionsAction.Review -> {
if (conditionsAction.operators.isNotEmpty()) {
@ -743,7 +783,7 @@ fun UsageConditionsView(
Column(modifier = Modifier.weight(1f).padding(bottom = DEFAULT_PADDING, top = DEFAULT_PADDING_HALF)) {
ConditionsTextView(rhId)
}
AcceptConditionsButton(conditionsAction.operators.map { it.operatorId }, close, if (conditionsAction.deadline != null) DEFAULT_PADDING_HALF else DEFAULT_PADDING * 2)
AcceptConditionsButton(conditionsAction.operators.map { it.operatorId }, close, if (conditionsAction.deadline != null || updated) DEFAULT_PADDING_HALF else DEFAULT_PADDING * 2)
if (conditionsAction.deadline != null) {
SectionTextFooter(
text = AnnotatedString(String.format(generalGetString(MR.strings.operator_conditions_accepted_for_enabled_operators_on), localDate(conditionsAction.deadline))),
@ -751,6 +791,10 @@ fun UsageConditionsView(
)
Spacer(Modifier.fillMaxWidth().height(DEFAULT_PADDING))
}
if (updated) {
ConditionsDiffButton()
Spacer(Modifier.fillMaxWidth().height(DEFAULT_PADDING))
}
}
is UsageConditionsAction.Accepted -> {

View file

@ -1859,6 +1859,7 @@
<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_updated_conditions">Updated conditions</string>
<string name="operator_in_order_to_use_accept_conditions"><![CDATA[To use the servers of <b>%s</b>, accept conditions of use.]]></string>
<string name="operator_use_for_messages">Use for messages</string>
<string name="operator_use_for_messages_receiving">To receive</string>