Browse Source

Merge pull request #180 from vector-im/feature/fre/create_room_module

Start new chat screen (UI)
misc/jme/add-logging-to-state-machine
Florian Renaud 2 years ago committed by GitHub
parent
commit
bef74438c0
  1. 11
      app/src/main/kotlin/io/element/android/x/node/LoggedInFlowNode.kt
  2. 1
      changelog.d/94.wip
  3. 1
      features/createroom/.gitignore
  4. 56
      features/createroom/build.gradle.kts
  5. 0
      features/createroom/consumer-rules.pro
  6. 21
      features/createroom/proguard-rules.pro
  7. 20
      features/createroom/src/main/AndroidManifest.xml
  8. 62
      features/createroom/src/main/kotlin/io/element/android/features/createroom/CreateRoomFlowNode.kt
  9. 22
      features/createroom/src/main/kotlin/io/element/android/features/createroom/root/CreateRoomRootEvents.kt
  10. 52
      features/createroom/src/main/kotlin/io/element/android/features/createroom/root/CreateRoomRootNode.kt
  11. 39
      features/createroom/src/main/kotlin/io/element/android/features/createroom/root/CreateRoomRootPresenter.kt
  12. 236
      features/createroom/src/main/kotlin/io/element/android/features/createroom/root/CreateRoomRootScreen.kt
  13. 23
      features/createroom/src/main/kotlin/io/element/android/features/createroom/root/CreateRoomRootState.kt
  14. 31
      features/createroom/src/main/kotlin/io/element/android/features/createroom/root/CreateRoomRootStateProvider.kt
  15. 53
      features/createroom/src/test/kotlin/io/element/android/features/createroom/root/CreateRoomRootPresenterTests.kt
  16. 6
      features/login/src/main/kotlin/io/element/android/features/login/changeserver/ChangeServerView.kt
  17. 6
      features/login/src/main/kotlin/io/element/android/features/login/root/LoginRootScreen.kt
  18. 8
      features/roomlist/src/main/kotlin/io/element/android/features/roomlist/RoomListNode.kt
  19. 20
      features/roomlist/src/main/kotlin/io/element/android/features/roomlist/RoomListView.kt
  20. 20
      libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/button/BackButton.kt
  21. 68
      libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/CenterAlignedTopAppBar.kt
  22. 91
      libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/DockedSearchBar.kt
  23. 80
      libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/TextButton.kt
  24. 26
      libraries/designsystem/src/main/res/drawable/ic_edit_square.xml
  25. 25
      libraries/designsystem/src/main/res/drawable/ic_groups.xml
  26. 25
      libraries/designsystem/src/main/res/drawable/ic_share.xml
  27. 11
      libraries/ui-strings/src/main/res/values/strings_eax.xml
  28. 5
      plugins/src/main/kotlin/extension/DependencyHandleScope.kt
  29. 1
      settings.gradle.kts
  30. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.root_null_DefaultGroup_CreateRoomRootViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png
  31. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.root_null_DefaultGroup_CreateRoomRootViewLightPreview_0_null_0,NEXUS_5,1.0,en].png
  32. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_2,NEXUS_5,1.0,en].png
  33. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_3,NEXUS_5,1.0,en].png
  34. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_4,NEXUS_5,1.0,en].png
  35. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_5,NEXUS_5,1.0,en].png
  36. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_2,NEXUS_5,1.0,en].png
  37. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_3,NEXUS_5,1.0,en].png
  38. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_4,NEXUS_5,1.0,en].png
  39. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_5,NEXUS_5,1.0,en].png
  40. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomlist.components_null_DefaultGroup_DefaultRoomListTopBarDarkPreview_0_null,NEXUS_5,1.0,en].png
  41. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomlist.components_null_DefaultGroup_DefaultRoomListTopBarLightPreview_0_null,NEXUS_5,1.0,en].png
  42. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomlist.components_null_DefaultGroup_SearchRoomListTopBarDarkPreview_0_null,NEXUS_5,1.0,en].png
  43. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomlist.components_null_DefaultGroup_SearchRoomListTopBarLightPreview_0_null,NEXUS_5,1.0,en].png
  44. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomlist_null_DefaultGroup_RoomListViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png
  45. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomlist_null_DefaultGroup_RoomListViewLightPreview_0_null_0,NEXUS_5,1.0,en].png
  46. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.components.button_null_DefaultGroup_BackButtonPreviewDark_0_null,NEXUS_5,1.0,en].png
  47. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.components.button_null_DefaultGroup_BackButtonPreviewLight_0_null,NEXUS_5,1.0,en].png
  48. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_CenterAlignedTopAppBarDarkPreview_0_null,NEXUS_5,1.0,en].png
  49. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_CenterAlignedTopAppBarLightPreview_0_null,NEXUS_5,1.0,en].png
  50. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_DockedSearchBarDarkPreview_0_null,NEXUS_5,1.0,en].png
  51. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_DockedSearchBarLightPreview_0_null,NEXUS_5,1.0,en].png
  52. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_TextButtonDarkPreview_0_null,NEXUS_5,1.0,en].png
  53. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_TextButtonLightPreview_0_null,NEXUS_5,1.0,en].png
  54. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_TextFieldDarkPreview_0_null,NEXUS_5,1.0,en].png
  55. BIN
      tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_TextFieldLightPreview_0_null,NEXUS_5,1.0,en].png

11
app/src/main/kotlin/io/element/android/x/node/LoggedInFlowNode.kt

@ -31,6 +31,7 @@ import com.bumble.appyx.core.node.ParentNode
import com.bumble.appyx.core.node.node import com.bumble.appyx.core.node.node
import com.bumble.appyx.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.BackStack
import com.bumble.appyx.navmodel.backstack.operation.push import com.bumble.appyx.navmodel.backstack.operation.push
import io.element.android.features.createroom.CreateRoomFlowNode
import io.element.android.features.preferences.PreferencesFlowNode import io.element.android.features.preferences.PreferencesFlowNode
import io.element.android.features.roomlist.RoomListNode import io.element.android.features.roomlist.RoomListNode
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
@ -86,6 +87,10 @@ class LoggedInFlowNode(
override fun onSettingsClicked() { override fun onSettingsClicked() {
backstack.push(NavTarget.Settings) backstack.push(NavTarget.Settings)
} }
override fun onCreateRoomClicked() {
backstack.push(NavTarget.CreateRoom)
}
} }
sealed interface NavTarget : Parcelable { sealed interface NavTarget : Parcelable {
@ -97,6 +102,9 @@ class LoggedInFlowNode(
@Parcelize @Parcelize
object Settings : NavTarget object Settings : NavTarget
@Parcelize
object CreateRoom : NavTarget
} }
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node { override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
@ -120,6 +128,9 @@ class LoggedInFlowNode(
NavTarget.Settings -> { NavTarget.Settings -> {
PreferencesFlowNode(buildContext, onOpenBugReport) PreferencesFlowNode(buildContext, onOpenBugReport)
} }
NavTarget.CreateRoom -> {
CreateRoomFlowNode(buildContext)
}
} }
} }

1
changelog.d/94.wip

@ -0,0 +1 @@
[Create and join rooms] Start new chat screen (UI)

1
features/createroom/.gitignore vendored

@ -0,0 +1 @@
/build

56
features/createroom/build.gradle.kts

@ -0,0 +1,56 @@
/*
* Copyright (c) 2023 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.
*/
// TODO: Remove once https://youtrack.jetbrains.com/issue/KTIJ-19369 is fixed
@Suppress("DSL_SCOPE_VIOLATION")
plugins {
id("io.element.android-compose-library")
alias(libs.plugins.ksp)
alias(libs.plugins.anvil)
id("kotlin-parcelize")
}
android {
namespace = "io.element.android.features.createroom"
}
anvil {
generateDaggerFactories.set(true)
}
dependencies {
anvil(projects.anvilcodegen)
implementation(projects.anvilannotations)
implementation(projects.libraries.core)
implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api)
implementation(projects.libraries.matrixui)
implementation(projects.libraries.designsystem)
implementation(projects.libraries.elementresources)
implementation(projects.libraries.uiStrings)
testImplementation(libs.test.junit)
testImplementation(libs.coroutines.test)
testImplementation(libs.molecule.runtime)
testImplementation(libs.test.truth)
testImplementation(libs.test.turbine)
testImplementation(projects.libraries.matrix.test)
androidTestImplementation(libs.test.junitext)
ksp(libs.showkase.processor)
}

0
features/createroom/consumer-rules.pro

21
features/createroom/proguard-rules.pro vendored

@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile

20
features/createroom/src/main/AndroidManifest.xml

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2023 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.
-->
<manifest>
</manifest>

62
features/createroom/src/main/kotlin/io/element/android/features/createroom/CreateRoomFlowNode.kt

