From 42efe750374ebf9c42ce4ab18398f400810f290d Mon Sep 17 00:00:00 2001 From: alexandreferris Date: Tue, 14 May 2024 05:55:41 -0300 Subject: [PATCH 1/6] feat: add privacy policy and terms of use URLs + screen titles and labels Signed-off-by: alexandreferris --- app/src/main/res/values/strings.xml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index ac1b79197a6..7aeb082b87c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -187,6 +187,8 @@ https://support.wire.com/hc/articles/115004082129 https://medium.com/wire-news/android-updates/home http://maps.google.com/maps?z=%1d&q=loc:%2f+%2f + https://wire.com/privacy-policy#:~:text=We%20process%20individual%20data%20about,%C2%A7%201%20a)%20GDPR). + https://wire.com/legal#:~:text=Wire%20is%20used%20for%20private,disable%20your%20access%20to%20Wire. Vault Archive @@ -197,6 +199,11 @@ App Settings Give Feedback Report Bug + About This App + Privacy Policy + Terms of Use + Copyright + © Wire Swiss GmbH Debug Settings API VERSIONING E2EI Manual Enrollment From 556a8f6d9ecfe446b71a169134de6c7d0ebdb179 Mon Sep 17 00:00:00 2001 From: alexandreferris Date: Tue, 14 May 2024 06:32:47 -0300 Subject: [PATCH 2/6] feat: add privacy policy and terms of use destination as external uri destination Signed-off-by: alexandreferris --- .../com/wire/android/navigation/OtherDestinations.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/kotlin/com/wire/android/navigation/OtherDestinations.kt b/app/src/main/kotlin/com/wire/android/navigation/OtherDestinations.kt index 2f705693509..b8cb41d8f8d 100644 --- a/app/src/main/kotlin/com/wire/android/navigation/OtherDestinations.kt +++ b/app/src/main/kotlin/com/wire/android/navigation/OtherDestinations.kt @@ -57,6 +57,16 @@ object SupportScreenDestination : ExternalUriDirection { get() = Uri.parse(BuildConfig.URL_SUPPORT) } +object PrivacyPolicyScreenDestination : ExternalUriStringResDirection { + override val uriStringRes: Int + get() = R.string.url_privacy_policy +} + +object TermsOfUseScreenDestination : ExternalUriStringResDirection { + override val uriStringRes: Int + get() = R.string.url_terms_of_use +} + object GiveFeedbackDestination : IntentDirection { override fun intent(context: Context): Intent { val intent = Intent(Intent.ACTION_SEND) From 9a642ddef61450f9b47256ed00c17d9979b3ab6a Mon Sep 17 00:00:00 2001 From: alexandreferris Date: Tue, 14 May 2024 06:33:33 -0300 Subject: [PATCH 3/6] feat: add about this app screen, state and viewmodel Signed-off-by: alexandreferris --- .../ui/settings/about/AboutThisAppScreen.kt | 185 ++++++++++++++++++ .../ui/settings/about/AboutThisAppState.kt | 22 +++ .../settings/about/AboutThisAppViewModel.kt | 53 +++++ 3 files changed, 260 insertions(+) create mode 100644 app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppScreen.kt create mode 100644 app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppState.kt create mode 100644 app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppViewModel.kt diff --git a/app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppScreen.kt b/app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppScreen.kt new file mode 100644 index 00000000000..e876feec986 --- /dev/null +++ b/app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppScreen.kt @@ -0,0 +1,185 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.android.ui.settings.about + +import android.content.Context +import android.widget.Toast +import androidx.compose.foundation.ScrollState +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.ClipboardManager +import androidx.compose.ui.platform.LocalClipboardManager +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.hilt.navigation.compose.hiltViewModel +import com.ramcosta.composedestinations.annotation.Destination +import com.ramcosta.composedestinations.annotation.RootNavGraph +import com.wire.android.BuildConfig +import com.wire.android.R +import com.wire.android.model.Clickable +import com.wire.android.navigation.NavigationCommand +import com.wire.android.navigation.Navigator +import com.wire.android.navigation.handleNavigation +import com.wire.android.ui.common.dimensions +import com.wire.android.ui.common.scaffold.WireScaffold +import com.wire.android.ui.common.topappbar.NavigationIconType +import com.wire.android.ui.common.topappbar.WireCenterAlignedTopAppBar +import com.wire.android.ui.home.settings.SettingsItem + +@RootNavGraph +@Destination +@Composable +fun AboutThisAppScreen( + viewModel: AboutThisAppViewModel = hiltViewModel(), + navigator: Navigator +) { + val context = LocalContext.current + AboutThisAppContent( + state = viewModel.state, + onBackPressed = navigator::navigateBack, + onItemClicked = remember { + { + it.direction.handleNavigation( + context = context, + handleOtherDirection = { navigator.navigate(NavigationCommand(it)) } + ) + } + } + ) +} + +@Composable +private fun AboutThisAppContent( + state: AboutThisAppState, + onBackPressed: () -> Unit, + onItemClicked: (SettingsItem.DirectionItem) -> Unit +) { + val aboutThisAppContentState: AboutThisAppContentState = rememberAboutThisAppContentState() + + WireScaffold( + topBar = { + WireCenterAlignedTopAppBar( + title = stringResource(id = R.string.about_app_screen_title), + elevation = dimensions().spacing0x, + navigationIconType = NavigationIconType.Back, + onNavigationPressed = onBackPressed + ) + } + ) { internalPadding -> + Column( + modifier = Modifier + .fillMaxSize() + .verticalScroll(aboutThisAppContentState.scrollState) + .padding(internalPadding) + ) { + SettingsItem( + text = stringResource(id = R.string.settings_terms_of_use_label), + trailingIcon = R.drawable.ic_arrow_right, + onRowPressed = Clickable( + enabled = true, + onClick = { + onItemClicked(SettingsItem.TermsOfUse) + } + ) + ) + SettingsItem( + text = stringResource(id = R.string.settings_privacy_policy_label), + trailingIcon = R.drawable.ic_arrow_right, + onRowPressed = Clickable( + enabled = true, + onClick = { + onItemClicked(SettingsItem.PrivacyPolicy) + } + ) + ) + SettingsItem( + text = stringResource(id = R.string.settings_licenses_settings_label), + trailingIcon = R.drawable.ic_arrow_right, + onRowPressed = Clickable( + enabled = true, + onClick = { + onItemClicked(SettingsItem.Licenses) + } + ) + ) + SettingsItem( + title = stringResource(R.string.label_code_commit_id), + text = state.commitish, + trailingIcon = R.drawable.ic_copy, + onIconPressed = Clickable( + enabled = true, + onClick = { + aboutThisAppContentState.copyToClipboard(state.commitish) + } + ) + ) + SettingsItem( + title = stringResource(R.string.app_version), + text = BuildConfig.VERSION_NAME, + trailingIcon = R.drawable.ic_copy, + onIconPressed = Clickable( + enabled = true, + onClick = { + aboutThisAppContentState.copyToClipboard(BuildConfig.VERSION_NAME) + } + ) + ) + SettingsItem( + title = stringResource(R.string.label_copyright), + text = stringResource(id = R.string.label_copyright_value) + ) + } + } +} + +@Composable +fun rememberAboutThisAppContentState(): AboutThisAppContentState { + val context = LocalContext.current + val clipboardManager = LocalClipboardManager.current + val scrollState = rememberScrollState() + + return remember { + AboutThisAppContentState( + context = context, + clipboardManager = clipboardManager, + scrollState = scrollState + ) + } +} + +data class AboutThisAppContentState( + val context: Context, + val clipboardManager: ClipboardManager, + val scrollState: ScrollState +) { + fun copyToClipboard(text: String) { + clipboardManager.setText(AnnotatedString(text)) + Toast.makeText( + context, + context.getText(R.string.label_text_copied), + Toast.LENGTH_SHORT + ).show() + } +} diff --git a/app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppState.kt b/app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppState.kt new file mode 100644 index 00000000000..0743f21380a --- /dev/null +++ b/app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppState.kt @@ -0,0 +1,22 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.android.ui.settings.about + +data class AboutThisAppState( + val commitish: String = "null" +) diff --git a/app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppViewModel.kt b/app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppViewModel.kt new file mode 100644 index 00000000000..9377b8d4731 --- /dev/null +++ b/app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppViewModel.kt @@ -0,0 +1,53 @@ +/* + * Wire + * Copyright (C) 2024 Wire Swiss GmbH + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/. + */ +package com.wire.android.ui.settings.about + +import android.content.Context +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.wire.android.util.getGitBuildId +import dagger.hilt.android.lifecycle.HiltViewModel +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.launch +import javax.inject.Inject + +@HiltViewModel +class AboutThisAppViewModel @Inject constructor( + @ApplicationContext private val context: Context +) : ViewModel() { + + var state by mutableStateOf( + AboutThisAppState() + ) + + init { + setGitHash() + } + + private fun setGitHash() { + viewModelScope.launch { + val gitBuildId = context.getGitBuildId() + state = state.copy( + commitish = gitBuildId + ) + } + } +} From 2b12e799e52254c85b2e10d26eba95924b676a7b Mon Sep 17 00:00:00 2001 From: alexandreferris Date: Tue, 14 May 2024 06:34:12 -0300 Subject: [PATCH 4/6] feat: add privacy policy and terms of use direction item, remove Licenses and add AboutApp screen on SettingsScreen Signed-off-by: alexandreferris --- .../android/ui/home/settings/SettingsItem.kt | 21 +++++++++++++++++++ .../ui/home/settings/SettingsScreen.kt | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/wire/android/ui/home/settings/SettingsItem.kt b/app/src/main/kotlin/com/wire/android/ui/home/settings/SettingsItem.kt index 9203dd155b6..85d12ea5337 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/settings/SettingsItem.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/settings/SettingsItem.kt @@ -33,11 +33,14 @@ import com.ramcosta.composedestinations.spec.Direction import com.wire.android.R import com.wire.android.model.Clickable import com.wire.android.navigation.GiveFeedbackDestination +import com.wire.android.navigation.PrivacyPolicyScreenDestination import com.wire.android.navigation.ReportBugDestination import com.wire.android.navigation.SupportScreenDestination +import com.wire.android.navigation.TermsOfUseScreenDestination import com.wire.android.ui.common.RowItemTemplate import com.wire.android.ui.common.clickable import com.wire.android.ui.common.dimensions +import com.wire.android.ui.destinations.AboutThisAppScreenDestination import com.wire.android.ui.destinations.AppSettingsScreenDestination import com.wire.android.ui.destinations.AppearanceScreenDestination import com.wire.android.ui.destinations.BackupAndRestoreScreenDestination @@ -147,6 +150,18 @@ sealed class SettingsItem(open val id: String, open val title: UIText) { direction = PrivacySettingsConfigScreenDestination ) + data object TermsOfUse : DirectionItem( + id = "terms_of_use", + title = UIText.StringResource(R.string.settings_terms_of_use_label), + direction = TermsOfUseScreenDestination + ) + + data object PrivacyPolicy : DirectionItem( + id = "privacy_policy", + title = UIText.StringResource(R.string.settings_privacy_policy_label), + direction = PrivacyPolicyScreenDestination + ) + data object Licenses : DirectionItem( id = "other_licenses", title = UIText.StringResource(R.string.settings_licenses_settings_label), @@ -188,6 +203,12 @@ sealed class SettingsItem(open val id: String, open val title: UIText) { id = "app_lock", title = UIText.StringResource(R.string.settings_app_lock_title), ) + + data object AboutApp : DirectionItem( + id = "about_app", + title = UIText.StringResource(R.string.about_app_screen_title), + direction = AboutThisAppScreenDestination + ) } @PreviewMultipleThemes diff --git a/app/src/main/kotlin/com/wire/android/ui/home/settings/SettingsScreen.kt b/app/src/main/kotlin/com/wire/android/ui/home/settings/SettingsScreen.kt index afac552afba..155b71e8045 100644 --- a/app/src/main/kotlin/com/wire/android/ui/home/settings/SettingsScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/home/settings/SettingsScreen.kt @@ -144,9 +144,9 @@ fun SettingsScreenContent( if (BuildConfig.DEBUG_SCREEN_ENABLED) { add(SettingsItem.DebugSettings) } - add(SettingsItem.Licenses) add(SettingsItem.GiveFeedback) add(SettingsItem.ReportBug) + add(SettingsItem.AboutApp) }, onItemClicked = onItemClicked From 6f15dedbafb99940f6ba9285f8c0c819c3dd85fd Mon Sep 17 00:00:00 2001 From: alexandreferris Date: Tue, 14 May 2024 07:42:01 -0300 Subject: [PATCH 5/6] feat: add UI preview Signed-off-by: alexandreferris --- .../android/ui/settings/about/AboutThisAppScreen.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppScreen.kt b/app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppScreen.kt index e876feec986..c94102dd074 100644 --- a/app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppScreen.kt +++ b/app/src/main/kotlin/com/wire/android/ui/settings/about/AboutThisAppScreen.kt @@ -47,6 +47,8 @@ import com.wire.android.ui.common.scaffold.WireScaffold import com.wire.android.ui.common.topappbar.NavigationIconType import com.wire.android.ui.common.topappbar.WireCenterAlignedTopAppBar import com.wire.android.ui.home.settings.SettingsItem +import com.wire.android.ui.theme.WireTheme +import com.wire.android.util.ui.PreviewMultipleThemes @RootNavGraph @Destination @@ -183,3 +185,13 @@ data class AboutThisAppContentState( ).show() } } + +@PreviewMultipleThemes +@Composable +private fun PreviewAboutThisAppScreen() = WireTheme { + AboutThisAppContent( + state = AboutThisAppState(commitish = "abcd-1234"), + onBackPressed = { }, + onItemClicked = { } + ) +} From a1475b7f0ef448758128cc9f55f5fc61e0e8af9f Mon Sep 17 00:00:00 2001 From: alexandreferris Date: Tue, 14 May 2024 08:00:50 -0300 Subject: [PATCH 6/6] feat: add translatable=false to label_copyright_value Signed-off-by: alexandreferris --- app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7aeb082b87c..89f3eb68b8d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -203,7 +203,7 @@ Privacy Policy Terms of Use Copyright - © Wire Swiss GmbH + © Wire Swiss GmbH Debug Settings API VERSIONING E2EI Manual Enrollment