From 97db09d65d682242ce072bb4fcb5f8e9d1c66056 Mon Sep 17 00:00:00 2001 From: Evgenii Kozlov Date: Wed, 10 Jul 2024 15:39:16 +0200 Subject: [PATCH] DROID-2635 Discussions | Tech | New module, MVVM components, feature toggle, basic views (#1387) --- app/build.gradle | 1 + .../anytype/app/DefaultFeatureToggles.kt | 2 + .../di/feature/discussions/DiscussionsDI.kt | 52 ++++ .../anytype/di/feature/home/HomescreenDI.kt | 2 + .../anytype/ui/home/HomeScreenFragment.kt | 28 ++ .../core_utils/tools/FeatureToggles.kt | 2 + feature-discussions/build.gradle | 60 ++++ .../src/main/AndroidManifest.xml | 2 + .../presentation/DiscussionView.kt | 10 + .../presentation/DiscussionViewModel.kt | 7 + .../DiscussionViewModelFactory.kt | 11 + .../ui/DiscussionPreviews.kt | 73 +++++ .../ui/DiscussionScreen.kt | 273 ++++++++++++++++++ .../src/main/res/drawable/ic_send_message.xml | 9 + settings.gradle | 1 + 15 files changed, 533 insertions(+) create mode 100644 app/src/main/java/com/anytypeio/anytype/di/feature/discussions/DiscussionsDI.kt create mode 100644 feature-discussions/build.gradle create mode 100644 feature-discussions/src/main/AndroidManifest.xml create mode 100644 feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionView.kt create mode 100644 feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModel.kt create mode 100644 feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModelFactory.kt create mode 100644 feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionPreviews.kt create mode 100644 feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionScreen.kt create mode 100644 feature-discussions/src/main/res/drawable/ic_send_message.xml diff --git a/app/build.gradle b/app/build.gradle index 52cb6214d4..cc95f4ced1 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -160,6 +160,7 @@ dependencies { implementation project(':ui-settings') implementation project(':crash-reporting') implementation project(':payments') + implementation project(':feature-discussions') implementation project(':gallery-experience') //Compile time dependencies diff --git a/app/src/main/java/com/anytypeio/anytype/app/DefaultFeatureToggles.kt b/app/src/main/java/com/anytypeio/anytype/app/DefaultFeatureToggles.kt index 4cc444dab3..e632882506 100644 --- a/app/src/main/java/com/anytypeio/anytype/app/DefaultFeatureToggles.kt +++ b/app/src/main/java/com/anytypeio/anytype/app/DefaultFeatureToggles.kt @@ -31,4 +31,6 @@ class DefaultFeatureToggles @Inject constructor( override val isConciseLogging: Boolean = true override val enableSpaces: Boolean = true + + override val enableDiscussionDemo: Boolean = false } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/discussions/DiscussionsDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/discussions/DiscussionsDI.kt new file mode 100644 index 0000000000..81bf0e36c9 --- /dev/null +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/discussions/DiscussionsDI.kt @@ -0,0 +1,52 @@ +package com.anytypeio.anytype.di.feature.discussions + +import androidx.lifecycle.ViewModelProvider +import com.anytypeio.anytype.analytics.base.Analytics +import com.anytypeio.anytype.core_utils.di.scope.PerScreen +import com.anytypeio.anytype.di.common.ComponentDependencies +import com.anytypeio.anytype.domain.base.AppCoroutineDispatchers +import com.anytypeio.anytype.domain.block.repo.BlockRepository +import com.anytypeio.anytype.domain.misc.UrlBuilder +import com.anytypeio.anytype.domain.multiplayer.UserPermissionProvider +import com.anytypeio.anytype.feature_discussions.presentation.DiscussionViewModelFactory +import com.anytypeio.anytype.middleware.EventProxy +import dagger.Binds +import dagger.Component +import dagger.Module + +@Component( + dependencies = [DiscussionComponentDependencies::class], + modules = [ + DiscussionModule::class, + DiscussionModule.Declarations::class + ] +) +@PerScreen +interface DiscussionComponent { + @Component.Factory + interface Factory { + fun create(dependencies: DiscussionComponentDependencies): DiscussionComponent + } +} + +@Module +object DiscussionModule { + @Module + interface Declarations { + @PerScreen + @Binds + fun bindViewModelFactory( + factory: DiscussionViewModelFactory + ): ViewModelProvider.Factory + + } +} + +interface DiscussionComponentDependencies : ComponentDependencies { + fun blockRepository(): BlockRepository + fun appCoroutineDispatchers(): AppCoroutineDispatchers + fun analytics(): Analytics + fun urlBuilder(): UrlBuilder + fun userPermissionProvider(): UserPermissionProvider + fun eventProxy(): EventProxy +} \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/di/feature/home/HomescreenDI.kt b/app/src/main/java/com/anytypeio/anytype/di/feature/home/HomescreenDI.kt index e668315cf3..dba18afa35 100644 --- a/app/src/main/java/com/anytypeio/anytype/di/feature/home/HomescreenDI.kt +++ b/app/src/main/java/com/anytypeio/anytype/di/feature/home/HomescreenDI.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModelProvider import com.anytypeio.anytype.analytics.base.Analytics import com.anytypeio.anytype.core_models.Payload import com.anytypeio.anytype.core_utils.di.scope.PerScreen +import com.anytypeio.anytype.core_utils.tools.FeatureToggles import com.anytypeio.anytype.di.common.ComponentDependencies import com.anytypeio.anytype.di.feature.widgets.SelectWidgetSourceSubcomponent import com.anytypeio.anytype.di.feature.widgets.SelectWidgetTypeSubcomponent @@ -287,4 +288,5 @@ interface HomeScreenDependencies : ComponentDependencies { fun notificationChannel(): NotificationsChannel fun activeSpaceMembers() : ActiveSpaceMemberSubscriptionContainer fun analyticSpaceHelperDelegate(): AnalyticSpaceHelperDelegate + fun featureToggles(): FeatureToggles } \ No newline at end of file diff --git a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt index d18f357fa6..d37c15f08c 100644 --- a/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt +++ b/app/src/main/java/com/anytypeio/anytype/ui/home/HomeScreenFragment.kt @@ -4,9 +4,16 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.MaterialTheme +import androidx.compose.material.Surface import androidx.compose.runtime.collectAsState +import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.compose.ui.res.colorResource @@ -16,14 +23,21 @@ import androidx.fragment.app.viewModels import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController import androidx.navigation.fragment.findNavController import com.anytypeio.anytype.R import com.anytypeio.anytype.core_models.Id import com.anytypeio.anytype.core_ui.extensions.throttledClick import com.anytypeio.anytype.core_utils.ext.argOrNull import com.anytypeio.anytype.core_utils.ext.toast +import com.anytypeio.anytype.core_utils.tools.FeatureToggles import com.anytypeio.anytype.core_utils.ui.BaseComposeFragment import com.anytypeio.anytype.di.common.componentManager +import com.anytypeio.anytype.feature_discussions.ui.DiscussionPreview +import com.anytypeio.anytype.feature_discussions.ui.DiscussionScreenPreview +import com.anytypeio.anytype.feature_discussions.ui.DiscussionScreenWrapper import com.anytypeio.anytype.other.DefaultDeepLinkResolver import com.anytypeio.anytype.presentation.home.Command import com.anytypeio.anytype.presentation.home.HomeScreenViewModel @@ -38,6 +52,7 @@ import com.anytypeio.anytype.ui.settings.space.SpaceSettingsFragment import com.anytypeio.anytype.ui.settings.typography import com.anytypeio.anytype.ui.widgets.SelectWidgetSourceFragment import com.anytypeio.anytype.ui.widgets.SelectWidgetTypeFragment +import com.google.accompanist.navigation.material.rememberBottomSheetNavigator import javax.inject.Inject import kotlinx.coroutines.launch import timber.log.Timber @@ -53,6 +68,9 @@ class HomeScreenFragment : BaseComposeFragment() { @Inject lateinit var factory: HomeScreenViewModel.Factory + @Inject + lateinit var featureToggles: FeatureToggles + private val vm by viewModels { factory } override fun onCreateView( @@ -112,6 +130,10 @@ class HomeScreenFragment : BaseComposeFragment() { onObjectCheckboxClicked = vm::onObjectCheckboxClicked, onSpaceShareIconClicked = vm::onSpaceShareIconClicked ) + + if (featureToggles.enableDiscussionDemo) { + DiscussionScreenWrapper() + } } } } @@ -309,6 +331,12 @@ class HomeScreenFragment : BaseComposeFragment() { componentManager().homeScreenComponent.release() } + override fun onApplyWindowRootInsets(view: View) { + if (!featureToggles.enableDiscussionDemo) { + super.onApplyWindowRootInsets(view) + } + } + companion object { const val SHOW_MNEMONIC_KEY = "arg.home-screen.show-mnemonic" const val DEEP_LINK_KEY = "arg.home-screen.deep-link" diff --git a/core-utils/src/main/java/com/anytypeio/anytype/core_utils/tools/FeatureToggles.kt b/core-utils/src/main/java/com/anytypeio/anytype/core_utils/tools/FeatureToggles.kt index 78259eb531..b5cb11d5e9 100644 --- a/core-utils/src/main/java/com/anytypeio/anytype/core_utils/tools/FeatureToggles.kt +++ b/core-utils/src/main/java/com/anytypeio/anytype/core_utils/tools/FeatureToggles.kt @@ -17,4 +17,6 @@ interface FeatureToggles { val isLogEditorControlPanelMachine: Boolean val enableSpaces: Boolean + + val enableDiscussionDemo: Boolean } \ No newline at end of file diff --git a/feature-discussions/build.gradle b/feature-discussions/build.gradle new file mode 100644 index 0000000000..ab4278284b --- /dev/null +++ b/feature-discussions/build.gradle @@ -0,0 +1,60 @@ +plugins { + id "com.android.library" + id "kotlin-android" + alias(libs.plugins.compose.compiler) +} + +android { + buildFeatures { + compose true + } + + namespace 'com.anytypeio.anytype.feature_discussions' + + testOptions { + unitTests.returnDefaultValues = true + } +} + +dependencies { + implementation project(':domain') + implementation project(':core-ui') + implementation project(':analytics') + implementation project(':core-models') + implementation project(':core-utils') + implementation project(':localization') + implementation project(':presentation') + implementation project(':library-emojifier') + implementation libs.navigationCompose + + compileOnly libs.javaxInject + + implementation libs.lifecycleViewModel + implementation libs.lifecycleRuntime + + implementation libs.appcompat + implementation libs.compose + implementation libs.composeFoundation + implementation libs.composeToolingPreview + implementation libs.composeMaterial3 + + implementation libs.coilCompose + + debugImplementation libs.composeTooling + + implementation libs.timber + + testImplementation libs.junit + testImplementation libs.kotlinTest + testImplementation libs.mockitoKotlin + testImplementation libs.coroutineTesting + testImplementation libs.liveDataTesting + testImplementation libs.archCoreTesting + testImplementation libs.androidXTestCore + testImplementation libs.robolectric + testImplementation libs.timberJUnit + testImplementation libs.turbine + + testImplementation project(":test:utils") + testImplementation project(":test:core-models-stub") +} \ No newline at end of file diff --git a/feature-discussions/src/main/AndroidManifest.xml b/feature-discussions/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..1d26c87a17 --- /dev/null +++ b/feature-discussions/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionView.kt b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionView.kt new file mode 100644 index 0000000000..6ec33e0ebf --- /dev/null +++ b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionView.kt @@ -0,0 +1,10 @@ +package com.anytypeio.anytype.feature_discussions.presentation + +sealed interface DiscussionView { + data class Message( + val id: String, + val msg: String, + val author: String, + val timestamp: Long + ) : DiscussionView +} \ No newline at end of file diff --git a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModel.kt b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModel.kt new file mode 100644 index 0000000000..ad9b9a4733 --- /dev/null +++ b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModel.kt @@ -0,0 +1,7 @@ +package com.anytypeio.anytype.feature_discussions.presentation + +import com.anytypeio.anytype.presentation.common.BaseViewModel + +class DiscussionViewModel : BaseViewModel() { + +} \ No newline at end of file diff --git a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModelFactory.kt b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModelFactory.kt new file mode 100644 index 0000000000..f2aa018e28 --- /dev/null +++ b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/presentation/DiscussionViewModelFactory.kt @@ -0,0 +1,11 @@ +package com.anytypeio.anytype.feature_discussions.presentation + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import javax.inject.Inject + +class DiscussionViewModelFactory @Inject constructor( +) : ViewModelProvider.Factory { + @Suppress("UNCHECKED_CAST") + override fun create(modelClass: Class): T = DiscussionViewModel() as T +} \ No newline at end of file diff --git a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionPreviews.kt b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionPreviews.kt new file mode 100644 index 0000000000..3782e23f08 --- /dev/null +++ b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionPreviews.kt @@ -0,0 +1,73 @@ +package com.anytypeio.anytype.feature_discussions.ui + +import android.content.res.Configuration +import androidx.compose.runtime.Composable +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.tooling.preview.Preview +import com.anytypeio.anytype.feature_discussions.R +import com.anytypeio.anytype.feature_discussions.presentation.DiscussionView +import kotlin.time.DurationUnit +import kotlin.time.toDuration + +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Light Mode") +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO, name = "Dark Mode") +@Composable +fun DiscussionPreview() { + Messages( + messages = listOf( + DiscussionView.Message( + id = "1", + msg = stringResource(id = R.string.default_text_placeholder), + author = "Walter", + timestamp = System.currentTimeMillis() + ), + DiscussionView.Message( + id = "2", + msg = stringResource(id = R.string.default_text_placeholder), + author = "Leo", + timestamp = System.currentTimeMillis() + ), + DiscussionView.Message( + id = "3", + msg = stringResource(id = R.string.default_text_placeholder), + author = "Gilbert", + timestamp = System.currentTimeMillis() + ) + ) + ) +} + +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Light Mode") +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO, name = "Dark Mode") +@Composable +fun DiscussionScreenPreview() { + DiscussionScreen( + title = "Conversations with friends", + messages = buildList { + repeat(30) { idx -> + add( + DiscussionView.Message( + id = idx.toString(), + msg = stringResource(id = R.string.default_text_placeholder), + author = "User ${idx.inc()}", + timestamp = + System.currentTimeMillis() + - 30.toDuration(DurationUnit.DAYS).inWholeMilliseconds + + idx.toDuration(DurationUnit.DAYS).inWholeMilliseconds + ) + ) + } + } + ) +} + +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES, name = "Light Mode") +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_NO, name = "Dark Mode") +@Composable +fun BubblePreview() { + Bubble( + name = "Leo Marx", + msg = stringResource(id = R.string.default_text_placeholder), + timestamp = System.currentTimeMillis() + ) +} \ No newline at end of file diff --git a/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionScreen.kt b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionScreen.kt new file mode 100644 index 0000000000..54b1c52e46 --- /dev/null +++ b/feature-discussions/src/main/java/com/anytypeio/anytype/feature_discussions/ui/DiscussionScreen.kt @@ -0,0 +1,273 @@ +package com.anytypeio.anytype.feature_discussions.ui + +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +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.clip +import androidx.compose.ui.graphics.SolidColor +import androidx.compose.ui.res.colorResource +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.unit.dp +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.anytypeio.anytype.core_ui.foundation.Divider +import com.anytypeio.anytype.core_ui.views.BodyRegular +import com.anytypeio.anytype.core_ui.views.Caption1Regular +import com.anytypeio.anytype.core_ui.views.HeadlineTitle +import com.anytypeio.anytype.core_ui.views.PreviewTitle2Medium +import com.anytypeio.anytype.core_ui.views.Relations2 +import com.anytypeio.anytype.core_utils.const.DateConst.DEFAULT_DATE_FORMAT +import com.anytypeio.anytype.core_utils.ext.formatTimeInMillis +import com.anytypeio.anytype.feature_discussions.R +import com.anytypeio.anytype.feature_discussions.presentation.DiscussionView + + +@Composable +fun DiscussionScreenWrapper() { + NavHost( + navController = rememberNavController(), + startDestination = "discussions" + ) { + composable( + route = "discussions" + ) { + Surface( + modifier = Modifier + .fillMaxSize() + .background(color = colorResource(id = R.color.background_primary)) + ) { + DiscussionScreenPreview() + } + } + } +} + +/** + * TODO: do date formating before rendering? + */ +@Composable +fun DiscussionScreen( + title: String, + messages: List +) { + Column( + modifier = Modifier + .fillMaxSize() + .windowInsetsPadding(WindowInsets.systemBars) + ) { + Text( + style = HeadlineTitle, + text = title, + color = colorResource(id = R.color.text_primary), + modifier = Modifier.padding( + top = 20.dp, + start = 20.dp, + end = 20.dp, + bottom = 8.dp + ) + ) + Text( + style = Relations2, + text = "Discussion", + color = colorResource(id = R.color.text_secondary), + modifier = Modifier.padding( + bottom = 8.dp, + start = 20.dp + ) + ) + Messages( + modifier = Modifier.weight(1.0f), + messages = messages + ) + Divider( + paddingStart = 0.dp, + paddingEnd = 0.dp + ) + Row( + modifier = Modifier + .imePadding() + .fillMaxWidth() + .height(56.dp) + ) { + Box( + modifier = Modifier + .padding(horizontal = 4.dp) + .clip(CircleShape) + .align(Alignment.CenterVertically) + .clickable { + // TODO + } + ) { + Image( + painter = painterResource(id = R.drawable.ic_plus_32), + contentDescription = "Plus button", + modifier = Modifier + .align(Alignment.Center) + .clickable { + // TODO + } + ) + } + + var textField by rememberSaveable { mutableStateOf("") } + + BasicTextField( + value = textField, + onValueChange = { textField = it }, + textStyle = BodyRegular.copy( + color = colorResource(id = R.color.text_primary) + ), + modifier = Modifier + .imePadding() + .weight(1f) + .padding( + start = 4.dp, + end = 4.dp + ) + .align(Alignment.CenterVertically) + , + cursorBrush = SolidColor(colorResource(id = R.color.palette_system_blue)) + ) + Box( + modifier = Modifier + .padding(horizontal = 4.dp) + .clip(CircleShape) + .align(Alignment.CenterVertically) + .clickable { + // TODO + } + ) { + Image( + painter = painterResource(id = R.drawable.ic_send_message), + contentDescription = "Send message button", + modifier = Modifier + .padding(horizontal = 4.dp, vertical = 4.dp) + .align(Alignment.Center) + ) + } + } + } +} + + +@Composable +fun Messages( + modifier: Modifier = Modifier, + messages: List +) { + LazyColumn( + modifier = modifier, + verticalArrangement = Arrangement.spacedBy(12.dp), + ) { + itemsIndexed( + messages, + key = { _, msg -> msg.id } + ) { idx, msg -> + if (idx == 0) + Spacer(modifier = Modifier.height(36.dp)) + Row( + modifier = Modifier.padding(horizontal = 48.dp) + ) { + Box( + modifier = Modifier + .size(32.dp) + .background( + colorResource(id = R.color.palette_system_blue), + shape = CircleShape + ) + .align(Alignment.Bottom) + ) + Spacer(modifier = Modifier.width(8.dp)) + Bubble( + name = msg.author, + msg = msg.msg, + timestamp = msg.timestamp + ) + } + if (idx == messages.lastIndex) { + Spacer(modifier = Modifier.height(36.dp)) + } + } + } +} + +@Composable +fun Bubble( + name: String, + msg: String, + timestamp: Long +) { + Box( + modifier = Modifier + .fillMaxWidth() + .background( + color = colorResource(id = R.color.palette_very_light_grey), + shape = RoundedCornerShape(24.dp) + ) + ) { + Row( + modifier = Modifier.padding( + start = 16.dp, + end = 16.dp, + top = 12.dp + ) + ) { + Text( + text = name, + style = PreviewTitle2Medium, + color = colorResource(id = R.color.text_primary), + maxLines = 1, + modifier = Modifier.weight(1f) + ) + Text( + text = timestamp.formatTimeInMillis( + DEFAULT_DATE_FORMAT + ), + style = Caption1Regular, + color = colorResource(id = R.color.text_secondary), + maxLines = 1 + ) + } + Text( + modifier = Modifier.padding( + top = 32.dp, + start = 16.dp, + end = 16.dp, + bottom = 12.dp + ), + text = msg, + style = BodyRegular, + color = colorResource(id = R.color.text_primary) + ) + } +} \ No newline at end of file diff --git a/feature-discussions/src/main/res/drawable/ic_send_message.xml b/feature-discussions/src/main/res/drawable/ic_send_message.xml new file mode 100644 index 0000000000..a805f8c00d --- /dev/null +++ b/feature-discussions/src/main/res/drawable/ic_send_message.xml @@ -0,0 +1,9 @@ + + + diff --git a/settings.gradle b/settings.gradle index 160a4225ab..0970583d6d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -64,3 +64,4 @@ include ':crash-reporting' include ':localization' include ':payments' include ':gallery-experience' +include ':feature-discussions'