diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 521eafb3d3..d2f3ca18d1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,7 +51,7 @@ jobs: ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }} persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' diff --git a/.github/workflows/build_enterprise.yml b/.github/workflows/build_enterprise.yml index 861efd7665..3ff2803bf8 100644 --- a/.github/workflows/build_enterprise.yml +++ b/.github/workflows/build_enterprise.yml @@ -56,7 +56,7 @@ jobs: - name: Clone submodules run: git submodule update --init --recursive - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' diff --git a/.github/workflows/generate_github_pages.yml b/.github/workflows/generate_github_pages.yml index a9bee5c09d..33fdec38a4 100644 --- a/.github/workflows/generate_github_pages.yml +++ b/.github/workflows/generate_github_pages.yml @@ -19,7 +19,7 @@ jobs: - name: ⏬ Checkout with LFS uses: nschloe/action-cached-lfs-checkout@385a8ecc719e50b8c71af6ab01a624b486b7c3bc # v1.2.5 - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' diff --git a/.github/workflows/gradle-wrapper-update.yml b/.github/workflows/gradle-wrapper-update.yml index e98c7ca9eb..8db2b5fb6b 100644 --- a/.github/workflows/gradle-wrapper-update.yml +++ b/.github/workflows/gradle-wrapper-update.yml @@ -16,9 +16,8 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + - uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 name: Use JDK 21 - if: (github.event_name == 'pull_request' && github.event.pull_request.fork == null) || github.event_name == 'workflow_dispatch' with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' diff --git a/.github/workflows/maestro-local.yml b/.github/workflows/maestro-local.yml index a3f08728e5..99a64da5f2 100644 --- a/.github/workflows/maestro-local.yml +++ b/.github/workflows/maestro-local.yml @@ -44,7 +44,7 @@ jobs: # https://github.com/actions/checkout/issues/881 ref: ${{ github.ref }} persist-credentials: false - - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + - uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 name: Use JDK 21 with: distribution: 'temurin' # See 'Supported distributions' for available options diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index f9c960fa8d..c32b277f5c 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -36,7 +36,7 @@ jobs: with: persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' diff --git a/.github/workflows/nightlyReports.yml b/.github/workflows/nightlyReports.yml index e3e1ad6d72..ff2b74a753 100644 --- a/.github/workflows/nightlyReports.yml +++ b/.github/workflows/nightlyReports.yml @@ -37,7 +37,7 @@ jobs: uses: nschloe/action-cached-lfs-checkout@385a8ecc719e50b8c71af6ab01a624b486b7c3bc # v1.2.5 - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' @@ -80,7 +80,7 @@ jobs: with: persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml index 8aac9e5794..14dc493029 100644 --- a/.github/workflows/quality.yml +++ b/.github/workflows/quality.yml @@ -69,7 +69,7 @@ jobs: with: persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' @@ -108,7 +108,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} run: git submodule update --init --recursive - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' @@ -149,7 +149,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} run: git submodule update --init --recursive - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' @@ -183,7 +183,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} run: git submodule update --init --recursive - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' @@ -228,7 +228,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} run: git submodule update --init --recursive - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' @@ -269,7 +269,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} run: git submodule update --init --recursive - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' diff --git a/.github/workflows/recordScreenshots.yml b/.github/workflows/recordScreenshots.yml index 6edb0492e4..273eac3c34 100644 --- a/.github/workflows/recordScreenshots.yml +++ b/.github/workflows/recordScreenshots.yml @@ -54,7 +54,7 @@ jobs: with: persist-credentials: false - name: ☕️ Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5d59c9530b..e6b83a1fc3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -38,7 +38,7 @@ jobs: with: persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' @@ -82,7 +82,7 @@ jobs: - name: Clone submodules run: git submodule update --init --recursive - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' @@ -126,7 +126,7 @@ jobs: with: persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' diff --git a/.github/workflows/sonar.yml b/.github/workflows/sonar.yml index ac9a69c0e8..db1cf2ecfb 100644 --- a/.github/workflows/sonar.yml +++ b/.github/workflows/sonar.yml @@ -45,7 +45,7 @@ jobs: ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.ref }} persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' diff --git a/.github/workflows/sync-localazy.yml b/.github/workflows/sync-localazy.yml index 6bd5c84283..bb8ead3aa3 100644 --- a/.github/workflows/sync-localazy.yml +++ b/.github/workflows/sync-localazy.yml @@ -17,7 +17,7 @@ jobs: with: persist-credentials: false - name: Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5f646cacf7..6edb31ce4f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -63,7 +63,7 @@ jobs: if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'element-hq/element-x-android' }} run: git submodule update --init --recursive - name: ☕️ Use JDK 21 - uses: actions/setup-java@1bcf9fb12cf4aa7d266a90ae39939e61372fe520 # v5.4.0 + uses: actions/setup-java@0f481fcb613427c0f801b606911222b5b6f3083a # v5.5.0 with: distribution: 'temurin' # See 'Supported distributions' for available options java-version: '21' diff --git a/enterprise b/enterprise index cca96c4fc2..60de13ffd7 160000 --- a/enterprise +++ b/enterprise @@ -1 +1 @@ -Subproject commit cca96c4fc24b6e2fd1ccf9265c8283ac9bf63dc0 +Subproject commit 60de13ffd7dea97fd4fec6fb6af49b5288e67ff2 diff --git a/features/enterprise/api/build.gradle.kts b/features/enterprise/api/build.gradle.kts index 1c541c5080..5e7f81e4b4 100644 --- a/features/enterprise/api/build.gradle.kts +++ b/features/enterprise/api/build.gradle.kts @@ -17,4 +17,5 @@ dependencies { implementation(projects.libraries.compound) implementation(projects.libraries.architecture) implementation(projects.libraries.matrix.api) + implementation(projects.libraries.wellknown.api) } diff --git a/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/EnterpriseService.kt b/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/EnterpriseService.kt index 92d8b9b646..7b595966d4 100644 --- a/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/EnterpriseService.kt +++ b/features/enterprise/api/src/main/kotlin/io/element/android/features/enterprise/api/EnterpriseService.kt @@ -11,6 +11,7 @@ package io.element.android.features.enterprise.api import androidx.compose.ui.graphics.Color import io.element.android.compound.colors.SemanticColorsLightDark import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.wellknown.api.ElementWellKnown import kotlinx.coroutines.flow.Flow interface EnterpriseService { @@ -41,6 +42,11 @@ interface EnterpriseService { */ fun getNoisyNotificationChannelId(sessionId: SessionId): String? + /** + * Gets the overridden Element Well-Known data if it has been set, or null if not set. + */ + fun overriddenElementWellKnown(): ElementWellKnown? + companion object { const val ANY_ACCOUNT_PROVIDER = "*" } diff --git a/features/enterprise/impl-foss/build.gradle.kts b/features/enterprise/impl-foss/build.gradle.kts index f0c63f5655..a45c8ae167 100644 --- a/features/enterprise/impl-foss/build.gradle.kts +++ b/features/enterprise/impl-foss/build.gradle.kts @@ -23,6 +23,7 @@ dependencies { api(projects.features.enterprise.api) implementation(projects.libraries.architecture) implementation(projects.libraries.matrix.api) + implementation(projects.libraries.wellknown.api) testCommonDependencies(libs) testImplementation(projects.libraries.matrix.test) diff --git a/features/enterprise/impl-foss/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseService.kt b/features/enterprise/impl-foss/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseService.kt index 6e3ed5d3cc..bc2a3f1bf1 100644 --- a/features/enterprise/impl-foss/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseService.kt +++ b/features/enterprise/impl-foss/src/main/kotlin/io/element/android/features/enterprise/impl/DefaultEnterpriseService.kt @@ -15,6 +15,7 @@ import io.element.android.compound.colors.SemanticColorsLightDark import io.element.android.features.enterprise.api.BugReportUrl import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.wellknown.api.ElementWellKnown import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf @@ -45,4 +46,6 @@ class DefaultEnterpriseService : EnterpriseService { } override fun getNoisyNotificationChannelId(sessionId: SessionId): String? = null + + override fun overriddenElementWellKnown(): ElementWellKnown? = null } diff --git a/features/enterprise/test/build.gradle.kts b/features/enterprise/test/build.gradle.kts index c37fc53de3..99dbe733dd 100644 --- a/features/enterprise/test/build.gradle.kts +++ b/features/enterprise/test/build.gradle.kts @@ -18,5 +18,6 @@ dependencies { implementation(projects.libraries.architecture) implementation(projects.libraries.compound) implementation(projects.libraries.matrix.api) + implementation(projects.libraries.wellknown.api) implementation(projects.tests.testutils) } diff --git a/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeEnterpriseService.kt b/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeEnterpriseService.kt index 805c75be6a..f6379bef30 100644 --- a/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeEnterpriseService.kt +++ b/features/enterprise/test/src/main/kotlin/io/element/android/features/enterprise/test/FakeEnterpriseService.kt @@ -13,6 +13,7 @@ import io.element.android.compound.colors.SemanticColorsLightDark import io.element.android.features.enterprise.api.BugReportUrl import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.libraries.matrix.api.core.SessionId +import io.element.android.libraries.wellknown.api.ElementWellKnown import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.simulateLongTask import kotlinx.coroutines.flow.Flow @@ -31,6 +32,7 @@ class FakeEnterpriseService( private val unifiedPushDefaultPushGatewayResult: () -> String? = { lambdaError() }, private val getNoisyNotificationChannelIdResult: (SessionId?) -> String? = { lambdaError() }, private val tweakMasUrlResult: (String, String) -> String = { _, _ -> lambdaError() }, + private val overrideWellKnownResult: () -> ElementWellKnown? = { lambdaError() }, ) : EnterpriseService { private val brandColorState = MutableStateFlow(initialBrandColor) private val semanticColorsState = MutableStateFlow(initialSemanticColors) @@ -79,4 +81,8 @@ class FakeEnterpriseService( override fun getNoisyNotificationChannelId(sessionId: SessionId): String? { return getNoisyNotificationChannelIdResult(sessionId) } + + override fun overriddenElementWellKnown(): ElementWellKnown? { + return overrideWellKnownResult() + } } diff --git a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/group/GroupHeaderView.kt b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/group/GroupHeaderView.kt index 883c591fd2..9dbeb83a3c 100644 --- a/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/group/GroupHeaderView.kt +++ b/features/messages/impl/src/main/kotlin/io/element/android/features/messages/impl/timeline/components/group/GroupHeaderView.kt @@ -26,9 +26,11 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.rotate import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.Role import androidx.compose.ui.semantics.clearAndSetSemantics import androidx.compose.ui.semantics.contentDescription +import androidx.compose.ui.semantics.stateDescription import androidx.compose.ui.unit.dp import io.element.android.compound.theme.ElementTheme import io.element.android.compound.tokens.generated.CompoundIcons @@ -37,6 +39,7 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Surface import io.element.android.libraries.designsystem.theme.components.Text +import io.element.android.libraries.ui.strings.CommonStrings private val CORNER_RADIUS = 8.dp @@ -52,6 +55,8 @@ fun GroupHeaderView( val backgroundColor = Color.Transparent val shape = RoundedCornerShape(CORNER_RADIUS) + val expandedStateDescription = stringResource(CommonStrings.a11y_state_expanded) + val collapsedStateDescription = stringResource(CommonStrings.a11y_state_collapsed) Box( modifier = modifier .fillMaxWidth() @@ -62,6 +67,7 @@ fun GroupHeaderView( ) .clearAndSetSemantics { contentDescription = text + stateDescription = if (isExpanded) expandedStateDescription else collapsedStateDescription }, contentAlignment = Alignment.Center ) { diff --git a/features/preferences/api/build.gradle.kts b/features/preferences/api/build.gradle.kts index b5a08b9435..c43259918d 100644 --- a/features/preferences/api/build.gradle.kts +++ b/features/preferences/api/build.gradle.kts @@ -6,7 +6,7 @@ * Please see LICENSE files in the repository root for full details. */ plugins { - id("io.element.android-library") + id("io.element.android-compose-library") id("kotlin-parcelize") } diff --git a/features/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/ExtraDeveloperOptionsRenderer.kt b/features/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/ExtraDeveloperOptionsRenderer.kt new file mode 100644 index 0000000000..7d7eec9d8b --- /dev/null +++ b/features/preferences/api/src/main/kotlin/io/element/android/features/preferences/api/ExtraDeveloperOptionsRenderer.kt @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.preferences.api + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier + +/** + * Component for rendering extra developer options in the preferences screen. + */ +interface ExtraDeveloperOptionsRenderer { + @Composable + fun Render(modifier: Modifier) +} diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsNode.kt index 98c7d89633..a8a8c63eed 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsNode.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsNode.kt @@ -18,6 +18,7 @@ import com.bumble.appyx.core.plugin.Plugin import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode +import io.element.android.features.preferences.api.ExtraDeveloperOptionsRenderer import io.element.android.libraries.architecture.callback import io.element.android.libraries.designsystem.showkase.getBrowserIntent import io.element.android.libraries.di.SessionScope @@ -28,6 +29,7 @@ class DeveloperSettingsNode( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val presenter: DeveloperSettingsPresenter, + private val extraDeveloperOptionsRenderer: ExtraDeveloperOptionsRenderer, ) : Node(buildContext, plugins = plugins) { interface Callback : Plugin { fun navigateToPushHistory() @@ -51,6 +53,7 @@ class DeveloperSettingsNode( onOpenShowkase = ::openShowkase, onPushHistoryClick = callback::navigateToPushHistory, onBackClick = callback::onDone, + extraOptions = { extraDeveloperOptionsRenderer.Render(Modifier) }, ) } } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt index 45009d1f71..0e5f4026ef 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/DeveloperSettingsView.kt @@ -43,6 +43,7 @@ fun DeveloperSettingsView( onPushHistoryClick: () -> Unit, onBackClick: () -> Unit, modifier: Modifier = Modifier, + extraOptions: @Composable () -> Unit = {}, ) { if (state.showLoader) { ProgressDialog() @@ -97,6 +98,9 @@ fun DeveloperSettingsView( ) } } + + extraOptions() + val cache = state.cacheSize PreferenceCategory(title = "Cache") { ListItem( diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/NoopExtraDeveloperOptionsRenderer.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/NoopExtraDeveloperOptionsRenderer.kt new file mode 100644 index 0000000000..da0540a93f --- /dev/null +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/NoopExtraDeveloperOptionsRenderer.kt @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.features.preferences.impl.developer + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesBinding +import io.element.android.features.preferences.api.ExtraDeveloperOptionsRenderer + +@ContributesBinding(AppScope::class) +class NoopExtraDeveloperOptionsRenderer : ExtraDeveloperOptionsRenderer { + @Composable + override fun Render(modifier: Modifier) { + // No-op + } +} diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/appsettings/AppDeveloperSettingsNode.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/appsettings/AppDeveloperSettingsNode.kt index ae5e710d4b..89ef240a95 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/appsettings/AppDeveloperSettingsNode.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/appsettings/AppDeveloperSettingsNode.kt @@ -18,6 +18,7 @@ import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.Assisted import dev.zacsweers.metro.AssistedInject import io.element.android.annotations.ContributesNode +import io.element.android.features.preferences.api.ExtraDeveloperOptionsRenderer import io.element.android.features.preferences.api.PreferencesEntryPoint import io.element.android.libraries.architecture.callback import io.element.android.libraries.designsystem.showkase.getBrowserIntent @@ -28,6 +29,7 @@ class AppDeveloperSettingsNode( @Assisted buildContext: BuildContext, @Assisted plugins: List, private val presenter: AppDeveloperSettingsPresenter, + private val extraDeveloperOptionsRenderer: ExtraDeveloperOptionsRenderer, ) : Node(buildContext, plugins = plugins) { private val callback: PreferencesEntryPoint.DeveloperSettingsCallback = callback() @@ -45,6 +47,7 @@ class AppDeveloperSettingsNode( modifier = modifier, onOpenShowkase = ::openShowkase, onBackClick = callback::onDone, + extraOptions = { extraDeveloperOptionsRenderer.Render(Modifier) }, ) } } diff --git a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/appsettings/AppDeveloperSettingsPage.kt b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/appsettings/AppDeveloperSettingsPage.kt index 81e1304e7b..d7d62aa325 100644 --- a/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/appsettings/AppDeveloperSettingsPage.kt +++ b/features/preferences/impl/src/main/kotlin/io/element/android/features/preferences/impl/developer/appsettings/AppDeveloperSettingsPage.kt @@ -24,6 +24,7 @@ fun AppDeveloperSettingsPage( onOpenShowkase: () -> Unit, onBackClick: () -> Unit, modifier: Modifier = Modifier, + extraOptions: @Composable () -> Unit = {}, ) { BackHandler( onBack = onBackClick, @@ -40,6 +41,7 @@ fun AppDeveloperSettingsPage( onOpenShowkase = onOpenShowkase, modifier = Modifier.padding(top = 8.dp) ) + extraOptions() } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 07f6098a34..e6326709bd 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ # Project android_gradle_plugin = "9.2.1" # When updating this, please also update the version in the file ./idea/kotlinc.xml -kotlin = "2.4.0" +kotlin = "2.4.10" kotlinpoet = "2.3.0" ksp = "2.3.10" firebaseAppDistribution = "5.3.0" @@ -32,7 +32,7 @@ accompanist = "0.37.3" # Test test_core = "1.7.0" -roborazzi = "1.67.0" +roborazzi = "1.68.0" # Jetbrain datetime = "0.8.0" @@ -51,10 +51,10 @@ telephoto = "0.19.0" haze = "1.7.2" # Dependency analysis -dependencyAnalysis = "3.16.0" +dependencyAnalysis = "3.16.1" # DI -metro = "1.3.0" +metro = "1.3.2" # Auto service autoservice = "1.1.1" @@ -84,7 +84,7 @@ kotlinpoet-ksp = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlin kover_gradle_plugin = { module = "org.jetbrains.kotlinx:kover-gradle-plugin", version.ref = "kover" } ksp_gradle_plugin = { module = "com.google.devtools.ksp:com.google.devtools.ksp.gradle.plugin", version.ref = "ksp" } # https://firebase.google.com/docs/android/setup#available-libraries -google_firebase_bom = "com.google.firebase:firebase-bom:34.15.0" +google_firebase_bom = "com.google.firebase:firebase-bom:34.16.0" firebase_appdistribution_gradle = { module = "com.google.firebase:firebase-appdistribution-gradle", version.ref = "firebaseAppDistribution" } autonomousapps_dependencyanalysis_plugin = { module = "com.autonomousapps:dependency-analysis-gradle-plugin", version.ref = "dependencyAnalysis" } ksp_plugin = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" } @@ -242,7 +242,7 @@ sigpwned_emoji4j = "com.sigpwned:emoji4j-core:16.0.0" metro_runtime = { module = "dev.zacsweers.metro:runtime", version.ref = "metro" } # Element Call -element_call_embedded = "io.element.android:element-call-embedded:0.20.3" +element_call_embedded = "io.element.android:element-call-embedded:0.22.0" # Auto services google_autoservice = { module = "com.google.auto.service:auto-service", version.ref = "autoservice" } diff --git a/libraries/ui-strings/src/main/res/values/temporary.xml b/libraries/ui-strings/src/main/res/values/temporary.xml index c0573cc6c2..2526f254d3 100644 --- a/libraries/ui-strings/src/main/res/values/temporary.xml +++ b/libraries/ui-strings/src/main/res/values/temporary.xml @@ -8,6 +8,8 @@ "Mark as read" "Jump to first unread message" + "Expanded" + "Collapsed" Allow access to local network Your homeserver is on your local network. To connect, Element needs permission to reach other devices on this network. Active diff --git a/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/ElementWellKnownParser.kt b/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/ElementWellKnownParser.kt new file mode 100644 index 0000000000..db0a323a5f --- /dev/null +++ b/libraries/wellknown/api/src/main/kotlin/io/element/android/libraries/wellknown/api/ElementWellKnownParser.kt @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.wellknown.api + +fun interface ElementWellKnownParser { + fun parse(json: String): Result +} diff --git a/libraries/wellknown/impl/build.gradle.kts b/libraries/wellknown/impl/build.gradle.kts index 1e2c4d7d61..6e7cc5ef1c 100644 --- a/libraries/wellknown/impl/build.gradle.kts +++ b/libraries/wellknown/impl/build.gradle.kts @@ -34,6 +34,7 @@ dependencies { implementation(projects.libraries.matrix.api) implementation(projects.libraries.network) implementation(projects.libraries.cachestore.api) + implementation(projects.features.enterprise.api) implementation(projects.services.toolbox.api) testCommonDependencies(libs) @@ -41,5 +42,6 @@ dependencies { testImplementation(projects.libraries.cachestore.test) testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.wellknown.test) + testImplementation(projects.features.enterprise.test) testImplementation(projects.services.toolbox.test) } diff --git a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultElementWellKnownParser.kt b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultElementWellKnownParser.kt new file mode 100644 index 0000000000..4cf72366e0 --- /dev/null +++ b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultElementWellKnownParser.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2026 Element Creations Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial. + * Please see LICENSE files in the repository root for full details. + */ + +package io.element.android.libraries.wellknown.impl + +import dev.zacsweers.metro.AppScope +import dev.zacsweers.metro.ContributesBinding +import io.element.android.libraries.androidutils.json.JsonProvider +import io.element.android.libraries.core.extensions.runCatchingExceptions +import io.element.android.libraries.wellknown.api.ElementWellKnown +import io.element.android.libraries.wellknown.api.ElementWellKnownParser + +@ContributesBinding(AppScope::class) +class DefaultElementWellKnownParser( + private val jsonProvider: JsonProvider, +) : ElementWellKnownParser { + override fun parse(json: String): Result { + return runCatchingExceptions { + val decoder = jsonProvider() + decoder.decodeFromString(json).map() + } + } +} diff --git a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt index 3446cdcb65..66654dd228 100644 --- a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt +++ b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetriever.kt @@ -9,13 +9,14 @@ package io.element.android.libraries.wellknown.impl import dev.zacsweers.metro.ContributesBinding -import io.element.android.libraries.androidutils.json.JsonProvider +import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.libraries.core.extensions.mapCatchingExceptions import io.element.android.libraries.di.SessionScope import io.element.android.libraries.di.annotations.SessionCoroutineScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.exception.ClientException import io.element.android.libraries.wellknown.api.ElementWellKnown +import io.element.android.libraries.wellknown.api.ElementWellKnownParser import io.element.android.libraries.wellknown.api.ElementWellknownStore import io.element.android.libraries.wellknown.api.SessionWellknownRetriever import io.element.android.libraries.wellknown.api.WellknownRetrieverResult @@ -26,14 +27,20 @@ import timber.log.Timber @ContributesBinding(SessionScope::class) class DefaultSessionWellknownRetriever( private val matrixClient: MatrixClient, - private val json: JsonProvider, @SessionCoroutineScope private val sessionCoroutineScope: CoroutineScope, private val elementWellknownStore: ElementWellknownStore, + private val elementWellKnownParser: ElementWellKnownParser, + private val enterpriseService: EnterpriseService, ) : SessionWellknownRetriever { private val domain by lazy { matrixClient.userIdServerName() } override suspend fun getElementWellKnown(): WellknownRetrieverResult { + val overriddenElementWellKnown = enterpriseService.overriddenElementWellKnown() + if (overriddenElementWellKnown != null) { + return WellknownRetrieverResult.Success(overriddenElementWellKnown) + } + val cacheData = elementWellknownStore.get(domain) return when (cacheData) { is WellknownRetrieverResult.Success -> { @@ -69,7 +76,7 @@ class DefaultSessionWellknownRetriever( .getUrl(url) .mapCatchingExceptions { val data = String(it) - val parsed = json().decodeFromString(data).map() + val parsed = elementWellKnownParser.parse(data).getOrThrow() // Also store in cache, if valid elementWellknownStore.update(domain, data) .onFailure { exception -> diff --git a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellKnownStore.kt b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellKnownStore.kt index c3cfcc5019..50c8caeafc 100644 --- a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellKnownStore.kt +++ b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellKnownStore.kt @@ -9,11 +9,11 @@ package io.element.android.libraries.wellknown.impl import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding -import io.element.android.libraries.androidutils.json.JsonProvider import io.element.android.libraries.cachestore.api.CacheData import io.element.android.libraries.cachestore.api.CacheStore import io.element.android.libraries.core.extensions.runCatchingExceptions import io.element.android.libraries.wellknown.api.ElementWellKnown +import io.element.android.libraries.wellknown.api.ElementWellKnownParser import io.element.android.libraries.wellknown.api.ElementWellknownStore import io.element.android.libraries.wellknown.api.WellknownRetrieverResult import io.element.android.services.toolbox.api.systemclock.SystemClock @@ -21,14 +21,14 @@ import io.element.android.services.toolbox.api.systemclock.SystemClock @ContributesBinding(AppScope::class) class DefaultWellKnownStore( private val cacheStore: CacheStore, - private val json: JsonProvider, + private val elementWellKnownParser: ElementWellKnownParser, private val systemClock: SystemClock, ) : ElementWellknownStore { override suspend fun get(domain: String): WellknownRetrieverResult { return runCatchingExceptions { val cachedData = cacheStore.getData(key(domain)) if (cachedData != null) { - val data = json().decodeFromString(cachedData.value).map() + val data = elementWellKnownParser.parse(cachedData.value).getOrThrow() if (systemClock.epochMillis() > cachedData.updatedAt + CACHE_VALIDITY_MILLIS) { WellknownRetrieverResult.Outdated(data) } else { diff --git a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetriever.kt b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetriever.kt index a43584d542..10f668cfb0 100644 --- a/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetriever.kt +++ b/libraries/wellknown/impl/src/main/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetriever.kt @@ -10,6 +10,7 @@ package io.element.android.libraries.wellknown.impl import dev.zacsweers.metro.AppScope import dev.zacsweers.metro.ContributesBinding +import io.element.android.features.enterprise.api.EnterpriseService import io.element.android.libraries.androidutils.json.JsonProvider import io.element.android.libraries.core.extensions.runCatchingExceptions import io.element.android.libraries.core.uri.ensureProtocol @@ -28,8 +29,14 @@ class DefaultWellknownRetriever( private val retrofitFactory: RetrofitFactory, private val elementWellknownStore: ElementWellknownStore, private val jsonProvider: JsonProvider, + private val enterpriseService: EnterpriseService, ) : WellknownRetriever { override suspend fun getElementWellKnown(baseUrl: String): WellknownRetrieverResult { + val overriddenElementWellKnown = enterpriseService.overriddenElementWellKnown() + if (overriddenElementWellKnown != null) { + return WellknownRetrieverResult.Success(overriddenElementWellKnown) + } + val domain = URL(baseUrl).host return buildWellknownApi(baseUrl) .map { wellknownApi -> diff --git a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt index 6a2a12774b..f54cf919d9 100644 --- a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt +++ b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultSessionWellknownRetrieverTest.kt @@ -11,15 +11,16 @@ package io.element.android.libraries.wellknown.impl import com.google.common.truth.Truth.assertThat +import io.element.android.features.enterprise.test.FakeEnterpriseService import io.element.android.features.wellknown.test.FakeElementWellknownStore import io.element.android.features.wellknown.test.anElementWellKnown import io.element.android.libraries.androidutils.json.DefaultJsonProvider -import io.element.android.libraries.androidutils.json.JsonProvider import io.element.android.libraries.matrix.api.exception.ClientException import io.element.android.libraries.matrix.test.AN_EXCEPTION import io.element.android.libraries.matrix.test.FakeMatrixClient import io.element.android.libraries.wellknown.api.CustomRecoveryPassphrase import io.element.android.libraries.wellknown.api.ElementWellKnown +import io.element.android.libraries.wellknown.api.ElementWellKnownParser import io.element.android.libraries.wellknown.api.WellknownRetrieverResult import io.element.android.tests.testutils.lambda.lambdaError import io.element.android.tests.testutils.lambda.lambdaRecorder @@ -276,7 +277,7 @@ class DefaultSessionWellknownRetrieverTest { Result.success("{}".toByteArray()) }, cacheStore = cacheStore, - jsonProvider = JsonProvider { error("Failed to parse JSON") } + elementWellKnownParser = { Result.failure(IllegalStateException("Failed to parse JSON")) } ) assertThat(sut.getElementWellKnown()).isInstanceOf(WellknownRetrieverResult.Error::class.java) // Ensure that the cache is deleted after the failure to parse it @@ -320,20 +321,43 @@ class DefaultSessionWellknownRetrieverTest { ) } + @Test + fun `get element wellknown was overridden`() = runTest { + val getLambda = lambdaRecorder> { Result.failure(IllegalStateException("BOOM")) } + val wellKnown = anElementWellKnown() + + val sut = createDefaultSessionWellknownRetriever( + getUrlLambda = getLambda, + enterpriseService = FakeEnterpriseService( + overrideWellKnownResult = { wellKnown } + ) + ) + + // The overridden value is returned + assertThat(sut.getElementWellKnown()).isEqualTo( + WellknownRetrieverResult.Success(wellKnown) + ) + + // And the endpoint is never hit + getLambda.assertions().isNeverCalled() + } + private fun parsedWellKnownContent() = DefaultJsonProvider().invoke().decodeFromString(WELLKNOWN_CONTENT).map() private fun TestScope.createDefaultSessionWellknownRetriever( cacheStore: FakeElementWellknownStore = FakeElementWellknownStore(), getUrlLambda: (String) -> Result, - jsonProvider: JsonProvider = DefaultJsonProvider(), + elementWellKnownParser: ElementWellKnownParser = DefaultElementWellKnownParser(DefaultJsonProvider()), + enterpriseService: FakeEnterpriseService = FakeEnterpriseService(overrideWellKnownResult = { null }), ) = DefaultSessionWellknownRetriever( matrixClient = FakeMatrixClient( userIdServerNameLambda = { "user.domain.org" }, getUrlLambda = getUrlLambda, ), - json = jsonProvider, sessionCoroutineScope = backgroundScope, elementWellknownStore = cacheStore, + elementWellKnownParser = elementWellKnownParser, + enterpriseService = enterpriseService, ) companion object { diff --git a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellKnownStoreTest.kt b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellKnownStoreTest.kt index 11ec521fed..b53041faf8 100644 --- a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellKnownStoreTest.kt +++ b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellKnownStoreTest.kt @@ -13,6 +13,7 @@ import io.element.android.libraries.androidutils.json.DefaultJsonProvider import io.element.android.libraries.cachestore.api.CacheData import io.element.android.libraries.sessionstorage.test.InMemoryCacheStore import io.element.android.libraries.wellknown.api.CustomRecoveryPassphrase +import io.element.android.libraries.wellknown.api.ElementWellKnownParser import io.element.android.libraries.wellknown.api.WellknownRetrieverResult import io.element.android.services.toolbox.test.systemclock.A_FAKE_TIMESTAMP import io.element.android.services.toolbox.test.systemclock.FakeSystemClock @@ -150,9 +151,10 @@ class DefaultWellKnownStoreTest { private fun createDefaultWellKnownStore( cacheStore: InMemoryCacheStore = InMemoryCacheStore(), systemClock: FakeSystemClock = FakeSystemClock(), + elementWellKnownParser: ElementWellKnownParser = DefaultElementWellKnownParser(jsonProvider), ) = DefaultWellKnownStore( cacheStore = cacheStore, - json = jsonProvider, systemClock = systemClock, + elementWellKnownParser = elementWellKnownParser, ) } diff --git a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetrieverTest.kt b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetrieverTest.kt index 3ee5b2b91f..96ae4c2b17 100644 --- a/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetrieverTest.kt +++ b/libraries/wellknown/impl/src/test/kotlin/io/element/android/libraries/wellknown/impl/DefaultWellknownRetrieverTest.kt @@ -11,6 +11,7 @@ package io.element.android.libraries.wellknown.impl import com.google.common.truth.Truth.assertThat +import io.element.android.features.enterprise.test.FakeEnterpriseService import io.element.android.features.wellknown.test.FakeElementWellknownStore import io.element.android.features.wellknown.test.anElementWellKnown import io.element.android.libraries.androidutils.json.DefaultJsonProvider @@ -19,6 +20,7 @@ import io.element.android.libraries.network.RetrofitFactory import io.element.android.libraries.wellknown.api.CustomRecoveryPassphrase import io.element.android.libraries.wellknown.api.ElementWellKnown import io.element.android.libraries.wellknown.api.WellknownRetrieverResult +import io.element.android.tests.testutils.lambda.lambdaRecorder import io.mockk.every import io.mockk.mockk import io.mockk.verify @@ -236,6 +238,27 @@ class DefaultWellknownRetrieverTest { assertThat(cacheStore.get(WELLKNOWN_URL)).isEqualTo(WellknownRetrieverResult.NotFound) } + @Test + fun `get element wellknown was overridden`() = runTest { + val getLambda = lambdaRecorder { mockCall() } + val wellKnown = anElementWellKnown() + + val sut = createDefaultWellknownRetriever( + callFactory = getLambda, + enterpriseService = FakeEnterpriseService( + overrideWellKnownResult = { wellKnown } + ) + ) + + // The overridden value is returned + assertThat(sut.getElementWellKnown(WELLKNOWN_URL)).isEqualTo( + WellknownRetrieverResult.Success(wellKnown) + ) + + // And the endpoint is never hit + getLambda.assertions().isNeverCalled() + } + private fun defaultResponse( body: String = WELLKNOWN_CONTENT, status: Int = 200, @@ -251,6 +274,7 @@ class DefaultWellknownRetrieverTest { callFactory: Call.Factory = Call.Factory { _: Request -> mockCall(defaultResponse()) }, cacheStore: FakeElementWellknownStore = FakeElementWellknownStore(), jsonProvider: JsonProvider = DefaultJsonProvider(), + enterpriseService: FakeEnterpriseService = FakeEnterpriseService(overrideWellKnownResult = { null }), ) = DefaultWellknownRetriever( retrofitFactory = RetrofitFactory( callFactory = { callFactory }, @@ -258,6 +282,7 @@ class DefaultWellknownRetrieverTest { ), jsonProvider = jsonProvider, elementWellknownStore = cacheStore, + enterpriseService = enterpriseService, ) companion object { diff --git a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt index 97def07130..914941d766 100644 --- a/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt +++ b/tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt @@ -88,6 +88,8 @@ class KonsistPreviewTest { "BackgroundVerticalGradientPreview", "ColorAliasesPreview", "EmojiItemWithPopupPreview", + "EnterpriseExtraDeveloperOptionsRendererBottomSheetPreview", + "EnterpriseExtraDeveloperOptionsRendererListItemPreview", "FocusedEventPreview", "GradientFloatingActionButtonCircleShapePreview", "HeaderFooterPageScrollablePreview", diff --git a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesViewA11y_en.png b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesViewA11y_en.png index b2b3f0b813..f47e74ab7b 100644 --- a/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesViewA11y_en.png +++ b/tests/uitests/src/test/snapshots/images/features.messages.impl_MessagesViewA11y_en.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:02c4892eaa7d27c867266c428374b64e5915ec50ddcdf8b1d532e1cbc6f56462 -size 130436 +oid sha256:5823ae9a382421609200d569799505706180b94c6923f315caa81f8767ac58f8 +size 131340