Merge branch 'develop' of https://github.com/vector-im/element-x-android-poc into develop
This commit is contained in:
commit
20fcf51e1e
28 changed files with 330 additions and 45 deletions
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
7
app/src/main/java/io/element/android/x/Showkase.kt
Normal file
7
app/src/main/java/io/element/android/x/Showkase.kt
Normal 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
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
|
|
@ -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"),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
@ -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(),
|
||||||
|
|
|
||||||
|
|
@ -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" }
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue