diff --git a/apps/ios/Shared/ContentView.swift b/apps/ios/Shared/ContentView.swift index 65631954e5..5418f4bcdd 100644 --- a/apps/ios/Shared/ContentView.swift +++ b/apps/ios/Shared/ContentView.swift @@ -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_() } diff --git a/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift b/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift index 1a0a736acd..24379cf9e3 100644 --- a/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift +++ b/apps/ios/Shared/Views/Onboarding/ChooseServerOperators.swift @@ -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)) } diff --git a/apps/ios/Shared/Views/Onboarding/WhatsNewView.swift b/apps/ios/Shared/Views/Onboarding/WhatsNewView.swift index f2b4dd7928..4547c6d20a 100644 --- a/apps/ios/Shared/Views/Onboarding/WhatsNewView.swift +++ b/apps/ios/Shared/Views/Onboarding/WhatsNewView.swift @@ -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)) } diff --git a/apps/ios/Shared/Views/UserSettings/NetworkAndServers/NetworkAndServers.swift b/apps/ios/Shared/Views/UserSettings/NetworkAndServers/NetworkAndServers.swift index 16aa98bc5f..7d8424a67d 100644 --- a/apps/ios/Shared/Views/UserSettings/NetworkAndServers/NetworkAndServers.swift +++ b/apps/ios/Shared/Views/UserSettings/NetworkAndServers/NetworkAndServers.swift @@ -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]>) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt index 2375e26dd4..e551ed9635 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/chatlist/ChatListView.kt @@ -145,7 +145,13 @@ fun ChatListView(chatModel: ChatModel, userPickerState: MutableStateFlow 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) { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/NetworkAndServers.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/NetworkAndServers.kt index 835e01ec27..c211ba4c66 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/NetworkAndServers.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/usersettings/networkAndServers/NetworkAndServers.kt @@ -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>, userServers: MutableState>, + 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 -> { diff --git a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml index 83f085fe3a..d6f182bc02 100644 --- a/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml +++ b/apps/multiplatform/common/src/commonMain/resources/MR/base/strings.xml @@ -1859,6 +1859,7 @@ View conditions Accept conditions Conditions of use + Updated conditions %s, accept conditions of use.]]> Use for messages To receive