This commit is contained in:
ganfra 2022-11-29 21:28:25 +01:00
commit 20fcf51e1e
28 changed files with 330 additions and 45 deletions

View file

@ -125,4 +125,7 @@ dependencies {
debugImplementation "androidx.compose.ui:ui-tooling" debugImplementation "androidx.compose.ui:ui-tooling"
debugImplementation "androidx.compose.ui:ui-test-manifest" debugImplementation "androidx.compose.ui:ui-test-manifest"
implementation 'com.airbnb.android:mavericks-compose:3.0.1' implementation 'com.airbnb.android:mavericks-compose:3.0.1'
implementation("com.airbnb.android:showkase:1.0.0-beta14")
ksp("com.airbnb.android:showkase-processor:1.0.0-beta14")
} }

View file

@ -13,13 +13,23 @@ import androidx.compose.animation.AnimatedContentScope
import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.material3.MaterialTheme import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
import androidx.compose.material3.*
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.core.view.WindowCompat import androidx.core.view.WindowCompat
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import com.airbnb.android.showkase.models.Showkase
import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi import com.google.accompanist.navigation.material.ExperimentalMaterialNavigationApi
import com.ramcosta.composedestinations.DestinationsNavHost import com.ramcosta.composedestinations.DestinationsNavHost
import com.ramcosta.composedestinations.animations.defaults.RootNavGraphDefaultAnimations import com.ramcosta.composedestinations.animations.defaults.RootNavGraphDefaultAnimations
@ -40,8 +50,38 @@ class MainActivity : ComponentActivity() {
// FIXME Scrolling is broken on login screens. Commenting this line fixes the issue. // FIXME Scrolling is broken on login screens. Commenting this line fixes the issue.
WindowCompat.setDecorFitsSystemWindows(window, false) WindowCompat.setDecorFitsSystemWindows(window, false)
setContent { setContent {
ElementXTheme { Box(modifier = Modifier.fillMaxSize()) {
MainScreen(viewModel = viewModel) ElementXTheme {
MainScreen(viewModel = viewModel)
}
ShowkaseButton(
onClick = { startActivity(Showkase.getBrowserIntent(this@MainActivity)) }
)
}
}
}
}
@Composable
private fun ShowkaseButton(
onClick: () -> Unit = {}
) {
val showkaseButtonVisible = remember { mutableStateOf(true) }
if (showkaseButtonVisible.value) {
Button(
modifier = Modifier
.padding(top = 32.dp, start = 16.dp),
onClick = onClick
) {
Text(text = "Showkase Browser")
IconButton(
modifier = Modifier
.padding(start = 8.dp)
.size(16.dp),
onClick = { showkaseButtonVisible.value = false },
) {
Icon(imageVector = Icons.Filled.Close, contentDescription = "")
} }
} }
} }
@ -122,6 +162,6 @@ private fun LogNavigation(navController: NavHostController) {
@Composable @Composable
@Preview @Preview
private fun MainContentPreview() { fun MainContentPreview() {
MainContent(startRoute = OnBoardingScreenNavigationDestination) MainContent(startRoute = OnBoardingScreenNavigationDestination)
} }

View file

@ -0,0 +1,7 @@
package io.element.android.x
import com.airbnb.android.showkase.annotation.ShowkaseRoot
import com.airbnb.android.showkase.annotation.ShowkaseRootModule
@ShowkaseRoot
class ElementRootModule : ShowkaseRootModule

View file

@ -1,8 +1,10 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
// TODO Convert to .kts
plugins { plugins {
id 'com.android.application' version '7.3.0' apply false id 'com.android.application' version '7.3.0' apply false
id 'com.android.library' version '7.3.0' apply false id 'com.android.library' version '7.3.0' apply false
id 'org.jetbrains.kotlin.android' version '1.7.20' apply false id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
id 'com.google.devtools.ksp' version '1.7.20-1.0.7' apply false
} }
task clean(type: Delete) { task clean(type: Delete) {

View file

@ -1,6 +1,14 @@
### VersionCatalog
### Jetpack Compose ### Jetpack Compose
https://developer.android.com/jetpack/compose/mental-model https://developer.android.com/jetpack/compose/mental-model
https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-api-guidelines.md#api-guidelines-for-jetpack-compose https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-api-guidelines.md#api-guidelines-for-jetpack-compose
Preview
https://alexzh.com/jetpack-compose-preview/
https://github.com/airbnb/Showkase

View file

@ -1,5 +1,7 @@
plugins { plugins {
id("io.element.android-compose") id("io.element.android-compose")
// TODO Move to common config
id("com.google.devtools.ksp") version "1.7.20-1.0.7"
} }
android { android {
@ -16,4 +18,7 @@ dependencies {
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.3") androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0") androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
// TODO Move to common config
ksp("com.airbnb.android:showkase-processor:1.0.0-beta14")
} }

View file

@ -202,7 +202,7 @@ fun LoginContent(
@Composable @Composable
@Preview @Preview
private fun LoginContentPreview() { fun LoginContentPreview() {
ElementXTheme(darkTheme = false) { ElementXTheme(darkTheme = false) {
LoginContent( LoginContent(
state = LoginViewState( state = LoginViewState(

View file

@ -150,7 +150,7 @@ fun ChangeServerContent(
@Composable @Composable
@Preview @Preview
private fun ChangeServerContentPreview() { fun ChangeServerContentPreview() {
ChangeServerContent( ChangeServerContent(
state = ChangeServerViewState(homeserver = "matrix.org"), state = ChangeServerViewState(homeserver = "matrix.org"),
) )

View file

@ -1,5 +1,7 @@
plugins { plugins {
id("io.element.android-compose") id("io.element.android-compose")
// TODO Move to common config
id("com.google.devtools.ksp") version "1.7.20-1.0.7"
} }
android { android {
@ -20,4 +22,7 @@ dependencies {
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.3") androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0") androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
}
// TODO Move to common config
ksp("com.airbnb.android:showkase-processor:1.0.0-beta14")
}

View file

@ -24,17 +24,19 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.LastBaseline import androidx.compose.ui.layout.LastBaseline
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
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.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.zIndex import androidx.compose.ui.zIndex
import com.airbnb.mvrx.compose.collectAsState import com.airbnb.mvrx.compose.collectAsState
import com.airbnb.mvrx.compose.mavericksViewModel import com.airbnb.mvrx.compose.mavericksViewModel
import io.element.android.x.core.compose.LogCompositions import io.element.android.x.core.compose.LogCompositions
import io.element.android.x.core.compose.PairCombinedPreviewParameter
import io.element.android.x.core.data.StableCharSequence import io.element.android.x.core.data.StableCharSequence
import io.element.android.x.designsystem.components.avatar.AvatarData import io.element.android.x.designsystem.components.avatar.AvatarData
import io.element.android.x.features.messages.components.* import io.element.android.x.features.messages.components.*
import io.element.android.x.features.messages.model.MessagesTimelineItemState import io.element.android.x.features.messages.model.*
import io.element.android.x.features.messages.model.MessagesViewState
import io.element.android.x.features.messages.model.content.* import io.element.android.x.features.messages.model.content.*
import io.element.android.x.features.messages.textcomposer.MessageComposerViewModel import io.element.android.x.features.messages.textcomposer.MessageComposerViewModel
import io.element.android.x.features.messages.textcomposer.MessageComposerViewState import io.element.android.x.features.messages.textcomposer.MessageComposerViewState
@ -42,6 +44,7 @@ import io.element.android.x.textcomposer.TextComposer
import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
import java.lang.Math.random
private val COMPOSER_HEIGHT = 112.dp private val COMPOSER_HEIGHT = 112.dp
@ -253,11 +256,11 @@ fun MessagesTopAppBar(
fun TimelineItems( fun TimelineItems(
lazyListState: LazyListState, lazyListState: LazyListState,
timelineItems: List<MessagesTimelineItemState>, timelineItems: List<MessagesTimelineItemState>,
hasMoreToLoad: Boolean,
onClick: (MessagesTimelineItemState.MessageEvent) -> Unit,
onLongClick: ((MessagesTimelineItemState.MessageEvent)) -> Unit,
onReachedLoadMore: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
hasMoreToLoad: Boolean = false,
onClick: (MessagesTimelineItemState.MessageEvent) -> Unit = {},
onLongClick: ((MessagesTimelineItemState.MessageEvent)) -> Unit = {},
onReachedLoadMore: () -> Unit = {},
) { ) {
Box(modifier = modifier.fillMaxWidth()) { Box(modifier = modifier.fillMaxWidth()) {
LazyColumn( LazyColumn(
@ -385,6 +388,7 @@ fun MessageEventRow(
content = messageEvent.content, content = messageEvent.content,
modifier = contentModifier modifier = contentModifier
) )
else -> TODO() /* compiler issue ? */
} }
} }
MessagesReactionsView( MessagesReactionsView(
@ -502,4 +506,76 @@ internal fun MessagesLoadingMoreIndicator() {
) )
} }
} }
class MessagesItemGroupPositionToMessagesTimelineItemContentProvider :
PairCombinedPreviewParameter<MessagesItemGroupPosition, MessagesTimelineItemContent>(
MessagesItemGroupPositionProvider() to MessagesTimelineItemContentProvider()
)
@Preview(showBackground = true)
@Composable
fun TimelineItemsPreview(
@PreviewParameter(MessagesTimelineItemContentProvider::class)
content: MessagesTimelineItemContent
) {
TimelineItems(
lazyListState = LazyListState(),
timelineItems = listOf(
// 3 items (First Middle Last) with isMine = false
createMessageEvent(
isMine = false,
content = content,
groupPosition = MessagesItemGroupPosition.First
),
createMessageEvent(
isMine = false,
content = content,
groupPosition = MessagesItemGroupPosition.Middle
),
createMessageEvent(
isMine = false,
content = content,
groupPosition = MessagesItemGroupPosition.Last
),
// 3 items (First Middle Last) with isMine = true
createMessageEvent(
isMine = true,
content = content,
groupPosition = MessagesItemGroupPosition.First
),
createMessageEvent(
isMine = true,
content = content,
groupPosition = MessagesItemGroupPosition.Middle
),
createMessageEvent(
isMine = true,
content = content,
groupPosition = MessagesItemGroupPosition.Last
),
),
hasMoreToLoad = true,
)
}
private fun createMessageEvent(
isMine: Boolean,
content: MessagesTimelineItemContent,
groupPosition: MessagesItemGroupPosition
): MessagesTimelineItemState {
return MessagesTimelineItemState.MessageEvent(
id = random().toString(),
senderId = "senderId",
senderAvatar = AvatarData("sender"),
content = content,
reactionsState = MessagesItemReactionState(
listOf(
AggregatedReaction("👍", "1")
)
),
isMine = isMine,
senderDisplayName = "sender",
groupPosition = groupPosition,
)
}

View file

@ -9,6 +9,7 @@ import io.element.android.x.features.messages.model.MessagesItemAction
import io.element.android.x.features.messages.model.MessagesItemActionsSheetState import io.element.android.x.features.messages.model.MessagesItemActionsSheetState
import io.element.android.x.features.messages.model.MessagesTimelineItemState import io.element.android.x.features.messages.model.MessagesTimelineItemState
import io.element.android.x.features.messages.model.MessagesViewState import io.element.android.x.features.messages.model.MessagesViewState
import io.element.android.x.features.messages.model.content.MessagesTimelineItemRedactedContent
import io.element.android.x.matrix.MatrixClient import io.element.android.x.matrix.MatrixClient
import io.element.android.x.matrix.MatrixInstance import io.element.android.x.matrix.MatrixInstance
import io.element.android.x.matrix.media.MediaResolver import io.element.android.x.matrix.media.MediaResolver
@ -104,13 +105,19 @@ class MessagesViewModel(
fun computeActionsSheetState(messagesTimelineItemState: MessagesTimelineItemState.MessageEvent) { fun computeActionsSheetState(messagesTimelineItemState: MessagesTimelineItemState.MessageEvent) {
suspend { suspend {
val actions = mutableListOf( val actions =
MessagesItemAction.Forward, if (messagesTimelineItemState.content is MessagesTimelineItemRedactedContent) {
MessagesItemAction.Copy, emptyList()
) } else {
if (messagesTimelineItemState.isMine) { mutableListOf(
actions.add(MessagesItemAction.Redact) MessagesItemAction.Forward,
} MessagesItemAction.Copy,
).also {
if (messagesTimelineItemState.isMine) {
it.add(MessagesItemAction.Redact)
}
}
}
MessagesItemActionsSheetState( MessagesItemActionsSheetState(
targetItem = messagesTimelineItemState, targetItem = messagesTimelineItemState,
actions = actions actions = actions

View file

@ -1,5 +1,7 @@
package io.element.android.x.features.messages.model package io.element.android.x.features.messages.model
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
sealed interface MessagesItemGroupPosition { sealed interface MessagesItemGroupPosition {
object First : MessagesItemGroupPosition object First : MessagesItemGroupPosition
object Middle : MessagesItemGroupPosition object Middle : MessagesItemGroupPosition
@ -12,3 +14,12 @@ sealed interface MessagesItemGroupPosition {
} }
} }
internal class MessagesItemGroupPositionProvider : PreviewParameterProvider<MessagesItemGroupPosition> {
override val values = sequenceOf(
MessagesItemGroupPosition.First,
MessagesItemGroupPosition.Middle,
MessagesItemGroupPosition.Last,
MessagesItemGroupPosition.None,
)
}

View file

@ -9,7 +9,7 @@ sealed interface MessagesTimelineItemState {
) : MessagesTimelineItemState ) : MessagesTimelineItemState
data class MessageEvent( data class MessageEvent(
val id: String = "", val id: String,
val senderId: String, val senderId: String,
val senderDisplayName: String?, val senderDisplayName: String?,
val senderAvatar: AvatarData, val senderAvatar: AvatarData,

View file

@ -1,3 +1,31 @@
package io.element.android.x.features.messages.model.content package io.element.android.x.features.messages.model.content
sealed interface MessagesTimelineItemContent import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import org.matrix.rustcomponents.sdk.EncryptedMessage
import org.matrix.rustcomponents.sdk.FormattedBody
import org.matrix.rustcomponents.sdk.MessageFormat
sealed interface MessagesTimelineItemContent
class MessagesTimelineItemContentProvider : PreviewParameterProvider<MessagesTimelineItemContent> {
override val values = sequenceOf(
MessagesTimelineItemEmoteContent(
body = "Emote",
formattedBody = FormattedBody(MessageFormat.HTML, "Formatted emote")
),
MessagesTimelineItemEncryptedContent(
encryptedMessage = EncryptedMessage.Unknown
),
// TODO MessagesTimelineItemImageContent(),
MessagesTimelineItemNoticeContent(
body = "Notice",
formattedBody = FormattedBody(MessageFormat.HTML, "Formatted notice")
),
MessagesTimelineItemRedactedContent,
MessagesTimelineItemTextContent(
body = "Text",
formattedBody = FormattedBody(MessageFormat.HTML, "Formatted text")
),
MessagesTimelineItemUnknownContent,
)
}

View file

@ -1,5 +1,7 @@
plugins { plugins {
id("io.element.android-compose") id("io.element.android-compose")
// TODO Move to common config
id("com.google.devtools.ksp") version "1.7.20-1.0.7"
} }
android { android {
@ -17,4 +19,6 @@ dependencies {
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.3") androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0") androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
// TODO Move to common config
ksp("com.airbnb.android:showkase-processor:1.0.0-beta14")
} }

View file

@ -1,5 +1,7 @@
plugins { plugins {
id("io.element.android-compose") id("io.element.android-compose")
// TODO Move to common config
id("com.google.devtools.ksp") version "1.7.20-1.0.7"
} }
android { android {
@ -17,4 +19,6 @@ dependencies {
testImplementation("junit:junit:4.13.2") testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.3") androidTestImplementation("androidx.test.ext:junit:1.1.3")
androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0") androidTestImplementation("androidx.test.espresso:espresso-core:3.4.0")
// TODO Move to common config
ksp("com.airbnb.android:showkase-processor:1.0.0-beta14")
} }

View file

@ -145,7 +145,7 @@ private fun LazyListState.isScrolled(): Boolean {
@Preview @Preview
@Composable @Composable
private fun PreviewableRoomListContent() { fun PreviewableRoomListContent() {
ElementXTheme(darkTheme = false) { ElementXTheme(darkTheme = false) {
RoomListContent( RoomListContent(
roomSummaries = stubbedRoomSummaries(), roomSummaries = stubbedRoomSummaries(),
@ -162,7 +162,7 @@ private fun PreviewableRoomListContent() {
@Preview @Preview
@Composable @Composable
private fun PreviewableDarkRoomListContent() { fun PreviewableDarkRoomListContent() {
ElementXTheme(darkTheme = true) { ElementXTheme(darkTheme = true) {
RoomListContent( RoomListContent(
roomSummaries = stubbedRoomSummaries(), roomSummaries = stubbedRoomSummaries(),

View file

@ -3,6 +3,7 @@
android_gradle_plugin = "7.3.1" android_gradle_plugin = "7.3.1"
firebase_gradle_plugin = "3.0.2" firebase_gradle_plugin = "3.0.2"
kotlin = "1.7.20" kotlin = "1.7.20"
ksp = "1.7.20-1.0.7"
# AndroidX # AndroidX
material = "1.6.1" material = "1.6.1"
@ -92,3 +93,5 @@ wysiwyg = { module = "io.element.android:wysiwyg", version.ref = "wysiwyg" }
[bundles] [bundles]
[plugins]
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }

View file

@ -1,6 +1,7 @@
plugins { plugins {
id 'com.android.library' id 'com.android.library'
id 'org.jetbrains.kotlin.android' id 'org.jetbrains.kotlin.android'
id 'io.element.android-compose'
} }
android { android {

View file

@ -0,0 +1,14 @@
package io.element.android.x.core.compose
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
open class PairCombinedPreviewParameter<T1, T2>(
private val provider: Pair<PreviewParameterProvider<T1>, PreviewParameterProvider<T2>>
) : PreviewParameterProvider<Pair<T1, T2>> {
override val values: Sequence<Pair<T1, T2>>
get() = provider.first.values.flatMap { first ->
provider.second.values.map { second ->
first to second
}
}
}

View file

@ -1,5 +1,7 @@
plugins { plugins {
id("io.element.android-compose") id("io.element.android-compose")
// TODO Move to common config
id("com.google.devtools.ksp") version "1.7.20-1.0.7"
} }
android { android {
@ -9,5 +11,7 @@ android {
// Should not be there, but this is a POC // Should not be there, but this is a POC
implementation("io.coil-kt:coil-compose:2.2.1") implementation("io.coil-kt:coil-compose:2.2.1")
implementation(libs.accompanist.systemui) implementation(libs.accompanist.systemui)
// TODO Move to common config
ksp("com.airbnb.android:showkase-processor:1.0.0-beta14")
} }
} }

View file

@ -1,8 +1,11 @@
package io.element.android.x.designsystem package io.element.android.x.designsystem
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import com.airbnb.android.showkase.annotation.ShowkaseColor
@ShowkaseColor(name = "LightGrey", group = "Material Design")
val LightGrey = Color(0x993C3C43) val LightGrey = Color(0x993C3C43)
@ShowkaseColor(name = "DarkGrey", group = "Material Design")
val DarkGrey = Color(0x99EBEBF5) val DarkGrey = Color(0x99EBEBF5)
val AvatarGradientStart = Color(0xFF4CA1AF) val AvatarGradientStart = Color(0xFF4CA1AF)

View file

@ -7,24 +7,31 @@ import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import com.airbnb.android.showkase.annotation.ShowkaseTypography
@ShowkaseTypography(name = "Body Large", group = "Element")
val bodyLarge = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
)
@ShowkaseTypography(name = "Headline Small", group = "Element")
val headlineSmall = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Bold,
fontSize = 32.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
)
// Set of Material typography styles to start with // Set of Material typography styles to start with
val Typography = Typography( val Typography = Typography(
bodyLarge = bodyLarge,
bodyLarge = TextStyle( headlineSmall = headlineSmall,
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Normal,
fontSize = 16.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
),
headlineSmall = TextStyle(
fontFamily = FontFamily.Default,
fontWeight = FontWeight.Bold,
fontSize = 32.sp,
lineHeight = 24.sp,
letterSpacing = 0.5.sp
),
/* Other default text styles to override /* Other default text styles to override
titleLarge = TextStyle( titleLarge = TextStyle(
fontFamily = FontFamily.Default, fontFamily = FontFamily.Default,

View file

@ -51,6 +51,6 @@ fun ProgressDialog(text: String? = null, onDismiss: () -> Unit = {}) {
@Composable @Composable
@Preview @Preview
private fun ProgressDialogPreview() { fun ProgressDialogPreview() {
ProgressDialog("test dialog content") ProgressDialog("test dialog content")
} }

View file

@ -71,7 +71,7 @@ fun ConfirmationDialog(
@Composable @Composable
@Preview @Preview
private fun ConfirmationDialogPreview() { fun ConfirmationDialogPreview() {
ConfirmationDialog( ConfirmationDialog(
isDisplayed = remember { mutableStateOf(true) }, isDisplayed = remember { mutableStateOf(true) },
title = "Title", title = "Title",

View file

@ -1,5 +1,7 @@
plugins { plugins {
id("io.element.android-compose") id("io.element.android-compose")
// TODO Move to common config
id("com.google.devtools.ksp") version "1.7.20-1.0.7"
} }
android { android {
@ -15,4 +17,6 @@ dependencies {
implementation(libs.wysiwyg) implementation(libs.wysiwyg)
implementation(libs.androidx.constraintlayout) implementation(libs.androidx.constraintlayout)
implementation("com.google.android.material:material:1.7.0") implementation("com.google.android.material:material:1.7.0")
// TODO Move to common config
ksp("com.airbnb.android:showkase-processor:1.0.0-beta14")
} }

View file

@ -3,8 +3,18 @@ package io.element.android.x.textcomposer
import android.graphics.Color import android.graphics.Color
import android.net.Uri import android.net.Uri
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalInspectionMode
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.viewinterop.AndroidView import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
import androidx.core.view.isVisible import androidx.core.view.isVisible
@ -20,6 +30,10 @@ fun TextComposer(
composerCanSendMessage: Boolean, composerCanSendMessage: Boolean,
composerText: String?, composerText: String?,
) { ) {
if (LocalInspectionMode.current) {
FakeComposer(modifier)
return
}
val isInDarkMode = isSystemInDarkTheme() val isInDarkMode = isSystemInDarkTheme()
AndroidView( AndroidView(
modifier = modifier, modifier = modifier,
@ -75,10 +89,28 @@ fun TextComposer(
) )
} }
@Composable
private fun FakeComposer(modifier: Modifier) {
// AndroidView is not Available in this mode, just render a Text
Box(
modifier = modifier
.fillMaxWidth()
.height(80.dp)
) {
Text(
modifier = Modifier
.align(Alignment.Center),
textAlign = TextAlign.Center,
text = "Composer Preview",
fontSize = 20.sp
)
}
}
private fun MessageComposerView.setup(isDarkMode: Boolean) { private fun MessageComposerView.setup(isDarkMode: Boolean) {
val editTextColor = if(isDarkMode){ val editTextColor = if (isDarkMode) {
Color.WHITE Color.WHITE
}else{ } else {
Color.BLACK Color.BLACK
} }
editText.setTextColor(editTextColor) editText.setTextColor(editTextColor)
@ -87,3 +119,16 @@ private fun MessageComposerView.setup(isDarkMode: Boolean) {
emojiButton?.isVisible = true emojiButton?.isVisible = true
sendButton.isVisible = true sendButton.isVisible = true
} }
@Preview
@Composable
fun TextComposerPreview() {
TextComposer(
onSendMessage = {},
fullscreen = false,
onFullscreenToggle = { },
onComposerTextChange = {},
composerCanSendMessage = true,
composerText = "Message",
)
}

View file

@ -5,6 +5,8 @@ import extension.proguardConfig
plugins { plugins {
id("com.android.library") id("com.android.library")
id("kotlin-android") id("kotlin-android")
// alias(libs.plugins.ksp)
// id("com.google.devtools.ksp") // version "1.7.20-1.0.7"
} }
android { android {
@ -28,4 +30,6 @@ dependencies {
debugImplementation("androidx.compose.ui:ui-tooling") debugImplementation("androidx.compose.ui:ui-tooling")
debugImplementation("androidx.compose.ui:ui-test-manifest") debugImplementation("androidx.compose.ui:ui-test-manifest")
implementation("com.airbnb.android:showkase:1.0.0-beta14")
// ksp("com.airbnb.android:showkase-processor:1.0.0-beta14")
} }