diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 6568ae17..2407f590 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -1,4 +1,4 @@ -import java.util.* +import java.util.Properties plugins { alias(libs.plugins.android.application) @@ -21,8 +21,8 @@ android { applicationId = "com.hmoa.app" minSdk = 26 targetSdk = 34 - versionCode = 36 - versionName = "1.3.0" + versionCode = 37 + versionName = "1.3.1" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" manifestPlaceholders["REDIRECTION_PATH"] = localProperties["REDIRECTION_PATH"] as String @@ -46,7 +46,10 @@ android { buildTypes { release { isMinifyEnabled = false - proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro") + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) signingConfig = signingConfigs.getByName("release") isDebuggable = false } @@ -69,9 +72,18 @@ android { excludes += "META-INF/gradle/incremental.annotation.processors" } } -} + applicationVariants.all { + this.mergeResourcesProvider.configure { + doLast { + copy { + from(":HMOA_ANDROID_SECRET") + } + } + } + } +} dependencies { implementation(project(":feature-home")) diff --git a/app/src/main/java/com/hmoa/app/navigation/NavHost.kt b/app/src/main/java/com/hmoa/app/navigation/NavHost.kt index 3827b997..228d2f6d 100644 --- a/app/src/main/java/com/hmoa/app/navigation/NavHost.kt +++ b/app/src/main/java/com/hmoa/app/navigation/NavHost.kt @@ -225,10 +225,10 @@ fun SetUpNavGraph( /** magazine 모듈 */ magazineMain( - onNavHome = navController::navigateToHome, - onNavPerfumeDesc = navController::navigateToPerfume, - onNavCommunityDesc = navController::navigateToCommunityDescriptionRoute, - onNavMagazineDesc = navController::navigateToMagazineDesc + navHome = navController::navigateToHome, + navPerfumeDesc = navController::navigateToPerfume, + navCommunityDesc = navController::navigateToCommunityDescriptionRoute, + navMagazineDesc = navController::navigateToMagazineDesc ) magazineDesc( navBack = navController::navigateToBack, diff --git a/feature-hpedia/build.gradle.kts b/feature-hpedia/build.gradle.kts index b40e8626..8e3d53e1 100644 --- a/feature-hpedia/build.gradle.kts +++ b/feature-hpedia/build.gradle.kts @@ -37,6 +37,18 @@ android { buildFeatures { compose = true } + tasks.withType() { + compilerOptions.freeCompilerArgs.addAll( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.buildDir.absolutePath}/compose_metrics", + ) + } + tasks.withType() { + compilerOptions.freeCompilerArgs.addAll( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.buildDir.absolutePath}/compose_reports", + ) + } } dependencies { diff --git a/feature-hpedia/src/main/java/com/hmoa/feature_hpedia/Screen/HPediaScreen.kt b/feature-hpedia/src/main/java/com/hmoa/feature_hpedia/Screen/HPediaScreen.kt index be5fc762..fb2bfa5f 100644 --- a/feature-hpedia/src/main/java/com/hmoa/feature_hpedia/Screen/HPediaScreen.kt +++ b/feature-hpedia/src/main/java/com/hmoa/feature_hpedia/Screen/HPediaScreen.kt @@ -29,7 +29,7 @@ import com.hmoa.feature_community.Screen.CommunityHomeRoute @Composable fun HPediaRoute( - navHPediaSearch: (String) -> Unit, + navHPediaSearch: (keyword: String) -> Unit, navCommunityDesc: (befRoute: CommunityRoute, communityId: Int) -> Unit, navCommunityGraph: () -> Unit, navLogin: () -> Unit @@ -45,7 +45,7 @@ fun HPediaRoute( @Composable fun HPediaScreen( - navHPediaSearch: (String) -> Unit, + navHPediaSearch: (keyword: String) -> Unit, navCommunityDesc: (communityRoute: CommunityRoute, communityId: Int) -> Unit, navCommunityGraph: () -> Unit, onErrorHandleLoginAgain: () -> Unit, @@ -61,9 +61,7 @@ fun HPediaScreen( .padding(horizontal = 16.dp) ) { HPediaScreenTitle("HPedia") - SelectSearchType( - navHPediaSearch = navHPediaSearch - ) + SelectSearchType(navHPediaSearch = navHPediaSearch) } Spacer(Modifier.height(27.dp)) CommunityHomeRoute( @@ -91,9 +89,7 @@ fun HPediaScreenTitle(title: String) { } @Composable -fun SelectSearchType( - navHPediaSearch: (String) -> Unit -) { +fun SelectSearchType(navHPediaSearch: (keyword: String) -> Unit) { val data = listOf( listOf("용어", "Top notes\n탑노트란?"), listOf("노트", "woody\n우디"), @@ -117,9 +113,7 @@ fun SelectSearchType( .fillMaxHeight() .weight(1f) .background(color = Color.Black, shape = RectangleShape) - .clickable { - navHPediaSearch(data[0]) - } + .clickable {navHPediaSearch(data[0])} .padding(16.dp) ) { Text( @@ -134,9 +128,7 @@ fun SelectSearchType( style = textStyle ) } - if (idx != 2) { - Spacer(Modifier.width(8.dp)) - } + if (idx != 2) {Spacer(Modifier.width(8.dp))} } } -} +} \ No newline at end of file diff --git a/feature-hpedia/src/main/java/com/hmoa/feature_hpedia/Screen/HpediaSearchScreen.kt b/feature-hpedia/src/main/java/com/hmoa/feature_hpedia/Screen/HpediaSearchScreen.kt index 42685dc4..b0322891 100644 --- a/feature-hpedia/src/main/java/com/hmoa/feature_hpedia/Screen/HpediaSearchScreen.kt +++ b/feature-hpedia/src/main/java/com/hmoa/feature_hpedia/Screen/HpediaSearchScreen.kt @@ -1,6 +1,5 @@ package com.hmoa.feature_hpedia.Screen -import android.util.Log import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement @@ -14,6 +13,8 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color @@ -27,9 +28,11 @@ import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems -import com.hmoa.core_designsystem.component.TopBar +import com.hmoa.core_common.ErrorUiState import com.hmoa.core_designsystem.R +import com.hmoa.core_designsystem.component.ErrorUiSetView import com.hmoa.core_designsystem.component.SearchTopBar +import com.hmoa.core_designsystem.component.TopBar import com.hmoa.core_model.response.NoteDefaultResponseDto import com.hmoa.core_model.response.PerfumerDefaultResponseDto import com.hmoa.core_model.response.TermDefaultResponseDto @@ -39,23 +42,26 @@ import com.hmoa.feature_hpedia.ViewModel.HPediaSearchViewModel fun HPediaSearchRoute( type : String?, navBack : () -> Unit, - navHPediaDesc : (Int, String) -> Unit, + navHPediaDesc : (hpediaId: Int, type: String) -> Unit, viewModel : HPediaSearchViewModel = hiltViewModel() ){ viewModel.setType(type) + val errState by viewModel.errorUiState.collectAsStateWithLifecycle() val topBarState = viewModel.topBarState.collectAsStateWithLifecycle() val searchWord = viewModel.searchWord.collectAsStateWithLifecycle() val type = viewModel.type.collectAsStateWithLifecycle() val result = viewModel.communityPagingSource().collectAsLazyPagingItems() + val onClearWord = remember<() -> Unit> {{viewModel.updateSearchWord("")}} HPediaSearchScreen( + errState = errState, type = type.value, topBarState = topBarState.value, - onChagneTopBarState = { viewModel.updateTopBarState(it) }, + onChagneTopBarState = viewModel::updateTopBarState, searchWord = searchWord.value, - onChangeSearchWord = { viewModel.updateSearchWord(it) }, - onClearWord = { viewModel.updateSearchWord("") }, + onChangeSearchWord = viewModel::updateSearchWord, + onClearWord = onClearWord, onClickSearch = { }, termResult = if(type.value == "용어") (result as LazyPagingItems) else null, noteResult = if(type.value == "노트") (result as LazyPagingItems) else null, @@ -67,41 +73,50 @@ fun HPediaSearchRoute( @Composable fun HPediaSearchScreen( + errState: ErrorUiState, type : String?, topBarState : Boolean, - onChagneTopBarState : (Boolean) -> Unit, + onChagneTopBarState : (topBarState: Boolean) -> Unit, searchWord : String, - onChangeSearchWord : (String) -> Unit, + onChangeSearchWord : (keyword: String) -> Unit, onClearWord : () -> Unit, onClickSearch : () -> Unit, termResult : LazyPagingItems? = null, noteResult : LazyPagingItems? = null, perfumerResult : LazyPagingItems? = null, navBack: () -> Unit, - navHPediaDesc: (Int, String) -> Unit + navHPediaDesc: (hpediaId: Int, type: String) -> Unit ){ - Column( - modifier = Modifier - .fillMaxSize() - .background(color = Color.White) - ){ - HPediaEventTopBar( - type = type ?: "Null Type", - topBarState = topBarState, - onChagneTopBarState = onChagneTopBarState, - searchWord = searchWord, - onChangeSearchWord = onChangeSearchWord, - onClearWord = onClearWord, - onClickSearch = onClickSearch, - navBack = navBack - ) - HPediaSearchResult( - type = type ?: "Null Type", - termResult = termResult, - noteResult = noteResult, - perfumerResult = perfumerResult, - navHPediaDesc = navHPediaDesc + if (errState is ErrorUiState.ErrorData && errState.isValidate()){ + ErrorUiSetView( + onLoginClick = navBack, + errorUiState = errState, + onCloseClick = navBack ) + } else { + Column( + modifier = Modifier + .fillMaxSize() + .background(color = Color.White) + ){ + HPediaEventTopBar( + type = type ?: "Null Type", + topBarState = topBarState, + onChagneTopBarState = onChagneTopBarState, + searchWord = searchWord, + onChangeSearchWord = onChangeSearchWord, + onClearWord = onClearWord, + onClickSearch = onClickSearch, + navBack = navBack + ) + HPediaSearchResult( + type = type ?: "Null Type", + termResult = termResult, + noteResult = noteResult, + perfumerResult = perfumerResult, + navHPediaDesc = navHPediaDesc + ) + } } } @@ -109,9 +124,9 @@ fun HPediaSearchScreen( fun HPediaEventTopBar( type : String, topBarState : Boolean, - onChagneTopBarState : (Boolean) -> Unit, + onChagneTopBarState : (topBarState: Boolean) -> Unit, searchWord : String, - onChangeSearchWord : (String) -> Unit, + onChangeSearchWord : (keyword: String) -> Unit, onClearWord : () -> Unit, onClickSearch : () -> Unit, navBack : () -> Unit @@ -127,12 +142,10 @@ fun HPediaEventTopBar( } else { TopBar( title = type, - navIcon = painterResource(com.hmoa.core_designsystem.R.drawable.ic_back), + navIcon = painterResource(R.drawable.ic_back), onNavClick = navBack, - menuIcon = painterResource(com.hmoa.core_designsystem.R.drawable.ic_search), - onMenuClick = { - onChagneTopBarState(true) - } + menuIcon = painterResource(R.drawable.ic_search), + onMenuClick = {onChagneTopBarState(true)} ) } } @@ -143,13 +156,16 @@ fun HPediaSearchResult( termResult : LazyPagingItems? = null, noteResult : LazyPagingItems? = null, perfumerResult : LazyPagingItems? = null, - navHPediaDesc: (Int, String) -> Unit + navHPediaDesc: (hpediaId: Int, type: String) -> Unit ){ LazyColumn( modifier = Modifier.fillMaxSize() ){ if(termResult != null){ - items(termResult.itemSnapshotList){ + items( + items = termResult.itemSnapshotList, + key = {it!!.termId} + ){ if (it != null){ HPediaResultItem( type = type, @@ -162,7 +178,10 @@ fun HPediaSearchResult( } } else if (noteResult != null) { - items(noteResult.itemSnapshotList){ + items( + items = noteResult.itemSnapshotList, + key = {it!!.noteId} + ){ if (it != null){ HPediaResultItem( type = type, @@ -175,8 +194,10 @@ fun HPediaSearchResult( } } else if (perfumerResult != null){ - Log.d("HOTFIX", "perfumers : ${perfumerResult.itemSnapshotList}") - items(perfumerResult.itemSnapshotList){ + items( + items = perfumerResult.itemSnapshotList, + key = {it!!.perfumerId} + ){ if (it != null){ HPediaResultItem( type = type, @@ -197,15 +218,13 @@ fun HPediaResultItem( id : Int, koTitle : String, engTitle : String, - navHPediaDesc: (Int, String) -> Unit + navHPediaDesc: (hpediaId: Int, type: String) -> Unit ){ Row( modifier = Modifier .fillMaxWidth() .height(50.dp) - .clickable { - navHPediaDesc(id, type) - } + .clickable { navHPediaDesc(id, type) } .padding(horizontal = 16.dp), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.SpaceBetween diff --git a/feature-hpedia/src/main/java/com/hmoa/feature_hpedia/ViewModel/HPediaSearchViewModel.kt b/feature-hpedia/src/main/java/com/hmoa/feature_hpedia/ViewModel/HPediaSearchViewModel.kt index 0bd84b1c..a54681e5 100644 --- a/feature-hpedia/src/main/java/com/hmoa/feature_hpedia/ViewModel/HPediaSearchViewModel.kt +++ b/feature-hpedia/src/main/java/com/hmoa/feature_hpedia/ViewModel/HPediaSearchViewModel.kt @@ -6,13 +6,18 @@ import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.PagingData import androidx.paging.cachedIn +import com.hmoa.core_common.ErrorUiState import com.hmoa.core_domain.repository.SearchRepository import com.hmoa.feature_community.ViewModel.PAGE_SIZE import com.hmoa.feature_hpedia.SearchResultPagingSource import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.update import javax.inject.Inject @@ -33,29 +38,42 @@ class HPediaSearchViewModel @Inject constructor( private val _topBarState = MutableStateFlow(false) val topBarState get() = _topBarState.asStateFlow() - //err 상태 - private val _errState = MutableStateFlow(null) - val errState get() = _errState.asStateFlow() - + private var expiredTokenErrorState = MutableStateFlow(false) + private var wrongTypeTokenErrorState = MutableStateFlow(false) + private var unLoginedErrorState = MutableStateFlow(false) + private var generalErrorState = MutableStateFlow>(Pair(false, null)) + val errorUiState: StateFlow = combine( + expiredTokenErrorState, + wrongTypeTokenErrorState, + unLoginedErrorState, + generalErrorState + ) { expiredTokenError, wrongTypeTokenError, unknownError, generalError -> + ErrorUiState.ErrorData( + expiredTokenError = expiredTokenError, + wrongTypeTokenError = wrongTypeTokenError, + unknownError = unknownError, + generalError = generalError + ) + }.stateIn( + scope = viewModelScope, + started = SharingStarted.WhileSubscribed(5_000), + initialValue = ErrorUiState.Loading + ) //type 설정 fun setType(newType : String?){ if (newType == null) { - _errState.update{ "Type is NULL" } - } else { - _type.update{ newType } + generalErrorState.update{ Pair(true, "해당 글에 오류가 발생했습니다") } + return } + _type.update{ newType } } //상단바 상태 수정 - fun updateTopBarState(state : Boolean) { - _topBarState.update{ state } - } + fun updateTopBarState(state : Boolean) { _topBarState.update{ state } } //검색어 변경 - fun updateSearchWord(newSearchWord : String){ - _searchWord.update{ newSearchWord } - } + fun updateSearchWord(newSearchWord : String){ _searchWord.update{ newSearchWord } } //paging데이터 외부 노출 fun communityPagingSource() : Flow> = Pager( diff --git a/feature-magazine/build.gradle.kts b/feature-magazine/build.gradle.kts index 1847563f..4b51ffad 100644 --- a/feature-magazine/build.gradle.kts +++ b/feature-magazine/build.gradle.kts @@ -37,6 +37,18 @@ android { buildFeatures { compose = true } + tasks.withType() { + compilerOptions.freeCompilerArgs.addAll( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.buildDir.absolutePath}/compose_metrics", + ) + } + tasks.withType() { + compilerOptions.freeCompilerArgs.addAll( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.buildDir.absolutePath}/compose_reports", + ) + } } dependencies { @@ -50,6 +62,7 @@ dependencies { implementation(libs.navigation.compose) implementation(libs.bundles.lifecycle) implementation(libs.bundles.basic) + implementation(libs.kotlinx.collections.immutable) implementation(libs.bundles.hilt) kapt(libs.hilt.android.compiler) @@ -62,4 +75,4 @@ dependencies { testImplementation(libs.junit.jupiter.api) testImplementation(libs.junit.jupiter.engine) testImplementation(libs.testing) -} +} \ No newline at end of file diff --git a/feature-magazine/src/main/java/com/hmoa/feature_magazine/Navigation/MagazineNavigation.kt b/feature-magazine/src/main/java/com/hmoa/feature_magazine/Navigation/MagazineNavigation.kt index 828bca77..6deae2bf 100644 --- a/feature-magazine/src/main/java/com/hmoa/feature_magazine/Navigation/MagazineNavigation.kt +++ b/feature-magazine/src/main/java/com/hmoa/feature_magazine/Navigation/MagazineNavigation.kt @@ -13,17 +13,17 @@ fun NavHostController.navigateToMagazineHome() = navigate(MagazineRoute.Magazine } fun NavHostController.navigateToMagazineDesc(magazineId : Int) = navigate("${MagazineRoute.MagazineDescRoute.name}/${magazineId}") fun NavGraphBuilder.magazineMain( - onNavHome : () -> Unit, - onNavPerfumeDesc : (Int) -> Unit, - onNavCommunityDesc : (befRoute: CommunityRoute, communityId: Int) -> Unit, - onNavMagazineDesc : (Int) -> Unit, + navHome : () -> Unit, + navPerfumeDesc : (perfumeId: Int) -> Unit, + navCommunityDesc : (befRoute: CommunityRoute, communityId: Int) -> Unit, + navMagazineDesc : (magazineId: Int) -> Unit, ){ composable(MagazineRoute.Magazine.name){ MagazineMainRoute( - onNavHome = onNavHome, - onNavPerfumeDesc = onNavPerfumeDesc, - onNavCommunityDesc = onNavCommunityDesc, - onNavMagazineDesc = onNavMagazineDesc + navHome = navHome, + navPerfumeDesc = navPerfumeDesc, + navCommunityDesc = navCommunityDesc, + navMagazineDesc = navMagazineDesc ) } } diff --git a/feature-magazine/src/main/java/com/hmoa/feature_magazine/Screen/MagazineMain.kt b/feature-magazine/src/main/java/com/hmoa/feature_magazine/Screen/MagazineMain.kt index bf615497..fb685a17 100644 --- a/feature-magazine/src/main/java/com/hmoa/feature_magazine/Screen/MagazineMain.kt +++ b/feature-magazine/src/main/java/com/hmoa/feature_magazine/Screen/MagazineMain.kt @@ -26,41 +26,45 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.hilt.navigation.compose.hiltViewModel import androidx.lifecycle.compose.collectAsStateWithLifecycle -import androidx.paging.ItemSnapshotList import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems import com.hmoa.core_common.ErrorUiState import com.hmoa.core_designsystem.R -import com.hmoa.core_designsystem.component.* +import com.hmoa.core_designsystem.component.AppLoadingScreen +import com.hmoa.core_designsystem.component.CircleImageView +import com.hmoa.core_designsystem.component.ErrorUiSetView +import com.hmoa.core_designsystem.component.ImageView +import com.hmoa.core_designsystem.component.TopBar import com.hmoa.core_designsystem.theme.CustomColor import com.hmoa.core_domain.entity.navigation.CommunityRoute import com.hmoa.core_model.response.MagazineSummaryResponseDto -import com.hmoa.core_model.response.MagazineTastingCommentResponseDto -import com.hmoa.core_model.response.RecentPerfumeResponseDto +import com.hmoa.core_model.response.MagazineTastingCommentResponseDtoItem +import com.hmoa.core_model.response.RecentPerfumeResponseDtoItem import com.hmoa.feature_magazine.ViewModel.MagazineMainUiState import com.hmoa.feature_magazine.ViewModel.MagazineMainViewModel +import kotlinx.collections.immutable.ImmutableList @Composable fun MagazineMainRoute( - onNavHome: () -> Unit, - onNavPerfumeDesc: (Int) -> Unit, - onNavCommunityDesc: (befRoute: CommunityRoute, communityId: Int) -> Unit, - onNavMagazineDesc: (Int) -> Unit, + navHome: () -> Unit, + navPerfumeDesc: (perfumeId: Int) -> Unit, + navCommunityDesc: (befRoute: CommunityRoute, communityId: Int) -> Unit, + navMagazineDesc: (magazineId: Int) -> Unit, viewModel: MagazineMainViewModel = hiltViewModel() ) { val uiState = viewModel.uiState.collectAsStateWithLifecycle() val errorState = viewModel.errorUiState.collectAsStateWithLifecycle() val magazineList = viewModel.magazinePagingSource().collectAsLazyPagingItems() - val onPostClick = remember<(Int) -> Unit>{{onNavCommunityDesc(CommunityRoute.CommunityHomeRoute, it)}} + val onCommunityClick = remember<(Int) -> Unit>{{navCommunityDesc(CommunityRoute.CommunityHomeRoute, it)}} MagazineMainScreen( uiState = uiState.value, errorState = errorState.value, magazineList = magazineList, - onNavHome = onNavHome, - onNavPerfumeDesc = onNavPerfumeDesc, - onNavCommunityDesc = onPostClick, - onNavMagazineDesc = onNavMagazineDesc + navHome = navHome, + onPerfumeClick = navPerfumeDesc, + onCommunityClick = onCommunityClick, + onMagazineClick = navMagazineDesc ) } @@ -69,75 +73,78 @@ fun MagazineMainScreen( uiState: MagazineMainUiState, errorState: ErrorUiState, magazineList: LazyPagingItems, - onNavHome: () -> Unit, - onNavPerfumeDesc: (Int) -> Unit, - onNavCommunityDesc: (Int) -> Unit, - onNavMagazineDesc: (Int) -> Unit + navHome: () -> Unit, + onPerfumeClick: (perfumeId: Int) -> Unit, + onCommunityClick: (communityId: Int) -> Unit, + onMagazineClick: (magazineId: Int) -> Unit ) { when (uiState) { MagazineMainUiState.Loading -> AppLoadingScreen() is MagazineMainUiState.MagazineMain -> { - MagazineFullContent( - magazineList = magazineList.itemSnapshotList, + MagazineContent( + magazineList = magazineList, perfumeList = uiState.perfumes, reviewList = uiState.reviews, - onNavPerfumeDesc = onNavPerfumeDesc, - onNavCommunityDesc = onNavCommunityDesc, - onNavMagazineDesc = onNavMagazineDesc + onPerfumeClick = onPerfumeClick, + onCommunityClick = onCommunityClick, + onMagazineClick = onMagazineClick ) } - - is MagazineMainUiState.Error -> { + MagazineMainUiState.Error -> { ErrorUiSetView( - onLoginClick = { onNavHome() }, + onLoginClick = navHome, errorUiState = errorState, - onCloseClick = { onNavHome() } + onCloseClick = navHome ) } } } @Composable -private fun MagazineFullContent( - magazineList: ItemSnapshotList, - perfumeList: RecentPerfumeResponseDto, - reviewList: MagazineTastingCommentResponseDto, - onNavPerfumeDesc: (Int) -> Unit, - onNavCommunityDesc: (Int) -> Unit, - onNavMagazineDesc: (Int) -> Unit +private fun MagazineContent( + magazineList: LazyPagingItems, + perfumeList: ImmutableList, + reviewList: ImmutableList, + onPerfumeClick: (perfumeId: Int) -> Unit, + onCommunityClick: (communityId: Int) -> Unit, + onMagazineClick: (magazineId: Int) -> Unit ) { - if (magazineList.isNotEmpty()) { - val magazines = magazineList.subList(0, 5) + if (magazineList.itemSnapshotList.isNotEmpty()) { + val magazines = remember{ + if (magazineList.itemSnapshotList.size > 5) { magazineList.itemSnapshotList.subList(0, 5) } + else { magazineList.itemSnapshotList } + } LazyColumn( modifier = Modifier .fillMaxSize(), verticalArrangement = Arrangement.spacedBy(56.dp) ) { item { - MagazineTitleBox( - magazines = magazines.filterNotNull() - ) + MagazineTitleBox(magazines = magazines.filterNotNull()) Spacer(Modifier.height(32.dp)) ReleasePerfumeList( perfumeList = perfumeList, - onNavPerfumeDesc = onNavPerfumeDesc + onPerfumeClick = onPerfumeClick ) Spacer(Modifier.height(52.dp)) Top10Reviews( reviews = reviewList, - onNavCommunityDesc = onNavCommunityDesc + onCommunityClick = onCommunityClick ) Spacer(Modifier.height(52.dp)) MagazineHeader() Spacer(Modifier.height(24.dp)) } - items(magazineList) { magazine -> + items( + items = magazines, + key = {it!!.magazineId} + ) { magazine -> if (magazine != null) { MagazineContent( imageUrl = magazine.previewImgUrl, title = magazine.title, preview = magazine.preview, - onNavMagazineDesc = { onNavMagazineDesc(magazine.magazineId) } + onNavMagazineDesc = { onMagazineClick(magazine.magazineId) } ) } } @@ -229,8 +236,8 @@ private fun MagazineTitleBox( @Composable private fun ReleasePerfumeList( - perfumeList: RecentPerfumeResponseDto?, - onNavPerfumeDesc: (Int) -> Unit + perfumeList: ImmutableList, + onPerfumeClick: (perfumeId: Int) -> Unit ) { Column( modifier = Modifier @@ -257,13 +264,16 @@ private fun ReleasePerfumeList( modifier = Modifier.padding(16.dp), horizontalArrangement = Arrangement.spacedBy(8.dp) ) { - items(perfumeList ?: emptyList()) { perfume -> + items( + items = perfumeList, + key = {it.perfumeId} + ) { perfume -> PerfumeDescItem( imageUrl = perfume.perfumeImgUrl, brandName = perfume.brandName, perfumeName = perfume.perfumeName, releaseDate = perfume.releaseDate, - onNavPerfumeDesc = { onNavPerfumeDesc(perfume.perfumeId) } + onNavPerfumeDesc = { onPerfumeClick(perfume.perfumeId) } ) } } @@ -272,8 +282,8 @@ private fun ReleasePerfumeList( @Composable private fun Top10Reviews( - reviews: MagazineTastingCommentResponseDto, - onNavCommunityDesc: (Int) -> Unit + reviews: ImmutableList, + onCommunityClick: (communityId: Int) -> Unit ) { Column { Text( @@ -296,13 +306,16 @@ private fun Top10Reviews( modifier = Modifier.padding(horizontal = 16.dp), horizontalArrangement = Arrangement.spacedBy(8.dp) ) { - items(reviews) { review -> + items( + items = reviews, + key = {it.communityId} + ) { review -> ReviewContent( title = review.title, profileImg = review.profileImg, nickname = review.nickname, content = review.content, - onNavCommunityDesc = { onNavCommunityDesc(review.communityId) } + onNavCommunityDesc = { onCommunityClick(review.communityId) } ) } } @@ -385,9 +398,7 @@ private fun PerfumeDescItem( onNavPerfumeDesc: () -> Unit ) { Column( - modifier = Modifier.clickable { - onNavPerfumeDesc() - } + modifier = Modifier.clickable {onNavPerfumeDesc()} ) { Box( modifier = Modifier.size(155.dp) @@ -438,9 +449,7 @@ private fun ReviewContent( .height(206.dp) .background(color = Color.White) .border(width = 1.dp, color = CustomColor.gray2, shape = RectangleShape) - .clickable { - onNavCommunityDesc() - } + .clickable { onNavCommunityDesc() } .padding(horizontal = 20.dp) .padding(bottom = 20.dp, top = 24.dp) ) { @@ -480,4 +489,4 @@ private fun ReviewContent( overflow = TextOverflow.Ellipsis ) } -} +} \ No newline at end of file diff --git a/feature-magazine/src/main/java/com/hmoa/feature_magazine/ViewModel/MagazineMainViewModel.kt b/feature-magazine/src/main/java/com/hmoa/feature_magazine/ViewModel/MagazineMainViewModel.kt index b7f16060..10817bd3 100644 --- a/feature-magazine/src/main/java/com/hmoa/feature_magazine/ViewModel/MagazineMainViewModel.kt +++ b/feature-magazine/src/main/java/com/hmoa/feature_magazine/ViewModel/MagazineMainViewModel.kt @@ -1,10 +1,12 @@ package com.hmoa.feature_magazine.ViewModel +import androidx.compose.runtime.Stable import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.paging.Pager import androidx.paging.PagingConfig import androidx.paging.cachedIn +import com.hmoa.core_common.ErrorMessageType import com.hmoa.core_common.ErrorUiState import com.hmoa.core_common.Result import com.hmoa.core_common.asResult @@ -12,10 +14,12 @@ import com.hmoa.core_domain.repository.MagazineRepository import com.hmoa.core_domain.repository.PerfumeRepository import com.hmoa.core_model.data.ErrorMessage import com.hmoa.core_model.response.MagazineSummaryResponseDto -import com.hmoa.core_model.response.MagazineTastingCommentResponseDto -import com.hmoa.core_model.response.RecentPerfumeResponseDto +import com.hmoa.core_model.response.MagazineTastingCommentResponseDtoItem +import com.hmoa.core_model.response.RecentPerfumeResponseDtoItem import com.hmoa.feature_magazine.MagazinePagingSource import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.collections.immutable.ImmutableList +import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted @@ -31,8 +35,7 @@ class MagazineMainViewModel @Inject constructor( private val perfumeRepository: PerfumeRepository, private val magazineRepository : MagazineRepository ) : ViewModel() { - private val PAGE_SIZE = 5 - + private val MAGAZINE_PAGE_SIZE = 5 private val perfumeFlow = flow{ val result = perfumeRepository.getRecentPerfumes() if (result.errorMessage is ErrorMessage) throw Exception(result.errorMessage!!.message) @@ -71,20 +74,24 @@ class MagazineMainViewModel @Inject constructor( perfumeFlow, communityFlow ){ perfumes, communities -> - if (perfumes is Result.Loading || communities is Result.Loading){ - MagazineMainUiState.Loading - } else if (perfumes is Result.Error || communities is Result.Error){ + if (perfumes is Result.Loading || communities is Result.Loading){ MagazineMainUiState.Loading} + else if (perfumes is Result.Error || communities is Result.Error){ val errMsg = if (perfumes is Result.Error) perfumes.exception.message else (communities as Result.Error).exception.message - generalErrorState.update{ Pair(true, errMsg) } - MagazineMainUiState.Error(errMsg ?: "Error Message is NULL") + when(errMsg){ + ErrorMessageType.UNKNOWN_ERROR.name -> unLoginedErrorState.update{true} + ErrorMessageType.WRONG_TYPE_TOKEN.name -> wrongTypeTokenErrorState.update{true} + ErrorMessageType.EXPIRED_TOKEN.name -> expiredTokenErrorState.update{true} + else -> generalErrorState.update{ Pair(true, errMsg) } + } + MagazineMainUiState.Error } else { val perfumeList = (perfumes as Result.Success).data val communityList = (communities as Result.Success).data MagazineMainUiState.MagazineMain( - perfumes = perfumeList, - reviews = communityList + perfumes = perfumeList.toImmutableList(), + reviews = communityList.toImmutableList() ) } }.stateIn( @@ -94,24 +101,18 @@ class MagazineMainViewModel @Inject constructor( ) fun magazinePagingSource(): Flow> = Pager( - config = PagingConfig(pageSize = PAGE_SIZE), - pagingSourceFactory = { - getMagazinePaging() - } + config = PagingConfig(pageSize = MAGAZINE_PAGE_SIZE), + pagingSourceFactory = {getMagazinePaging()} ).flow.cachedIn(viewModelScope) - private fun getMagazinePaging() = MagazinePagingSource( - magazineRepository = magazineRepository, - ) + private fun getMagazinePaging() = MagazinePagingSource(magazineRepository = magazineRepository) } sealed interface MagazineMainUiState{ data object Loading : MagazineMainUiState data class MagazineMain ( - val perfumes : RecentPerfumeResponseDto, - val reviews : MagazineTastingCommentResponseDto + @Stable val perfumes : ImmutableList, + @Stable val reviews : ImmutableList ) : MagazineMainUiState - data class Error( - val message : String - ) : MagazineMainUiState -} + data object Error : MagazineMainUiState +} \ No newline at end of file diff --git a/feature-userInfo/build.gradle.kts b/feature-userInfo/build.gradle.kts index af8f4473..e6bb10cd 100644 --- a/feature-userInfo/build.gradle.kts +++ b/feature-userInfo/build.gradle.kts @@ -47,6 +47,18 @@ android { compose = true buildConfig = true } + tasks.withType() { + compilerOptions.freeCompilerArgs.addAll( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=${project.buildDir.absolutePath}/compose_metrics", + ) + } + tasks.withType() { + compilerOptions.freeCompilerArgs.addAll( + "-P", + "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=${project.buildDir.absolutePath}/compose_reports", + ) + } } dependencies { diff --git a/feature-userInfo/src/main/java/com/hmoa/feature_userinfo/Screen/EditProfilePage.kt b/feature-userInfo/src/main/java/com/hmoa/feature_userinfo/Screen/EditProfilePage.kt index 5bb63e31..9739bf08 100644 --- a/feature-userInfo/src/main/java/com/hmoa/feature_userinfo/Screen/EditProfilePage.kt +++ b/feature-userInfo/src/main/java/com/hmoa/feature_userinfo/Screen/EditProfilePage.kt @@ -79,7 +79,7 @@ fun EditProfilePage( uiState: EditProfileUiState, errState: ErrorUiState, onChangeInfo : (nickname: String, profileImg: String?) -> Unit, - checkDuplication : (String) -> Unit, + checkDuplication : (nickname: String) -> Unit, resetIsDup: () -> Unit, navBack: () -> Unit, navLogin: () -> Unit, @@ -116,9 +116,7 @@ private fun EditProfileContent( val isDuplicated by data.isDuplicated.collectAsStateWithLifecycle(false) val initNickname by data.nickname.collectAsStateWithLifecycle() var profileImg by remember{mutableStateOf(data.profileImg)} - val launcher = rememberLauncherForActivityResult( - contract = ActivityResultContracts.GetContent() - ){ + val launcher = rememberLauncherForActivityResult(contract = ActivityResultContracts.GetContent()){ if (it != null){ profileImg = it.toString() } } val isNextEnabled by remember{derivedStateOf{(isDuplicated != null && isDuplicated!!) || profileImg != data.profileImg}} @@ -182,9 +180,7 @@ private fun EditProfileContent( } @Composable -private fun EditProfileButton( - launcher: ManagedActivityResultLauncher -){ +private fun EditProfileButton(launcher: ManagedActivityResultLauncher){ Box( modifier = Modifier .size(20.dp) @@ -193,9 +189,7 @@ private fun EditProfileButton( ) { IconButton( modifier = Modifier.size(16.dp), - onClick = { - launcher.launch("image/*") - } + onClick = {launcher.launch("image/*")} ) { Icon( modifier = Modifier.fillMaxSize(), diff --git a/feature-userInfo/src/main/java/com/hmoa/feature_userinfo/Screen/MyActivityPage.kt b/feature-userInfo/src/main/java/com/hmoa/feature_userinfo/Screen/MyActivityPage.kt index 10093759..772a5d20 100644 --- a/feature-userInfo/src/main/java/com/hmoa/feature_userinfo/Screen/MyActivityPage.kt +++ b/feature-userInfo/src/main/java/com/hmoa/feature_userinfo/Screen/MyActivityPage.kt @@ -94,9 +94,7 @@ fun MyActivityPage( tint = CustomColor.gray2 ) } - if (idx != columnData.lastIndex){ - HorizontalDivider(thickness = 1.dp, color = CustomColor.gray2) - } + if (idx != columnData.lastIndex){ HorizontalDivider(thickness = 1.dp, color = CustomColor.gray2) } } } } diff --git a/feature-userInfo/src/main/java/com/hmoa/feature_userinfo/viewModel/CommentViewModel.kt b/feature-userInfo/src/main/java/com/hmoa/feature_userinfo/viewModel/CommentViewModel.kt index 907e926c..115bbebc 100644 --- a/feature-userInfo/src/main/java/com/hmoa/feature_userinfo/viewModel/CommentViewModel.kt +++ b/feature-userInfo/src/main/java/com/hmoa/feature_userinfo/viewModel/CommentViewModel.kt @@ -77,9 +77,7 @@ class CommentViewModel @Inject constructor( ) //type 변환 - fun changeType(newType: MyPageCategory){ - _type.update{ newType } - } + fun changeType(newType: MyPageCategory){ _type.update{ newType } } //댓글 Paging private fun commentPagingSource(type : String) : Flow> = Pager(