@ -0,0 +1,62 @@
/*
* Copyright (c) 2023 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 io.element.android.features.createroom
import android.os.Parcelable
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.bumble.appyx.core.composable.Children
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.node.ParentNode
import com.bumble.appyx.navmodel.backstack.BackStack
import io.element.android.features.createroom.root.CreateRoomRootNode
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
import io.element.android.libraries.architecture.createNode
import kotlinx.parcelize.Parcelize
class CreateRoomFlowNode(
buildContext: BuildContext,
private val backstack: BackStack<NavTarget> = BackStack(
initialElement = NavTarget.Root,
savedStateMap = buildContext.savedStateMap,
),
) : ParentNode<CreateRoomFlowNode.NavTarget>(
navModel = backstack,
buildContext = buildContext
) {
sealed interface NavTarget : Parcelable {
@Parcelize
object Root : NavTarget
}
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
return when (navTarget) {
NavTarget.Root -> createNode<CreateRoomRootNode>(buildContext)
}
}
@Composable
override fun View(modifier: Modifier) {
Children(
navModel = backstack,
modifier = modifier,
transitionHandler = rememberDefaultTransitionHandler()
)
}
}

22
features/createroom/src/main/kotlin/io/element/android/features/createroom/root/CreateRoomRootEvents.kt

@ -0,0 +1,22 @@
/*
* Copyright (c) 2023 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 io.element.android.features.createroom.root
sealed interface CreateRoomRootEvents {
object CreateRoom : CreateRoomRootEvents
object InvitePeople : CreateRoomRootEvents
}

52
features/createroom/src/main/kotlin/io/element/android/features/createroom/root/CreateRoomRootNode.kt

@ -0,0 +1,52 @@
/*
* Copyright (c) 2023 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 io.element.android.features.createroom.root
import android.os.Parcelable
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode
import io.element.android.libraries.di.SessionScope
import kotlinx.parcelize.Parcelize
@ContributesNode(SessionScope::class)
class CreateRoomRootNode @AssistedInject constructor(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
private val presenter: CreateRoomRootPresenter,
) : Node(buildContext, plugins = plugins) {
sealed interface NavTarget : Parcelable {
@Parcelize
object Root : NavTarget
}
@Composable
override fun View(modifier: Modifier) {
val state = presenter.present()
CreateRoomRootScreen(
state = state,
modifier = modifier,
onClosePressed = this::navigateUp,
)
}
}

39
features/createroom/src/main/kotlin/io/element/android/features/createroom/root/CreateRoomRootPresenter.kt

@ -0,0 +1,39 @@
/*
* Copyright (c) 2023 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 io.element.android.features.createroom.root
import androidx.compose.runtime.Composable
import io.element.android.libraries.architecture.Presenter
import javax.inject.Inject
class CreateRoomRootPresenter @Inject constructor() : Presenter<CreateRoomRootState> {
@Composable
override fun present(): CreateRoomRootState {
fun handleEvents(event: CreateRoomRootEvents) {
when (event) {
CreateRoomRootEvents.CreateRoom -> Unit // Todo Handle create room action
CreateRoomRootEvents.InvitePeople -> Unit // Todo Handle invite people action
}
}
return CreateRoomRootState(
eventSink = ::handleEvents
)
}
}

236
features/createroom/src/main/kotlin/io/element/android/features/createroom/root/CreateRoomRootScreen.kt

@ -0,0 +1,236 @@
/*
* Copyright (c) 2023 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 io.element.android.features.createroom.root
import androidx.annotation.DrawableRes
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.Search
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.SearchBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.CenterAlignedTopAppBar
import io.element.android.libraries.designsystem.theme.components.DockedSearchBar
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.R as DrawableR
import io.element.android.libraries.ui.strings.R as StringR
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CreateRoomRootScreen(
state: CreateRoomRootState,
modifier: Modifier = Modifier,
onClosePressed: () -> Unit = {},
) {
var searchText by rememberSaveable { mutableStateOf("") }
var isSearchActive by rememberSaveable { mutableStateOf(false) }
Scaffold(
modifier = modifier.fillMaxWidth(),
topBar = {
if (!isSearchActive) {
CreateRoomRootViewTopBar(onClosePressed = onClosePressed)
}
}
) { paddingValues ->
Column(
modifier = Modifier.padding(paddingValues),
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
CreateRoomSearchBar(
modifier = Modifier.fillMaxWidth(),
text = searchText,
placeHolderTitle = stringResource(StringR.string.search_for_someone),
active = isSearchActive,
onActiveChanged = { isSearchActive = it },
onTextChanged = { searchText = it },
)
if (!isSearchActive) {
CreateRoomActionButtonsList(
onNewRoomClicked = { state.eventSink(CreateRoomRootEvents.CreateRoom) },
onInvitePeopleClicked = { state.eventSink(CreateRoomRootEvents.InvitePeople) },
)
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CreateRoomRootViewTopBar(
modifier: Modifier = Modifier,
onClosePressed: () -> Unit = {},
) {
CenterAlignedTopAppBar(
modifier = modifier,
title = {
Text(
text = stringResource(id = StringR.string.start_chat),
fontSize = 16.sp,
fontWeight = FontWeight.SemiBold,
)
},
actions = {
IconButton(onClick = onClosePressed) {
Icon(imageVector = Icons.Default.Close, contentDescription = stringResource(id = StringR.string.action_close))
}
}
)
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CreateRoomSearchBar(
text: String,
placeHolderTitle: String,
active: Boolean,
modifier: Modifier = Modifier,
onActiveChanged: (Boolean) -> Unit = {},
onTextChanged: (String) -> Unit = {},
) {
val focusManager = LocalFocusManager.current
if (!active) {
onTextChanged("")
focusManager.clearFocus()
}
DockedSearchBar(
query = text,
onQueryChange = onTextChanged,
onSearch = { focusManager.clearFocus() },
active = active,
onActiveChange = onActiveChanged,
modifier = modifier
.padding(horizontal = if (!active) 16.dp else 0.dp),
placeholder = {
Text(
text = placeHolderTitle,
modifier = Modifier.alpha(0.4f), // FIXME align on Design system theme (removing alpha should be fine)
)
},
leadingIcon = if (active) {
{ BackButton(onClick = { onActiveChanged(false) }) }
} else null,
trailingIcon = {
if (active) {
IconButton(onClick = { onTextChanged("") }) {
Icon(Icons.Default.Close, stringResource(StringR.string.a11y_clear))
}
} else {
Icon(
imageVector = Icons.Default.Search,
contentDescription = stringResource(StringR.string.search),
modifier = Modifier.alpha(0.4f), // FIXME align on Design system theme (removing alpha should be fine)
)
}
},
shape = if (!active) SearchBarDefaults.dockedShape else SearchBarDefaults.fullScreenShape,
colors = if (!active) SearchBarDefaults.colors() else SearchBarDefaults.colors(containerColor = Color.Transparent),
content = {},
)
}
@Composable
fun CreateRoomActionButtonsList(
modifier: Modifier = Modifier,
onNewRoomClicked: () -> Unit = {},
onInvitePeopleClicked: () -> Unit = {},
) {
Column(modifier = modifier) {
CreateRoomActionButton(
iconRes = DrawableR.drawable.ic_groups,
text = stringResource(id = StringR.string.new_room),
onClick = onNewRoomClicked,
)
CreateRoomActionButton(
iconRes = DrawableR.drawable.ic_share,
text = stringResource(id = StringR.string.invite_people_menu),
onClick = onInvitePeopleClicked,
)
}
}
@Composable
fun CreateRoomActionButton(
@DrawableRes iconRes: Int,
text: String,
modifier: Modifier = Modifier,
onClick: () -> Unit = {},
) {
Row(
modifier = modifier
.fillMaxWidth()
.heightIn(min = 56.dp)
.clickable { onClick() }
.padding(horizontal = 16.dp),
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Icon(
modifier = Modifier.alpha(0.5f), // FIXME align on Design system theme (removing alpha should be fine)
resourceId = iconRes,
contentDescription = null,
)
Text(text = text)
}
}
@Preview
@Composable
fun CreateRoomRootViewLightPreview(@PreviewParameter(CreateRoomRootStateProvider::class) state: CreateRoomRootState) =
ElementPreviewLight { ContentToPreview(state) }
@Preview
@Composable
fun CreateRoomRootViewDarkPreview(@PreviewParameter(CreateRoomRootStateProvider::class) state: CreateRoomRootState) =
ElementPreviewDark { ContentToPreview(state) }
@Composable
private fun ContentToPreview(state: CreateRoomRootState) {
CreateRoomRootScreen(
state = state,
)
}

23
features/createroom/src/main/kotlin/io/element/android/features/createroom/root/CreateRoomRootState.kt

@ -0,0 +1,23 @@
/*
* Copyright (c) 2023 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 io.element.android.features.createroom.root
// TODO add your ui models. Remove the eventSink if you don't have events.
// Do not use default value, so no member get forgotten in the presenters.
data class CreateRoomRootState(
val eventSink: (CreateRoomRootEvents) -> Unit
)

31
features/createroom/src/main/kotlin/io/element/android/features/createroom/root/CreateRoomRootStateProvider.kt

@ -0,0 +1,31 @@
/*
* Copyright (c) 2023 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 io.element.android.features.createroom.root
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
open class CreateRoomRootStateProvider : PreviewParameterProvider<CreateRoomRootState> {
override val values: Sequence<CreateRoomRootState>
get() = sequenceOf(
aCreateRoomRootState(),
// Add other state here
)
}
fun aCreateRoomRootState() = CreateRoomRootState(
eventSink = {}
)

53
features/createroom/src/test/kotlin/io/element/android/features/createroom/root/CreateRoomRootPresenterTests.kt

@ -0,0 +1,53 @@
/*
* Copyright (c) 2023 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.
*/
@file:OptIn(ExperimentalCoroutinesApi::class)
package io.element.android.features.createroom.root
import app.cash.molecule.RecompositionClock
import app.cash.molecule.moleculeFlow
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runTest
import org.junit.Test
class CreateRoomRootPresenterTests {
@Test
fun `present - initial state`() = runTest {
val presenter = CreateRoomRootPresenter()
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
assertThat(initialState)
}
}
@Test
fun `present - send event`() = runTest {
val presenter = CreateRoomRootPresenter()
moleculeFlow(RecompositionClock.Immediate) {
presenter.present()
}.test {
val initialState = awaitItem()
initialState.eventSink(CreateRoomRootEvents.CreateRoom) // Not implemented yet
initialState.eventSink(CreateRoomRootEvents.InvitePeople) // Not implemented yet
}
}
}

6
features/login/src/main/kotlin/io/element/android/features/login/changeserver/ChangeServerView.kt

@ -60,7 +60,7 @@ import io.element.android.libraries.designsystem.components.form.textFieldState
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.LocalColors import io.element.android.libraries.designsystem.theme.LocalColors
import io.element.android.libraries.designsystem.theme.components.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
@ -104,7 +104,7 @@ fun ChangeServerView(
topBar = { topBar = {
TopAppBar( TopAppBar(
title = {}, title = {},
navigationIcon = { BackButton(action = onBackPressed, enabled = interactionEnabled) } navigationIcon = { BackButton(onClick = onBackPressed, enabled = interactionEnabled) }
) )
} }
) { padding -> ) { padding ->
@ -192,7 +192,7 @@ fun ChangeServerView(
IconButton(onClick = { IconButton(onClick = {
homeserverFieldState = "" homeserverFieldState = ""
}, enabled = interactionEnabled) { }, enabled = interactionEnabled) {
Icon(imageVector = Icons.Filled.Close, contentDescription = stringResource(StringR.string.action_clear)) Icon(imageVector = Icons.Filled.Close, contentDescription = stringResource(StringR.string.a11y_clear))
} }
} }
} else null, } else null,

6
features/login/src/main/kotlin/io/element/android/features/login/root/LoginRootScreen.kt

@ -68,7 +68,7 @@ import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
import io.element.android.libraries.designsystem.components.form.textFieldState import io.element.android.libraries.designsystem.components.form.textFieldState
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Icon import io.element.android.libraries.designsystem.theme.components.Icon
@ -101,7 +101,7 @@ fun LoginRootScreen(
topBar = { topBar = {
TopAppBar( TopAppBar(
title = {}, title = {},
navigationIcon = { BackButton(action = onBackPressed, enabled = interactionEnabled) }, navigationIcon = { BackButton(onClick = onBackPressed, enabled = interactionEnabled) },
) )
} }
) { padding -> ) { padding ->
@ -267,7 +267,7 @@ internal fun LoginForm(
IconButton(onClick = { IconButton(onClick = {
loginFieldState = "" loginFieldState = ""
}) { }) {
Icon(imageVector = Icons.Filled.Close, contentDescription = stringResource(StringR.string.action_clear)) Icon(imageVector = Icons.Filled.Close, contentDescription = stringResource(StringR.string.a11y_clear))
} }
} }
} else null, } else null,

8
features/roomlist/src/main/kotlin/io/element/android/features/roomlist/RoomListNode.kt

@ -38,6 +38,7 @@ class RoomListNode @AssistedInject constructor(
interface Callback : Plugin { interface Callback : Plugin {
fun onRoomClicked(roomId: RoomId) fun onRoomClicked(roomId: RoomId)
fun onSettingsClicked() fun onSettingsClicked()
fun onCreateRoomClicked()
} }
private fun onRoomClicked(roomId: RoomId) { private fun onRoomClicked(roomId: RoomId) {
@ -48,6 +49,10 @@ class RoomListNode @AssistedInject constructor(
plugins<Callback>().forEach { it.onSettingsClicked() } plugins<Callback>().forEach { it.onSettingsClicked() }
} }
private fun onCreateRoomClicked() {
plugins<Callback>().forEach { it.onCreateRoomClicked() }
}
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
val state = presenter.present() val state = presenter.present()
@ -55,7 +60,8 @@ class RoomListNode @AssistedInject constructor(
state = state, state = state,
modifier = modifier, modifier = modifier,
onRoomClicked = this::onRoomClicked, onRoomClicked = this::onRoomClicked,
onOpenSettings = this::onOpenSettings onOpenSettings = this::onOpenSettings,
onCreateRoomClicked = this::onCreateRoomClicked,
) )
} }
} }

20
features/roomlist/src/main/kotlin/io/element/android/features/roomlist/RoomListView.kt

@ -22,6 +22,7 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.rememberTopAppBarState import androidx.compose.material3.rememberTopAppBarState
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -31,6 +32,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.Velocity import androidx.compose.ui.unit.Velocity
@ -42,11 +44,15 @@ import io.element.android.features.roomlist.model.RoomListState
import io.element.android.features.roomlist.model.RoomListStateProvider import io.element.android.features.roomlist.model.RoomListStateProvider
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.theme.components.FloatingActionButton
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.Scaffold import io.element.android.libraries.designsystem.theme.components.Scaffold
import io.element.android.libraries.designsystem.utils.LogCompositions import io.element.android.libraries.designsystem.utils.LogCompositions
import io.element.android.libraries.matrix.api.core.RoomId import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.ui.model.MatrixUser import io.element.android.libraries.matrix.ui.model.MatrixUser
import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.ImmutableList
import io.element.android.libraries.designsystem.R as DrawableR
import io.element.android.libraries.ui.strings.R as StringR
@Composable @Composable
fun RoomListView( fun RoomListView(
@ -54,6 +60,7 @@ fun RoomListView(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
onRoomClicked: (RoomId) -> Unit = {}, onRoomClicked: (RoomId) -> Unit = {},
onOpenSettings: () -> Unit = {}, onOpenSettings: () -> Unit = {},
onCreateRoomClicked: () -> Unit = {},
) { ) {
fun onFilterChanged(filter: String) { fun onFilterChanged(filter: String) {
state.eventSink(RoomListEvents.UpdateFilter(filter)) state.eventSink(RoomListEvents.UpdateFilter(filter))
@ -72,6 +79,7 @@ fun RoomListView(
onFilterChanged = ::onFilterChanged, onFilterChanged = ::onFilterChanged,
onOpenSettings = onOpenSettings, onOpenSettings = onOpenSettings,
onScrollOver = ::onVisibleRangedChanged, onScrollOver = ::onVisibleRangedChanged,
onCreateRoomClicked = onCreateRoomClicked,
) )
} }
@ -86,6 +94,7 @@ fun RoomListContent(
onFilterChanged: (String) -> Unit = {}, onFilterChanged: (String) -> Unit = {},
onOpenSettings: () -> Unit = {}, onOpenSettings: () -> Unit = {},
onScrollOver: (IntRange) -> Unit = {}, onScrollOver: (IntRange) -> Unit = {},
onCreateRoomClicked: () -> Unit = {},
) { ) {
fun onRoomClicked(room: RoomListRoomSummary) { fun onRoomClicked(room: RoomListRoomSummary) {
onRoomClicked(room.roomId) onRoomClicked(room.roomId)
@ -148,7 +157,16 @@ fun RoomListContent(
} }
} }
} }
} },
floatingActionButton = {
FloatingActionButton(
// FIXME align on Design system theme
containerColor = MaterialTheme.colorScheme.primary,
onClick = onCreateRoomClicked
) {
Icon(resourceId = DrawableR.drawable.ic_edit_square, contentDescription = stringResource(id = StringR.string.a11y_create_message))
}
},
) )
} }

20
libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/BackButton.kt → libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/components/button/BackButton.kt

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package io.element.android.libraries.designsystem.theme.components package io.element.android.libraries.designsystem.components.button
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
@ -26,22 +26,24 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.ui.strings.R.string as StringR import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.ui.strings.R as StringR
@Composable @Composable
fun BackButton( fun BackButton(
action: () -> Unit, onClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
icon: ImageVector = Icons.Default.ArrowBack, imageVector: ImageVector = Icons.Default.ArrowBack,
contentDescription: String = stringResource(StringR.action_back), contentDescription: String = stringResource(StringR.string.a11y_back),
enabled: Boolean = true enabled: Boolean = true
) { ) {
IconButton( IconButton(
modifier = modifier, modifier = modifier,
onClick = action, onClick = onClick,
enabled = enabled, enabled = enabled,
) { ) {
Icon(imageVector = icon, contentDescription = contentDescription) Icon(imageVector = imageVector, contentDescription = contentDescription)
} }
} }
@ -56,7 +58,7 @@ internal fun BackButtonPreviewDark() = ElementPreviewDark { ContentToPreview() }
@Composable @Composable
private fun ContentToPreview() { private fun ContentToPreview() {
Column { Column {
BackButton(action = { }, enabled = true, contentDescription = "Back") BackButton(onClick = { }, enabled = true, contentDescription = "Back")
BackButton(action = { }, enabled = false, contentDescription = "Back") BackButton(onClick = { }, enabled = false, contentDescription = "Back")
} }
} }

68
libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/CenterAlignedTopAppBar.kt

@ -0,0 +1,68 @@
/*
* Copyright (c) 2023 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.
*/
@file:OptIn(ExperimentalMaterial3Api::class)
package io.element.android.libraries.designsystem.theme.components
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.TopAppBarColors
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CenterAlignedTopAppBar(
title: @Composable () -> Unit,
modifier: Modifier = Modifier,
navigationIcon: @Composable () -> Unit = {},
actions: @Composable RowScope.() -> Unit = {},
windowInsets: WindowInsets = TopAppBarDefaults.windowInsets,
colors: TopAppBarColors = TopAppBarDefaults.centerAlignedTopAppBarColors(),
scrollBehavior: TopAppBarScrollBehavior? = null,
) {
androidx.compose.material3.CenterAlignedTopAppBar(
title = title,
modifier = modifier,
navigationIcon = navigationIcon,
actions = actions,
windowInsets = windowInsets,
colors = colors,
scrollBehavior = scrollBehavior,
)
}
@Preview
@Composable
internal fun CenterAlignedTopAppBarLightPreview() =
ElementPreviewLight { ContentToPreview() }
@Preview
@Composable
internal fun CenterAlignedTopAppBarDarkPreview() =
ElementPreviewDark { ContentToPreview() }
@Composable
private fun ContentToPreview() {
CenterAlignedTopAppBar(title = { Text(text = "Title") })
}

91
libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/DockedSearchBar.kt

@ -0,0 +1,91 @@
/*
* Copyright (c) 2023 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.
*/
@file:OptIn(ExperimentalMaterial3Api::class)
package io.element.android.libraries.designsystem.theme.components
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.SearchBarColors
import androidx.compose.material3.SearchBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DockedSearchBar(
query: String,
onQueryChange: (String) -> Unit,
onSearch: (String) -> Unit,
active: Boolean,
onActiveChange: (Boolean) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
placeholder: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
shape: Shape = SearchBarDefaults.dockedShape,
colors: SearchBarColors = SearchBarDefaults.colors(),
tonalElevation: Dp = SearchBarDefaults.Elevation,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable ColumnScope.() -> Unit,
) {
androidx.compose.material3.DockedSearchBar(
query = query,
onQueryChange = onQueryChange,
onSearch = onSearch,
active = active,
onActiveChange = onActiveChange,
modifier = modifier,
enabled = enabled,
placeholder = placeholder,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
shape = shape,
colors = colors,
tonalElevation = tonalElevation,
interactionSource = interactionSource,
content = content,
)
}
@Preview
@Composable
internal fun DockedSearchBarLightPreview() = ElementPreviewLight { ContentToPreview() }
@Preview
@Composable
internal fun DockedSearchBarDarkPreview() = ElementPreviewDark { ContentToPreview() }
@Composable
private fun ContentToPreview() {
DockedSearchBar(
query = "Some text",
onQueryChange = {},
onSearch = {},
active = false,
onActiveChange = {},
content = {},
)
}

80
libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/components/TextButton.kt

