Skip to content

Commit 34898f1

Browse files
authored
Merge pull request #4660 from vector-im/feature/bma/legals
Legals
2 parents 8fefee9 + bf7907a commit 34898f1

31 files changed

+627
-130
lines changed

changelog.d/4638.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add a help section in the settings.

changelog.d/4660.feature

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Create a legal screen in the setting to group all the different policies.

matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsService.kt

+8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.matrix.android.sdk.api.session.terms
1818

19+
import org.matrix.android.sdk.internal.session.terms.TermsResponse
20+
1921
interface TermsService {
2022
enum class ServiceType {
2123
IntegrationManager,
@@ -28,4 +30,10 @@ interface TermsService {
2830
baseUrl: String,
2931
agreedUrls: List<String>,
3032
token: String?)
33+
34+
/**
35+
* Get the homeserver terms, from the register API.
36+
* Will be updated once https://github.com/matrix-org/matrix-doc/pull/3012 will be implemented.
37+
*/
38+
suspend fun getHomeserverTerms(baseUrl: String): TermsResponse
3139
}

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/DefaultTermsService.kt

+25-1
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@ package org.matrix.android.sdk.internal.session.terms
1818

1919
import dagger.Lazy
2020
import okhttp3.OkHttpClient
21+
import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
22+
import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse
2123
import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes
2224
import org.matrix.android.sdk.api.session.events.model.toModel
2325
import org.matrix.android.sdk.api.session.terms.GetTermsResponse
2426
import org.matrix.android.sdk.api.session.terms.TermsService
27+
import org.matrix.android.sdk.api.util.JsonDict
2528
import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate
2629
import org.matrix.android.sdk.internal.network.NetworkConstants
2730
import org.matrix.android.sdk.internal.network.RetrofitFactory
@@ -55,6 +58,27 @@ internal class DefaultTermsService @Inject constructor(
5558
return GetTermsResponse(termsResponse, getAlreadyAcceptedTermUrlsFromAccountData())
5659
}
5760

61+
/**
62+
* We use a trick here to get the homeserver T&C, we use the register API
63+
*/
64+
override suspend fun getHomeserverTerms(baseUrl: String): TermsResponse {
65+
return try {
66+
executeRequest(null) {
67+
termsAPI.register(baseUrl + NetworkConstants.URI_API_PREFIX_PATH_R0 + "register")
68+
}
69+
// Return empty result if it succeed, but it should never happen
70+
TermsResponse()
71+
} catch (throwable: Throwable) {
72+
@Suppress("UNCHECKED_CAST")
73+
TermsResponse(
74+
policies = (throwable.toRegistrationFlowResponse()
75+
?.params
76+
?.get(LoginFlowTypes.TERMS) as? JsonDict)
77+
?.get("policies") as? JsonDict
78+
)
79+
}
80+
}
81+
5882
override suspend fun agreeToTerms(serviceType: TermsService.ServiceType,
5983
baseUrl: String,
6084
agreedUrls: List<String>,
@@ -91,7 +115,7 @@ internal class DefaultTermsService @Inject constructor(
91115
private fun buildUrl(baseUrl: String, serviceType: TermsService.ServiceType): String {
92116
val servicePath = when (serviceType) {
93117
TermsService.ServiceType.IntegrationManager -> NetworkConstants.URI_INTEGRATION_MANAGER_PATH
94-
TermsService.ServiceType.IdentityService -> NetworkConstants.URI_IDENTITY_PATH_V2
118+
TermsService.ServiceType.IdentityService -> NetworkConstants.URI_IDENTITY_PATH_V2
95119
}
96120
return "${baseUrl.ensureTrailingSlash()}$servicePath"
97121
}

matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsAPI.kt

+10
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.matrix.android.sdk.internal.session.terms
1818

19+
import org.matrix.android.sdk.api.util.JsonDict
20+
import org.matrix.android.sdk.api.util.emptyJsonDict
1921
import org.matrix.android.sdk.internal.network.HttpHeaders
2022
import retrofit2.http.Body
2123
import retrofit2.http.GET
@@ -37,4 +39,12 @@ internal interface TermsAPI {
3739
suspend fun agreeToTerms(@Url url: String,
3840
@Body params: AcceptTermsBody,
3941
@Header(HttpHeaders.Authorization) token: String)
42+
43+
/**
44+
* API to retrieve the terms for a homeserver. The API /terms does not exist yet, so retrieve the terms from the login flow.
45+
* We do not care about the result (Credentials)
46+
*/
47+
@POST
48+
suspend fun register(@Url url: String,
49+
@Body body: JsonDict = emptyJsonDict)
4050
}

vector/src/main/java/im/vector/app/core/di/FragmentModule.kt

+6
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ import im.vector.app.features.settings.devtools.KeyRequestsFragment
133133
import im.vector.app.features.settings.devtools.OutgoingKeyRequestListFragment
134134
import im.vector.app.features.settings.homeserver.HomeserverSettingsFragment
135135
import im.vector.app.features.settings.ignored.VectorSettingsIgnoredUsersFragment
136+
import im.vector.app.features.settings.legals.LegalsFragment
136137
import im.vector.app.features.settings.locale.LocalePickerFragment
137138
import im.vector.app.features.settings.notifications.VectorSettingsAdvancedNotificationPreferenceFragment
138139
import im.vector.app.features.settings.notifications.VectorSettingsNotificationPreferenceFragment
@@ -699,6 +700,11 @@ interface FragmentModule {
699700
@FragmentKey(DiscoverySettingsFragment::class)
700701
fun bindDiscoverySettingsFragment(fragment: DiscoverySettingsFragment): Fragment
701702

703+
@Binds
704+
@IntoMap
705+
@FragmentKey(LegalsFragment::class)
706+
fun bindLegalsFragment(fragment: LegalsFragment): Fragment
707+
702708
@Binds
703709
@IntoMap
704710
@FragmentKey(ReviewTermsFragment::class)

vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt

+6
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ import im.vector.app.features.settings.devtools.KeyRequestListViewModel
8585
import im.vector.app.features.settings.devtools.KeyRequestViewModel
8686
import im.vector.app.features.settings.homeserver.HomeserverSettingsViewModel
8787
import im.vector.app.features.settings.ignored.IgnoredUsersViewModel
88+
import im.vector.app.features.settings.legals.LegalsViewModel
8889
import im.vector.app.features.settings.locale.LocalePickerViewModel
8990
import im.vector.app.features.settings.push.PushGatewaysViewModel
9091
import im.vector.app.features.settings.threepids.ThreePidsSettingsViewModel
@@ -504,6 +505,11 @@ interface MavericksViewModelModule {
504505
@MavericksViewModelKey(DiscoverySettingsViewModel::class)
505506
fun discoverySettingsViewModelFactory(factory: DiscoverySettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
506507

508+
@Binds
509+
@IntoMap
510+
@MavericksViewModelKey(LegalsViewModel::class)
511+
fun legalsViewModelFactory(factory: LegalsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
512+
507513
@Binds
508514
@IntoMap
509515
@MavericksViewModelKey(RoomDetailViewModel::class)

vector/src/main/java/im/vector/app/core/utils/Dialogs.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import android.webkit.WebViewClient
2323
import android.widget.TextView
2424
import com.google.android.material.dialog.MaterialAlertDialogBuilder
2525
import im.vector.app.R
26-
import im.vector.app.features.discovery.IdentityServerWithTerms
26+
import im.vector.app.features.discovery.ServerAndPolicies
2727
import me.gujun.android.span.link
2828
import me.gujun.android.span.span
2929

@@ -45,7 +45,7 @@ fun Context.displayInWebView(url: String) {
4545
.show()
4646
}
4747

48-
fun Context.showIdentityServerConsentDialog(identityServerWithTerms: IdentityServerWithTerms?,
48+
fun Context.showIdentityServerConsentDialog(identityServerWithTerms: ServerAndPolicies?,
4949
consentCallBack: (() -> Unit)) {
5050
// Build the message
5151
val content = span {

vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewEvents.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
package im.vector.app.features.contactsbook
1818

1919
import im.vector.app.core.platform.VectorViewEvents
20-
import im.vector.app.features.discovery.IdentityServerWithTerms
20+
import im.vector.app.features.discovery.ServerAndPolicies
2121

2222
sealed class ContactsBookViewEvents : VectorViewEvents {
2323
data class Failure(val throwable: Throwable) : ContactsBookViewEvents()
24-
data class OnPoliciesRetrieved(val identityServerWithTerms: IdentityServerWithTerms?) : ContactsBookViewEvents()
24+
data class OnPoliciesRetrieved(val identityServerWithTerms: ServerAndPolicies?) : ContactsBookViewEvents()
2525
}

vector/src/main/java/im/vector/app/features/discovery/DiscoveryPolicyItem.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import im.vector.app.R
2424
import im.vector.app.core.epoxy.ClickListener
2525
import im.vector.app.core.epoxy.VectorEpoxyHolder
2626
import im.vector.app.core.epoxy.onClick
27+
import im.vector.app.core.extensions.setTextOrHide
2728

2829
@EpoxyModelClass(layout = R.layout.item_discovery_policy)
2930
abstract class DiscoveryPolicyItem : EpoxyModelWithHolder<DiscoveryPolicyItem.Holder>() {
@@ -40,7 +41,7 @@ abstract class DiscoveryPolicyItem : EpoxyModelWithHolder<DiscoveryPolicyItem.Ho
4041
override fun bind(holder: Holder) {
4142
super.bind(holder)
4243
holder.title.text = name
43-
holder.url.text = url
44+
holder.url.setTextOrHide(url)
4445
holder.view.onClick(clickListener)
4546
}
4647

vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsController.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,6 @@ class DiscoverySettingsController @Inject constructor(
433433
fun onTapUpdateUserConsent(newValue: Boolean)
434434
fun onTapRetryToRetrieveBindings()
435435
fun onPolicyUrlsExpandedStateToggled(newExpandedState: Boolean)
436-
fun onPolicyTapped(policy: IdentityServerPolicy)
436+
fun onPolicyTapped(policy: ServerPolicy)
437437
}
438438
}

vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsFragment.kt

+4-3
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,11 @@ class DiscoverySettingsFragment @Inject constructor(
167167
val pidList = state.emailList().orEmpty() + state.phoneNumbersList().orEmpty()
168168
val hasBoundIds = pidList.any { it.isShared() == SharedState.SHARED }
169169

170+
val serverUrl = state.identityServer()?.serverUrl.orEmpty()
170171
val message = if (hasBoundIds) {
171-
getString(R.string.settings_discovery_disconnect_with_bound_pid, state.identityServer(), state.identityServer())
172+
getString(R.string.settings_discovery_disconnect_with_bound_pid, serverUrl, serverUrl)
172173
} else {
173-
getString(R.string.disconnect_identity_server_dialog_content, state.identityServer())
174+
getString(R.string.disconnect_identity_server_dialog_content, serverUrl)
174175
}
175176

176177
MaterialAlertDialogBuilder(requireActivity())
@@ -203,7 +204,7 @@ class DiscoverySettingsFragment @Inject constructor(
203204
viewModel.handle(DiscoverySettingsAction.SetPoliciesExpandState(expanded = newExpandedState))
204205
}
205206

206-
override fun onPolicyTapped(policy: IdentityServerPolicy) {
207+
override fun onPolicyTapped(policy: ServerPolicy) {
207208
openUrlInChromeCustomTab(requireContext(), null, policy.url)
208209
}
209210

vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsState.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import com.airbnb.mvrx.MavericksState
2121
import com.airbnb.mvrx.Uninitialized
2222

2323
data class DiscoverySettingsState(
24-
val identityServer: Async<IdentityServerWithTerms?> = Uninitialized,
24+
val identityServer: Async<ServerAndPolicies?> = Uninitialized,
2525
val emailList: Async<List<PidInfo>> = Uninitialized,
2626
val phoneNumbersList: Async<List<PidInfo>> = Uninitialized,
2727
// Can be true if terms are updated

vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
7878
init {
7979
setState {
8080
copy(
81-
identityServer = Success(identityService.getCurrentIdentityServerUrl()?.let { IdentityServerWithTerms(it, emptyList()) }),
81+
identityServer = Success(identityService.getCurrentIdentityServerUrl()?.let { ServerAndPolicies(it, emptyList()) }),
8282
userConsent = identityService.getUserConsent()
8383
)
8484
}
@@ -151,7 +151,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
151151
val data = session.identityService().setNewIdentityServer(action.url)
152152
setState {
153153
copy(
154-
identityServer = Success(IdentityServerWithTerms(data, emptyList())),
154+
identityServer = Success(ServerAndPolicies(data, emptyList())),
155155
userConsent = false
156156
)
157157
}
@@ -401,7 +401,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor(
401401
}
402402
}
403403

404-
private suspend fun fetchIdentityServerWithTerms(): IdentityServerWithTerms? {
404+
private suspend fun fetchIdentityServerWithTerms(): ServerAndPolicies? {
405405
return session.fetchIdentityServerWithTerms(stringProvider.getString(R.string.resources_language))
406406
}
407407
}

vector/src/main/java/im/vector/app/features/discovery/Extensions.kt

+27-14
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,35 @@ package im.vector.app.features.discovery
1919
import im.vector.app.core.utils.ensureProtocol
2020
import org.matrix.android.sdk.api.session.Session
2121
import org.matrix.android.sdk.api.session.terms.TermsService
22+
import org.matrix.android.sdk.internal.session.terms.TermsResponse
2223

23-
suspend fun Session.fetchIdentityServerWithTerms(userLanguage: String): IdentityServerWithTerms? {
24-
val identityServerUrl = identityService().getCurrentIdentityServerUrl()
25-
return identityServerUrl?.let {
26-
val terms = getTerms(TermsService.ServiceType.IdentityService, identityServerUrl.ensureProtocol())
27-
.serverResponse
28-
.getLocalizedTerms(userLanguage)
29-
val policyUrls = terms.mapNotNull {
30-
val name = it.localizedName ?: it.policyName
31-
val url = it.localizedUrl
32-
if (name == null || url == null) {
33-
null
34-
} else {
35-
IdentityServerPolicy(name = name, url = url)
24+
suspend fun Session.fetchIdentityServerWithTerms(userLanguage: String): ServerAndPolicies? {
25+
return identityService().getCurrentIdentityServerUrl()
26+
?.let { identityServerUrl ->
27+
val termsResponse = getTerms(TermsService.ServiceType.IdentityService, identityServerUrl.ensureProtocol())
28+
.serverResponse
29+
buildServerAndPolicies(identityServerUrl, termsResponse, userLanguage)
3630
}
31+
}
32+
33+
suspend fun Session.fetchHomeserverWithTerms(userLanguage: String): ServerAndPolicies {
34+
val homeserverUrl = sessionParams.homeServerUrl
35+
val terms = getHomeserverTerms(homeserverUrl.ensureProtocol())
36+
return buildServerAndPolicies(homeserverUrl, terms, userLanguage)
37+
}
38+
39+
private fun buildServerAndPolicies(serviceUrl: String,
40+
termsResponse: TermsResponse,
41+
userLanguage: String): ServerAndPolicies {
42+
val terms = termsResponse.getLocalizedTerms(userLanguage)
43+
val policyUrls = terms.mapNotNull {
44+
val name = it.localizedName ?: it.policyName
45+
val url = it.localizedUrl
46+
if (name == null || url == null) {
47+
null
48+
} else {
49+
ServerPolicy(name = name, url = url)
3750
}
38-
IdentityServerWithTerms(identityServerUrl, policyUrls)
3951
}
52+
return ServerAndPolicies(serviceUrl, policyUrls)
4053
}

vector/src/main/java/im/vector/app/features/discovery/IdentityServerWithTerms.kt renamed to vector/src/main/java/im/vector/app/features/discovery/ServerAndPolicies.kt

+3-3
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616

1717
package im.vector.app.features.discovery
1818

19-
data class IdentityServerWithTerms(
19+
data class ServerAndPolicies(
2020
val serverUrl: String,
21-
val policies: List<IdentityServerPolicy>
21+
val policies: List<ServerPolicy>
2222
)
2323

24-
data class IdentityServerPolicy(
24+
data class ServerPolicy(
2525
val name: String,
2626
val url: String
2727
)

vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt

+1-5
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,16 @@ import javax.inject.Inject
3535
class VectorPreferences @Inject constructor(private val context: Context) {
3636

3737
companion object {
38+
const val SETTINGS_HELP_PREFERENCE_KEY = "SETTINGS_HELP_PREFERENCE_KEY"
3839
const val SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY = "SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY"
3940
const val SETTINGS_VERSION_PREFERENCE_KEY = "SETTINGS_VERSION_PREFERENCE_KEY"
4041
const val SETTINGS_SDK_VERSION_PREFERENCE_KEY = "SETTINGS_SDK_VERSION_PREFERENCE_KEY"
4142
const val SETTINGS_OLM_VERSION_PREFERENCE_KEY = "SETTINGS_OLM_VERSION_PREFERENCE_KEY"
4243
const val SETTINGS_LOGGED_IN_PREFERENCE_KEY = "SETTINGS_LOGGED_IN_PREFERENCE_KEY"
4344
const val SETTINGS_HOME_SERVER_PREFERENCE_KEY = "SETTINGS_HOME_SERVER_PREFERENCE_KEY"
4445
const val SETTINGS_IDENTITY_SERVER_PREFERENCE_KEY = "SETTINGS_IDENTITY_SERVER_PREFERENCE_KEY"
45-
const val SETTINGS_APP_TERM_CONDITIONS_PREFERENCE_KEY = "SETTINGS_APP_TERM_CONDITIONS_PREFERENCE_KEY"
46-
const val SETTINGS_PRIVACY_POLICY_PREFERENCE_KEY = "SETTINGS_PRIVACY_POLICY_PREFERENCE_KEY"
4746
const val SETTINGS_DISCOVERY_PREFERENCE_KEY = "SETTINGS_DISCOVERY_PREFERENCE_KEY"
4847

49-
const val SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY"
50-
const val SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY"
51-
const val SETTINGS_COPYRIGHT_PREFERENCE_KEY = "SETTINGS_COPYRIGHT_PREFERENCE_KEY"
5248
const val SETTINGS_CLEAR_CACHE_PREFERENCE_KEY = "SETTINGS_CLEAR_CACHE_PREFERENCE_KEY"
5349
const val SETTINGS_CLEAR_MEDIA_CACHE_PREFERENCE_KEY = "SETTINGS_CLEAR_MEDIA_CACHE_PREFERENCE_KEY"
5450
const val SETTINGS_USER_SETTINGS_PREFERENCE_KEY = "SETTINGS_USER_SETTINGS_PREFERENCE_KEY"

0 commit comments

Comments
 (0)