From fe8088b1ef94df89d4f3afc806562cca6b47f77d Mon Sep 17 00:00:00 2001 From: sangwook Date: Sat, 26 Oct 2024 15:52:57 +0900 Subject: [PATCH 1/3] [mod] #136 design system --- .../component/dialog/RecordyDialog.kt | 6 ++-- .../component/videoplayer/RecordyVideoText.kt | 9 ++++++ .../src/main/res/drawable/ic_seemore.xml | 15 ++++++++++ .../src/main/res/drawable/ic_viskit_logo.xml | 30 +++++++++++++++++++ 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 core/designsystem/src/main/res/drawable/ic_seemore.xml create mode 100644 core/designsystem/src/main/res/drawable/ic_viskit_logo.xml diff --git a/core/designsystem/src/main/java/com/record/designsystem/component/dialog/RecordyDialog.kt b/core/designsystem/src/main/java/com/record/designsystem/component/dialog/RecordyDialog.kt index 44f41a3c..b8a6156d 100644 --- a/core/designsystem/src/main/java/com/record/designsystem/component/dialog/RecordyDialog.kt +++ b/core/designsystem/src/main/java/com/record/designsystem/component/dialog/RecordyDialog.kt @@ -38,7 +38,7 @@ fun RecordyDialog( Column( modifier = Modifier .fillMaxWidth() - .background(color = RecordyTheme.colors.gray08, shape = shape) + .background(color = RecordyTheme.colors.gray10, shape = shape) .padding(horizontal = 16.dp) .padding(bottom = 24.dp, top = 28.dp), horizontalAlignment = Alignment.CenterHorizontally, @@ -76,8 +76,8 @@ fun RecordyDialog( text = negativeButtonLabel, shape = RoundedCornerShape(8.dp), enabled = true, - backgroundColor = RecordyTheme.colors.gray06, - textColor = RecordyTheme.colors.gray01, + backgroundColor = RecordyTheme.colors.gray07, + textColor = RecordyTheme.colors.gray03, textStyle = RecordyTheme.typography.button2, onClick = { onDismissRequest() }, modifier = Modifier diff --git a/core/designsystem/src/main/java/com/record/designsystem/component/videoplayer/RecordyVideoText.kt b/core/designsystem/src/main/java/com/record/designsystem/component/videoplayer/RecordyVideoText.kt index a46bff66..993a143a 100644 --- a/core/designsystem/src/main/java/com/record/designsystem/component/videoplayer/RecordyVideoText.kt +++ b/core/designsystem/src/main/java/com/record/designsystem/component/videoplayer/RecordyVideoText.kt @@ -45,6 +45,7 @@ fun RecordyVideoText( onNicknameClick: () -> Unit = {}, onBookmarkClick: () -> Unit = {}, onDeleteClick: () -> Unit = {}, + onMoreClick: () -> Unit = {}, ) { var boxSize by remember { mutableStateOf(IntSize.Zero) } var expanded by remember { mutableStateOf(false) } @@ -128,6 +129,14 @@ fun RecordyVideoText( style = RecordyTheme.typography.body2M, color = RecordyTheme.colors.gray01, ) + Spacer(modifier = Modifier.height(8.dp)) + Icon( + modifier = Modifier + .customClickable { onMoreClick() }, + painter = painterResource(id = R.drawable.ic_seemore), + contentDescription = "see more", + tint = RecordyTheme.colors.gray01, + ) Spacer(modifier = Modifier.height(if (isMyVideo) 16.dp else 20.dp)) if (isMyVideo) { Icon( diff --git a/core/designsystem/src/main/res/drawable/ic_seemore.xml b/core/designsystem/src/main/res/drawable/ic_seemore.xml new file mode 100644 index 00000000..6261dcb5 --- /dev/null +++ b/core/designsystem/src/main/res/drawable/ic_seemore.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/core/designsystem/src/main/res/drawable/ic_viskit_logo.xml b/core/designsystem/src/main/res/drawable/ic_viskit_logo.xml new file mode 100644 index 00000000..08e2a383 --- /dev/null +++ b/core/designsystem/src/main/res/drawable/ic_viskit_logo.xml @@ -0,0 +1,30 @@ + + + + + + + + + + From ac13a971cf27468955b34a9e0ffcd80a03faaa51 Mon Sep 17 00:00:00 2001 From: sangwook Date: Sat, 26 Oct 2024 15:53:28 +0900 Subject: [PATCH 2/3] [feat] #136 location permission --- app/src/main/AndroidManifest.xml | 2 ++ feature/home/build.gradle.kts | 1 + feature/home/src/main/AndroidManifest.xml | 3 ++- gradle/libs.versions.toml | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 0164e11e..69c4d0fb 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -12,6 +12,8 @@ android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28" tools:ignore="ScopedStorage" /> + + - \ No newline at end of file + + diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 71518883..1b3c8753 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -61,6 +61,7 @@ google-service = "4.4.2" material = "1.12.0" firebase-bom = "33.1.1" crashlytics = "3.0.2" +google-location = "21.3.0" # Compose Versions compose-compiler = "1.5.1" @@ -219,6 +220,7 @@ firebase-database = { group = "com.google.firebase", name = "firebase-database-k accompanist-insets = { module = "com.google.accompanist:accompanist-insets", version.ref = "accompanistInsets" } accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanistPermissions" } accompanist-systemuicontroller = { module = "com.google.accompanist:accompanist-systemuicontroller", version.ref = "accompanistPermissions" } +google-location = { group = "com.google.android.gms", name = "play-services-location", version.ref = "google-location"} # AWS aws-android-sdk-cognito = { module = "com.amazonaws:aws-android-sdk-cognito", version.ref = "awsAndroidSdkMobileClient" } From a5ad1c1951f5ec7bec7a4526e7d9928ff1106d4c Mon Sep 17 00:00:00 2001 From: sangwook Date: Sat, 26 Oct 2024 15:53:37 +0900 Subject: [PATCH 3/3] [mod] #136 home ui --- .../main/java/com/record/home/Exhibition.kt | 12 + .../main/java/com/record/home/HomeContract.kt | 14 +- .../main/java/com/record/home/HomeScreen.kt | 401 +++++++----------- .../java/com/record/home/HomeViewModel.kt | 152 ++----- .../src/main/java/com/record/home/Location.kt | 6 + 5 files changed, 204 insertions(+), 381 deletions(-) create mode 100644 feature/home/src/main/java/com/record/home/Exhibition.kt create mode 100644 feature/home/src/main/java/com/record/home/Location.kt diff --git a/feature/home/src/main/java/com/record/home/Exhibition.kt b/feature/home/src/main/java/com/record/home/Exhibition.kt new file mode 100644 index 00000000..c1378fa2 --- /dev/null +++ b/feature/home/src/main/java/com/record/home/Exhibition.kt @@ -0,0 +1,12 @@ +package com.record.home + +import com.record.video.model.VideoData +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList + +data class Exhibition( + val location: String, + val name: String, + val exhibitionCount: Int, + val userVideo: ImmutableList = emptyList().toImmutableList(), +) diff --git a/feature/home/src/main/java/com/record/home/HomeContract.kt b/feature/home/src/main/java/com/record/home/HomeContract.kt index 5da09f9c..d4e54b50 100644 --- a/feature/home/src/main/java/com/record/home/HomeContract.kt +++ b/feature/home/src/main/java/com/record/home/HomeContract.kt @@ -1,22 +1,20 @@ package com.record.home -import com.record.model.VideoType import com.record.ui.base.SideEffect import com.record.ui.base.UiState -import com.record.video.model.VideoData import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList data class HomeState( - val chipList: ImmutableList = listOf("전체").toImmutableList(), - val popularList: ImmutableList = emptyList().toImmutableList(), - val recentList: ImmutableList = emptyList().toImmutableList(), - val selectedChipIndex: Int? = 0, + val exhibitionList: ImmutableList = emptyList().toImmutableList(), val isLoading: Boolean = false, + val location: Location = Location(0.0, 0.0), + val showLocationPermissionDialog: Boolean = true, ) : UiState sealed interface HomeSideEffect : SideEffect { data object navigateToUpload : HomeSideEffect - data class navigateToVideo(val id: Long, val type: VideoType, val keyword: String?) : HomeSideEffect - data object collapseToolbar : HomeSideEffect + data class navigateToVideo(val id: Long, val location: String) : HomeSideEffect + data class navigateToDetail(val id: Long) : HomeSideEffect + data object launchSettingIntent : HomeSideEffect } diff --git a/feature/home/src/main/java/com/record/home/HomeScreen.kt b/feature/home/src/main/java/com/record/home/HomeScreen.kt index c4e509b9..03f3a148 100644 --- a/feature/home/src/main/java/com/record/home/HomeScreen.kt +++ b/feature/home/src/main/java/com/record/home/HomeScreen.kt @@ -1,67 +1,54 @@ package com.record.home -import androidx.compose.foundation.Image +import android.Manifest +import android.content.pm.PackageManager +import android.location.Location +import android.util.Log +import androidx.activity.compose.rememberLauncherForActivityResult +import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.background import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.BoxScope import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer 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.width import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyRow import androidx.compose.foundation.lazy.itemsIndexed +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Icon import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.alpha -import androidx.compose.ui.graphics.Brush -import androidx.compose.ui.graphics.Color -import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.painterResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.IntSize import androidx.compose.ui.unit.dp +import androidx.core.app.ActivityCompat import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import com.airbnb.lottie.compose.LottieAnimation -import com.airbnb.lottie.compose.LottieCompositionSpec -import com.airbnb.lottie.compose.LottieConstants -import com.airbnb.lottie.compose.animateLottieCompositionAsState -import com.airbnb.lottie.compose.rememberLottieComposition +import com.google.android.gms.location.FusedLocationProviderClient +import com.google.android.gms.location.LocationServices import com.record.designsystem.R import com.record.designsystem.component.RecordyVideoThumbnail -import com.record.designsystem.component.button.RecordyChipButton +import com.record.designsystem.component.dialog.RecordyDialog import com.record.designsystem.theme.RecordyTheme -import com.record.home.component.UploadFloatingButton import com.record.model.VideoType -import com.record.ui.extension.customClickable import com.record.ui.lifecycle.LaunchedEffectWithLifecycle import com.record.video.model.VideoData +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch -import me.onebone.toolbar.CollapsingToolbarScaffold -import me.onebone.toolbar.CollapsingToolbarScaffoldState -import me.onebone.toolbar.CollapsingToolbarScope -import me.onebone.toolbar.ExperimentalToolbarApi -import me.onebone.toolbar.ScrollStrategy -import me.onebone.toolbar.rememberCollapsingToolbarScaffoldState -@OptIn(ExperimentalToolbarApi::class) @Composable fun HomeRoute( padding: PaddingValues, @@ -71,283 +58,158 @@ fun HomeRoute( navigateToUpload: () -> Unit = {}, ) { val state by viewModel.uiState.collectAsStateWithLifecycle() - val toolbarScaffoldState = rememberCollapsingToolbarScaffoldState() val coroutineScope = rememberCoroutineScope() + LaunchedEffectWithLifecycle { - viewModel.getVideos() viewModel.sideEffect.collectLatest { sideEffect -> when (sideEffect) { HomeSideEffect.navigateToUpload -> navigateToUpload() is HomeSideEffect.navigateToVideo -> { - navigateToVideoDetail(sideEffect.type, sideEffect.id, sideEffect.keyword, 0) + // navigateToVideoDetail(sideEffect.type, sideEffect.id, sideEffect.keyword, 0) } - HomeSideEffect.collapseToolbar -> { - coroutineScope.launch { - toolbarScaffoldState.toolbarState.collapse(500) - } - } + HomeSideEffect.launchSettingIntent -> TODO() + is HomeSideEffect.navigateToDetail -> TODO() } } } HomeScreen( modifier = modifier.padding(bottom = padding.calculateBottomPadding()), state = state, - toolbarState = toolbarScaffoldState, - onUploadButtonClick = viewModel::navigateToUpload, - onChipButtonClick = viewModel::selectCategory, - onVideoClick = viewModel::navigateToVideo, - onBookmarkClick = viewModel::bookmark, + showLocationPermissionDialog = viewModel::showLocationPermissionDialog, + updateLocation = viewModel::updateLocation, ) } @Composable fun HomeScreen( modifier: Modifier = Modifier, - toolbarState: CollapsingToolbarScaffoldState, state: HomeState, - onUploadButtonClick: () -> Unit, - onChipButtonClick: (Int) -> Unit, - onVideoClick: (Long, VideoType) -> Unit, - onBookmarkClick: (Long) -> Unit, + showLocationPermissionDialog: (Boolean) -> Unit, + updateLocation: (Double, Double) -> Unit, ) { - var boxSize by remember { - mutableStateOf(IntSize.Zero) - } - Box( - modifier = modifier - .fillMaxSize() - .onGloballyPositioned { layoutCoordinates -> - boxSize = layoutCoordinates.size + val configuration = LocalConfiguration.current + val screenWidth = configuration.screenWidthDp.dp + val context = LocalContext.current + val launcher = rememberLauncherForActivityResult( + contract = ActivityResultContracts.RequestPermission(), + ) { isGranted -> + if (isGranted) { + val fusedLocationClient: FusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context) + + // 위치 정보 요청 + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + return@rememberLauncherForActivityResult } - .background( - brush = Brush.verticalGradient( - listOf(Color(0x339babfb), Color(0x00000000)), - startY = boxSize.height.toFloat() * 0.0f, - endY = boxSize.height.toFloat() * 0.3f, - ), - ), - ) { - BackgroundAnimation() - CollapsingToolbar( - toolbarState = toolbarState, - state = state, - onChipButtonClick = onChipButtonClick, - onVideoClick = onVideoClick, - onBookmarkClick = onBookmarkClick, - ) - UploadFloatingButton( - modifier = Modifier - .align(Alignment.BottomEnd) - .padding(bottom = 15.dp, end = 16.dp), - onClick = onUploadButtonClick, - ) - if (state.isLoading) { - LoadingLottie() + fusedLocationClient.lastLocation.addOnSuccessListener { location: Location? -> + location?.let { + updateLocation(it.latitude, it.longitude) + Log.e("위치", "${it.latitude} ${it.longitude}") + } + } + showLocationPermissionDialog(false) + } else { + showLocationPermissionDialog(true) } } -} - -@Composable -fun BoxScope.BackgroundAnimation() { - val composition by rememberLottieComposition(spec = LottieCompositionSpec.RawRes(R.raw.bubble)) - val progress by animateLottieCompositionAsState( - composition, - iterations = LottieConstants.IterateForever, - speed = 1.0f, - ) - LottieAnimation( - composition, - { progress }, - modifier = Modifier - .align(Alignment.TopCenter), - ) -} - -@Composable -fun LoadingLottie() { - val composition by rememberLottieComposition(spec = LottieCompositionSpec.RawRes(R.raw.loading_lotties)) - val progress by animateLottieCompositionAsState( - composition, - iterations = LottieConstants.IterateForever, - speed = 4.0f, - ) - Box( - modifier = Modifier - .fillMaxSize() - .customClickable(rippleEnabled = false) {} - .background(color = RecordyTheme.colors.black50), - ) { - LottieAnimation( - composition, - { progress }, - modifier = Modifier - .align(Alignment.Center), - ) - } -} -@Composable -fun CollapsingToolbar( - toolbarState: CollapsingToolbarScaffoldState, - state: HomeState, - onChipButtonClick: (Int) -> Unit, - onVideoClick: (Long, VideoType) -> Unit, - onBookmarkClick: (Long) -> Unit, -) { - CollapsingToolbarScaffold( - modifier = Modifier - .fillMaxSize(), - state = toolbarState, - scrollStrategy = ScrollStrategy.ExitUntilCollapsed, - enabled = true, - toolbar = { - ToolbarContent(toolbarState) - }, - ) { - ChipRow(toolbarState, state.chipList, state.selectedChipIndex, onChipButtonClick) - Content( - state = state, - onVideoClick = onVideoClick, - onBookmarkClick = onBookmarkClick, + LaunchedEffectWithLifecycle { + launcher.launch( + Manifest.permission.ACCESS_FINE_LOCATION, ) } -} -@Composable -fun CollapsingToolbarScope.ToolbarContent(toolbarState: CollapsingToolbarScaffoldState) { - val topPadding = (32 + 12 * toolbarState.toolbarState.progress).dp - val alpha = toolbarState.toolbarState.progress * 2 - 0.5f - Image( - painter = painterResource(R.drawable.ic_recordy_logo), - contentDescription = "logo", - modifier = Modifier - .padding(start = 16.dp, top = topPadding, bottom = 12.dp) - .pin(), - ) Box( - modifier = Modifier - .fillMaxWidth() - .height(246.dp) - .road(Alignment.CenterEnd, Alignment.BottomStart) - .alpha(alpha) - .padding(start = 16.dp), + modifier = modifier + .fillMaxSize(), ) { - Row( + LazyColumn( modifier = Modifier - .fillMaxWidth() - .align(Alignment.BottomCenter), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.Bottom, + .fillMaxSize(), ) { - Text( - text = "오늘은 어떤 키워드로\n공간을 둘러볼까요?", - modifier = Modifier - .weight(192f) - .padding(bottom = 28.dp), - style = RecordyTheme.typography.title1, - color = RecordyTheme.colors.white, - ) - - Image( - modifier = Modifier - .weight(140f) - .padding(end = 12.dp), - painter = painterResource(R.drawable.img_home_graphic), - contentDescription = "home", - ) + item { + Box { + Icon( + modifier = Modifier + .align(Alignment.CenterStart) + .padding(start = 16.dp) + .padding(top = 66.dp, bottom = 32.dp), + painter = painterResource(id = R.drawable.ic_viskit_logo), + tint = RecordyTheme.colors.viskitYellow500, + contentDescription = "logo", + ) + } + } + itemsIndexed(state.exhibitionList) { i, exhibition -> + ExhibitionContatiner(exhibition, screenWidth) + } } - } -} -@OptIn(ExperimentalToolbarApi::class) -@Composable -fun ChipRow( - state: CollapsingToolbarScaffoldState, - chipList: List, - selectedChip: Int?, - onChipButtonClick: (Int) -> Unit, -) { - LazyRow( - modifier = Modifier - .padding(bottom = 12.dp), - horizontalArrangement = Arrangement.spacedBy(8.dp), - ) { - item { Spacer(modifier = Modifier.width(8.dp)) } - itemsIndexed(chipList) { i, item -> - RecordyChipButton( - text = item, - isActive = selectedChip == i, - onClick = { - onChipButtonClick(i) - }, + if (state.showLocationPermissionDialog) { + RecordyDialog( + graphicAsset = R.drawable.img_trashcan, + title = "필수 권한 허용해 주세요", + subTitle = "내 위치 기반 공간 추천을 위해\n사용자의 위치에 접근하도록 허용해 주세요.", + negativeButtonLabel = "취소", + positiveButtonLabel = "삭제", + onDismissRequest = { }, + onPositiveButtonClick = { }, ) } - item { Spacer(modifier = Modifier.width(8.dp)) } } } @Composable -fun Content( - state: HomeState, - onVideoClick: (Long, VideoType) -> Unit, - onBookmarkClick: (Long) -> Unit, +private fun ExhibitionContatiner( + exhibition: Exhibition, + screenWidth: Dp, + onVideoClick: (Long, VideoType) -> Unit = { i, j -> }, + onBookmarkClick: (Long) -> Unit = {}, + videoType: VideoType = VideoType.RECENT, ) { - val configuration = LocalConfiguration.current - val screenWidth = configuration.screenWidthDp.dp - LazyColumn( - modifier = Modifier - .fillMaxWidth() - .padding(top = 44.dp), - ) { - item { - Section( - title = "이번 주 인기 기록", - videoList = state.popularList, - screenWidth = screenWidth, - onVideoClick = onVideoClick, - onBookmarkClick = onBookmarkClick, - videoType = VideoType.POPULAR, - ) - Section( - title = "방금 막 올라왔어요", - videoList = state.recentList, - screenWidth = screenWidth, - onVideoClick = onVideoClick, - onBookmarkClick = onBookmarkClick, - videoType = VideoType.RECENT, + Column { + Row( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 16.dp, vertical = 16.dp) + .background(color = RecordyTheme.colors.gray10, shape = RoundedCornerShape(8.dp)), + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Column( + modifier = Modifier.padding(16.dp), + verticalArrangement = Arrangement.spacedBy(4.dp), + ) { + Text( + text = exhibition.location, + style = RecordyTheme.typography.caption1M, + color = RecordyTheme.colors.gray05, + ) + Text( + text = exhibition.name, + style = RecordyTheme.typography.title3, + color = RecordyTheme.colors.gray01, + ) + Text( + text = exhibition.exhibitionCount.toString(), + style = RecordyTheme.typography.body2SB, + color = RecordyTheme.colors.viskitYellow500, + ) + } + Icon( + modifier = Modifier + .align(Alignment.CenterVertically) + .padding(16.dp), + tint = RecordyTheme.colors.gray01, + painter = painterResource(id = R.drawable.ic_angle_right_24), + contentDescription = "next", ) - Spacer(modifier = Modifier.height(56.dp)) } - } -} -@Composable -fun Section( - title: String, - videoList: List, - screenWidth: Dp, - onVideoClick: (Long, VideoType) -> Unit, - onBookmarkClick: (Long) -> Unit, - videoType: VideoType, -) { - Column( - modifier = Modifier - .fillMaxWidth(), - ) { - Text( - text = title, - style = RecordyTheme.typography.subtitle, - color = RecordyTheme.colors.white, - modifier = Modifier - .padding(horizontal = 16.dp) - .padding(top = 16.dp, bottom = 12.dp), - ) LazyRow( horizontalArrangement = Arrangement.spacedBy(12.dp), ) { item { Spacer(modifier = Modifier.width(4.dp)) } - itemsIndexed(videoList) { index, videoData -> + itemsIndexed(exhibition.userVideo) { index, videoData -> RecordyVideoThumbnail( modifier = Modifier.width(screenWidth / 8 * 3), imageUri = videoData.previewUrl, @@ -367,5 +229,34 @@ fun Section( @Composable fun PreviewHome() { RecordyTheme { + HomeScreen( + state = HomeState( + exhibitionList = + listOf( + Exhibition( + "서울 종로구", + "국립현대미술관", + 7, + userVideo = listOf( + VideoData( + bookmarkId = 1, + id = 1, + isBookmark = false, + bookmarkCount = 7, + content = "ㅎㅇ", + videoUrl = "ggg", + previewUrl = "ggg", + location = "korea", + uploaderId = 1, + nickname = "안녕", + isMine = false, + ), + ).toImmutableList(), + ), + ).toImmutableList(), + ), + showLocationPermissionDialog = {}, + updateLocation = { i, j -> }, + ) } } diff --git a/feature/home/src/main/java/com/record/home/HomeViewModel.kt b/feature/home/src/main/java/com/record/home/HomeViewModel.kt index 965cb915..f6270daa 100644 --- a/feature/home/src/main/java/com/record/home/HomeViewModel.kt +++ b/feature/home/src/main/java/com/record/home/HomeViewModel.kt @@ -1,10 +1,6 @@ package com.record.home -import android.util.Log import androidx.lifecycle.viewModelScope -import com.record.keyword.repository.KeywordRepository -import com.record.model.VideoType -import com.record.model.exception.ApiError import com.record.ui.base.BaseViewModel import com.record.video.repository.VideoRepository import dagger.hilt.android.lifecycle.HiltViewModel @@ -15,139 +11,59 @@ import javax.inject.Inject @HiltViewModel class HomeViewModel @Inject constructor( private val videoRepository: VideoRepository, - private val keywordRepository: KeywordRepository, ) : BaseViewModel(HomeState()) { - fun navigateToUpload() { - postSideEffect(HomeSideEffect.navigateToUpload) + fun navigateToVideo(videoId: Long, location: String) { + postSideEffect(HomeSideEffect.navigateToVideo(videoId, location)) } - fun selectCategory(categoryIndex: Int) { - intent { - copy(selectedChipIndex = categoryIndex) - } - postSideEffect(HomeSideEffect.collapseToolbar) - getPopularVideos() - getRecentVideos() - } - - fun getVideos() { - getPreferenceKeywords() - getPopularVideos() - getRecentVideos() - } - - private fun getPreferenceKeywords() { - viewModelScope.launch { - val newList = listOf("전체") - keywordRepository.getKeywords().onSuccess { - intent { - copy(chipList = (newList + it.keywords).toImmutableList()) - } - }.onFailure { - when (it) { - is ApiError -> { - Log.e("error", it.message) - } - } - } - } + fun showLocationPermissionDialog(isShow: Boolean) = intent { + copy(showLocationPermissionDialog = isShow) } - private fun getRecentVideos() { - viewModelScope.launch { - val keyIndex = uiState.value.selectedChipIndex - val keyword = if (keyIndex != null) listOf(uiState.value.chipList[keyIndex]) else null - videoRepository.getRecentVideos( - keywords = keyword, - cursor = 0, - pageSize = 10, - ).onSuccess { - intent { - copy(recentList = it.data.toImmutableList()) - } - }.onFailure { - when (it) { - is ApiError -> { - Log.e("error", it.message) - } - } - } - } - } - - private fun getPopularVideos() { - viewModelScope.launch { - val keyIndex = uiState.value.selectedChipIndex - val keyword = if (keyIndex != null) listOf(uiState.value.chipList[keyIndex]) else null - videoRepository.getPopularVideos( - keywords = keyword, - pageNumber = 0, - pageSize = 10, - ).onSuccess { - intent { - copy(popularList = it.data.toImmutableList()) - } - }.onFailure { - when (it) { - is ApiError -> { - Log.e("error", it.message) - } - } - } - } - } - - fun navigateToVideo(videoId: Long, type: VideoType) { - val selectedIndex = uiState.value.selectedChipIndex - val selectedKeyword = if (selectedIndex != null) uiState.value.chipList[selectedIndex] else null - postSideEffect(HomeSideEffect.navigateToVideo(videoId, type, selectedKeyword)) + fun updateLocation(latitude: Double, longitude: Double) = intent { + copy(location = Location(latitude, longitude)) } fun bookmark(id: Long) { intent { - val updatedRecentList = uiState.value.recentList.map { video -> - if (video.id == id) { - video.copy(isBookmark = !video.isBookmark) - } else { - video - } - } - - val updatedPopularList = uiState.value.popularList.map { video -> - if (video.id == id) { - video.copy(isBookmark = !video.isBookmark) - } else { - video - } + val updatedList = uiState.value.exhibitionList.map { exhibition -> + Exhibition( + location = exhibition.location, + name = exhibition.name, + exhibitionCount = exhibition.exhibitionCount, + userVideo = exhibition.userVideo.map { video -> + if (video.id == id) { + video.copy(isBookmark = !video.isBookmark) + } else { + video + } + }.toImmutableList(), + ) } copy( - recentList = updatedRecentList.toImmutableList(), - popularList = updatedPopularList.toImmutableList(), + exhibitionList = updatedList.toImmutableList(), ) } viewModelScope.launch { videoRepository.bookmark(id).onSuccess { - val updatedRecentList1 = uiState.value.recentList.map { video -> - if (video.id == id) { - video.copy(isBookmark = it) - } else { - video - } - } - - val updatedPopularList1 = uiState.value.popularList.map { video -> - if (video.id == id) { - video.copy(isBookmark = it) - } else { - video - } + val updatedList = uiState.value.exhibitionList.map { exhibition -> + Exhibition( + location = exhibition.location, + name = exhibition.name, + exhibitionCount = exhibition.exhibitionCount, + userVideo = exhibition.userVideo.map { video -> + if (video.id == id) { + video.copy(isBookmark = !video.isBookmark) + } else { + video + } + }.toImmutableList(), + ) } - intent { copy( - recentList = updatedRecentList1.toImmutableList(), - popularList = updatedPopularList1.toImmutableList(), + exhibitionList = updatedList.toImmutableList(), ) } }.onFailure { diff --git a/feature/home/src/main/java/com/record/home/Location.kt b/feature/home/src/main/java/com/record/home/Location.kt new file mode 100644 index 00000000..02e15874 --- /dev/null +++ b/feature/home/src/main/java/com/record/home/Location.kt @@ -0,0 +1,6 @@ +package com.record.home + +data class Location( + val latitude: Double, + val longitude: Double, +)