@ -0,0 +1,80 @@
/*
* Copyright (c) 2023 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 io.element.android.libraries.designsystem.theme.components
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.ButtonColors
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ButtonElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.tooling.preview.Preview
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
@Composable
fun TextButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
shape: Shape = ButtonDefaults.textShape,
colors: ButtonColors = ButtonDefaults.textButtonColors(),
elevation: ButtonElevation? = null,
border: BorderStroke? = null,
contentPadding: PaddingValues = ButtonDefaults.TextButtonContentPadding,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
content: @Composable RowScope.() -> Unit
) {
androidx.compose.material3.TextButton(
onClick = onClick,
modifier = modifier,
enabled = enabled,
shape = shape,
colors = colors,
elevation = elevation,
border = border,
contentPadding = contentPadding,
interactionSource = interactionSource,
content = content,
)
}
@Preview
@Composable
internal fun TextButtonLightPreview() = ElementPreviewLight { ContentToPreview() }
@Preview
@Composable
internal fun TextButtonDarkPreview() = ElementPreviewDark { ContentToPreview() }
@Composable
private fun ContentToPreview() {
Column {
TextButton(onClick = {}, enabled = true) {
Text(text = "Click me! - Enabled")
}
TextButton(onClick = {}, enabled = false) {
Text(text = "Click me! - Disabled")
}
}
}

26
libraries/designsystem/src/main/res/drawable/ic_edit_square.xml

@ -0,0 +1,26 @@
<!--
~ Copyright (c) 2023 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:tint="#000000"
android:width="21dp"
android:height="22dp"
android:viewportWidth="21"
android:viewportHeight="22">
<path
android:pathData="M1.5,21.7C1.1,21.7 0.75,21.55 0.45,21.25C0.15,20.95 0,20.6 0,20.2V5.2C0,4.8 0.15,4.45 0.45,4.15C0.75,3.85 1.1,3.7 1.5,3.7H11.625L10.125,5.2H1.5V20.2H16.5V11.5L18,10V20.2C18,20.6 17.85,20.95 17.55,21.25C17.25,21.55 16.9,21.7 16.5,21.7H1.5ZM13.55,3.9L14.625,4.95L7.5,12.05V14.2H9.625L16.775,7.05L17.825,8.1L10.7,15.25C10.567,15.383 10.404,15.492 10.212,15.575C10.021,15.658 9.825,15.7 9.625,15.7H6.75C6.533,15.7 6.354,15.629 6.213,15.488C6.071,15.346 6,15.167 6,14.95V12.075C6,11.875 6.042,11.679 6.125,11.488C6.208,11.296 6.317,11.133 6.45,11L13.55,3.9ZM17.825,8.1L13.55,3.9L16.05,1.4C16.333,1.117 16.688,0.975 17.112,0.975C17.538,0.975 17.892,1.125 18.175,1.425L20.275,3.55C20.558,3.85 20.7,4.204 20.7,4.613C20.7,5.021 20.55,5.367 20.25,5.65L17.825,8.1Z"
android:fillColor="#ffffff"/>
</vector>

25
libraries/designsystem/src/main/res/drawable/ic_groups.xml

@ -0,0 +1,25 @@
<!--
~ Copyright (c) 2023 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/black"
android:pathData="M1.365,17.788C1.12,17.788 0.915,17.705 0.749,17.54C0.583,17.374 0.5,17.168 0.5,16.923V16.569C0.5,15.894 0.844,15.346 1.531,14.927C2.219,14.508 3.126,14.298 4.251,14.298C4.454,14.298 4.647,14.305 4.829,14.318C5.011,14.332 5.187,14.355 5.358,14.389C5.168,14.681 5.028,14.995 4.94,15.332C4.852,15.668 4.808,16.024 4.808,16.4V17.788H1.365ZM7.408,17.788C7.147,17.788 6.931,17.702 6.759,17.529C6.586,17.355 6.5,17.141 6.5,16.885V16.438C6.5,15.483 7.006,14.713 8.018,14.128C9.03,13.543 10.356,13.25 11.996,13.25C13.651,13.25 14.982,13.543 15.989,14.128C16.996,14.713 17.5,15.483 17.5,16.438V16.885C17.5,17.141 17.413,17.355 17.24,17.529C17.067,17.702 16.852,17.788 16.596,17.788H7.408ZM19.192,17.788V16.4C19.192,16.024 19.145,15.668 19.05,15.332C18.955,14.995 18.819,14.681 18.642,14.389C18.813,14.355 18.989,14.332 19.17,14.318C19.352,14.305 19.545,14.298 19.75,14.298C20.875,14.298 21.781,14.508 22.469,14.927C23.156,15.346 23.5,15.894 23.5,16.569V16.923C23.5,17.168 23.417,17.374 23.251,17.54C23.085,17.705 22.88,17.788 22.635,17.788H19.192ZM12,14.75C10.954,14.75 10.059,14.892 9.315,15.176C8.572,15.46 8.159,15.799 8.077,16.192V16.288H15.923V16.192C15.831,15.788 15.415,15.447 14.677,15.168C13.938,14.889 13.046,14.75 12,14.75ZM4.25,13.327C3.777,13.327 3.375,13.159 3.044,12.824C2.713,12.489 2.548,12.086 2.548,11.615C2.548,11.145 2.713,10.742 3.044,10.407C3.375,10.071 3.777,9.904 4.25,9.904C4.723,9.904 5.127,10.071 5.461,10.407C5.794,10.742 5.961,11.145 5.961,11.615C5.961,12.086 5.794,12.489 5.459,12.824C5.124,13.159 4.721,13.327 4.25,13.327ZM19.75,13.327C19.277,13.327 18.873,13.159 18.539,12.824C18.205,12.489 18.038,12.086 18.038,11.615C18.038,11.145 18.206,10.742 18.541,10.407C18.876,10.071 19.279,9.904 19.75,9.904C20.223,9.904 20.625,10.071 20.956,10.407C21.286,10.742 21.452,11.145 21.452,11.615C21.452,12.086 21.286,12.489 20.956,12.824C20.625,13.159 20.223,13.327 19.75,13.327ZM12,12.5C11.279,12.5 10.666,12.248 10.161,11.743C9.656,11.238 9.404,10.625 9.404,9.904C9.404,9.183 9.656,8.57 10.161,8.065C10.666,7.56 11.279,7.308 12,7.308C12.721,7.308 13.334,7.56 13.839,8.065C14.344,8.57 14.596,9.183 14.596,9.904C14.596,10.625 14.344,11.238 13.839,11.743C13.334,12.248 12.721,12.5 12,12.5ZM12.002,8.808C11.691,8.808 11.431,8.913 11.22,9.122C11.009,9.332 10.904,9.592 10.904,9.902C10.904,10.212 11.009,10.473 11.218,10.684C11.428,10.895 11.688,11 11.998,11C12.308,11 12.569,10.895 12.78,10.685C12.991,10.476 13.096,10.216 13.096,9.906C13.096,9.595 12.991,9.335 12.781,9.124C12.572,8.913 12.312,8.808 12.002,8.808Z" />
</vector>

25
libraries/designsystem/src/main/res/drawable/ic_share.xml

@ -0,0 +1,25 @@
<!--
~ Copyright (c) 2023 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/black"
android:pathData="M18.001,21.75C17.237,21.75 16.588,21.483 16.053,20.948C15.518,20.413 15.25,19.764 15.25,19C15.25,18.875 15.26,18.746 15.28,18.612C15.3,18.478 15.33,18.355 15.369,18.242L7.973,13.911C7.709,14.174 7.408,14.38 7.071,14.528C6.734,14.676 6.377,14.75 6,14.75C5.236,14.75 4.587,14.483 4.052,13.948C3.517,13.414 3.25,12.765 3.25,12.001C3.25,11.238 3.517,10.588 4.052,10.053C4.587,9.518 5.236,9.25 6,9.25C6.377,9.25 6.734,9.324 7.071,9.472C7.408,9.62 7.709,9.826 7.973,10.089L15.369,5.758C15.33,5.645 15.3,5.522 15.28,5.388C15.26,5.254 15.25,5.125 15.25,5C15.25,4.236 15.517,3.587 16.052,3.052C16.586,2.517 17.235,2.25 17.999,2.25C18.762,2.25 19.412,2.517 19.947,3.052C20.482,3.586 20.75,4.235 20.75,4.999C20.75,5.762 20.483,6.412 19.948,6.947C19.413,7.482 18.764,7.75 18,7.75C17.623,7.75 17.266,7.676 16.929,7.528C16.592,7.38 16.291,7.174 16.027,6.912L8.631,11.242C8.67,11.355 8.7,11.478 8.72,11.611C8.74,11.745 8.75,11.874 8.75,11.998C8.75,12.122 8.74,12.252 8.72,12.387C8.7,12.521 8.67,12.645 8.631,12.758L16.027,17.088C16.291,16.826 16.592,16.62 16.929,16.472C17.266,16.324 17.623,16.25 18,16.25C18.764,16.25 19.413,16.517 19.948,17.052C20.483,17.586 20.75,18.235 20.75,18.999C20.75,19.762 20.483,20.412 19.948,20.947C19.414,21.482 18.765,21.75 18.001,21.75ZM18,6.25C18.347,6.25 18.643,6.129 18.886,5.886C19.128,5.643 19.25,5.347 19.25,5C19.25,4.653 19.128,4.357 18.886,4.114C18.643,3.871 18.347,3.75 18,3.75C17.653,3.75 17.357,3.871 17.114,4.114C16.871,4.357 16.75,4.653 16.75,5C16.75,5.347 16.871,5.643 17.114,5.886C17.357,6.129 17.653,6.25 18,6.25ZM6,13.25C6.347,13.25 6.643,13.128 6.886,12.886C7.129,12.643 7.25,12.347 7.25,12C7.25,11.653 7.129,11.357 6.886,11.114C6.643,10.871 6.347,10.75 6,10.75C5.653,10.75 5.357,10.871 5.114,11.114C4.871,11.357 4.75,11.653 4.75,12C4.75,12.347 4.871,12.643 5.114,12.886C5.357,13.128 5.653,13.25 6,13.25ZM18,20.25C18.347,20.25 18.643,20.128 18.886,19.886C19.128,19.643 19.25,19.347 19.25,19C19.25,18.653 19.128,18.357 18.886,18.114C18.643,17.871 18.347,17.75 18,17.75C17.653,17.75 17.357,17.871 17.114,18.114C16.871,18.357 16.75,18.653 16.75,19C16.75,19.347 16.871,19.643 17.114,19.886C17.357,20.128 17.653,20.25 18,20.25Z" />
</vector>

11
libraries/ui-strings/src/main/res/values/strings_eax.xml

@ -2,17 +2,20 @@
<resources> <resources>
<!-- Add new strings for Element X Android here --> <!-- Add new strings for Element X Android here -->
<string name="action_back">Back</string> <!-- Common -->
<string name="action_clear">Clear</string> <string name="a11y_back">Back</string>
<string name="a11y_clear">Clear</string>
<!-- Login -->
<string name="login_form_title">Enter your details</string> <string name="login_form_title">Enter your details</string>
<string name="ex_login_username_hint">Email or username</string> <string name="ex_login_username_hint">Email or username</string>
<string name="login_show_password">Show password</string> <string name="login_show_password">Show password</string>
<string name="login_hide_password">Hide password</string> <string name="login_hide_password">Hide password</string>
<string name="ex_choose_server_subtitle">What is the address of your server?</string> <string name="ex_choose_server_subtitle">What is the address of your server?</string>
<string name="server_selection_server_footer">You can only connect to an existing server that supports sliding sync. Your homeserver admin will need to configure it.</string> <string name="server_selection_server_footer">You can only connect to an existing server that supports sliding sync. Your homeserver admin will need to configure it.</string>
<string name="server_selection_sliding_sync_alert_title">Server not supported</string> <string name="server_selection_sliding_sync_alert_title">Server not supported</string>
<string name="server_selection_sliding_sync_alert_message">This server currently doesn\'t support sliding sync.</string> <string name="server_selection_sliding_sync_alert_message">This server currently doesn\'t support sliding sync.</string>
<!-- Create room -->
<string name="search_for_someone">Search for someone</string>
<string name="new_room">New room</string>
</resources> </resources>

5
plugins/src/main/kotlin/extension/DependencyHandleScope.kt

@ -39,7 +39,9 @@ fun DependencyHandlerScope.composeDependencies(libs: LibrariesForLibs) {
androidTestImplementation(composeBom) androidTestImplementation(composeBom)
implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material:material") implementation("androidx.compose.material:material")
implementation("androidx.compose.material3:material3") // Override BOM version, SearchBar is not available in the actual version
// do not use latest version because of clashes on androidx lifecycle dependency
implementation("androidx.compose.material3:material3:1.1.0-alpha04")
implementation("androidx.compose.material:material-icons-extended") implementation("androidx.compose.material:material-icons-extended")
implementation("androidx.compose.ui:ui-tooling-preview") implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.activity:activity-compose:1.6.1") implementation("androidx.activity:activity-compose:1.6.1")
@ -67,4 +69,5 @@ fun DependencyHandlerScope.allFeatures() {
implementation(project(":features:messages")) implementation(project(":features:messages"))
implementation(project(":features:rageshake")) implementation(project(":features:rageshake"))
implementation(project(":features:preferences")) implementation(project(":features:preferences"))
implementation(project(":features:createroom"))
} }

1
settings.gradle.kts

@ -57,6 +57,7 @@ include(":features:roomlist")
include(":features:messages") include(":features:messages")
include(":features:rageshake") include(":features:rageshake")
include(":features:preferences") include(":features:preferences")
include(":features:createroom")
include(":libraries:designsystem") include(":libraries:designsystem")
include(":libraries:di") include(":libraries:di")
include(":tests:uitests") include(":tests:uitests")

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.root_null_DefaultGroup_CreateRoomRootViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.createroom.root_null_DefaultGroup_CreateRoomRootViewLightPreview_0_null_0,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_2,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_3,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_4,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenDarkPreview_0_null_5,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_2,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_3,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_4,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.login.root_null_DefaultGroup_LoginRootScreenLightPreview_0_null_5,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomlist.components_null_DefaultGroup_DefaultRoomListTopBarDarkPreview_0_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomlist.components_null_DefaultGroup_DefaultRoomListTopBarLightPreview_0_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomlist.components_null_DefaultGroup_SearchRoomListTopBarDarkPreview_0_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomlist.components_null_DefaultGroup_SearchRoomListTopBarLightPreview_0_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomlist_null_DefaultGroup_RoomListViewDarkPreview_0_null_0,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.features.roomlist_null_DefaultGroup_RoomListViewLightPreview_0_null_0,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.components.button_null_DefaultGroup_BackButtonPreviewDark_0_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.components.button_null_DefaultGroup_BackButtonPreviewLight_0_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_CenterAlignedTopAppBarDarkPreview_0_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_CenterAlignedTopAppBarLightPreview_0_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_DockedSearchBarDarkPreview_0_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_DockedSearchBarLightPreview_0_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_TextButtonDarkPreview_0_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_TextButtonLightPreview_0_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_TextFieldDarkPreview_0_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.

BIN
tests/uitests/src/test/snapshots/images/io.element.android.tests.uitests_ScreenshotTest_preview_tests[io.element.android.libraries.designsystem.theme.components_null_DefaultGroup_TextFieldLightPreview_0_null,NEXUS_5,1.0,en].png (Stored with Git LFS)

Binary file not shown.
Loading…
Cancel
Save