mirror of
https://github.com/anyproto/anytype-kotlin.git
synced 2025-06-08 05:47:05 +09:00
DROID-2635 Discussions | Tech | New module, MVVM components, feature toggle, basic views (#1387)
This commit is contained in:
parent
5a2b43b1dd
commit
97db09d65d
15 changed files with 533 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -31,4 +31,6 @@ class DefaultFeatureToggles @Inject constructor(
|
|||
override val isConciseLogging: Boolean = true
|
||||
|
||||
override val enableSpaces: Boolean = true
|
||||
|
||||
override val enableDiscussionDemo: Boolean = false
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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<HomeScreenViewModel> { 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"
|
||||
|
|
|
@ -17,4 +17,6 @@ interface FeatureToggles {
|
|||
val isLogEditorControlPanelMachine: Boolean
|
||||
|
||||
val enableSpaces: Boolean
|
||||
|
||||
val enableDiscussionDemo: Boolean
|
||||
}
|
60
feature-discussions/build.gradle
Normal file
60
feature-discussions/build.gradle
Normal file
|
@ -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")
|
||||
}
|
2
feature-discussions/src/main/AndroidManifest.xml
Normal file
2
feature-discussions/src/main/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest/>
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.anytypeio.anytype.feature_discussions.presentation
|
||||
|
||||
import com.anytypeio.anytype.presentation.common.BaseViewModel
|
||||
|
||||
class DiscussionViewModel : BaseViewModel() {
|
||||
|
||||
}
|
|
@ -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 <T : ViewModel> create(modelClass: Class<T>): T = DiscussionViewModel() as T
|
||||
}
|
|
@ -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()
|
||||
)
|
||||
}
|
|
@ -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<DiscussionView.Message>
|
||||
) {
|
||||
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<DiscussionView.Message>
|
||||
) {
|
||||
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)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="32dp"
|
||||
android:height="32dp"
|
||||
android:viewportWidth="32"
|
||||
android:viewportHeight="32">
|
||||
<path
|
||||
android:pathData="M5.406,25.615C4.709,24.9 5.032,24.094 5.564,23.088L8.329,17.813C8.688,17.153 8.966,16.915 9.565,16.899L25.466,16.285C25.653,16.277 25.758,16.154 25.758,16.001C25.75,15.855 25.653,15.724 25.466,15.717L9.565,15.164C8.943,15.141 8.658,14.88 8.329,14.235L5.511,8.829C5.009,7.869 4.717,7.094 5.406,6.387C5.953,5.827 6.823,5.934 7.692,6.333L25.518,14.481C25.998,14.696 26.38,14.934 26.635,15.195C27.122,15.694 27.122,16.308 26.635,16.807C26.38,17.068 25.998,17.306 25.518,17.521L7.789,25.63C6.793,26.083 5.946,26.167 5.406,25.615Z"
|
||||
android:fillColor="@color/glyph_selected"/>
|
||||
</vector>
|
|
@ -64,3 +64,4 @@ include ':crash-reporting'
|
|||
include ':localization'
|
||||
include ':payments'
|
||||
include ':gallery-experience'
|
||||
include ':feature-discussions'
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue