diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 8e2be33fe..b97597095 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -1,4 +1,4 @@
-import java.util.Properties
+import java.util.*
plugins {
alias(libs.plugins.android.application)
@@ -21,7 +21,7 @@ android {
applicationId = "com.hmoa.app"
minSdk = 26
targetSdk = 34
- versionCode = 33
+ versionCode = 35
versionName = "1.2.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
@@ -90,6 +90,7 @@ dependencies {
implementation(project(":core-repository"))
implementation(project(":core-common"))
+ implementation(libs.app.update.ktx)
implementation(libs.bootpay) //부트페이
implementation(libs.bundles.kakao.login) // kakao
implementation(libs.bundles.hilt) // hilt
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index cdfe52f31..2848e56b9 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -30,7 +30,7 @@
android:usesCleartextTraffic="true"
tools:targetApi="31">
@@ -64,7 +64,7 @@
@@ -72,4 +72,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/java/com/hmoa/app/FcmAppService.kt b/app/src/main/java/com/hmoa/app/service/FcmAppService.kt
similarity index 69%
rename from app/src/main/java/com/hmoa/app/FcmAppService.kt
rename to app/src/main/java/com/hmoa/app/service/FcmAppService.kt
index 10828577e..236698f7f 100644
--- a/app/src/main/java/com/hmoa/app/FcmAppService.kt
+++ b/app/src/main/java/com/hmoa/app/service/FcmAppService.kt
@@ -1,4 +1,4 @@
-package com.hmoa.app
+package com.hmoa.app.service
import android.app.Notification
import android.app.NotificationChannel
@@ -8,28 +8,36 @@ import android.content.Context
import android.content.Intent
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
+import com.hmoa.app.view.MainActivity
class FcmAppService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
super.onNewToken(token)
}
+
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
- if(remoteMessage.data.isNotEmpty()){
+ if (remoteMessage.data.isNotEmpty()) {
sendNotification(remoteMessage.data)
}
}
- private fun sendNotification(fcmData : Map){
+
+ private fun sendNotification(fcmData: Map) {
val CHANNEL_DEFAULT_IMPORTANCE = "channelId"
val ONGOING_NOTIFICATION = 1
- val notificationIntent = Intent(this, MainActivity::class.java).apply{
+ val notificationIntent = Intent(this, MainActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
- putExtra("deeplink",fcmData["deeplink"])
- putExtra("id",fcmData["id"])
+ putExtra("deeplink", fcmData["deeplink"])
+ putExtra("id", fcmData["id"])
}
- val pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
+ val pendingIntent = PendingIntent.getActivity(
+ this,
+ 0,
+ notificationIntent,
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
+ )
val notification = Notification.Builder(this, CHANNEL_DEFAULT_IMPORTANCE)
.setContentTitle(fcmData["title"])
@@ -41,9 +49,10 @@ class FcmAppService : FirebaseMessagingService() {
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
- val channel = NotificationChannel(CHANNEL_DEFAULT_IMPORTANCE, "HMOA Channel", NotificationManager.IMPORTANCE_DEFAULT)
+ val channel =
+ NotificationChannel(CHANNEL_DEFAULT_IMPORTANCE, "HMOA Channel", NotificationManager.IMPORTANCE_DEFAULT)
notificationManager.createNotificationChannel(channel)
notificationManager.notify(ONGOING_NOTIFICATION, notification)
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/hmoa/app/MainActivity.kt b/app/src/main/java/com/hmoa/app/view/MainActivity.kt
similarity index 73%
rename from app/src/main/java/com/hmoa/app/MainActivity.kt
rename to app/src/main/java/com/hmoa/app/view/MainActivity.kt
index dabd29521..3b4ec8e22 100644
--- a/app/src/main/java/com/hmoa/app/MainActivity.kt
+++ b/app/src/main/java/com/hmoa/app/view/MainActivity.kt
@@ -1,4 +1,4 @@
-package com.hmoa.app
+package com.hmoa.app.view
import android.Manifest
import android.content.Intent
@@ -8,6 +8,8 @@ import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.activity.compose.setContent
+import androidx.activity.result.ActivityResult
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.layout.Box
@@ -32,19 +34,23 @@ import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
+import com.google.android.material.snackbar.Snackbar
+import com.google.android.play.core.appupdate.AppUpdateInfo
+import com.google.android.play.core.appupdate.AppUpdateManager
+import com.google.android.play.core.appupdate.AppUpdateManagerFactory
+import com.google.android.play.core.appupdate.AppUpdateOptions
+import com.google.android.play.core.install.model.AppUpdateType
+import com.google.android.play.core.install.model.InstallStatus
+import com.google.android.play.core.install.model.UpdateAvailability
import com.google.firebase.messaging.FirebaseMessaging
+import com.hmoa.app.BuildConfig
import com.hmoa.app.navigation.SetUpNavGraph
+import com.hmoa.app.viewmodel.AppViewModel
import com.hmoa.core_common.permissions
import com.hmoa.core_designsystem.BottomScreen
import com.hmoa.core_designsystem.component.HomeTopBar
import com.hmoa.core_designsystem.component.MainBottomBar
-import com.hmoa.core_domain.entity.navigation.AuthenticationRoute
-import com.hmoa.core_domain.entity.navigation.CommunityRoute
-import com.hmoa.core_domain.entity.navigation.HPediaRoute
-import com.hmoa.core_domain.entity.navigation.HomeRoute
-import com.hmoa.core_domain.entity.navigation.MagazineRoute
-import com.hmoa.core_domain.entity.navigation.PerfumeRoute
-import com.hmoa.core_domain.entity.navigation.UserInfoRoute
+import com.hmoa.core_domain.entity.navigation.*
import com.hmoa.feature_brand.navigation.navigateToBrandSearch
import com.hmoa.feature_fcm.navigateToAlarmScreen
import com.hmoa.feature_home.navigation.navigateToHome
@@ -86,10 +92,94 @@ class MainActivity : AppCompatActivity() {
BottomScreen.Magazine.name,
BottomScreen.MyPage.name
)
+ private lateinit var appUpdateManager: AppUpdateManager
+ private val activityResultLauncher =
+ registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result: ActivityResult ->
+ handleUpdateResult(result)
+ }
+
+ // Displays the snackbar notification and call to action.
+ fun popupSnackbarForCompleteUpdate() {
+ Snackbar.make(
+ findViewById(com.hmoa.core_designsystem.R.drawable.ic_fab),
+ "새로운 업데이트 다운로드가 완료되었습니다.",
+ Snackbar.LENGTH_INDEFINITE
+ ).apply {
+ setAction("재시작") { appUpdateManager.completeUpdate() }
+ show()
+ }
+ }
+
+ private fun checkImmediateUpdateAvailability() {
+ appUpdateManager.appUpdateInfo.addOnSuccessListener { appUpdateInfo ->
+ if (shouldTriggerImmediateUpdate(appUpdateInfo)) {
+ Log.d("checkUpdateAvailability", "ImemediateUpdate")
+ startImmediateUpdate(appUpdateInfo)
+ }
+ }.addOnFailureListener { e ->
+ Log.e("UpdateFlow", "Failed to check update availability", e)
+ }
+ }
+
+ private fun checkFlexibleUpdateAvailability() {
+ appUpdateManager.appUpdateInfo.addOnSuccessListener { appUpdateInfo ->
+ if (shouldTriggerFlexibleUpdate(appUpdateInfo)) {
+ Log.d("checkUpdateAvailability", "ImemediateUpdate")
+ startFlexibleUpdate(appUpdateInfo)
+ if (appUpdateInfo.installStatus() == InstallStatus.DOWNLOADED) {
+ popupSnackbarForCompleteUpdate()
+ }
+ }
+ }.addOnFailureListener { e ->
+ Log.e("UpdateFlow", "Failed to check update availability", e)
+ }
+ }
+
+
+ private fun shouldTriggerImmediateUpdate(appUpdateInfo: AppUpdateInfo): Boolean {
+ return appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE &&
+ appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)
+ }
+
+ private fun shouldTriggerFlexibleUpdate(appUpdateInfo: AppUpdateInfo): Boolean {
+ return appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE &&
+ appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.FLEXIBLE)
+ }
+
+
+ private fun startImmediateUpdate(appUpdateInfo: AppUpdateInfo) {
+ appUpdateManager.startUpdateFlowForResult(
+ appUpdateInfo,
+ activityResultLauncher,
+ AppUpdateOptions.newBuilder(AppUpdateType.IMMEDIATE).build()
+ )
+ }
+
+ private fun startFlexibleUpdate(appUpdateInfo: AppUpdateInfo) {
+ appUpdateManager.startUpdateFlowForResult(
+ appUpdateInfo,
+ activityResultLauncher,
+ AppUpdateOptions.newBuilder(AppUpdateType.FLEXIBLE).build()
+ )
+ }
+
+ private fun handleUpdateResult(result: ActivityResult) {
+ if (result.resultCode == RESULT_OK) {
+ Log.d("UpdateFlow", "Update flow completed successfully!")
+ } else {
+ Log.e("UpdateFlow", "Update flow failed! Result code: ${result.resultCode}")
+ // 필요시 재시도 로직 추가 가능
+ }
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
installSplashScreen()
WindowCompat.setDecorFitsSystemWindows(window, false)
+
+ appUpdateManager = AppUpdateManagerFactory.create(this)
+ checkImmediateUpdateAvailability()
+
requestNotificationPermission()
BootpayAnalytics.init(this, BuildConfig.BOOTPAY_APPLICATION_ID)
@@ -162,6 +252,11 @@ class MainActivity : AppCompatActivity() {
}
}
+ override fun onResume() {
+ super.onResume()
+ checkFlexibleUpdateAvailability()
+ }
+
//firebase 초기 토큰 처리
private fun initializeFirebaseSetting(fcmToken: String?, onSaveFcmToken: (token: String) -> Unit) {
FirebaseMessaging.getInstance().token.addOnSuccessListener {
@@ -273,4 +368,4 @@ class MainActivity : AppCompatActivity() {
lifecycleScope.launch { viewModel.saveNotificationEnabled(true) }
}
}
-}
\ No newline at end of file
+}
diff --git a/app/src/main/java/com/hmoa/app/AppViewModel.kt b/app/src/main/java/com/hmoa/app/viewmodel/AppViewModel.kt
similarity index 93%
rename from app/src/main/java/com/hmoa/app/AppViewModel.kt
rename to app/src/main/java/com/hmoa/app/viewmodel/AppViewModel.kt
index daaaf2b65..6b1adb339 100644
--- a/app/src/main/java/com/hmoa/app/AppViewModel.kt
+++ b/app/src/main/java/com/hmoa/app/viewmodel/AppViewModel.kt
@@ -1,4 +1,4 @@
-package com.hmoa.app
+package com.hmoa.app.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@@ -7,8 +7,6 @@ import com.hmoa.core_domain.repository.LoginRepository
import com.hmoa.core_model.request.FCMTokenSaveRequestDto
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import javax.inject.Inject
@@ -43,4 +41,4 @@ class AppViewModel @Inject constructor(
suspend fun saveNotificationEnabled(isEnabled: Boolean) =
viewModelScope.launch { fcmRepository.saveNotificationEnabled(isEnabled) }
-}
\ No newline at end of file
+}
diff --git a/feature-home/src/main/java/com/hmoa/feature_home/PerfumeNameSearchPagingSource.kt b/feature-home/src/main/java/com/hmoa/feature_home/PerfumeNameSearchPagingSource.kt
deleted file mode 100644
index e42c5731d..000000000
--- a/feature-home/src/main/java/com/hmoa/feature_home/PerfumeNameSearchPagingSource.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.hmoa.feature_home
-
-import androidx.paging.PagingSource
-import androidx.paging.PagingState
-import com.hmoa.core_domain.repository.SearchRepository
-import com.hmoa.core_model.response.PerfumeNameSearchResponseDto
-
-class PerfumeNameSearchPagingSource(
- val searchRepository: SearchRepository,
- val word: String
-) : PagingSource() {
- override fun getRefreshKey(state: PagingState): Int? {
- return state.anchorPosition?.let {
- state.closestPageToPosition(it)?.prevKey?.plus(1)
- ?: state.closestPageToPosition(it)?.nextKey?.minus(1)
- }
- }
-
- override suspend fun load(params: LoadParams): LoadResult {
- val pageNumber = params.key ?: 0
- try {
- val response = searchRepository.getPerfumeName(page = pageNumber, searchWord = word)
-
- if (response.errorMessage != null) {
- throw Exception(response.errorMessage!!.message)
- }
-
- val prevKey = if (pageNumber > 0) pageNumber - 1 else null
- val nextKey = if (response.data!!.isEmpty()) null else pageNumber + 1
-
- return LoadResult.Page(
- data = response.data!!,
- prevKey = prevKey,
- nextKey = nextKey
- )
- } catch (e: Exception) {
- return LoadResult.Error(e)
- }
- }
-
-}
\ No newline at end of file
diff --git a/feature-home/src/main/java/com/hmoa/feature_home/PerfumePagingSource.kt b/feature-home/src/main/java/com/hmoa/feature_home/PerfumePagingSource.kt
new file mode 100644
index 000000000..d5ee53887
--- /dev/null
+++ b/feature-home/src/main/java/com/hmoa/feature_home/PerfumePagingSource.kt
@@ -0,0 +1,36 @@
+package com.hmoa.feature_home
+
+import androidx.paging.PagingSource
+import androidx.paging.PagingState
+
+class PerfumePagingSource(
+ private val fetcher: suspend (pageNumber: Int) -> R,
+ private val mapper: (R) -> List
+) : PagingSource() {
+
+ override fun getRefreshKey(state: PagingState): Int? {
+ return state.anchorPosition?.let {
+ state.closestPageToPosition(it)?.prevKey?.plus(1)
+ ?: state.closestPageToPosition(it)?.nextKey?.minus(1)
+ }
+ }
+
+ override suspend fun load(params: LoadParams): LoadResult {
+ val pageNumber = params.key ?: 0
+ return try {
+ val response = fetcher(pageNumber)
+ val data = mapper(response)
+
+ val prevKey = if (pageNumber > 0) pageNumber - 1 else null
+ val nextKey = if (data.isEmpty()) null else pageNumber + 1
+
+ LoadResult.Page(
+ data = data,
+ prevKey = prevKey,
+ nextKey = nextKey
+ )
+ } catch (e: Exception) {
+ LoadResult.Error(e)
+ }
+ }
+}
diff --git a/feature-home/src/main/java/com/hmoa/feature_home/PerfumeSearchPagingSource.kt b/feature-home/src/main/java/com/hmoa/feature_home/PerfumeSearchPagingSource.kt
deleted file mode 100644
index d10a2ae3f..000000000
--- a/feature-home/src/main/java/com/hmoa/feature_home/PerfumeSearchPagingSource.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package com.hmoa.feature_home
-
-import androidx.paging.PagingSource
-import androidx.paging.PagingState
-import com.hmoa.core_domain.repository.SearchRepository
-import com.hmoa.core_model.response.PerfumeSearchResponseDto
-
-class PerfumeSearchPagingSource(
- val searchRepository: SearchRepository,
- val word: String
-) : PagingSource() {
- override fun getRefreshKey(state: PagingState): Int? {
- return state.anchorPosition?.let {
- state.closestPageToPosition(it)?.prevKey?.plus(1)
- ?: state.closestPageToPosition(it)?.nextKey?.minus(1)
- }
- }
-
- override suspend fun load(params: LoadParams): LoadResult {
- val pageNumber = params.key ?: 0
- try {
- val response = searchRepository.getPerfume(page = pageNumber, searchWord = word)
-
- if (response.errorMessage != null) {
- throw Exception(response.errorMessage!!.message)
- }
-
- val prevKey = if (pageNumber > 0) pageNumber - 1 else null
- val nextKey = if (response.data!!.isEmpty()) null else pageNumber + 1
-
- return LoadResult.Page(
- data = response.data!!,
- prevKey = prevKey,
- nextKey = nextKey
- )
- } catch (e: Exception) {
- return LoadResult.Error(e)
- }
- }
-
-
-}
\ No newline at end of file
diff --git a/feature-home/src/main/java/com/hmoa/feature_home/screen/PerfumeSearchScreen.kt b/feature-home/src/main/java/com/hmoa/feature_home/screen/PerfumeSearchScreen.kt
index fd45d1f21..b0ad7ceba 100644
--- a/feature-home/src/main/java/com/hmoa/feature_home/screen/PerfumeSearchScreen.kt
+++ b/feature-home/src/main/java/com/hmoa/feature_home/screen/PerfumeSearchScreen.kt
@@ -138,7 +138,7 @@ fun PerfumeNameSearchResultList(
LazyColumn(modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp)) {
items(perfumeNameList?.itemSnapshotList?.items ?: emptyList()) {
Text(
- text = it!!.perfumeName ?: "",
+ text = it.perfumeName,
modifier = Modifier.clickable { onPerfumeSearchResultClick(it.perfumeName) }
.padding(vertical = 10.dp).fillMaxWidth(),
style = TextStyle(fontWeight = FontWeight.Normal, fontSize = 14.sp)
@@ -156,14 +156,14 @@ fun PerfumeSearchResultList(
columns = GridCells.Fixed(2),
horizontalArrangement = Arrangement.Center
) {
- items(perfumeList?.itemSnapshotList?.items ?: emptyList()) {
+ items(perfumeList?.itemSnapshotList?.items ?: emptyList(), key = { it.perfumeId }) {
Column(modifier = Modifier.clickable { onPerfumeSearchResultClick(it.perfumeName) }
.padding(bottom = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally) {
PerfumeItemView(
- imageUrl = it?.perfumeImageUrl ?: "",
- perfumeName = it?.perfumeName ?: "",
- brandName = it?.brandName ?: "",
+ imageUrl = it.perfumeImageUrl,
+ perfumeName = it.perfumeName,
+ brandName = it.brandName,
containerWidth = 160,
containerHeight = 160,
imageWidth = 0.7f,
diff --git a/feature-home/src/main/java/com/hmoa/feature_home/viewmodel/PerfumeSearchViewmodel.kt b/feature-home/src/main/java/com/hmoa/feature_home/viewmodel/PerfumeSearchViewmodel.kt
index 10f3ffe74..0afe14dc7 100644
--- a/feature-home/src/main/java/com/hmoa/feature_home/viewmodel/PerfumeSearchViewmodel.kt
+++ b/feature-home/src/main/java/com/hmoa/feature_home/viewmodel/PerfumeSearchViewmodel.kt
@@ -11,8 +11,7 @@ import com.hmoa.core_domain.entity.data.PerfumeSearchViewType
import com.hmoa.core_domain.repository.SearchRepository
import com.hmoa.core_model.response.PerfumeNameSearchResponseDto
import com.hmoa.core_model.response.PerfumeSearchResponseDto
-import com.hmoa.feature_home.PerfumeNameSearchPagingSource
-import com.hmoa.feature_home.PerfumeSearchPagingSource
+import com.hmoa.feature_home.PerfumePagingSource
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -37,9 +36,16 @@ class PerfumeSearchViewmodel @Inject constructor(private val searchRepository: S
getPagingPerfumeNameSearchResults()
}
- fun perfumeNameSearchPagingSource(word: String) = PerfumeNameSearchPagingSource(searchRepository, word)
+ fun perfumeNameSearchPagingSource(word: String) =
+ PerfumePagingSource(
+ fetcher = { pageNumber -> searchRepository.getPerfumeName(pageNumber, word) },
+ mapper = { it.data ?: emptyList() }
+ )
- fun perfumeSearchPagingSource(word: String) = PerfumeSearchPagingSource(searchRepository, word)
+ fun perfumeSearchPagingSource(word: String) = PerfumePagingSource(
+ fetcher = { pageNumber -> searchRepository.getPerfume(page = pageNumber, searchWord = word) },
+ mapper = { it.data ?: emptyList() }
+ )
fun getPagingPerfumeNameSearchResults(): Flow>? {
if (_perfumeNameSearchWordState.value != null) {
diff --git a/feature-perfume/src/main/java/com/hmoa/feature_perfume/PerfumeCommentLatestPagingSource.kt b/feature-perfume/src/main/java/com/hmoa/feature_perfume/PerfumeCommentLatestPagingSource.kt
deleted file mode 100644
index b7fbd2a64..000000000
--- a/feature-perfume/src/main/java/com/hmoa/feature_perfume/PerfumeCommentLatestPagingSource.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.hmoa.feature_perfume
-
-import androidx.paging.PagingSource
-import androidx.paging.PagingState
-import com.hmoa.core_domain.repository.PerfumeCommentRepository
-import com.hmoa.core_model.response.PerfumeCommentResponseDto
-
-class PerfumeCommentLatestPagingSource(
- private val perfumeCommentRepository: PerfumeCommentRepository,
- private val perfumeId: Int,
-) : PagingSource() {
- private var commentCounts = 0
- private var cursor = 0
-
- override suspend fun load(params: LoadParams): LoadResult {
- val pageNumber = params.key ?: 0
- try {
- val response =
- perfumeCommentRepository.getPerfumeCommentsLatest(
- pageNumber,
- cursor = cursor,
- perfumeId = perfumeId
- )
- commentCounts = response.commentCount
- cursor = response.comments.get(response.comments.lastIndex).id
- val prevKey = if (pageNumber > 0) pageNumber - 1 else null
- val nextKey = if (response.lastPage) null else pageNumber + 1
-
- return LoadResult.Page(
- data = response.comments,
- prevKey = prevKey,
- nextKey = nextKey
- )
- } catch (e: Exception) {
- return LoadResult.Error(e)
- }
- }
-
- override fun getRefreshKey(state: PagingState): Int? {
- return state.anchorPosition?.let {
- state.closestPageToPosition(it)?.prevKey?.plus(1)
- ?: state.closestPageToPosition(it)?.nextKey?.minus(1)
- }
- }
-}
\ No newline at end of file
diff --git a/feature-perfume/src/main/java/com/hmoa/feature_perfume/PerfumeCommentLikePagingSource.kt b/feature-perfume/src/main/java/com/hmoa/feature_perfume/PerfumeCommentPagingSource.kt
similarity index 74%
rename from feature-perfume/src/main/java/com/hmoa/feature_perfume/PerfumeCommentLikePagingSource.kt
rename to feature-perfume/src/main/java/com/hmoa/feature_perfume/PerfumeCommentPagingSource.kt
index efe33afdd..988ce3817 100644
--- a/feature-perfume/src/main/java/com/hmoa/feature_perfume/PerfumeCommentLikePagingSource.kt
+++ b/feature-perfume/src/main/java/com/hmoa/feature_perfume/PerfumeCommentPagingSource.kt
@@ -2,12 +2,11 @@ package com.hmoa.feature_perfume
import androidx.paging.PagingSource
import androidx.paging.PagingState
-import com.hmoa.core_domain.repository.PerfumeCommentRepository
+import com.hmoa.core_model.response.PerfumeCommentGetResponseDto
import com.hmoa.core_model.response.PerfumeCommentResponseDto
-class PerfumeCommentLikePagingSource(
- private val perfumeCommentRepository: PerfumeCommentRepository,
- private val perfumeId: Int,
+class PerfumeCommentPagingSource(
+ private val fetcher: suspend (pageNumber: Int, cursor: Int) -> PerfumeCommentGetResponseDto,
) : PagingSource() {
private var commentCounts = 0
private var cursor = 0
@@ -15,11 +14,7 @@ class PerfumeCommentLikePagingSource(
override suspend fun load(params: LoadParams): LoadResult {
val pageNumber = params.key ?: 0
try {
- val response =
- perfumeCommentRepository.getPerfumeCommentsLikest(
- page = pageNumber.toString(),
- perfumeId = perfumeId.toString()
- )
+ val response = fetcher(pageNumber, cursor)
commentCounts = response.commentCount
cursor = response.comments.get(response.comments.lastIndex).id
val prevKey = if (pageNumber > 0) pageNumber - 1 else null
@@ -41,4 +36,4 @@ class PerfumeCommentLikePagingSource(
?: state.closestPageToPosition(it)?.nextKey?.minus(1)
}
}
-}
\ No newline at end of file
+}
diff --git a/feature-perfume/src/main/java/com/hmoa/feature_perfume/viewmodel/PerfumeCommentViewmodel.kt b/feature-perfume/src/main/java/com/hmoa/feature_perfume/viewmodel/PerfumeCommentViewmodel.kt
index dac39c292..77c437d41 100644
--- a/feature-perfume/src/main/java/com/hmoa/feature_perfume/viewmodel/PerfumeCommentViewmodel.kt
+++ b/feature-perfume/src/main/java/com/hmoa/feature_perfume/viewmodel/PerfumeCommentViewmodel.kt
@@ -7,15 +7,14 @@ import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import androidx.paging.cachedIn
+import com.hmoa.core_domain.entity.data.SortType
import com.hmoa.core_domain.repository.LoginRepository
import com.hmoa.core_domain.repository.PerfumeCommentRepository
import com.hmoa.core_domain.repository.ReportRepository
import com.hmoa.core_domain.usecase.UpdateLikePerfumeCommentUseCase
-import com.hmoa.core_domain.entity.data.SortType
import com.hmoa.core_model.request.TargetRequestDto
import com.hmoa.core_model.response.PerfumeCommentResponseDto
-import com.hmoa.feature_perfume.PerfumeCommentLatestPagingSource
-import com.hmoa.feature_perfume.PerfumeCommentLikePagingSource
+import com.hmoa.feature_perfume.PerfumeCommentPagingSource
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
@@ -77,15 +76,21 @@ class PerfumeCommentViewmodel @Inject constructor(
_unLoginedErrorState.update { true }
}
- fun latestPerfumeCommentPagingSource(perfumeId: Int) = PerfumeCommentLatestPagingSource(
- perfumeId = perfumeId,
- perfumeCommentRepository = perfumeCommentRepository
- )
+ fun latestPerfumeCommentPagingSource(perfumeId: Int) = PerfumeCommentPagingSource(fetcher = { pageNumber, cursor ->
+ perfumeCommentRepository.getPerfumeCommentsLatest(
+ pageNumber,
+ cursor = cursor,
+ perfumeId = perfumeId
+ )
+ })
+
+ fun likePerfumeCommentPagingSource(perfumeId: Int) = PerfumeCommentPagingSource(fetcher = { pageNumber, cursor ->
+ perfumeCommentRepository.getPerfumeCommentsLikest(
+ pageNumber.toString(),
+ perfumeId = perfumeId.toString()
+ )
+ })
- fun likePerfumeCommentPagingSource(perfumeId: Int) = PerfumeCommentLikePagingSource(
- perfumeId = perfumeId,
- perfumeCommentRepository = perfumeCommentRepository
- )
fun getPagingLatestPerfumeComments(perfumeId: Int?): Flow>? {
if (perfumeId != null) {
@@ -152,4 +157,4 @@ class PerfumeCommentViewmodel @Inject constructor(
data object Error : PerfumeCommentUiState
}
-}
\ No newline at end of file
+}
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index c032c0233..84901f190 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -36,6 +36,7 @@ appcompat-version = "1.6.1"
splash-screen-version = "1.2.0-alpha01"
constraintlayout-version = "2.1.4"
lifecycle-version = "2.5.1"
+app-update-version = "2.1.0"
room-version = "2.6.1"
datastore-version = "1.0.0"
@@ -60,78 +61,79 @@ hilt-test-version = "2.44"
junit-jupiter-version = "5.3.1"
[libraries]
-bootpay = {group = "io.github.bootpay", name = "android", version.ref = "bootpay-version"}
-kakao-all = {group = "com.kakao.sdk", name = "v2-all", version.ref = "kakao-version"}
-kakao-user = {group = "com.kakao.sdk", name = "v2-user", version.ref = "kakao-version"}
-kakao-talk = {group = "com.kakao.sdk", name = "v2-talk", version.ref = "kakao-version"}
-kakao-share = {group = "com.kakao.sdk", name = "v2-share", version.ref = "kakao-version"}
-kakao-freind = {group = "com.kakao.sdk", name = "v2-friend", version.ref = "kakao-version"}
-kakao-cert = {group = "com.kakao.sdk", name = "v2-cert", version.ref = "kakao-version"}
-hilt-android = {group = "com.google.dagger", name = "hilt-android", version.ref = "hilt-version"}
-hilt-compiler = {group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt-version"}
-hilt-android-compiler = {group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt-version"}
-hilt-navigation-compose = {group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hilt-nav-compose-version"}
-hilt-viewmodel = {group = "androidx.hilt", name = "hilt-compiler", version.ref = "hilt-viewmodel-version"}
-ui-tooling-preview = {group = "androidx.compose.ui", name = "ui-tooling-preview", version.ref = "ui-version"}
-ui-tooling = {group = "androidx.compose.ui", name = "ui-tooling", version.ref = "ui-tooling-version"}
-ui = {group = "androidx.compose.ui", name = "ui", version.ref = "ui-version"}
-navigation-compose = {group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation-compose-version"}
-core-ktx = {group = "androidx.core", name = "core-ktx", version.ref = "core-ktx-version"}
-appcompat = {group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat-version"}
-splash-screen = {group = "androidx.core", name = "core-splashscreen", version.ref = "splash-screen-version"}
-google-material = {group = "com.google.android.material", name = "material", version.ref = "google-material-version"}
-material = {group = "androidx.compose.material", name = "material", version.ref = "material-version"}
-material3 = {group = "androidx.compose.material3", name = "material3", version.ref = "metarial3-version"}
-firebase-messaging = {group = "com.google.firebase", name = "firebase-messaging", version.ref = "firebase-messaging-version"}
-firebase-analytics = {group = "com.google.firebase", name = "firebase-analytics", version.ref = "firebase-analytics-version"}
-play-service-auth = {group = "com.google.android.gms", name = "play-services-auth", version.ref = "play-service-auth-version"}
-google-services = {group = "com.google.gms", name = "google-services", version.ref = "google-services-version"}
-open-licenses = {group = "com.google.android.gms", name = "play-services-oss-licenses", version.ref = "oss-licenses-version"}
-room-ktx = {group = "androidx.room", name = "room-ktx", version.ref = "room-version"}
-room-compiler = {group = "androidx.room", name = "room-compiler", version.ref = "room-version"}
-datastore = {group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastore-version"}
-junit = {group = "junit", name = "junit", version.ref = "junit-version"}
-junit-ktx = {group = "androidx.test.ext", name = "junit-ktx", version.ref = "junit-ktx-version"}
-junit-ext = {group = "androidx.test.ext", name = "junit", version.ref = "junit-ext-version"}
-mockito-core = {group = "org.mockito", name = "mockito-core", version.ref = "mockito-version"}
-mockito-inline = {group = "org.mockito", name = "mockito-inline", version.ref = "mockito-version"}
-mockito-android = {group = "org.mockito", name = "mockito-android", version.ref = "mockito-version"}
-mockito-kotlin = {group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockito-kotlin-version"}
-espresso = {group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-version"}
-coroutine-test = {group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutine-test-version"}
-reflect = {group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin-reflect-version"}
-hilt-android-test = {group = "com.google.dagger", name = "hilt-android-testing", version.ref = "hilt-test-version"}
-sandwich = {group = "com.github.skydoves", name="sandwich", version.ref = "sandwich-version"}
-kotlinx-serialization-json = {group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-version"}
-coil-gif = {group = "io.coil-kt", name = "coil-gif", version.ref = "coil-version"}
-coil-compose = {group = "io.coil-kt", name = "coil-compose", version.ref = "coil-version"}
-landscapist-glide = {group = "com.github.skydoves", name = "landscapist-glide", version.ref = "landscapist-glide-version"}
-bumptech-glide = {group = "com.github.bumptech.glide", name = "glide", version.ref = "bumptech-glide-version"}
-accommpanist-pager = {group = "com.google.accompanist", name = "accompanist-pager", version.ref = "paging-version"}
-retrofit = {group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit-version"}
-retrofit-gson = {group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit-version"}
-logging-interceptor = {group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp3-version"}
-lifecycle-viewmodel-ktx = {group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycle-version"}
-lifecycle-viewmodel-compose = {group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle-version"}
-lifecycle-runtime = {group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle-version"}
-constraintlayout = {group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout-version"}
-junit-jupiter-api = {group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit-jupiter-version"}
-junit-jupiter-engine = {group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit-jupiter-version"}
-paging-compose = {group = "androidx.paging", name = "paging-compose", version.ref = "paging-compose-version"}
-core-gson = {group = "com.google.code.gson", name = "gson", version.ref = "gson-version"}
-ui-test-junit4 = {group = "androidx.compose.ui", name = "ui-test-junit4", version.ref = "junit4-version"}
-ui-test-manifest = {group = "androidx.compose.ui", name = "ui-test-manifest", version.ref = "junit4-version"}
-kotlinx-collections-immutable = {group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version.ref = "kotlinx-collections-immutable-version"}
-testing = {group = "org.testing", name = "testing", version.ref = "testing-version"}
+app-update-ktx = { group = "com.google.android.play", name = "app-update-ktx", version.ref = "app-update-version" }
+bootpay = { group = "io.github.bootpay", name = "android", version.ref = "bootpay-version" }
+kakao-all = { group = "com.kakao.sdk", name = "v2-all", version.ref = "kakao-version" }
+kakao-user = { group = "com.kakao.sdk", name = "v2-user", version.ref = "kakao-version" }
+kakao-talk = { group = "com.kakao.sdk", name = "v2-talk", version.ref = "kakao-version" }
+kakao-share = { group = "com.kakao.sdk", name = "v2-share", version.ref = "kakao-version" }
+kakao-freind = { group = "com.kakao.sdk", name = "v2-friend", version.ref = "kakao-version" }
+kakao-cert = { group = "com.kakao.sdk", name = "v2-cert", version.ref = "kakao-version" }
+hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt-version" }
+hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt-version" }
+hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "hilt-version" }
+hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hilt-nav-compose-version" }
+hilt-viewmodel = { group = "androidx.hilt", name = "hilt-compiler", version.ref = "hilt-viewmodel-version" }
+ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview", version.ref = "ui-version" }
+ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling", version.ref = "ui-tooling-version" }
+ui = { group = "androidx.compose.ui", name = "ui", version.ref = "ui-version" }
+navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation-compose-version" }
+core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx-version" }
+appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat-version" }
+splash-screen = { group = "androidx.core", name = "core-splashscreen", version.ref = "splash-screen-version" }
+google-material = { group = "com.google.android.material", name = "material", version.ref = "google-material-version" }
+material = { group = "androidx.compose.material", name = "material", version.ref = "material-version" }
+material3 = { group = "androidx.compose.material3", name = "material3", version.ref = "metarial3-version" }
+firebase-messaging = { group = "com.google.firebase", name = "firebase-messaging", version.ref = "firebase-messaging-version" }
+firebase-analytics = { group = "com.google.firebase", name = "firebase-analytics", version.ref = "firebase-analytics-version" }
+play-service-auth = { group = "com.google.android.gms", name = "play-services-auth", version.ref = "play-service-auth-version" }
+google-services = { group = "com.google.gms", name = "google-services", version.ref = "google-services-version" }
+open-licenses = { group = "com.google.android.gms", name = "play-services-oss-licenses", version.ref = "oss-licenses-version" }
+room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room-version" }
+room-compiler = { group = "androidx.room", name = "room-compiler", version.ref = "room-version" }
+datastore = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastore-version" }
+junit = { group = "junit", name = "junit", version.ref = "junit-version" }
+junit-ktx = { group = "androidx.test.ext", name = "junit-ktx", version.ref = "junit-ktx-version" }
+junit-ext = { group = "androidx.test.ext", name = "junit", version.ref = "junit-ext-version" }
+mockito-core = { group = "org.mockito", name = "mockito-core", version.ref = "mockito-version" }
+mockito-inline = { group = "org.mockito", name = "mockito-inline", version.ref = "mockito-version" }
+mockito-android = { group = "org.mockito", name = "mockito-android", version.ref = "mockito-version" }
+mockito-kotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version.ref = "mockito-kotlin-version" }
+espresso = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espresso-version" }
+coroutine-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "coroutine-test-version" }
+reflect = { group = "org.jetbrains.kotlin", name = "kotlin-reflect", version.ref = "kotlin-reflect-version" }
+hilt-android-test = { group = "com.google.dagger", name = "hilt-android-testing", version.ref = "hilt-test-version" }
+sandwich = { group = "com.github.skydoves", name = "sandwich", version.ref = "sandwich-version" }
+kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-version" }
+coil-gif = { group = "io.coil-kt", name = "coil-gif", version.ref = "coil-version" }
+coil-compose = { group = "io.coil-kt", name = "coil-compose", version.ref = "coil-version" }
+landscapist-glide = { group = "com.github.skydoves", name = "landscapist-glide", version.ref = "landscapist-glide-version" }
+bumptech-glide = { group = "com.github.bumptech.glide", name = "glide", version.ref = "bumptech-glide-version" }
+accommpanist-pager = { group = "com.google.accompanist", name = "accompanist-pager", version.ref = "paging-version" }
+retrofit = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit-version" }
+retrofit-gson = { group = "com.squareup.retrofit2", name = "converter-gson", version.ref = "retrofit-version" }
+logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp3-version" }
+lifecycle-viewmodel-ktx = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-ktx", version.ref = "lifecycle-version" }
+lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose", version.ref = "lifecycle-version" }
+lifecycle-runtime = { group = "androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "lifecycle-version" }
+constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout-version" }
+junit-jupiter-api = { group = "org.junit.jupiter", name = "junit-jupiter-api", version.ref = "junit-jupiter-version" }
+junit-jupiter-engine = { group = "org.junit.jupiter", name = "junit-jupiter-engine", version.ref = "junit-jupiter-version" }
+paging-compose = { group = "androidx.paging", name = "paging-compose", version.ref = "paging-compose-version" }
+core-gson = { group = "com.google.code.gson", name = "gson", version.ref = "gson-version" }
+ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4", version.ref = "junit4-version" }
+ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest", version.ref = "junit4-version" }
+kotlinx-collections-immutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version.ref = "kotlinx-collections-immutable-version" }
+testing = { group = "org.testing", name = "testing", version.ref = "testing-version" }
[plugins]
-android-application = {id = "com.android.application", version.ref = "android-application"}
-kotlin-android = {id = "org.jetbrains.kotlin.android", version.ref = "kotlin-android"}
-kotlin-jvm = {id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin-jvm"}
-android-library = {id = "com.android.library", version.ref = "android-library"}
-hilt-android = {id = "com.google.dagger.hilt.android", version.ref = "hilt-android"}
-kotlin-plugin-serialization = {id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin-serialization"}
-google-services = {id = "com.google.gms.google-services", version.ref = "plugin-google-services"}
+android-application = { id = "com.android.application", version.ref = "android-application" }
+kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin-android" }
+kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin-jvm" }
+android-library = { id = "com.android.library", version.ref = "android-library" }
+hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt-android" }
+kotlin-plugin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin-serialization" }
+google-services = { id = "com.google.gms.google-services", version.ref = "plugin-google-services" }
[bundles]
kakao-login = ["kakao-all", "kakao-user", "kakao-talk", "kakao-cert", "kakao-share", "kakao-freind"]
@@ -145,4 +147,4 @@ coil = ["coil-gif", "coil-compose"]
glide = ["landscapist-glide", "bumptech-glide"]
retrofit = ["retrofit", "retrofit-gson"]
lifecycle = ["lifecycle-runtime", "lifecycle-viewmodel-compose", "lifecycle-viewmodel-ktx"]
-android-test-mockito = ["mockito-core", "mockito-android", "mockito-kotlin"]
\ No newline at end of file
+android-test-mockito = ["mockito-core", "mockito-android", "mockito-kotlin"]