Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Home] 후원사 카드 이미지 애니메이션(무한/자동 스크롤) #129

Merged
merged 9 commits into from
Jul 31, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -2,80 +2,143 @@ package com.droidknights.app2023.feature.home

import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.scrollBy
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.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.droidknights.app2023.core.designsystem.component.KnightsCard
import com.droidknights.app2023.core.designsystem.component.NetworkImage
import com.droidknights.app2023.core.designsystem.theme.KnightsTheme
import com.droidknights.app2023.core.model.Sponsor
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive

private const val SCROLL_DELAY_MILLIS = 20L
private const val SCROLL_PIXEL_UNIT = 4f

@Composable
fun SponsorCard(
// TODO: 실제 데이터와 연결
uiState: SponsorsUiState = SponsorsUiState(emptyList()),
uiState: SponsorsUiState =
listOf(
Sponsor(
name = "Sponsor1",
homepage = "https://www.instagram.com/droid_knights",
grade = Sponsor.Grade.GOLD,
imageUrl = "https://picsum.photos/id/237/200/200",
),
Sponsor(
name = "Sponsor2",
homepage = "https://www.instagram.com/droid_knights",
grade = Sponsor.Grade.PLATINUM,
imageUrl = "https://picsum.photos/id/204/200/200",
),
Sponsor(
name = "Sponsor3",
homepage = "https://www.instagram.com/droid_knights",
grade = Sponsor.Grade.PLATINUM,
imageUrl = "https://picsum.photos/id/203/200/200",
),
Sponsor(
name = "Sponsor4",
homepage = "https://www.instagram.com/droid_knights",
grade = Sponsor.Grade.PLATINUM,
imageUrl = "https://picsum.photos/id/202/200/200",
),
Sponsor(
name = "Sponsor5",
homepage = "https://www.instagram.com/droid_knights",
grade = Sponsor.Grade.PLATINUM,
imageUrl = "https://picsum.photos/id/201/200/200",
),
Sponsor(
name = "Sponsor6",
homepage = "https://www.instagram.com/droid_knights",
grade = Sponsor.Grade.PLATINUM,
imageUrl = "https://picsum.photos/id/200/200/200",
),
).let(::SponsorsUiState),
) {
KnightsCard {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 24.dp)
modifier = Modifier.fillMaxWidth()
) {
Text(
text = stringResource(id = R.string.sponsor_card_title),
style = KnightsTheme.typography.headlineSmallBL,
color = Color(0xFF000000),
modifier = Modifier.padding(top = 24.dp),
)
Text(
text = stringResource(
id = R.string.sponsor_card_description,
uiState.platinumCount,
uiState.goldCount
),
style = KnightsTheme.typography.titleSmallR,
color = Color(0xFF868686),
modifier = Modifier.padding(top = 8.dp),
)
SponsorGroup(uiState.sponsors)
Column(modifier = Modifier.padding(horizontal = 24.dp)) {
Text(
text = stringResource(id = R.string.sponsor_card_title),
style = KnightsTheme.typography.headlineSmallBL,
color = Color(0xFF000000),
modifier = Modifier.padding(top = 24.dp),
)
Text(
text = stringResource(
id = R.string.sponsor_card_description,
uiState.platinumCount,
uiState.goldCount
),
style = KnightsTheme.typography.titleSmallR,
color = Color(0xFF868686),
modifier = Modifier.padding(top = 8.dp),
)
}
if (uiState.isNotEmpty()) {
SponsorGroup(uiState.sponsors)
}
}
}
}

// TODO: 이미지 연결 및 동적으로 배치
// TODO: 세로 두 줄 고정 필요
@Composable
private fun SponsorGroup(
sponsors: List<Sponsor>,
) {
Row(
horizontalArrangement = Arrangement
.spacedBy(
space = 8.dp,
alignment = Alignment.CenterHorizontally,
),
val scrollState = rememberLazyListState()
val lifecycleOwner = LocalLifecycleOwner.current

LazyRow(
state = scrollState,
horizontalArrangement = Arrangement.spacedBy(
space = 14.dp,
alignment = Alignment.CenterHorizontally,
),
userScrollEnabled = false,
modifier = Modifier
.fillMaxWidth()
.padding(24.dp),
.padding(vertical = 24.dp)
.fillMaxWidth(),
) {
sponsors.forEach {
SponsorLogo(it)
items(count = Int.MAX_VALUE) { index ->
SponsorLogo(sponsor = sponsors[index % sponsors.size])
}
}
LaunchedEffect(Unit) {
lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
while (isActive) {
scrollState.scrollBy(SCROLL_PIXEL_UNIT)
delay(SCROLL_DELAY_MILLIS)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ data class SponsorsUiState(val sponsors: List<Sponsor>) {

val goldCount: Int
get() = sponsors.count { it.grade == Sponsor.Grade.GOLD }

fun isNotEmpty() = sponsors.isNotEmpty()
}