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/build.gradle b/build.gradle index 4c3734892d..e17f357905 100644 --- a/build.gradle +++ b/build.gradle @@ -1,12 +1,11 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - apply from: 'dependencies.gradle' + apply from: 'dependencies_groups.gradle' repositories { google() - jcenter() maven { url "https://plugins.gradle.org/m2/" } @@ -37,45 +36,50 @@ allprojects { apply plugin: "org.jlleitschuh.gradle.ktlint" repositories { - // For olm library. This has to be declared first, to ensure that Olm library is not downloaded from another repo + // For olm library. + maven { + url 'https://gitlab.matrix.org/api/v4/projects/27/packages/maven' + content { + groups.olm.regex.each { includeGroupByRegex it } + groups.olm.group.each { includeGroup it } + } + } maven { url 'https://jitpack.io' content { - // Use this repo only for olm library - includeGroupByRegex "org\\.matrix\\.gitlab\\.matrix-org" - // And also for FilePicker - includeGroupByRegex "com\\.github\\.jaiselrahman" - // And monarchy - includeGroupByRegex "com\\.github\\.Zhuinden" - // And ucrop - includeGroupByRegex "com\\.github\\.yalantis" - // JsonViewer - includeGroupByRegex 'com\\.github\\.BillCarsonFr' - // PhotoView - includeGroupByRegex 'com\\.github\\.chrisbanes' - // PFLockScreen-Android - includeGroupByRegex 'com\\.github\\.vector-im' - // DraggableView - includeGroupByRegex 'com\\.github\\.hyuwah' - - // Chat effects - includeGroupByRegex 'com\\.github\\.jetradarmobile' - includeGroupByRegex 'nl\\.dionsegijn' - - // Voice RecordView - includeGroupByRegex 'com\\.github\\.Armen101' + groups.jitpack.regex.each { includeGroupByRegex it } + groups.jitpack.group.each { includeGroup it } } } - maven { url 'https://oss.sonatype.org/content/repositories/snapshots/' } // Jitsi repo maven { url "https://github.com/vector-im/jitsi_libre_maven/raw/main/android-sdk-3.10.0" // Note: to test Jitsi release you can use a local file like this: // url "file:///Users/bmarty/workspaces/jitsi_libre_maven/android-sdk-3.10.0" + content { + groups.jitsi.regex.each { includeGroupByRegex it } + groups.jitsi.group.each { includeGroup it } + } + } + google { + content { + groups.google.regex.each { includeGroupByRegex it } + groups.google.group.each { includeGroup it } + } + } + mavenCentral { + content { + groups.mavenCentral.regex.each { includeGroupByRegex it } + groups.mavenCentral.group.each { includeGroup it } + } + } + //noinspection JcenterRepositoryObsolete + jcenter { + content { + groups.jcenter.regex.each { includeGroupByRegex it } + groups.jcenter.group.each { includeGroup it } + } } - google() - mavenCentral() - jcenter() } tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all { 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/4592.bugfix b/changelog.d/4592.bugfix new file mode 100644 index 0000000000..b27e793100 --- /dev/null +++ b/changelog.d/4592.bugfix @@ -0,0 +1 @@ +Fix empty Dev Tools screen issue. 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/4647.misc b/changelog.d/4647.misc new file mode 100644 index 0000000000..a33afba138 --- /dev/null +++ b/changelog.d/4647.misc @@ -0,0 +1 @@ + Upgrade OLM to v3.2.7 and get it from our maven repository. \ No newline at end of file diff --git a/changelog.d/4650.misc b/changelog.d/4650.misc new file mode 100644 index 0000000000..3537441d51 --- /dev/null +++ b/changelog.d/4650.misc @@ -0,0 +1 @@ +Cleanup id ref. Use type views instead \ 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/4670.misc b/changelog.d/4670.misc new file mode 100644 index 0000000000..6b1233145b --- /dev/null +++ b/changelog.d/4670.misc @@ -0,0 +1 @@ +Add explicit dependency location, regarding the several maven repository. Also update some libraries (flexbox and alerter), and do some cleanup. \ No newline at end of file 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/dependencies_groups.gradle b/dependencies_groups.gradle new file mode 100644 index 0000000000..c677290adc --- /dev/null +++ b/dependencies_groups.gradle @@ -0,0 +1,200 @@ +ext.groups = [ + jitpack : [ + regex: [ + ], + group: [ + 'com.github.Armen101', + 'com.github.BillCarsonFr', + 'com.github.chrisbanes', + 'com.github.hyuwah', + 'com.github.jetradarmobile', + 'com.github.tapadoo', + 'com.github.vector-im', + 'com.github.yalantis', + 'com.github.Zhuinden', + ] + ], + olm : [ + regex: [ + ], + group: [ + 'org.matrix.android', + ] + ], + jitsi : [ + regex: [ + ], + group: [ + 'com.facebook.react', + 'org.jitsi.react', + 'org.webkit', + ] + ], + google : [ + regex: [ + 'androidx\\..*', + 'com\\.android\\.tools\\..*', + 'com\\.google\\.android\\..*', + ], + group: [ + 'com.google.firebase', + 'com.android', + 'com.android.tools', + ] + ], + mavenCentral: [ + regex: [ + ], + group: [ + 'com.adevinta.android', + 'com.airbnb.android', + 'com.almworks.sqlite4java', + 'com.arthenica', + 'com.atlassian.commonmark', + 'com.atlassian.pom', + 'com.beust', + 'com.davemorrissey.labs', + 'com.dropbox.core', + 'com.facebook.fresco', + 'com.facebook.infer.annotation', + 'com.facebook.soloader', + 'com.facebook.stetho', + 'com.fasterxml', + 'com.fasterxml.jackson', + 'com.fasterxml.jackson.core', + 'com.gabrielittner.threetenbp', + 'com.getkeepsafe.relinker', + 'com.github.bumptech.glide', + 'com.github.filippudak', + 'com.github.filippudak.progresspieview', + 'com.github.javaparser', + 'com.github.piasy', + 'com.github.shyiko.klob', + 'com.google', + 'com.google.auto.service', + 'com.google.auto.value', + 'com.google.code.findbugs', + 'com.google.code.gson', + 'com.google.dagger', + 'com.google.devtools.ksp', + 'com.google.errorprone', + 'com.google.googlejavaformat', + 'com.google.guava', + 'com.google.j2objc', + 'com.google.jimfs', + 'com.google.protobuf', + 'com.google.zxing', + 'com.googlecode.htmlcompressor', + 'com.googlecode.json-simple', + 'com.googlecode.libphonenumber', + 'com.ibm.icu', + 'com.jakewharton.android.repackaged', + 'com.jakewharton.timber', + 'com.linkedin.dexmaker', + 'com.nulab-inc', + 'com.otaliastudios.opengl', + 'com.parse.bolts', + 'com.pinterest', + 'com.pinterest.ktlint', + 'com.squareup', + 'com.squareup.duktape', + 'com.squareup.moshi', + 'com.squareup.okhttp3', + 'com.squareup.okio', + 'com.squareup.retrofit2', + 'com.sun.activation', + 'com.sun.istack', + 'com.sun.xml.bind', + 'com.sun.xml.bind.mvn', + 'com.sun.xml.fastinfoset', + 'com.thoughtworks.qdox', + 'com.vanniktech', + 'commons-cli', + 'commons-codec', + 'commons-io', + 'commons-logging', + 'info.picocli', + 'io.arrow-kt', + 'io.github.detekt.sarif4k', + 'io.github.reactivecircus.flowbinding', + 'io.jsonwebtoken', + 'io.kindedj', + 'io.mockk', + 'io.noties.markwon', + 'io.reactivex.rxjava2', + 'io.realm', + 'it.unimi.dsi', + 'jakarta.activation', + 'jakarta.xml.bind', + 'javax.annotation', + 'javax.inject', + 'jline', + 'jp.wasabeef', + 'junit', + 'me.leolin', + 'me.saket', + 'net.bytebuddy', + 'net.java', + 'net.java.dev.jna', + 'net.lachlanmckee', + 'net.ltgt.gradle.incap', + 'net.sf.jopt-simple', + 'net.sf.kxml', + 'nl.dionsegijn', + 'org.amshove.kluent', + 'org.apache', + 'org.apache.ant', + 'org.apache.commons', + 'org.apache.httpcomponents', + 'org.apache.sanselan', + 'org.bouncycastle', + 'org.checkerframework', + 'org.codehaus', + 'org.codehaus.groovy', + 'org.codehaus.mojo', + 'org.eclipse.ee4j', + 'org.ec4j.core', + 'org.glassfish.jaxb', + 'org.hamcrest', + 'org.jetbrains', + 'org.jetbrains.intellij.deps', + 'org.jetbrains.kotlin', + 'org.jetbrains.kotlinx', + 'org.jsoup', + 'org.junit', + 'org.junit.jupiter', + 'org.junit.platform', + 'org.jvnet.staxex', + 'org.mockito', + 'org.mongodb', + 'org.objenesis', + 'org.opentest4j', + 'org.ow2', + 'org.ow2.asm', + 'org.ow2.asm', + 'org.reactivestreams', + 'org.robolectric', + 'org.slf4j', + 'org.sonatype.oss', + 'org.testng', + 'org.threeten', + 'xerces', + 'xml-apis', + ] + ], + jcenter : [ + regex: [ + ], + group: [ + 'com.amulyakhare', + 'com.otaliastudios', + 'com.yqritc', + // https://github.com/cmelchior/realmfieldnameshelper/issues/42 + 'dk.ilios', + 'im.dlg', + 'me.dm7.barcodescanner', + 'me.gujun.android', + ] + ] +] + 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 e37231097d..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" } } @@ -140,8 +140,8 @@ dependencies { implementation libs.arrow.core implementation libs.arrow.instances - // olm lib is now hosted by jitpack: https://jitpack.io/#org.matrix.gitlab.matrix-org/olm - implementation 'org.matrix.gitlab.matrix-org:olm:3.2.4' + // olm lib is now hosted by maven at https://gitlab.matrix.org/api/v4/projects/27/packages/maven + implementation 'org.matrix.android:olm:3.2.7' // DI implementation libs.dagger.dagger @@ -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/tools/templates/ElementFeature/root/src/app_package/Activity.kt.ftl b/tools/templates/ElementFeature/root/src/app_package/Activity.kt.ftl index a4622d1d21..a5c097065e 100644 --- a/tools/templates/ElementFeature/root/src/app_package/Activity.kt.ftl +++ b/tools/templates/ElementFeature/root/src/app_package/Activity.kt.ftl @@ -35,9 +35,9 @@ class ${activityClass} : VectorBaseActivity(), ToolbarConfigurable { <#if createFragmentArgs> val fragmentArgs: ${fragmentArgsClass} = intent?.extras?.getParcelable(EXTRA_FRAGMENT_ARGS) ?: return - addFragment(R.id.simpleFragmentContainer, ${fragmentClass}::class.java, fragmentArgs) + addFragment(views.simpleFragmentContainer.id, ${fragmentClass}::class.java, fragmentArgs) <#else> - addFragment(R.id.simpleFragmentContainer, ${fragmentClass}::class.java) + addFragment(views.simpleFragmentContainer.id, ${fragmentClass}::class.java) } } diff --git a/vector/build.gradle b/vector/build.gradle index 278602859c..0ebfc90044 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" @@ -317,11 +316,6 @@ android { } } -configurations { - // videocache includes a sl4j logger which causes mockk to attempt to call the static android Log - testImplementation.exclude group: 'org.slf4j', module: 'slf4j-android' -} - dependencies { implementation project(":matrix-sdk-android") @@ -365,7 +359,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 @@ -398,7 +392,7 @@ dependencies { implementation libs.markwon.html implementation 'com.googlecode.htmlcompressor:htmlcompressor:1.5.2' implementation 'me.saket:better-link-movement-method:2.2.0' - implementation 'com.google.android:flexbox:2.0.1' + implementation 'com.google.android.flexbox:flexbox:3.0.0' implementation libs.androidx.autoFill implementation 'jp.wasabeef:glide-transformations:4.3.0' implementation 'com.github.vector-im:PFLockScreen-Android:1.0.0-beta12' @@ -415,7 +409,7 @@ dependencies { implementation 'com.arthenica:ffmpeg-kit-audio:4.5.LTS' // Alerter - implementation 'com.tapadoo.android:alerter:7.0.1' + implementation 'com.github.tapadoo:alerter:7.2.4' implementation 'com.otaliastudios:autocomplete:1.1.0' @@ -433,7 +427,6 @@ dependencies { implementation libs.github.glide kapt libs.github.glideCompiler - implementation 'com.danikula:videocache:2.7.1' implementation 'com.github.yalantis:ucrop:2.2.7' // Badge for compatibility 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/debug/AndroidManifest.xml b/vector/src/debug/AndroidManifest.xml index 07d8c2f87a..0b2b5cf90f 100644 --- a/vector/src/debug/AndroidManifest.xml +++ b/vector/src/debug/AndroidManifest.xml @@ -8,6 +8,7 @@ + diff --git a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt index 0f9ee5b0b3..a2b2b44ce3 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt @@ -35,6 +35,7 @@ import im.vector.app.core.utils.registerForPermissionsResult import im.vector.app.core.utils.toast import im.vector.app.databinding.ActivityDebugMenuBinding import im.vector.app.features.debug.analytics.DebugAnalyticsActivity +import im.vector.app.features.debug.features.DebugFeaturesSettingsActivity import im.vector.app.features.debug.sas.DebugSasEmojiActivity import im.vector.app.features.debug.settings.DebugPrivateSettingsActivity import im.vector.app.features.qrcode.QrCodeScannerActivity @@ -77,6 +78,7 @@ class DebugMenuActivity : VectorBaseActivity() { } private fun setupViews() { + views.debugFeatures.setOnClickListener { startActivity(Intent(this, DebugFeaturesSettingsActivity::class.java)) } views.debugPrivateSetting.setOnClickListener { openPrivateSettings() } views.debugAnalytics.setOnClickListener { startActivity(Intent(this, DebugAnalyticsActivity::class.java)) diff --git a/vector/src/debug/java/im/vector/app/features/debug/di/FeaturesModule.kt b/vector/src/debug/java/im/vector/app/features/debug/di/FeaturesModule.kt new file mode 100644 index 0000000000..0c4a3ef637 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/di/FeaturesModule.kt @@ -0,0 +1,48 @@ +/* + * 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.debug.di + +import android.content.Context +import dagger.Binds +import dagger.Module +import dagger.Provides +import dagger.hilt.InstallIn +import dagger.hilt.components.SingletonComponent +import im.vector.app.features.DefaultVectorFeatures +import im.vector.app.features.VectorFeatures +import im.vector.app.features.debug.features.DebugVectorFeatures + +@InstallIn(SingletonComponent::class) +@Module +interface FeaturesModule { + + @Binds + fun bindFeatures(debugFeatures: DebugVectorFeatures): VectorFeatures + + companion object { + + @Provides + fun providesDefaultVectorFeatures(): DefaultVectorFeatures { + return DefaultVectorFeatures() + } + + @Provides + fun providesDebugVectorFeatures(context: Context, defaultVectorFeatures: DefaultVectorFeatures): DebugVectorFeatures { + return DebugVectorFeatures(context, defaultVectorFeatures) + } + } +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesSettingsActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesSettingsActivity.kt new file mode 100644 index 0000000000..e31f073614 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesSettingsActivity.kt @@ -0,0 +1,52 @@ +/* + * 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.debug.features + +import android.os.Bundle +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.extensions.cleanup +import im.vector.app.core.extensions.configureWith +import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.FragmentGenericRecyclerBinding +import javax.inject.Inject + +@AndroidEntryPoint +class DebugFeaturesSettingsActivity : VectorBaseActivity() { + + @Inject lateinit var debugFeatures: DebugVectorFeatures + @Inject lateinit var debugFeaturesStateFactory: DebugFeaturesStateFactory + @Inject lateinit var controller: FeaturesController + + override fun getBinding() = FragmentGenericRecyclerBinding.inflate(layoutInflater) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + controller.listener = object : EnumFeatureItem.Listener { + override fun > onOptionSelected(option: T?, feature: Feature.EnumFeature) { + debugFeatures.overrideEnum(option, feature.type) + } + } + views.genericRecyclerView.configureWith(controller) + controller.setData(debugFeaturesStateFactory.create()) + } + + override fun onDestroy() { + controller.listener = null + views.genericRecyclerView.cleanup() + super.onDestroy() + } +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt new file mode 100644 index 0000000000..8d22fc599f --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt @@ -0,0 +1,46 @@ +/* + * 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.debug.features + +import im.vector.app.features.DefaultVectorFeatures +import javax.inject.Inject + +class DebugFeaturesStateFactory @Inject constructor( + private val debugFeatures: DebugVectorFeatures, + private val defaultFeatures: DefaultVectorFeatures +) { + + fun create(): FeaturesState { + return FeaturesState(listOf( + createEnumFeature( + label = "Login version", + selection = debugFeatures.loginVersion(), + default = defaultFeatures.loginVersion() + ) + )) + } + + private inline fun > createEnumFeature(label: String, selection: T, default: T): Feature { + return Feature.EnumFeature( + label = label, + selection = selection.takeIf { debugFeatures.hasEnumOverride(T::class) }, + default = default, + options = enumValues().toList(), + type = T::class + ) + } +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt b/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt new file mode 100644 index 0000000000..0831609e4f --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt @@ -0,0 +1,78 @@ +/* + * 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.debug.features + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.MutablePreferences +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.stringPreferencesKey +import androidx.datastore.preferences.preferencesDataStore +import im.vector.app.features.DefaultVectorFeatures +import im.vector.app.features.VectorFeatures +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.runBlocking +import kotlin.reflect.KClass + +private val Context.dataStore: DataStore by preferencesDataStore(name = "debug_features") + +class DebugVectorFeatures( + context: Context, + private val vectorFeatures: DefaultVectorFeatures +) : VectorFeatures { + + private val dataStore = context.dataStore + + override fun loginVersion(): VectorFeatures.LoginVersion { + return readPreferences().getEnum() ?: vectorFeatures.loginVersion() + } + + fun > hasEnumOverride(type: KClass) = readPreferences().containsEnum(type) + + fun > overrideEnum(value: T?, type: KClass) { + if (value == null) { + updatePreferences { it.removeEnum(type) } + } else { + updatePreferences { it.putEnum(value, type) } + } + } + + private fun readPreferences() = runBlocking { dataStore.data.first() } + + private fun updatePreferences(block: (MutablePreferences) -> Unit) = runBlocking { + dataStore.edit { block(it) } + } +} + +private fun > MutablePreferences.removeEnum(type: KClass) { + remove(enumPreferencesKey(type)) +} + +private fun > Preferences.containsEnum(type: KClass) = contains(enumPreferencesKey(type)) + +private fun > MutablePreferences.putEnum(value: T, type: KClass) { + this[enumPreferencesKey(type)] = value.name +} + +private inline fun > Preferences.getEnum(): T? { + return get(enumPreferencesKey())?.let { enumValueOf(it) } +} + +private inline fun > enumPreferencesKey() = enumPreferencesKey(T::class) + +private fun > enumPreferencesKey(type: KClass) = stringPreferencesKey("enum-${type.simpleName}") diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/EnumFeatureItem.kt b/vector/src/debug/java/im/vector/app/features/debug/features/EnumFeatureItem.kt new file mode 100644 index 0000000000..5dd2f9efa9 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/features/EnumFeatureItem.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2019 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.debug.features + +import android.view.View +import android.widget.AdapterView +import android.widget.ArrayAdapter +import android.widget.Spinner +import android.widget.TextView +import com.airbnb.epoxy.EpoxyAttribute +import com.airbnb.epoxy.EpoxyModelClass +import im.vector.app.core.epoxy.VectorEpoxyHolder +import im.vector.app.core.epoxy.VectorEpoxyModel + +@EpoxyModelClass(layout = im.vector.app.R.layout.item_feature) +abstract class EnumFeatureItem : VectorEpoxyModel() { + + @EpoxyAttribute + lateinit var feature: Feature.EnumFeature<*> + + @EpoxyAttribute(EpoxyAttribute.Option.DoNotHash) + var listener: Listener? = null + + override fun bind(holder: Holder) { + super.bind(holder) + holder.label.text = feature.label + + holder.optionsSpinner.apply { + val arrayAdapter = ArrayAdapter(context, android.R.layout.simple_spinner_dropdown_item) + arrayAdapter.add("DEFAULT - ${feature.default.name}") + arrayAdapter.addAll(feature.options.map { it.name }) + adapter = arrayAdapter + + feature.selection?.let { + setSelection(feature.options.indexOf(it) + 1, false) + } + + onItemSelectedListener = object : AdapterView.OnItemSelectedListener { + override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { + when (position) { + 0 -> listener?.onOptionSelected(option = null, feature) + else -> feature.onOptionSelected(position - 1) + } + } + + override fun onNothingSelected(parent: AdapterView<*>?) { + // do nothing + } + } + } + } + + private fun > Feature.EnumFeature.onOptionSelected(selection: Int) { + listener?.onOptionSelected(options[selection], this) + } + + class Holder : VectorEpoxyHolder() { + val label by bind(im.vector.app.R.id.feature_label) + val optionsSpinner by bind(im.vector.app.R.id.feature_options) + } + + interface Listener { + fun > onOptionSelected(option: T?, feature: Feature.EnumFeature) + } +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/FeaturesController.kt b/vector/src/debug/java/im/vector/app/features/debug/features/FeaturesController.kt new file mode 100644 index 0000000000..0a05c76d69 --- /dev/null +++ b/vector/src/debug/java/im/vector/app/features/debug/features/FeaturesController.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2019 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.debug.features + +import com.airbnb.epoxy.TypedEpoxyController +import javax.inject.Inject +import kotlin.reflect.KClass + +data class FeaturesState( + val features: List +) + +sealed interface Feature { + + data class EnumFeature>( + val label: String, + val selection: T?, + val default: T, + val options: List, + val type: KClass + ) : Feature +} + +class FeaturesController @Inject constructor() : TypedEpoxyController() { + + var listener: EnumFeatureItem.Listener? = null + + override fun buildModels(data: FeaturesState?) { + if (data == null) return + + data.features.forEachIndexed { index, feature -> + when (feature) { + is Feature.EnumFeature<*> -> enumFeatureItem { + id(index) + feature(feature) + listener(this@FeaturesController.listener) + } + } + } + } +} diff --git a/vector/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsActivity.kt b/vector/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsActivity.kt index 25a068e794..a28394e57d 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsActivity.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsActivity.kt @@ -17,7 +17,6 @@ package im.vector.app.features.debug.settings import dagger.hilt.android.AndroidEntryPoint -import im.vector.app.R import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.databinding.ActivitySimpleBinding @@ -30,7 +29,7 @@ class DebugPrivateSettingsActivity : VectorBaseActivity() override fun initUiAndData() { if (isFirstCreation()) { addFragment( - R.id.simpleFragmentContainer, + views.simpleFragmentContainer, DebugPrivateSettingsFragment::class.java ) } diff --git a/vector/src/debug/res/layout/activity_debug_menu.xml b/vector/src/debug/res/layout/activity_debug_menu.xml index 5aa33c4353..8b38c17b35 100644 --- a/vector/src/debug/res/layout/activity_debug_menu.xml +++ b/vector/src/debug/res/layout/activity_debug_menu.xml @@ -20,6 +20,12 @@ android:padding="@dimen/layout_horizontal_margin" android:showDividers="middle"> +