Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ private fun GetMainDataResponse.GrowthGraph.toDomain(): PresentationGrowthPoint
internal fun GetCurationResponse.toDomain(): Curation =
Curation(
guideMessage = guideMessage,
category = Category.from(value = type),
purpose = Purpose.from(value = purpose),
style = Style.from(value = style),
audience = Audience.from(value = audience),
materialType = materialType,
title = title,
sourceChannel = sourceChannel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package com.team.prezel.core.model.presentation

data class Curation(
val guideMessage: String,
val category: Category,
val purpose: Purpose,
val style: Style,
val audience: Audience,
val materialType: String,
val title: String,
val sourceChannel: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,22 @@ import kotlinx.serialization.Serializable
data class GetCurationResponse(
@SerialName("guideMessage")
val guideMessage: String,
@SerialName("imageUrl")
val imageUrl: String,
@SerialName("linkUrl")
val linkUrl: String,
@SerialName("type")
val type: String,
@SerialName("purpose")
val purpose: String,
@SerialName("style")
val style: String,
@SerialName("audience")
val audience: String,
@SerialName("materialType")
val materialType: String,
@SerialName("sourceChannel")
val sourceChannel: String,
@SerialName("title")
val title: String,
@SerialName("sourceChannel")
val sourceChannel: String,
@SerialName("linkUrl")
val linkUrl: String,
@SerialName("imageUrl")
val imageUrl: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalResources
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
Expand All @@ -28,6 +29,7 @@ import com.team.prezel.feature.home.impl.main.model.PracticeRecordsUiModel
import com.team.prezel.feature.home.impl.main.model.PresentationUiModel
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toPersistentList
import kotlinx.coroutines.launch
import kotlinx.datetime.LocalDate

@Composable
Expand All @@ -44,6 +46,7 @@ internal fun HomeScreen(
val pagerState = rememberPagerState(0) { uiState.presentationCount() }
val snackbarHostState = LocalSnackbarHostState.current
val resources = LocalResources.current
val scope = rememberCoroutineScope()

LaunchedEffect(Unit) {
viewModel.onIntent(HomeUiIntent.FetchData)
Expand Down Expand Up @@ -80,6 +83,13 @@ internal fun HomeScreen(
onClickCardGraphItemIndex = { presentationId, index ->
viewModel.onIntent(HomeUiIntent.ClickCardGraphItem(presentationId = presentationId, index = index))
},
onCurationLinkOpenFailed = {
scope.launch {
snackbarHostState.showPrezelSnackbar(
message = resources.getString(R.string.feature_home_impl_open_curation_link_failed),
)
}
},
modifier = modifier,
)
}
Expand Down Expand Up @@ -156,6 +166,7 @@ private fun HomeScreenPreview(uiState: HomeUiState) {
onClickVoiceRecordingAnalysis = {},
onClickFileUploadAnalysis = {},
onClickCardGraphItemIndex = { _, _ -> },
onCurationLinkOpenFailed = {},
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ internal fun HomeScreenContent(
onClickVoiceRecordingAnalysis: () -> Unit,
onClickFileUploadAnalysis: () -> Unit,
onClickCardGraphItemIndex: (presentationId: Long, index: Int) -> Unit,
onCurationLinkOpenFailed: () -> Unit,
modifier: Modifier = Modifier,
) {
val scope = rememberCoroutineScope()
Expand Down Expand Up @@ -85,6 +86,7 @@ internal fun HomeScreenContent(
onClickAnalyzePresentation = onClickAnalyzePresentation,
onClickWriteFeedback = onClickWriteFeedback,
onClickCardGraphItemIndex = onClickCardGraphItemIndex,
onCurationLinkOpenFailed = onCurationLinkOpenFailed,
)
}
}
Expand All @@ -102,6 +104,7 @@ private fun HomeContent(
onClickAnalyzePresentation: (PresentationUiModel) -> Unit,
onClickWriteFeedback: (PresentationUiModel) -> Unit,
onClickCardGraphItemIndex: (presentationId: Long, index: Int) -> Unit,
onCurationLinkOpenFailed: () -> Unit,
) {
when (uiState) {
HomeUiState.Loading -> Unit
Expand All @@ -123,6 +126,7 @@ private fun HomeContent(
onClickAnalyzePresentation = onClickAnalyzePresentation,
onClickWriteFeedback = onClickWriteFeedback,
onClickCardGraphItemIndex = { index -> onClickCardGraphItemIndex(uiState.presentation.id, index) },
onCurationLinkOpenFailed = onCurationLinkOpenFailed,
)
}

Expand All @@ -136,6 +140,7 @@ private fun HomeContent(
onClickAnalyzePresentation = onClickAnalyzePresentation,
onClickWriteFeedback = onClickWriteFeedback,
onClickCardGraphItemIndex = onClickCardGraphItemIndex,
onCurationLinkOpenFailed = onCurationLinkOpenFailed,
)
}
}
Expand Down Expand Up @@ -170,6 +175,7 @@ private fun HomePresentationContent(
onClickAnalyzePresentation: (PresentationUiModel) -> Unit,
onClickWriteFeedback: (PresentationUiModel) -> Unit,
onClickCardGraphItemIndex: (index: Int) -> Unit,
onCurationLinkOpenFailed: () -> Unit,
) {
HomePageLayout(
maxHeight = maxHeight,
Expand All @@ -179,6 +185,7 @@ private fun HomePresentationContent(
presentation = presentation,
onClickPracticeRecording = onClickPracticeRecording,
onClickCardGraphItemIndex = onClickCardGraphItemIndex,
onCurationLinkOpenFailed = onCurationLinkOpenFailed,
)
},
heroContent = {
Expand All @@ -201,6 +208,7 @@ private fun HomeMultipleContent(
onClickAnalyzePresentation: (PresentationUiModel) -> Unit,
onClickWriteFeedback: (PresentationUiModel) -> Unit,
onClickCardGraphItemIndex: (presentationId: Long, index: Int) -> Unit,
onCurationLinkOpenFailed: () -> Unit,
) {
HorizontalPager(
state = pagerState,
Expand All @@ -219,6 +227,7 @@ private fun HomeMultipleContent(
onClickAnalyzePresentation = onClickAnalyzePresentation,
onClickWriteFeedback = onClickWriteFeedback,
onClickCardGraphItemIndex = { index -> onClickCardGraphItemIndex(presentation.id, index) },
onCurationLinkOpenFailed = onCurationLinkOpenFailed,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package com.team.prezel.feature.home.impl.main.component.body

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.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import com.team.prezel.core.designsystem.component.PrezelAsyncImage
import com.team.prezel.core.designsystem.component.chip.chip.ChipSize
import com.team.prezel.core.designsystem.component.chip.chip.ChipType
import com.team.prezel.core.designsystem.component.chip.chip.PrezelChip
import com.team.prezel.core.designsystem.preview.BasicPreview
import com.team.prezel.core.designsystem.theme.PrezelTheme
import com.team.prezel.core.model.presentation.Audience
import com.team.prezel.core.model.presentation.Category
import com.team.prezel.core.model.presentation.Purpose
import com.team.prezel.core.model.presentation.Style
import com.team.prezel.core.ui.util.noRippleClickable
import com.team.prezel.feature.home.impl.main.model.CurationUiModel
import java.net.URI

@Composable
internal fun CurationCard(
curation: CurationUiModel,
onLinkOpenFailed: () -> Unit,
modifier: Modifier = Modifier,
) {
val uriHandler = LocalUriHandler.current

Row(
modifier = modifier
.fillMaxWidth()
.noRippleClickable {
if (curation.linkUrl.isSupportedWebUrl()) {
try {
uriHandler.openUri(curation.linkUrl)
} catch (_: IllegalArgumentException) {
onLinkOpenFailed()
}
} else {
onLinkOpenFailed()
}
},
horizontalArrangement = Arrangement.spacedBy(PrezelTheme.spacing.V16),
) {
Box(
modifier = Modifier
.size(width = 152.dp, height = 86.dp)
.clip(PrezelTheme.shapes.V4),
) {
PrezelAsyncImage(
url = curation.imageUrl,
contentDescription = "",
modifier = Modifier.fillMaxSize(),
contentScale = ContentScale.Crop,
)
PrezelChip(
text = curation.materialType,
modifier = Modifier.padding(PrezelTheme.spacing.V4),
type = ChipType.FILLED,
size = ChipSize.SMALL,
)
}

Column(
modifier = Modifier.height(86.dp),
verticalArrangement = Arrangement.spacedBy(PrezelTheme.spacing.V4),
) {
Text(
text = curation.title,
color = PrezelTheme.colors.textLarge,
overflow = TextOverflow.Ellipsis,
maxLines = 2,
style = PrezelTheme.typography.caption1Medium,
)
Text(
text = curation.sourceChannel,
color = PrezelTheme.colors.textSmall,
overflow = TextOverflow.Ellipsis,
maxLines = 1,
style = PrezelTheme.typography.caption2Regular,
)
}
}
}

private fun String.isSupportedWebUrl(): Boolean =
runCatching { URI(this) }
.getOrNull()
?.let { uri ->
!uri.host.isNullOrBlank() &&
(uri.scheme.equals("http", ignoreCase = true) || uri.scheme.equals("https", ignoreCase = true))
} == true

@BasicPreview
@Composable
private fun CurationCardPreview() {
PrezelTheme {
CurationCard(
curation = CurationUiModel(
guideMessage = "발표 흐름을 키워드별로 정리해보세요",
category = Category.EDUCATION,
purpose = Purpose.INFO,
style = Style.FORMAL,
audience = Audience.GENERAL,
materialType = "아티클",
title = "제목이 두 줄로 넘어가면 자연스럽게 말줄임표로 전환돼요",
sourceChannel = "계정 이름",
linkUrl = "https://example.com",
imageUrl = "",
),
onLinkOpenFailed = {},
)
}
}
Loading