Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions features/login/impl/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ setupDependencyInjection()
dependencies {
implementation(projects.appconfig)
implementation(projects.features.enterprise.api)
implementation(projects.features.preferences.api)
implementation(projects.features.rageshake.api)
implementation(projects.libraries.core)
implementation(projects.libraries.androidutils)
Expand All @@ -79,6 +80,7 @@ dependencies {
testCommonDependencies(libs, true)
testImplementation(projects.features.login.test)
testImplementation(projects.features.enterprise.test)
testImplementation(projects.features.preferences.test)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.oidc.test)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import io.element.android.features.login.impl.screens.createaccount.CreateAccoun
import io.element.android.features.login.impl.screens.loginpassword.LoginPasswordNode
import io.element.android.features.login.impl.screens.onboarding.OnBoardingNode
import io.element.android.features.login.impl.screens.searchaccountprovider.SearchAccountProviderNode
import io.element.android.features.preferences.api.PreferencesEntryPoint
import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTab
import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.BaseFlowNode
Expand All @@ -67,6 +68,7 @@ class LoginFlowNode(
@AppCoroutineScope
private val appCoroutineScope: CoroutineScope,
private val elementClassicConnection: ElementClassicConnection,
private val preferencesEntryPoint: PreferencesEntryPoint,
) : BaseFlowNode<LoginFlowNode.NavTarget>(
backstack = BackStack(
initialElement = NavTarget.CheckClassicFlow,
Expand Down Expand Up @@ -117,6 +119,9 @@ class LoginFlowNode(
@Parcelize
data object QrCode : NavTarget

@Parcelize
data object AppDeveloperSettings : NavTarget

@Parcelize
data class ConfirmAccountProvider(
val isAccountCreation: Boolean,
Expand Down Expand Up @@ -200,6 +205,10 @@ class LoginFlowNode(
backstack.push(NavTarget.CreateAccount(url))
}

override fun navigateToDeveloperSettings() {
backstack.push(NavTarget.AppDeveloperSettings)
}

override fun navigateToLoginPassword() {
backstack.push(NavTarget.LoginPassword())
}
Expand All @@ -220,6 +229,18 @@ class LoginFlowNode(
)
createNode<OnBoardingNode>(buildContext, listOf(callback, inputs))
}
NavTarget.AppDeveloperSettings -> {
val callback = object : PreferencesEntryPoint.DeveloperSettingsCallback {
override fun onDone() {
backstack.pop()
}
}
preferencesEntryPoint.createAppDeveloperSettingsNode(
parentNode = this,
buildContext = buildContext,
callback = callback,
)
}
NavTarget.ChooseAccountProvider -> {
val callback = object : ChooseAccountProviderNode.Callback {
override fun navigateToOidc(oidcDetails: OidcDetails) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class OnBoardingNode(
fun navigateToLoginPassword()
fun navigateToOidc(oidcDetails: OidcDetails)
fun navigateToCreateAccount(url: String)
fun navigateToDeveloperSettings()
fun onDone()
}

Expand Down Expand Up @@ -75,6 +76,7 @@ class OnBoardingNode(
onLearnMoreClick = { openLearnMorePage(context) },
onCreateAccountContinue = callback::navigateToCreateAccount,
onBackClick = callback::onDone,
onDeveloperSettingsClick = callback::navigateToDeveloperSettings,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import io.element.android.features.login.impl.login.LoginHelper
import io.element.android.features.rageshake.api.RageshakeFeatureAvailability
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.core.meta.BuildMeta
import io.element.android.libraries.core.meta.BuildType
import io.element.android.libraries.sessionstorage.api.SessionStore
import io.element.android.libraries.ui.utils.MultipleTapToUnlock
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -125,6 +126,7 @@ class OnBoardingPresenter(
return OnBoardingState(
isAddingAccount = isAddingAccount,
showBackButton = params.showBackButton,
showDeveloperSettings = buildMeta.buildType != BuildType.RELEASE,
productionApplicationName = buildMeta.productionApplicationName,
defaultAccountProvider = defaultAccountProvider,
mustChooseAccountProvider = mustChooseAccountProvider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import io.element.android.libraries.architecture.AsyncData
data class OnBoardingState(
val isAddingAccount: Boolean,
val showBackButton: Boolean,
val showDeveloperSettings: Boolean,
val productionApplicationName: String,
val defaultAccountProvider: String?,
val mustChooseAccountProvider: Boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ open class OnBoardingStateProvider : PreviewParameterProvider<OnBoardingState> {
),
anOnBoardingState(
showBackButton = true,
showDeveloperSettings = true,
),
)
}

fun anOnBoardingState(
isAddingAccount: Boolean = false,
showBackButton: Boolean = false,
showDeveloperSettings: Boolean = false,
productionApplicationName: String = "Element",
defaultAccountProvider: String? = null,
mustChooseAccountProvider: Boolean = false,
Expand All @@ -52,6 +54,7 @@ fun anOnBoardingState(
) = OnBoardingState(
isAddingAccount = isAddingAccount,
showBackButton = showBackButton,
showDeveloperSettings = showDeveloperSettings,
productionApplicationName = productionApplicationName,
defaultAccountProvider = defaultAccountProvider,
mustChooseAccountProvider = mustChooseAccountProvider,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import io.element.android.libraries.ui.strings.CommonStrings
fun OnBoardingView(
state: OnBoardingState,
onBackClick: () -> Unit,
onDeveloperSettingsClick: () -> Unit,
onSignInWithQrCode: () -> Unit,
onSignIn: (mustChooseAccountProvider: Boolean) -> Unit,
onCreateAccount: () -> Unit,
Expand Down Expand Up @@ -110,6 +111,7 @@ fun OnBoardingView(
loginView = loginView,
buttons = buttons,
onBackClick = onBackClick,
onDeveloperSettingsClick = onDeveloperSettingsClick,
)
}
}
Expand All @@ -120,6 +122,7 @@ private fun AddFirstAccountScaffold(
loginView: @Composable () -> Unit,
buttons: @Composable () -> Unit,
onBackClick: () -> Unit,
onDeveloperSettingsClick: () -> Unit,
modifier: Modifier = Modifier,
) {
OnBoardingPage(
Expand All @@ -136,6 +139,18 @@ private fun AddFirstAccountScaffold(
} else {
OnBoardingContent(state = state)
}
if (state.showDeveloperSettings) {
IconButton(
onClick = onDeveloperSettingsClick,
modifier = Modifier
.align(Alignment.TopStart),
) {
Icon(
imageVector = CompoundIcons.SettingsSolid(),
contentDescription = stringResource(CommonStrings.common_developer_options),
)
}
}
if (state.showBackButton) {
// Add icon button to "navigate back"
IconButton(
Expand Down Expand Up @@ -334,6 +349,7 @@ internal fun OnBoardingViewPreview(
OnBoardingView(
state = state,
onBackClick = {},
onDeveloperSettingsClick = {},
onSignInWithQrCode = {},
onSignIn = {},
onCreateAccount = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import io.element.android.features.enterprise.test.FakeEnterpriseService
import io.element.android.features.login.api.LoginEntryPoint
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
import io.element.android.features.login.impl.classic.FakeElementClassicConnection
import io.element.android.features.preferences.test.FakePreferencesEntryPoint
import io.element.android.libraries.oidc.test.customtab.FakeOidcActionFlow
import io.element.android.tests.testutils.lambda.lambdaError
import io.element.android.tests.testutils.node.TestParentNode
Expand All @@ -41,6 +42,7 @@ class DefaultLoginEntryPointTest {
oidcActionFlow = FakeOidcActionFlow(),
appCoroutineScope = backgroundScope,
elementClassicConnection = FakeElementClassicConnection(),
preferencesEntryPoint = FakePreferencesEntryPoint(),
)
}
val callback = object : LoginEntryPoint.Callback {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ package io.element.android.features.login.impl.screens.onboarding
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import com.google.testing.junit.testparameterinjector.KotlinTestParameters.namedTestValues
Expand Down Expand Up @@ -46,11 +47,15 @@ class OnboardingViewTest {
rule.setOnboardingView(
state = anOnBoardingState(
canCreateAccount = true,
showDeveloperSettings = false,
eventSink = eventSink,
),
onCreateAccount = callback,
)
rule.clickOn(R.string.screen_onboarding_sign_up)
// Developer settings should not be shown
val developerSettingsText = rule.activity.getString(CommonStrings.common_developer_options)
rule.onNodeWithContentDescription(developerSettingsText).assertDoesNotExist()
}
}

Expand Down Expand Up @@ -172,6 +177,22 @@ class OnboardingViewTest {
}
}

@Test
fun `clicking on settings calls the developer settings callback`() {
val eventSink = EventsRecorder<OnBoardingEvents>(expectEvents = false)
ensureCalledOnce { callback ->
rule.setOnboardingView(
state = anOnBoardingState(
showDeveloperSettings = true,
eventSink = eventSink,
),
onDeveloperSettingsClick = callback,
)
val text = rule.activity.getString(CommonStrings.common_developer_options)
rule.onNodeWithContentDescription(text).performClick()
}
}

@Test
fun `cannot report a problem when the feature is disabled`() {
val eventSink = EventsRecorder<OnBoardingEvents>(expectEvents = false)
Expand Down Expand Up @@ -235,6 +256,7 @@ class OnboardingViewTest {
private fun <R : TestRule> AndroidComposeTestRule<R, ComponentActivity>.setOnboardingView(
state: OnBoardingState,
onBackClick: () -> Unit = EnsureNeverCalled(),
onDeveloperSettingsClick: () -> Unit = EnsureNeverCalled(),
onSignInWithQrCode: () -> Unit = EnsureNeverCalled(),
onSignIn: (Boolean) -> Unit = EnsureNeverCalledWithParam(),
onCreateAccount: () -> Unit = EnsureNeverCalled(),
Expand All @@ -248,6 +270,7 @@ class OnboardingViewTest {
OnBoardingView(
state = state,
onBackClick = onBackClick,
onDeveloperSettingsClick = onDeveloperSettingsClick,
onSignInWithQrCode = onSignInWithQrCode,
onSignIn = onSignIn,
onCreateAccount = onCreateAccount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,14 @@ interface PreferencesEntryPoint : FeatureEntryPoint {
fun navigateToRoomNotificationSettings(roomId: RoomId)
fun navigateToEvent(roomId: RoomId, eventId: EventId)
}

fun createAppDeveloperSettingsNode(
parentNode: Node,
buildContext: BuildContext,
callback: DeveloperSettingsCallback,
): Node

interface DeveloperSettingsCallback : Plugin {
fun onDone()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import com.bumble.appyx.core.node.Node
import dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.ContributesBinding
import io.element.android.features.preferences.api.PreferencesEntryPoint
import io.element.android.features.preferences.impl.developer.appsettings.AppDeveloperSettingsNode
import io.element.android.libraries.architecture.createNode

@ContributesBinding(AppScope::class)
Expand All @@ -28,6 +29,17 @@ class DefaultPreferencesEntryPoint : PreferencesEntryPoint {
plugins = listOf(params, callback)
)
}

override fun createAppDeveloperSettingsNode(
parentNode: Node,
buildContext: BuildContext,
callback: PreferencesEntryPoint.DeveloperSettingsCallback,
): Node {
return parentNode.createNode<AppDeveloperSettingsNode>(
buildContext = buildContext,
plugins = listOf(callback),
)
}
}

internal fun PreferencesEntryPoint.InitialTarget.toNavTarget() = when (this) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,8 @@
package io.element.android.features.preferences.impl.developer

import androidx.compose.ui.graphics.Color
import io.element.android.features.preferences.impl.developer.tracing.LogLevelItem
import io.element.android.libraries.featureflag.ui.model.FeatureUiModel
import io.element.android.libraries.matrix.api.tracing.TraceLogPack

sealed interface DeveloperSettingsEvents {
data class UpdateEnabledFeature(val feature: FeatureUiModel, val isEnabled: Boolean) : DeveloperSettingsEvents
data class SetCustomElementCallBaseUrl(val baseUrl: String?) : DeveloperSettingsEvents
data class SetTracingLogLevel(val logLevel: LogLevelItem) : DeveloperSettingsEvents
data class ToggleTracingLogPack(val logPack: TraceLogPack, val enabled: Boolean) : DeveloperSettingsEvents
data class SetShowColorPicker(val show: Boolean) : DeveloperSettingsEvents
data class ChangeBrandColor(val color: Color?) : DeveloperSettingsEvents
data object ClearCache : DeveloperSettingsEvents
Expand Down
Loading
Loading