diff --git a/.github/workflows/triage-move-labelled.yml b/.github/workflows/triage-move-labelled.yml index 39f7a5de09..67c4e9dbab 100644 --- a/.github/workflows/triage-move-labelled.yml +++ b/.github/workflows/triage-move-labelled.yml @@ -34,7 +34,7 @@ jobs: with: headers: '{"GraphQL-Features": "projects_next_graphql"}' query: | - mutation add_to_project($projectid:String!,$contentid:String!) { + mutation add_to_project($projectid:ID!,$contentid:ID!) { addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) { projectNextItem { id @@ -47,45 +47,30 @@ jobs: PROJECT_ID: "PN_kwDOAM0swc0sUA" GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} - spaces_issues_to_old_board: - name: Spaces issues to old Delight project board - runs-on: ubuntu-latest - if: > - contains(github.event.issue.labels.*.name, 'A-Spaces') || - contains(github.event.issue.labels.*.name, 'A-Space-Settings') || - contains(github.event.issue.labels.*.name, 'A-Subspaces') - steps: - - uses: konradpabjan/move-labeled-or-milestoned-issue@219d384e03fa4b6460cd24f9f37d19eb033a4338 - with: - action-token: "${{ secrets.ELEMENT_BOT_TOKEN }}" - project-url: "https://github.com/orgs/vector-im/projects/6" - column-name: "📥 Inbox" - label-name: "A-Spaces" - - spaces_issues_to_new_board: - name: Spaces issues to new Delight project board - runs-on: ubuntu-latest - if: > - contains(github.event.issue.labels.*.name, 'A-Spaces') || - contains(github.event.issue.labels.*.name, 'A-Space-Settings') || - contains(github.event.issue.labels.*.name, 'A-Subspaces') - steps: - - uses: octokit/graphql-action@v2.x - with: - headers: '{"GraphQL-Features": "projects_next_graphql"}' - query: | - mutation add_to_project($projectid:String!,$contentid:String!) { - addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) { - projectNextItem { - id - } - } - } - projectid: ${{ env.PROJECT_ID }} - contentid: ${{ github.event.issue.node_id }} - env: - PROJECT_ID: "PN_kwDOAM0swc1HvQ" - GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} +# delight_issues_to_board: +# name: Spaces issues to new Delight project board +# runs-on: ubuntu-latest +# if: > +# contains(github.event.issue.labels.*.name, 'A-Spaces') || +# contains(github.event.issue.labels.*.name, 'A-Space-Settings') || +# contains(github.event.issue.labels.*.name, 'A-Subspaces') +# steps: +# - uses: octokit/graphql-action@v2.x +# with: +# headers: '{"GraphQL-Features": "projects_next_graphql"}' +# query: | +# mutation add_to_project($projectid:ID!,$contentid:ID!) { +# addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) { +# projectNextItem { +# id +# } +# } +# } +# projectid: ${{ env.PROJECT_ID }} +# contentid: ${{ github.event.issue.node_id }} +# env: +# PROJECT_ID: "PN_kwDOAM0swc1HvQ" +# GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} move_voice-message_issues: name: A-Voice Messages to voice message board @@ -97,7 +82,7 @@ jobs: with: headers: '{"GraphQL-Features": "projects_next_graphql"}' query: | - mutation add_to_project($projectid:String!,$contentid:String!) { + mutation add_to_project($projectid:ID!,$contentid:ID!) { addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) { projectNextItem { id @@ -120,7 +105,7 @@ jobs: with: headers: '{"GraphQL-Features": "projects_next_graphql"}' query: | - mutation add_to_project($projectid:String!,$contentid:String!) { + mutation add_to_project($projectid:ID!,$contentid:ID!) { addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) { projectNextItem { id @@ -132,3 +117,26 @@ jobs: env: PROJECT_ID: "PN_kwDOAM0swc0rRA" GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} + + move_message_bubbles_issues: + name: A-Message-Bubbles to Message bubbles board + runs-on: ubuntu-latest + if: > + contains(github.event.issue.labels.*.name, 'A-Message-Bubbles') + steps: + - uses: octokit/graphql-action@v2.x + with: + headers: '{"GraphQL-Features": "projects_next_graphql"}' + query: | + mutation add_to_project($projectid:ID!,$contentid:ID!) { + addProjectNextItem(input:{projectId:$projectid contentId:$contentid}) { + projectNextItem { + id + } + } + } + projectid: ${{ env.PROJECT_ID }} + contentid: ${{ github.event.issue.node_id }} + env: + PROJECT_ID: "PN_kwDOAM0swc3m-g" + GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} diff --git a/changelog.d/4278.feature b/changelog.d/4278.feature new file mode 100644 index 0000000000..fe82755186 --- /dev/null +++ b/changelog.d/4278.feature @@ -0,0 +1 @@ +Updates URL previews to match latest designs \ No newline at end of file diff --git a/changelog.d/4638.feature b/changelog.d/4638.feature new file mode 100644 index 0000000000..0f8bd36465 --- /dev/null +++ b/changelog.d/4638.feature @@ -0,0 +1 @@ +Add a help section in the settings. \ No newline at end of file diff --git a/changelog.d/4660.feature b/changelog.d/4660.feature new file mode 100644 index 0000000000..4eca82eaf5 --- /dev/null +++ b/changelog.d/4660.feature @@ -0,0 +1 @@ +Create a legal screen in the setting to group all the different policies. \ No newline at end of file diff --git a/changelog.d/4666.misc b/changelog.d/4666.misc new file mode 100644 index 0000000000..9401963de5 --- /dev/null +++ b/changelog.d/4666.misc @@ -0,0 +1 @@ +Add automation to move message bubbles issues to message bubbles board. diff --git a/changelog.d/4671.misc b/changelog.d/4671.misc new file mode 100644 index 0000000000..1d2282038e --- /dev/null +++ b/changelog.d/4671.misc @@ -0,0 +1 @@ +Fix graphql warning in issue workflow automation diff --git a/dependencies.gradle b/dependencies.gradle index aa57546de0..4a076a23bd 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,7 +7,7 @@ ext.versions = [ 'targetCompat' : JavaVersion.VERSION_11, ] -def gradle = "7.0.3" +def gradle = "7.0.4" // Ref: https://kotlinlang.org/releases.html def kotlin = "1.5.31" def kotlinCoroutines = "1.5.2" @@ -19,7 +19,7 @@ def moshi = "1.12.0" def lifecycle = "2.4.0" def flowBinding = "1.2.0" def epoxy = "4.6.2" -def mavericks = "2.4.0" +def mavericks = "2.5.0" def glide = "4.12.0" def bigImageViewer = "1.8.1" def jjwt = "0.11.2" diff --git a/library/ui-styles/src/main/res/values/dimens.xml b/library/ui-styles/src/main/res/values/dimens.xml index 519920786c..864f3d3d7f 100644 --- a/library/ui-styles/src/main/res/values/dimens.xml +++ b/library/ui-styles/src/main/res/values/dimens.xml @@ -39,4 +39,7 @@ 320dp + + + 8dp \ No newline at end of file diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index cec5982658..477f971e04 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -9,7 +9,7 @@ buildscript { mavenCentral() } dependencies { - classpath "io.realm:realm-gradle-plugin:10.8.1" + classpath "io.realm:realm-gradle-plugin:10.9.0" } } @@ -158,7 +158,7 @@ dependencies { implementation libs.apache.commonsImaging // Phone number https://github.com/google/libphonenumber - implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.38' + implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.39' testImplementation libs.tests.junit testImplementation 'org.robolectric:robolectric:4.7.3' diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsService.kt index 10ce0829d0..e64cf1872e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/terms/TermsService.kt @@ -16,6 +16,8 @@ package org.matrix.android.sdk.api.session.terms +import org.matrix.android.sdk.internal.session.terms.TermsResponse + interface TermsService { enum class ServiceType { IntegrationManager, @@ -28,4 +30,10 @@ interface TermsService { baseUrl: String, agreedUrls: List, token: String?) + + /** + * Get the homeserver terms, from the register API. + * Will be updated once https://github.com/matrix-org/matrix-doc/pull/3012 will be implemented. + */ + suspend fun getHomeserverTerms(baseUrl: String): TermsResponse } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/DefaultTermsService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/DefaultTermsService.kt index d40fd8d076..c52c6a404e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/DefaultTermsService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/DefaultTermsService.kt @@ -18,10 +18,13 @@ package org.matrix.android.sdk.internal.session.terms import dagger.Lazy import okhttp3.OkHttpClient +import org.matrix.android.sdk.api.auth.data.LoginFlowTypes +import org.matrix.android.sdk.api.failure.toRegistrationFlowResponse import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.terms.GetTermsResponse import org.matrix.android.sdk.api.session.terms.TermsService +import org.matrix.android.sdk.api.util.JsonDict import org.matrix.android.sdk.internal.di.UnauthenticatedWithCertificate import org.matrix.android.sdk.internal.network.NetworkConstants import org.matrix.android.sdk.internal.network.RetrofitFactory @@ -55,6 +58,27 @@ internal class DefaultTermsService @Inject constructor( return GetTermsResponse(termsResponse, getAlreadyAcceptedTermUrlsFromAccountData()) } + /** + * We use a trick here to get the homeserver T&C, we use the register API + */ + override suspend fun getHomeserverTerms(baseUrl: String): TermsResponse { + return try { + executeRequest(null) { + termsAPI.register(baseUrl + NetworkConstants.URI_API_PREFIX_PATH_R0 + "register") + } + // Return empty result if it succeed, but it should never happen + TermsResponse() + } catch (throwable: Throwable) { + @Suppress("UNCHECKED_CAST") + TermsResponse( + policies = (throwable.toRegistrationFlowResponse() + ?.params + ?.get(LoginFlowTypes.TERMS) as? JsonDict) + ?.get("policies") as? JsonDict + ) + } + } + override suspend fun agreeToTerms(serviceType: TermsService.ServiceType, baseUrl: String, agreedUrls: List, @@ -91,7 +115,7 @@ internal class DefaultTermsService @Inject constructor( private fun buildUrl(baseUrl: String, serviceType: TermsService.ServiceType): String { val servicePath = when (serviceType) { TermsService.ServiceType.IntegrationManager -> NetworkConstants.URI_INTEGRATION_MANAGER_PATH - TermsService.ServiceType.IdentityService -> NetworkConstants.URI_IDENTITY_PATH_V2 + TermsService.ServiceType.IdentityService -> NetworkConstants.URI_IDENTITY_PATH_V2 } return "${baseUrl.ensureTrailingSlash()}$servicePath" } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsAPI.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsAPI.kt index 91d27030de..fb6aff5a9e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsAPI.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/terms/TermsAPI.kt @@ -16,6 +16,8 @@ package org.matrix.android.sdk.internal.session.terms +import org.matrix.android.sdk.api.util.JsonDict +import org.matrix.android.sdk.api.util.emptyJsonDict import org.matrix.android.sdk.internal.network.HttpHeaders import retrofit2.http.Body import retrofit2.http.GET @@ -37,4 +39,12 @@ internal interface TermsAPI { suspend fun agreeToTerms(@Url url: String, @Body params: AcceptTermsBody, @Header(HttpHeaders.Authorization) token: String) + + /** + * API to retrieve the terms for a homeserver. The API /terms does not exist yet, so retrieve the terms from the login flow. + * We do not care about the result (Credentials) + */ + @POST + suspend fun register(@Url url: String, + @Body body: JsonDict = emptyJsonDict) } diff --git a/vector/build.gradle b/vector/build.gradle index d29f36c877..26bfd3badf 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -141,7 +141,6 @@ android { resValue "string", "build_number", "\"${buildNumber}\"" buildConfigField "im.vector.app.features.VectorFeatures.LoginVersion", "LOGIN_VERSION", "im.vector.app.features.VectorFeatures.LoginVersion.V1" - buildConfigField "im.vector.app.features.VectorFeatures.NotificationSettingsVersion", "NOTIFICATION_SETTINGS_VERSION", "im.vector.app.features.VectorFeatures.NotificationSettingsVersion.V2" buildConfigField "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy", "outboundSessionKeySharingStrategy", "im.vector.app.features.crypto.keysrequest.OutboundSessionKeySharingStrategy.WhenTyping" @@ -365,7 +364,7 @@ dependencies { implementation 'com.facebook.stetho:stetho:1.6.0' // Phone number https://github.com/google/libphonenumber - implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.38' + implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.39' // FlowBinding implementation libs.github.flowBinding diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt index 4dddc4c9cc..433a70b5e3 100644 --- a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt +++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt @@ -18,29 +18,19 @@ package im.vector.app.ui.robot.settings import androidx.test.espresso.Espresso.pressBack import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn -import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.espresso.tools.clickOnPreference -import im.vector.app.features.VectorFeatures class SettingsNotificationsRobot { fun crawl() { - when (BuildConfig.NOTIFICATION_SETTINGS_VERSION!!) { - VectorFeatures.NotificationSettingsVersion.V1 -> { - clickOn(R.string.settings_notification_advanced) - pressBack() - } - VectorFeatures.NotificationSettingsVersion.V2 -> { - clickOn(R.string.settings_notification_default) - pressBack() - clickOn(R.string.settings_notification_mentions_and_keywords) - // TODO Test adding a keyword? - pressBack() - clickOn(R.string.settings_notification_other) - pressBack() - } - } + clickOn(R.string.settings_notification_default) + pressBack() + clickOn(R.string.settings_notification_mentions_and_keywords) + // TODO Test adding a keyword? + pressBack() + clickOn(R.string.settings_notification_other) + pressBack() /* clickOn(R.string.settings_noisy_notifications_preferences) diff --git a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt index b8d00fac5a..43bb505a5e 100644 --- a/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/FragmentModule.kt @@ -133,6 +133,7 @@ import im.vector.app.features.settings.devtools.KeyRequestsFragment import im.vector.app.features.settings.devtools.OutgoingKeyRequestListFragment import im.vector.app.features.settings.homeserver.HomeserverSettingsFragment import im.vector.app.features.settings.ignored.VectorSettingsIgnoredUsersFragment +import im.vector.app.features.settings.legals.LegalsFragment import im.vector.app.features.settings.locale.LocalePickerFragment import im.vector.app.features.settings.notifications.VectorSettingsAdvancedNotificationPreferenceFragment import im.vector.app.features.settings.notifications.VectorSettingsNotificationPreferenceFragment @@ -699,6 +700,11 @@ interface FragmentModule { @FragmentKey(DiscoverySettingsFragment::class) fun bindDiscoverySettingsFragment(fragment: DiscoverySettingsFragment): Fragment + @Binds + @IntoMap + @FragmentKey(LegalsFragment::class) + fun bindLegalsFragment(fragment: LegalsFragment): Fragment + @Binds @IntoMap @FragmentKey(ReviewTermsFragment::class) diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt index cac694e84e..37721ca9f9 100644 --- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt @@ -85,6 +85,7 @@ import im.vector.app.features.settings.devtools.KeyRequestListViewModel import im.vector.app.features.settings.devtools.KeyRequestViewModel import im.vector.app.features.settings.homeserver.HomeserverSettingsViewModel import im.vector.app.features.settings.ignored.IgnoredUsersViewModel +import im.vector.app.features.settings.legals.LegalsViewModel import im.vector.app.features.settings.locale.LocalePickerViewModel import im.vector.app.features.settings.push.PushGatewaysViewModel import im.vector.app.features.settings.threepids.ThreePidsSettingsViewModel @@ -504,6 +505,11 @@ interface MavericksViewModelModule { @MavericksViewModelKey(DiscoverySettingsViewModel::class) fun discoverySettingsViewModelFactory(factory: DiscoverySettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *> + @Binds + @IntoMap + @MavericksViewModelKey(LegalsViewModel::class) + fun legalsViewModelFactory(factory: LegalsViewModel.Factory): MavericksAssistedViewModelFactory<*, *> + @Binds @IntoMap @MavericksViewModelKey(RoomDetailViewModel::class) diff --git a/vector/src/main/java/im/vector/app/core/ui/views/SendStateImageView.kt b/vector/src/main/java/im/vector/app/core/ui/views/SendStateImageView.kt index cb1d08d2e5..3d710e2b24 100644 --- a/vector/src/main/java/im/vector/app/core/ui/views/SendStateImageView.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/SendStateImageView.kt @@ -20,7 +20,7 @@ import android.content.Context import android.content.res.ColorStateList import android.util.AttributeSet import androidx.appcompat.widget.AppCompatImageView -import androidx.core.view.isVisible +import androidx.core.view.isInvisible import im.vector.app.R import im.vector.app.features.home.room.detail.timeline.item.SendStateDecoration import im.vector.app.features.themes.ThemeUtils @@ -38,28 +38,28 @@ class SendStateImageView @JvmOverloads constructor( } fun render(sendState: SendStateDecoration) { - isVisible = when (sendState) { + isInvisible = when (sendState) { SendStateDecoration.SENDING_NON_MEDIA -> { setImageResource(R.drawable.ic_sending_message) imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(context, R.attr.vctr_content_tertiary)) contentDescription = context.getString(R.string.event_status_a11y_sending) - true + false } SendStateDecoration.SENT -> { setImageResource(R.drawable.ic_message_sent) imageTintList = ColorStateList.valueOf(ThemeUtils.getColor(context, R.attr.vctr_content_tertiary)) contentDescription = context.getString(R.string.event_status_a11y_sent) - true + false } SendStateDecoration.FAILED -> { setImageResource(R.drawable.ic_sending_message_failed) imageTintList = null contentDescription = context.getString(R.string.event_status_a11y_failed) - true + false } SendStateDecoration.SENDING_MEDIA, SendStateDecoration.NONE -> { - false + true } } } diff --git a/vector/src/main/java/im/vector/app/core/utils/Dialogs.kt b/vector/src/main/java/im/vector/app/core/utils/Dialogs.kt index ad01546782..11b9a693da 100644 --- a/vector/src/main/java/im/vector/app/core/utils/Dialogs.kt +++ b/vector/src/main/java/im/vector/app/core/utils/Dialogs.kt @@ -23,7 +23,7 @@ import android.webkit.WebViewClient import android.widget.TextView import com.google.android.material.dialog.MaterialAlertDialogBuilder import im.vector.app.R -import im.vector.app.features.discovery.IdentityServerWithTerms +import im.vector.app.features.discovery.ServerAndPolicies import me.gujun.android.span.link import me.gujun.android.span.span @@ -45,7 +45,7 @@ fun Context.displayInWebView(url: String) { .show() } -fun Context.showIdentityServerConsentDialog(identityServerWithTerms: IdentityServerWithTerms?, +fun Context.showIdentityServerConsentDialog(identityServerWithTerms: ServerAndPolicies?, consentCallBack: (() -> Unit)) { // Build the message val content = span { diff --git a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt index b40d2d02f2..e106f7f75f 100644 --- a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt +++ b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt @@ -21,7 +21,6 @@ import im.vector.app.BuildConfig interface VectorFeatures { fun loginVersion(): LoginVersion - fun notificationSettingsVersion(): NotificationSettingsVersion enum class LoginVersion { V1, @@ -36,5 +35,4 @@ interface VectorFeatures { class DefaultVectorFeatures : VectorFeatures { override fun loginVersion(): VectorFeatures.LoginVersion = BuildConfig.LOGIN_VERSION - override fun notificationSettingsVersion(): VectorFeatures.NotificationSettingsVersion = BuildConfig.NOTIFICATION_SETTINGS_VERSION } diff --git a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewEvents.kt b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewEvents.kt index c7fd13a62c..cb8d137c05 100644 --- a/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/contactsbook/ContactsBookViewEvents.kt @@ -17,9 +17,9 @@ package im.vector.app.features.contactsbook import im.vector.app.core.platform.VectorViewEvents -import im.vector.app.features.discovery.IdentityServerWithTerms +import im.vector.app.features.discovery.ServerAndPolicies sealed class ContactsBookViewEvents : VectorViewEvents { data class Failure(val throwable: Throwable) : ContactsBookViewEvents() - data class OnPoliciesRetrieved(val identityServerWithTerms: IdentityServerWithTerms?) : ContactsBookViewEvents() + data class OnPoliciesRetrieved(val identityServerWithTerms: ServerAndPolicies?) : ContactsBookViewEvents() } diff --git a/vector/src/main/java/im/vector/app/features/discovery/DiscoveryPolicyItem.kt b/vector/src/main/java/im/vector/app/features/discovery/DiscoveryPolicyItem.kt index c97a2286ae..4df4146d2f 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/DiscoveryPolicyItem.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/DiscoveryPolicyItem.kt @@ -24,6 +24,7 @@ import im.vector.app.R import im.vector.app.core.epoxy.ClickListener import im.vector.app.core.epoxy.VectorEpoxyHolder import im.vector.app.core.epoxy.onClick +import im.vector.app.core.extensions.setTextOrHide @EpoxyModelClass(layout = R.layout.item_discovery_policy) abstract class DiscoveryPolicyItem : EpoxyModelWithHolder() { @@ -40,7 +41,7 @@ abstract class DiscoveryPolicyItem : EpoxyModelWithHolder = Uninitialized, + val identityServer: Async = Uninitialized, val emailList: Async> = Uninitialized, val phoneNumbersList: Async> = Uninitialized, // Can be true if terms are updated diff --git a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt index 4eb3fada28..19f233fe98 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/DiscoverySettingsViewModel.kt @@ -78,7 +78,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor( init { setState { copy( - identityServer = Success(identityService.getCurrentIdentityServerUrl()?.let { IdentityServerWithTerms(it, emptyList()) }), + identityServer = Success(identityService.getCurrentIdentityServerUrl()?.let { ServerAndPolicies(it, emptyList()) }), userConsent = identityService.getUserConsent() ) } @@ -151,7 +151,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor( val data = session.identityService().setNewIdentityServer(action.url) setState { copy( - identityServer = Success(IdentityServerWithTerms(data, emptyList())), + identityServer = Success(ServerAndPolicies(data, emptyList())), userConsent = false ) } @@ -401,7 +401,7 @@ class DiscoverySettingsViewModel @AssistedInject constructor( } } - private suspend fun fetchIdentityServerWithTerms(): IdentityServerWithTerms? { + private suspend fun fetchIdentityServerWithTerms(): ServerAndPolicies? { return session.fetchIdentityServerWithTerms(stringProvider.getString(R.string.resources_language)) } } diff --git a/vector/src/main/java/im/vector/app/features/discovery/Extensions.kt b/vector/src/main/java/im/vector/app/features/discovery/Extensions.kt index bf6bd89938..24d675695b 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/Extensions.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/Extensions.kt @@ -19,22 +19,35 @@ package im.vector.app.features.discovery import im.vector.app.core.utils.ensureProtocol import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.terms.TermsService +import org.matrix.android.sdk.internal.session.terms.TermsResponse -suspend fun Session.fetchIdentityServerWithTerms(userLanguage: String): IdentityServerWithTerms? { - val identityServerUrl = identityService().getCurrentIdentityServerUrl() - return identityServerUrl?.let { - val terms = getTerms(TermsService.ServiceType.IdentityService, identityServerUrl.ensureProtocol()) - .serverResponse - .getLocalizedTerms(userLanguage) - val policyUrls = terms.mapNotNull { - val name = it.localizedName ?: it.policyName - val url = it.localizedUrl - if (name == null || url == null) { - null - } else { - IdentityServerPolicy(name = name, url = url) +suspend fun Session.fetchIdentityServerWithTerms(userLanguage: String): ServerAndPolicies? { + return identityService().getCurrentIdentityServerUrl() + ?.let { identityServerUrl -> + val termsResponse = getTerms(TermsService.ServiceType.IdentityService, identityServerUrl.ensureProtocol()) + .serverResponse + buildServerAndPolicies(identityServerUrl, termsResponse, userLanguage) } - } - IdentityServerWithTerms(identityServerUrl, policyUrls) - } +} + +suspend fun Session.fetchHomeserverWithTerms(userLanguage: String): ServerAndPolicies { + val homeserverUrl = sessionParams.homeServerUrl + val terms = getHomeserverTerms(homeserverUrl.ensureProtocol()) + return buildServerAndPolicies(homeserverUrl, terms, userLanguage) +} + +private fun buildServerAndPolicies(serviceUrl: String, + termsResponse: TermsResponse, + userLanguage: String): ServerAndPolicies { + val terms = termsResponse.getLocalizedTerms(userLanguage) + val policyUrls = terms.mapNotNull { + val name = it.localizedName ?: it.policyName + val url = it.localizedUrl + if (name == null || url == null) { + null + } else { + ServerPolicy(name = name, url = url) + } + } + return ServerAndPolicies(serviceUrl, policyUrls) } diff --git a/vector/src/main/java/im/vector/app/features/discovery/IdentityServerWithTerms.kt b/vector/src/main/java/im/vector/app/features/discovery/ServerAndPolicies.kt similarity index 86% rename from vector/src/main/java/im/vector/app/features/discovery/IdentityServerWithTerms.kt rename to vector/src/main/java/im/vector/app/features/discovery/ServerAndPolicies.kt index 36bae0d0c5..17f1b0cff9 100644 --- a/vector/src/main/java/im/vector/app/features/discovery/IdentityServerWithTerms.kt +++ b/vector/src/main/java/im/vector/app/features/discovery/ServerAndPolicies.kt @@ -16,12 +16,12 @@ package im.vector.app.features.discovery -data class IdentityServerWithTerms( +data class ServerAndPolicies( val serverUrl: String, - val policies: List + val policies: List ) -data class IdentityServerPolicy( +data class ServerPolicy( val name: String, val url: String ) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt index 6aeb1519a9..5dfbf5d8f6 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/BaseEventItem.kt @@ -43,22 +43,12 @@ abstract class BaseEventItem : VectorEpoxyModel @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) lateinit var dimensionConverter: DimensionConverter - protected var ignoreSendStatusVisibility = false - @CallSuper override fun bind(holder: H) { super.bind(holder) holder.leftGuideline.updateLayoutParams { this.marginStart = leftGuideline } - // Ignore visibility of the send status icon? - holder.contentContainer.updateLayoutParams { - if (ignoreSendStatusVisibility) { - addRule(RelativeLayout.ALIGN_PARENT_END) - } else { - removeRule(RelativeLayout.ALIGN_PARENT_END) - } - } holder.checkableBackground.isChecked = highlighted } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageVoiceItem.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageVoiceItem.kt index fb7d0cabd5..f006c2aa35 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageVoiceItem.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/item/MessageVoiceItem.kt @@ -33,10 +33,6 @@ import im.vector.app.features.home.room.detail.timeline.helper.VoiceMessagePlayb @EpoxyModelClass(layout = R.layout.item_timeline_event_base) abstract class MessageVoiceItem : AbsMessageItem() { - init { - ignoreSendStatusVisibility = true - } - @EpoxyAttribute var mxcUrl: String = "" diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt index 3e08ce5589..631f00819c 100755 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/timeline/url/PreviewUrlView.kt @@ -19,13 +19,14 @@ package im.vector.app.features.home.room.detail.timeline.url import android.content.Context import android.util.AttributeSet import android.view.View -import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.view.isVisible +import com.google.android.material.card.MaterialCardView import im.vector.app.R import im.vector.app.core.extensions.setTextOrHide import im.vector.app.databinding.ViewUrlPreviewBinding import im.vector.app.features.home.room.detail.timeline.TimelineEventController import im.vector.app.features.media.ImageContentRenderer +import im.vector.app.features.themes.ThemeUtils import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.session.media.PreviewUrlData @@ -36,7 +37,7 @@ class PreviewUrlView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 -) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener { +) : MaterialCardView(context, attrs, defStyleAttr), View.OnClickListener { private lateinit var views: ViewUrlPreviewBinding @@ -44,6 +45,9 @@ class PreviewUrlView @JvmOverloads constructor( init { setupView() + radius = resources.getDimensionPixelSize(R.dimen.preview_url_view_corner_radius).toFloat() + cardElevation = 0f + setCardBackgroundColor(ThemeUtils.getColor(context, R.attr.vctr_system)) } private var state: PreviewUrlUiState = PreviewUrlUiState.Unknown @@ -121,9 +125,15 @@ class PreviewUrlView @JvmOverloads constructor( private fun renderData(previewUrlData: PreviewUrlData, imageContentRenderer: ImageContentRenderer) { isVisible = true + views.urlPreviewTitle.setTextOrHide(previewUrlData.title) views.urlPreviewImage.isVisible = previewUrlData.mxcUrl?.let { imageContentRenderer.render(it, views.urlPreviewImage) }.orFalse() views.urlPreviewDescription.setTextOrHide(previewUrlData.description) + views.urlPreviewDescription.maxLines = when { + previewUrlData.mxcUrl != null -> 2 + previewUrlData.title != null -> 3 + else -> 5 + } views.urlPreviewSite.setTextOrHide(previewUrlData.siteName.takeIf { it != previewUrlData.title }) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt index 6543cc8795..f67abfbc88 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt @@ -44,7 +44,6 @@ import im.vector.app.core.resources.UserPreferencesProvider import im.vector.app.databinding.FragmentRoomListBinding import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.home.room.filtered.FilteredRoomFooterItem -import im.vector.app.features.home.room.list.actions.RoomListActionsArgs import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel @@ -476,7 +475,7 @@ class RoomListFragment @Inject constructor( footerController.setData(it) } RoomListQuickActionsBottomSheet - .newInstance(room.roomId, RoomListActionsArgs.Mode.FULL) + .newInstance(room.roomId) .show(childFragmentManager, "ROOM_LIST_QUICK_ACTIONS") return true } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt index 014ce14c95..5d8cda94ae 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsBottomSheet.kt @@ -43,15 +43,8 @@ import javax.inject.Inject @Parcelize data class RoomListActionsArgs( - val roomId: String, - val mode: Mode -) : Parcelable { - - enum class Mode { - FULL, - NOTIFICATIONS - } -} + val roomId: String +) : Parcelable /** * Bottom sheet fragment that shows room information with list of contextual actions @@ -124,9 +117,9 @@ class RoomListQuickActionsBottomSheet : } companion object { - fun newInstance(roomId: String, mode: RoomListActionsArgs.Mode): RoomListQuickActionsBottomSheet { + fun newInstance(roomId: String): RoomListQuickActionsBottomSheet { return RoomListQuickActionsBottomSheet().apply { - setArguments(RoomListActionsArgs(roomId, mode)) + setArguments(RoomListActionsArgs(roomId)) } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt index a2d10cf818..b343013408 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt @@ -24,7 +24,6 @@ import im.vector.app.core.epoxy.bottomsheet.bottomSheetRoomPreviewItem import im.vector.app.core.epoxy.profiles.notifications.radioButtonItem import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.StringProvider -import im.vector.app.features.VectorFeatures import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.roomprofile.notifications.notificationOptions import im.vector.app.features.roomprofile.notifications.notificationStateMapped @@ -39,7 +38,6 @@ class RoomListQuickActionsEpoxyController @Inject constructor( private val avatarRenderer: AvatarRenderer, private val colorProvider: ColorProvider, private val stringProvider: StringProvider, - private val features: VectorFeatures ) : TypedEpoxyController() { var listener: Listener? = null @@ -48,54 +46,38 @@ class RoomListQuickActionsEpoxyController @Inject constructor( val notificationViewState = state.notificationSettingsViewState val roomSummary = notificationViewState.roomSummary() ?: return val host = this - val isV2 = features.notificationSettingsVersion() == VectorFeatures.NotificationSettingsVersion.V2 - // V2 always shows full details as we no longer display the sheet from RoomProfile > Notifications - val showFull = state.roomListActionsArgs.mode == RoomListActionsArgs.Mode.FULL || isV2 - - if (showFull) { - // Preview, favorite, settings - bottomSheetRoomPreviewItem { - id("room_preview") - avatarRenderer(host.avatarRenderer) - matrixItem(roomSummary.toMatrixItem()) - stringProvider(host.stringProvider) - colorProvider(host.colorProvider) - izLowPriority(roomSummary.isLowPriority) - izFavorite(roomSummary.isFavorite) - settingsClickListener { host.listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.Settings(roomSummary.roomId)) } - favoriteClickListener { host.listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.Favorite(roomSummary.roomId)) } - lowPriorityClickListener { host.listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.LowPriority(roomSummary.roomId)) } - } - - // Notifications - bottomSheetDividerItem { - id("notifications_separator") - } + // Preview, favorite, settings + bottomSheetRoomPreviewItem { + id("room_preview") + avatarRenderer(host.avatarRenderer) + matrixItem(roomSummary.toMatrixItem()) + stringProvider(host.stringProvider) + colorProvider(host.colorProvider) + izLowPriority(roomSummary.isLowPriority) + izFavorite(roomSummary.isFavorite) + settingsClickListener { host.listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.Settings(roomSummary.roomId)) } + favoriteClickListener { host.listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.Favorite(roomSummary.roomId)) } + lowPriorityClickListener { host.listener?.didSelectMenuAction(RoomListQuickActionsSharedAction.LowPriority(roomSummary.roomId)) } } - if (isV2) { - notificationViewState.notificationOptions.forEach { notificationState -> - val title = titleForNotificationState(notificationState) - radioButtonItem { - id(notificationState.name) - titleRes(title) - selected(notificationViewState.notificationStateMapped() == notificationState) - listener { - host.listener?.didSelectRoomNotificationState(notificationState) - } + // Notifications + bottomSheetDividerItem { + id("notifications_separator") + } + + notificationViewState.notificationOptions.forEach { notificationState -> + val title = titleForNotificationState(notificationState) + radioButtonItem { + id(notificationState.name) + titleRes(title) + selected(notificationViewState.notificationStateMapped() == notificationState) + listener { + host.listener?.didSelectRoomNotificationState(notificationState) } } - } else { - val selectedRoomState = notificationViewState.notificationState() - RoomListQuickActionsSharedAction.NotificationsAllNoisy(roomSummary.roomId).toBottomSheetItem(0, selectedRoomState) - RoomListQuickActionsSharedAction.NotificationsAll(roomSummary.roomId).toBottomSheetItem(1, selectedRoomState) - RoomListQuickActionsSharedAction.NotificationsMentionsOnly(roomSummary.roomId).toBottomSheetItem(2, selectedRoomState) - RoomListQuickActionsSharedAction.NotificationsMute(roomSummary.roomId).toBottomSheetItem(3, selectedRoomState) } - if (showFull) { - RoomListQuickActionsSharedAction.Leave(roomSummary.roomId, showIcon = !isV2).toBottomSheetItem(5) - } + RoomListQuickActionsSharedAction.Leave(roomSummary.roomId, showIcon = !true).toBottomSheetItem() } @StringRes @@ -106,18 +88,11 @@ class RoomListQuickActionsEpoxyController @Inject constructor( else -> null } - private fun RoomListQuickActionsSharedAction.toBottomSheetItem(index: Int, roomNotificationState: RoomNotificationState? = null) { + private fun RoomListQuickActionsSharedAction.Leave.toBottomSheetItem() { val host = this@RoomListQuickActionsEpoxyController - val selected = when (this) { - is RoomListQuickActionsSharedAction.NotificationsAllNoisy -> roomNotificationState == RoomNotificationState.ALL_MESSAGES_NOISY - is RoomListQuickActionsSharedAction.NotificationsAll -> roomNotificationState == RoomNotificationState.ALL_MESSAGES - is RoomListQuickActionsSharedAction.NotificationsMentionsOnly -> roomNotificationState == RoomNotificationState.MENTIONS_ONLY - is RoomListQuickActionsSharedAction.NotificationsMute -> roomNotificationState == RoomNotificationState.MUTE - else -> false - } return bottomSheetActionItem { - id("action_$index") - selected(selected) + id("action_leave") + selected(false) if (iconResId != null) { iconRes(iconResId) } else { diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index 2091fe04a1..5a8519ecb4 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -44,13 +44,10 @@ import im.vector.app.core.utils.copyToClipboard import im.vector.app.core.utils.startSharePlainTextIntent import im.vector.app.databinding.FragmentMatrixProfileBinding import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding -import im.vector.app.features.VectorFeatures import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.RoomDetailPendingAction import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore import im.vector.app.features.home.room.detail.upgrade.MigrateRoomBottomSheet -import im.vector.app.features.home.room.list.actions.RoomListActionsArgs -import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedAction import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedActionViewModel import kotlinx.coroutines.flow.launchIn @@ -69,8 +66,7 @@ data class RoomProfileArgs( class RoomProfileFragment @Inject constructor( private val roomProfileController: RoomProfileController, private val avatarRenderer: AvatarRenderer, - private val roomDetailPendingActionStore: RoomDetailPendingActionStore, - private val features: VectorFeatures + private val roomDetailPendingActionStore: RoomDetailPendingActionStore ) : VectorBaseFragment(), RoomProfileController.Callback { @@ -259,16 +255,7 @@ class RoomProfileFragment @Inject constructor( } override fun onNotificationsClicked() { - when (features.notificationSettingsVersion()) { - VectorFeatures.NotificationSettingsVersion.V1 -> { - RoomListQuickActionsBottomSheet - .newInstance(roomProfileArgs.roomId, RoomListActionsArgs.Mode.NOTIFICATIONS) - .show(childFragmentManager, "ROOM_PROFILE_NOTIFICATIONS") - } - VectorFeatures.NotificationSettingsVersion.V2 -> { - roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomNotificationSettings) - } - } + roomProfileSharedActionViewModel.post(RoomProfileSharedAction.OpenRoomNotificationSettings) } override fun onUploadsClicked() { diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index 6eb8d7c195..c9464550ac 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -35,6 +35,7 @@ import javax.inject.Inject class VectorPreferences @Inject constructor(private val context: Context) { companion object { + const val SETTINGS_HELP_PREFERENCE_KEY = "SETTINGS_HELP_PREFERENCE_KEY" const val SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY = "SETTINGS_CHANGE_PASSWORD_PREFERENCE_KEY" const val SETTINGS_VERSION_PREFERENCE_KEY = "SETTINGS_VERSION_PREFERENCE_KEY" const val SETTINGS_SDK_VERSION_PREFERENCE_KEY = "SETTINGS_SDK_VERSION_PREFERENCE_KEY" @@ -42,17 +43,8 @@ class VectorPreferences @Inject constructor(private val context: Context) { const val SETTINGS_LOGGED_IN_PREFERENCE_KEY = "SETTINGS_LOGGED_IN_PREFERENCE_KEY" const val SETTINGS_HOME_SERVER_PREFERENCE_KEY = "SETTINGS_HOME_SERVER_PREFERENCE_KEY" const val SETTINGS_IDENTITY_SERVER_PREFERENCE_KEY = "SETTINGS_IDENTITY_SERVER_PREFERENCE_KEY" - const val SETTINGS_APP_TERM_CONDITIONS_PREFERENCE_KEY = "SETTINGS_APP_TERM_CONDITIONS_PREFERENCE_KEY" - const val SETTINGS_PRIVACY_POLICY_PREFERENCE_KEY = "SETTINGS_PRIVACY_POLICY_PREFERENCE_KEY" const val SETTINGS_DISCOVERY_PREFERENCE_KEY = "SETTINGS_DISCOVERY_PREFERENCE_KEY" - const val SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY" - const val SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY" - const val SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY" - const val SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY = "SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY" - const val SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY" - const val SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY = "SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY" - const val SETTINGS_COPYRIGHT_PREFERENCE_KEY = "SETTINGS_COPYRIGHT_PREFERENCE_KEY" const val SETTINGS_CLEAR_CACHE_PREFERENCE_KEY = "SETTINGS_CLEAR_CACHE_PREFERENCE_KEY" const val SETTINGS_CLEAR_MEDIA_CACHE_PREFERENCE_KEY = "SETTINGS_CLEAR_MEDIA_CACHE_PREFERENCE_KEY" const val SETTINGS_USER_SETTINGS_PREFERENCE_KEY = "SETTINGS_USER_SETTINGS_PREFERENCE_KEY" diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt index 03b7c16274..31d9cf0426 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsHelpAboutFragment.kt @@ -22,11 +22,9 @@ import im.vector.app.R import im.vector.app.core.preference.VectorPreference import im.vector.app.core.utils.FirstThrottler import im.vector.app.core.utils.copyToClipboard -import im.vector.app.core.utils.displayInWebView import im.vector.app.core.utils.openAppSettingsPage import im.vector.app.core.utils.openUrlInChromeCustomTab import im.vector.app.features.version.VersionProvider -import im.vector.app.openOssLicensesMenuActivity import org.matrix.android.sdk.api.Matrix import javax.inject.Inject @@ -40,6 +38,15 @@ class VectorSettingsHelpAboutFragment @Inject constructor( private val firstThrottler = FirstThrottler(1000) override fun bindPref() { + // Help + findPreference(VectorPreferences.SETTINGS_HELP_PREFERENCE_KEY)!! + .onPreferenceClickListener = Preference.OnPreferenceClickListener { + if (firstThrottler.canHandle() is FirstThrottler.CanHandlerResult.Yes) { + openUrlInChromeCustomTab(requireContext(), null, VectorSettingsUrls.HELP) + } + false + } + // preference to start the App info screen, to facilitate App permissions access findPreference(APP_INFO_LINK_PREFERENCE_KEY)!! .onPreferenceClickListener = Preference.OnPreferenceClickListener { @@ -76,44 +83,6 @@ class VectorSettingsHelpAboutFragment @Inject constructor( // olm version findPreference(VectorPreferences.SETTINGS_OLM_VERSION_PREFERENCE_KEY)!! .summary = session.cryptoService().getCryptoVersion(requireContext(), false) - - // copyright - findPreference(VectorPreferences.SETTINGS_COPYRIGHT_PREFERENCE_KEY)!! - .onPreferenceClickListener = Preference.OnPreferenceClickListener { - openUrlInChromeCustomTab(requireContext(), null, VectorSettingsUrls.COPYRIGHT) - false - } - - // terms & conditions - findPreference(VectorPreferences.SETTINGS_APP_TERM_CONDITIONS_PREFERENCE_KEY)!! - .onPreferenceClickListener = Preference.OnPreferenceClickListener { - openUrlInChromeCustomTab(requireContext(), null, VectorSettingsUrls.TAC) - false - } - - // privacy policy - findPreference(VectorPreferences.SETTINGS_PRIVACY_POLICY_PREFERENCE_KEY)!! - .onPreferenceClickListener = Preference.OnPreferenceClickListener { - openUrlInChromeCustomTab(requireContext(), null, VectorSettingsUrls.PRIVACY_POLICY) - false - } - - // third party notice - findPreference(VectorPreferences.SETTINGS_THIRD_PARTY_NOTICES_PREFERENCE_KEY)!! - .onPreferenceClickListener = Preference.OnPreferenceClickListener { - if (firstThrottler.canHandle() is FirstThrottler.CanHandlerResult.Yes) { - activity?.displayInWebView(VectorSettingsUrls.THIRD_PARTY_LICENSES) - } - false - } - - // Note: preference is not visible on F-Droid build - findPreference(VectorPreferences.SETTINGS_OTHER_THIRD_PARTY_NOTICES_PREFERENCE_KEY)!! - .onPreferenceClickListener = Preference.OnPreferenceClickListener { - // See https://developers.google.com/android/guides/opensource - openOssLicensesMenuActivity(requireActivity()) - false - } } companion object { diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsUrls.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsUrls.kt index c5088aac6d..09249c4957 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsUrls.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsUrls.kt @@ -17,7 +17,7 @@ package im.vector.app.features.settings object VectorSettingsUrls { - + const val HELP = "https://element.io/help" const val COPYRIGHT = "https://element.io/copyright" const val TAC = "https://element.io/terms-of-service" const val PRIVACY_POLICY = "https://element.io/privacy" diff --git a/vector/src/main/java/im/vector/app/features/settings/legals/ElementLegals.kt b/vector/src/main/java/im/vector/app/features/settings/legals/ElementLegals.kt new file mode 100644 index 0000000000..de59f36604 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/legals/ElementLegals.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.legals + +import im.vector.app.R +import im.vector.app.core.resources.StringProvider +import im.vector.app.features.discovery.ServerPolicy +import im.vector.app.features.settings.VectorSettingsUrls +import javax.inject.Inject + +class ElementLegals @Inject constructor( + private val stringProvider: StringProvider +) { + /** + * Use ServerPolicy model + */ + fun getData(): List { + return listOf( + ServerPolicy(stringProvider.getString(R.string.settings_copyright), VectorSettingsUrls.COPYRIGHT), + ServerPolicy(stringProvider.getString(R.string.settings_app_term_conditions), VectorSettingsUrls.TAC), + ServerPolicy(stringProvider.getString(R.string.settings_privacy_policy), VectorSettingsUrls.PRIVACY_POLICY) + ) + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/legals/LegalsAction.kt b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsAction.kt new file mode 100644 index 0000000000..424c6bb78b --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsAction.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.legals + +import im.vector.app.core.platform.VectorViewModelAction + +sealed interface LegalsAction : VectorViewModelAction { + object Refresh : LegalsAction +} diff --git a/vector/src/main/java/im/vector/app/features/settings/legals/LegalsController.kt b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsController.kt new file mode 100644 index 0000000000..98e77ae7d5 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsController.kt @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.app.features.settings.legals + +import android.content.res.Resources +import com.airbnb.epoxy.TypedEpoxyController +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.Success +import com.airbnb.mvrx.Uninitialized +import im.vector.app.R +import im.vector.app.core.epoxy.errorWithRetryItem +import im.vector.app.core.epoxy.loadingItem +import im.vector.app.core.error.ErrorFormatter +import im.vector.app.core.resources.StringProvider +import im.vector.app.features.discovery.ServerAndPolicies +import im.vector.app.features.discovery.ServerPolicy +import im.vector.app.features.discovery.discoveryPolicyItem +import im.vector.app.features.discovery.settingsInfoItem +import im.vector.app.features.discovery.settingsSectionTitleItem +import javax.inject.Inject + +class LegalsController @Inject constructor( + private val stringProvider: StringProvider, + private val resources: Resources, + private val elementLegals: ElementLegals, + private val errorFormatter: ErrorFormatter +) : TypedEpoxyController() { + + var listener: Listener? = null + + override fun buildModels(data: LegalsState) { + buildAppSection() + buildHomeserverSection(data) + buildIdentityServerSection(data) + buildThirdPartyNotices() + } + + private fun buildAppSection() { + settingsSectionTitleItem { + id("appTitle") + titleResId(R.string.legals_application_title) + } + + buildPolicies("el", elementLegals.getData()) + } + + private fun buildHomeserverSection(data: LegalsState) { + settingsSectionTitleItem { + id("hsServerTitle") + titleResId(R.string.legals_home_server_title) + } + + buildPolicyAsync("hs", data.homeServer) + } + + private fun buildIdentityServerSection(data: LegalsState) { + if (data.hasIdentityServer) { + settingsSectionTitleItem { + id("idServerTitle") + titleResId(R.string.legals_identity_server_title) + } + + buildPolicyAsync("is", data.identityServer) + } + } + + private fun buildPolicyAsync(tag: String, serverAndPolicies: Async) { + val host = this + + when (serverAndPolicies) { + Uninitialized, + is Loading -> loadingItem { + id("loading_$tag") + } + is Success -> { + val policies = serverAndPolicies()?.policies + if (policies.isNullOrEmpty()) { + settingsInfoItem { + id("emptyPolicy") + helperText(host.stringProvider.getString(R.string.legals_no_policy_provided)) + } + } else { + buildPolicies(tag, policies) + } + } + is Fail -> { + errorWithRetryItem { + id("errorRetry_$tag") + text(host.errorFormatter.toHumanReadable(serverAndPolicies.error)) + listener { host.listener?.onTapRetry() } + } + } + } + } + + private fun buildPolicies(tag: String, policies: List) { + val host = this + + policies.forEach { policy -> + discoveryPolicyItem { + id(tag + policy.url) + name(policy.name) + url(policy.url.takeIf { it.startsWith("http") }) + clickListener { host.listener?.openPolicy(policy) } + } + } + } + + private fun buildThirdPartyNotices() { + val host = this + settingsSectionTitleItem { + id("thirdTitle") + titleResId(R.string.legals_third_party_notices) + } + + discoveryPolicyItem { + id("eltpn1") + name(host.stringProvider.getString(R.string.settings_third_party_notices)) + clickListener { host.listener?.openThirdPartyNotice() } + } + // Only on Gplay + if (resources.getBoolean(R.bool.isGplay)) { + discoveryPolicyItem { + id("eltpn2") + name(host.stringProvider.getString(R.string.settings_other_third_party_notices)) + clickListener { host.listener?.openThirdPartyNoticeGplay() } + } + } + } + + interface Listener { + fun onTapRetry() + fun openPolicy(policy: ServerPolicy) + fun openThirdPartyNotice() + fun openThirdPartyNoticeGplay() + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/legals/LegalsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsFragment.kt new file mode 100644 index 0000000000..f9b50bdead --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsFragment.kt @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.app.features.settings.legals + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState +import im.vector.app.R +import im.vector.app.core.extensions.cleanup +import im.vector.app.core.extensions.configureWith +import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.utils.FirstThrottler +import im.vector.app.core.utils.displayInWebView +import im.vector.app.core.utils.openUrlInChromeCustomTab +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import im.vector.app.features.discovery.ServerPolicy +import im.vector.app.features.settings.VectorSettingsUrls +import im.vector.app.openOssLicensesMenuActivity +import javax.inject.Inject + +class LegalsFragment @Inject constructor( + private val controller: LegalsController +) : VectorBaseFragment(), + LegalsController.Listener { + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGenericRecyclerBinding { + return FragmentGenericRecyclerBinding.inflate(inflater, container, false) + } + + private val viewModel by fragmentViewModel(LegalsViewModel::class) + private val firstThrottler = FirstThrottler(1000) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + controller.listener = this + views.genericRecyclerView.configureWith(controller) + } + + override fun onDestroyView() { + views.genericRecyclerView.cleanup() + controller.listener = null + super.onDestroyView() + } + + override fun invalidate() = withState(viewModel) { state -> + controller.setData(state) + } + + override fun onResume() { + super.onResume() + (activity as? AppCompatActivity)?.supportActionBar?.setTitle(R.string.preference_root_legals) + viewModel.handle(LegalsAction.Refresh) + } + + override fun onTapRetry() { + viewModel.handle(LegalsAction.Refresh) + } + + override fun openPolicy(policy: ServerPolicy) { + openUrl(policy.url) + } + + override fun openThirdPartyNotice() { + openUrl(VectorSettingsUrls.THIRD_PARTY_LICENSES) + } + + private fun openUrl(url: String) { + if (firstThrottler.canHandle() is FirstThrottler.CanHandlerResult.Yes) { + if (url.startsWith("file://")) { + activity?.displayInWebView(url) + } else { + openUrlInChromeCustomTab(requireContext(), null, url) + } + } + } + + override fun openThirdPartyNoticeGplay() { + if (firstThrottler.canHandle() is FirstThrottler.CanHandlerResult.Yes) { + // See https://developers.google.com/android/guides/opensource + openOssLicensesMenuActivity(requireActivity()) + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/legals/LegalsState.kt b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsState.kt new file mode 100644 index 0000000000..ad01f85338 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsState.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.legals + +import com.airbnb.mvrx.Async +import com.airbnb.mvrx.MavericksState +import com.airbnb.mvrx.Uninitialized +import im.vector.app.features.discovery.ServerAndPolicies + +data class LegalsState( + val homeServer: Async = Uninitialized, + val hasIdentityServer: Boolean = false, + val identityServer: Async = Uninitialized +) : MavericksState diff --git a/vector/src/main/java/im/vector/app/features/settings/legals/LegalsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsViewModel.kt new file mode 100644 index 0000000000..9d58535490 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/legals/LegalsViewModel.kt @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2021 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package im.vector.app.features.settings.legals + +import com.airbnb.mvrx.Fail +import com.airbnb.mvrx.Loading +import com.airbnb.mvrx.MavericksViewModelFactory +import com.airbnb.mvrx.Success +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import im.vector.app.R +import im.vector.app.core.di.MavericksAssistedViewModelFactory +import im.vector.app.core.di.hiltMavericksViewModelFactory +import im.vector.app.core.extensions.exhaustive +import im.vector.app.core.platform.EmptyViewEvents +import im.vector.app.core.platform.VectorViewModel +import im.vector.app.core.resources.StringProvider +import im.vector.app.features.discovery.fetchHomeserverWithTerms +import im.vector.app.features.discovery.fetchIdentityServerWithTerms +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.session.Session + +class LegalsViewModel @AssistedInject constructor( + @Assisted initialState: LegalsState, + private val session: Session, + private val stringProvider: StringProvider +) : VectorViewModel(initialState) { + + @AssistedFactory + interface Factory : MavericksAssistedViewModelFactory { + override fun create(initialState: LegalsState): LegalsViewModel + } + + companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() + + override fun handle(action: LegalsAction) { + when (action) { + LegalsAction.Refresh -> loadData() + }.exhaustive + } + + private fun loadData() = withState { state -> + loadHomeserver(state) + val url = session.identityService().getCurrentIdentityServerUrl() + if (url.isNullOrEmpty()) { + setState { copy(hasIdentityServer = false) } + } else { + setState { copy(hasIdentityServer = true) } + loadIdentityServer(state) + } + } + + private fun loadHomeserver(state: LegalsState) { + if (state.homeServer !is Success) { + setState { copy(homeServer = Loading()) } + viewModelScope.launch { + runCatching { session.fetchHomeserverWithTerms(stringProvider.getString(R.string.resources_language)) } + .fold( + onSuccess = { setState { copy(homeServer = Success(it)) } }, + onFailure = { setState { copy(homeServer = Fail(it)) } } + ) + } + } + } + + private fun loadIdentityServer(state: LegalsState) { + if (state.identityServer !is Success) { + setState { copy(identityServer = Loading()) } + viewModelScope.launch { + runCatching { session.fetchIdentityServerWithTerms(stringProvider.getString(R.string.resources_language)) } + .fold( + onSuccess = { setState { copy(identityServer = Success(it)) } }, + onFailure = { setState { copy(identityServer = Fail(it)) } } + ) + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index 3004d30913..4199bd1753 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -40,7 +40,6 @@ import im.vector.app.core.pushers.PushersManager import im.vector.app.core.services.GuardServiceStarter import im.vector.app.core.utils.isIgnoringBatteryOptimizations import im.vector.app.core.utils.requestDisablingBatteryOptimization -import im.vector.app.features.VectorFeatures import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.BackgroundSyncModeChooserDialog @@ -64,8 +63,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( private val pushManager: PushersManager, private val activeSessionHolder: ActiveSessionHolder, private val vectorPreferences: VectorPreferences, - private val guardServiceStarter: GuardServiceStarter, - private val features: VectorFeatures + private val guardServiceStarter: GuardServiceStarter ) : VectorSettingsBaseFragment(), BackgroundSyncModeChooserDialog.InteractionListener { @@ -147,7 +145,6 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( refreshBackgroundSyncPrefs() handleSystemPreference() - handleVersionedSettings() } private fun bindEmailNotifications() { @@ -312,15 +309,6 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( } } - private fun handleVersionedSettings() { - val isNotificationSettingsV2Enabled = features.notificationSettingsVersion() == VectorFeatures.NotificationSettingsVersion.V2 - - findPreference(VectorPreferences.SETTINGS_NOTIFICATION_ADVANCED_PREFERENCE_KEY)?.isVisible = !isNotificationSettingsV2Enabled - findPreference(VectorPreferences.SETTINGS_NOTIFICATION_DEFAULT_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled - findPreference(VectorPreferences.SETTINGS_NOTIFICATION_KEYWORD_AND_MENTIONS_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled - findPreference(VectorPreferences.SETTINGS_NOTIFICATION_OTHER_PREFERENCE_KEY)?.isVisible = isNotificationSettingsV2Enabled - } - override fun onResume() { super.onResume() activeSessionHolder.getSafeActiveSession()?.refreshPushers() diff --git a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewEvents.kt b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewEvents.kt index ffda0dd505..ef29e8015a 100644 --- a/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/userdirectory/UserListViewEvents.kt @@ -17,13 +17,13 @@ package im.vector.app.features.userdirectory import im.vector.app.core.platform.VectorViewEvents -import im.vector.app.features.discovery.IdentityServerWithTerms +import im.vector.app.features.discovery.ServerAndPolicies /** * Transient events for invite users to room screen */ sealed class UserListViewEvents : VectorViewEvents { data class Failure(val throwable: Throwable) : UserListViewEvents() - data class OnPoliciesRetrieved(val identityServerWithTerms: IdentityServerWithTerms?) : UserListViewEvents() + data class OnPoliciesRetrieved(val identityServerWithTerms: ServerAndPolicies?) : UserListViewEvents() data class OpenShareMatrixToLink(val link: String) : UserListViewEvents() } diff --git a/vector/src/main/res/drawable/ic_close_with_circular_bg.xml b/vector/src/main/res/drawable/ic_close_with_circular_bg.xml new file mode 100644 index 0000000000..5e54b638a0 --- /dev/null +++ b/vector/src/main/res/drawable/ic_close_with_circular_bg.xml @@ -0,0 +1,23 @@ + + + + + diff --git a/vector/src/main/res/drawable/ic_settings_root_legals.xml b/vector/src/main/res/drawable/ic_settings_root_legals.xml new file mode 100644 index 0000000000..8c5049b36e --- /dev/null +++ b/vector/src/main/res/drawable/ic_settings_root_legals.xml @@ -0,0 +1,10 @@ + + + diff --git a/vector/src/main/res/layout/item_discovery_policy.xml b/vector/src/main/res/layout/item_discovery_policy.xml index 453d236bab..2d90c3c0ed 100644 --- a/vector/src/main/res/layout/item_discovery_policy.xml +++ b/vector/src/main/res/layout/item_discovery_policy.xml @@ -5,9 +5,21 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="?attr/selectableItemBackground" + android:minHeight="80dp" android:padding="16dp" tools:viewBindingIgnore="true"> + + + tools:text="Copyright" /> + android:textColor="?android:textColorLink" + tools:text="https://element.io/copyright" /> @@ -116,27 +117,23 @@ android:id="@+id/messageContentRedactedStub" style="@style/TimelineContentStubBaseParams" android:layout_height="wrap_content" - android:layout_marginEnd="56dp" android:layout="@layout/item_timeline_event_redacted_stub" /> @@ -153,7 +150,7 @@ android:layout_marginBottom="4dp" android:contentDescription="@string/event_status_a11y_sending" android:src="@drawable/ic_sending_message" - android:visibility="gone" + android:visibility="invisible" tools:tint="?vctr_content_tertiary" tools:visibility="visible" /> diff --git a/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml b/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml index 0280efd848..3f9feb93af 100644 --- a/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml +++ b/vector/src/main/res/layout/item_timeline_event_text_message_stub.xml @@ -17,7 +17,7 @@ + tools:parentTag="com.google.android.material.card.MaterialCardView"> - - - + android:orientation="vertical"> - + - + - + + + + + \ No newline at end of file diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index ddb731a5e0..97bf7a7d6a 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1397,6 +1397,12 @@ Allow integrations Integration manager + ${app_name} policy + Your homeserver policy + Your identity server policy + Third party libraries + This server does not provide any policy. + Integrations are disabled "Enable 'Allow integrations' in Settings to do this." @@ -2270,7 +2276,13 @@ Voice & Video Help & About + Legals + Help + Help and support + Get help with using Element + Versions + System settings Register token @@ -3566,7 +3578,6 @@ Manage rooms and spaces - Show all rooms in Home All rooms you’re in will be shown in Home. diff --git a/vector/src/main/res/xml/vector_settings_help_about.xml b/vector/src/main/res/xml/vector_settings_help_about.xml index b36fba05c2..0388b545b7 100644 --- a/vector/src/main/res/xml/vector_settings_help_about.xml +++ b/vector/src/main/res/xml/vector_settings_help_about.xml @@ -1,47 +1,42 @@ - + - + - + - + - + - + - + - + - + + + + + \ No newline at end of file diff --git a/vector/src/main/res/xml/vector_settings_notifications.xml b/vector/src/main/res/xml/vector_settings_notifications.xml index 154e7cca0d..66ac93a4f9 100644 --- a/vector/src/main/res/xml/vector_settings_notifications.xml +++ b/vector/src/main/res/xml/vector_settings_notifications.xml @@ -20,14 +20,6 @@ - - + + \ No newline at end of file