diff --git a/app/build.gradle b/app/build.gradle index 5abb70b5..e32c3855 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -25,8 +25,8 @@ android { applicationId "com.hyeeyoung.wishboard" minSdkVersion 24 targetSdkVersion 34 - versionCode 39 - versionName "1.2.6" + versionCode 40 + versionName "1.2.7" compileSdk 34 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/com/hyeeyoung/wishboard/data/model/system/AppVersionDto.kt b/app/src/main/java/com/hyeeyoung/wishboard/data/model/system/AppVersionDto.kt new file mode 100644 index 00000000..f60071d6 --- /dev/null +++ b/app/src/main/java/com/hyeeyoung/wishboard/data/model/system/AppVersionDto.kt @@ -0,0 +1,14 @@ +package com.hyeeyoung.wishboard.data.model.system + +import com.hyeeyoung.wishboard.domain.model.system.AppVersion + +data class AppVersionDto( + val platform: String, + val minVersion: String, + val recommendedVersion: String, +) { + fun toDomain(): AppVersion = AppVersion( + minVersionCode = minVersion.toIntOrNull() ?: 0, + latestVersionCode = recommendedVersion.toIntOrNull() ?: 0 + ) +} diff --git a/app/src/main/java/com/hyeeyoung/wishboard/data/repositories/SystemRepositoryImpl.kt b/app/src/main/java/com/hyeeyoung/wishboard/data/repositories/SystemRepositoryImpl.kt new file mode 100644 index 00000000..ec013d36 --- /dev/null +++ b/app/src/main/java/com/hyeeyoung/wishboard/data/repositories/SystemRepositoryImpl.kt @@ -0,0 +1,13 @@ +package com.hyeeyoung.wishboard.data.repositories + +import com.hyeeyoung.wishboard.data.services.retrofit.SystemService +import com.hyeeyoung.wishboard.domain.model.system.AppVersion +import com.hyeeyoung.wishboard.domain.repositories.SystemRepository +import javax.inject.Inject + +class SystemRepositoryImpl @Inject constructor(private val systemService: SystemService) : + SystemRepository { + override suspend fun fetchAppVersion(): Result = runCatching { + systemService.fetchAppVersion().body()?.data?.toDomain() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/hyeeyoung/wishboard/data/services/retrofit/SystemService.kt b/app/src/main/java/com/hyeeyoung/wishboard/data/services/retrofit/SystemService.kt new file mode 100644 index 00000000..2e40783b --- /dev/null +++ b/app/src/main/java/com/hyeeyoung/wishboard/data/services/retrofit/SystemService.kt @@ -0,0 +1,14 @@ +package com.hyeeyoung.wishboard.data.services.retrofit + +import com.hyeeyoung.wishboard.data.model.base.BaseResponseResult +import com.hyeeyoung.wishboard.data.model.system.AppVersionDto +import retrofit2.Response +import retrofit2.http.GET +import retrofit2.http.Query + +interface SystemService { + @GET("version/check") + suspend fun fetchAppVersion( + @Query("osType") osType: String = "AOS" + ): Response> +} \ No newline at end of file diff --git a/app/src/main/java/com/hyeeyoung/wishboard/di/RepositoryModule.kt b/app/src/main/java/com/hyeeyoung/wishboard/di/RepositoryModule.kt index e5eb1fe2..795cd65b 100644 --- a/app/src/main/java/com/hyeeyoung/wishboard/di/RepositoryModule.kt +++ b/app/src/main/java/com/hyeeyoung/wishboard/di/RepositoryModule.kt @@ -33,4 +33,7 @@ abstract class RepositoryModule { @Binds abstract fun bindPhotoRepository(photoRepositoryImpl: PhotoRepositoryImpl): PhotoRepository + + @Binds + abstract fun bindSystemRepository(systemRepositoryImpl: SystemRepositoryImpl): SystemRepository } \ No newline at end of file diff --git a/app/src/main/java/com/hyeeyoung/wishboard/di/ServiceModule.kt b/app/src/main/java/com/hyeeyoung/wishboard/di/ServiceModule.kt index 31a4a546..6c77c13c 100644 --- a/app/src/main/java/com/hyeeyoung/wishboard/di/ServiceModule.kt +++ b/app/src/main/java/com/hyeeyoung/wishboard/di/ServiceModule.kt @@ -40,4 +40,9 @@ object ServiceModule { @Provides fun provideUserService(retrofit: Retrofit): UserService = retrofit.create(UserService::class.java) + + @Singleton + @Provides + fun provideSystemService(retrofit: Retrofit): SystemService = + retrofit.create(SystemService::class.java) } \ No newline at end of file diff --git a/app/src/main/java/com/hyeeyoung/wishboard/domain/model/system/AppVersionDto.kt b/app/src/main/java/com/hyeeyoung/wishboard/domain/model/system/AppVersionDto.kt new file mode 100644 index 00000000..05639678 --- /dev/null +++ b/app/src/main/java/com/hyeeyoung/wishboard/domain/model/system/AppVersionDto.kt @@ -0,0 +1,6 @@ +package com.hyeeyoung.wishboard.domain.model.system + +data class AppVersion( + val minVersionCode: Int, + val latestVersionCode: Int, +) diff --git a/app/src/main/java/com/hyeeyoung/wishboard/domain/repositories/SystemRepository.kt b/app/src/main/java/com/hyeeyoung/wishboard/domain/repositories/SystemRepository.kt new file mode 100644 index 00000000..950e7b41 --- /dev/null +++ b/app/src/main/java/com/hyeeyoung/wishboard/domain/repositories/SystemRepository.kt @@ -0,0 +1,7 @@ +package com.hyeeyoung.wishboard.domain.repositories + +import com.hyeeyoung.wishboard.domain.model.system.AppVersion + +interface SystemRepository { + suspend fun fetchAppVersion(): Result +} \ No newline at end of file diff --git a/app/src/main/java/com/hyeeyoung/wishboard/presentation/common/screens/OneButtonDialogFragment.kt b/app/src/main/java/com/hyeeyoung/wishboard/presentation/common/screens/OneButtonDialogFragment.kt index 6edc9c1f..079a2c3f 100644 --- a/app/src/main/java/com/hyeeyoung/wishboard/presentation/common/screens/OneButtonDialogFragment.kt +++ b/app/src/main/java/com/hyeeyoung/wishboard/presentation/common/screens/OneButtonDialogFragment.kt @@ -5,23 +5,52 @@ import android.view.View import com.hyeeyoung.wishboard.R import com.hyeeyoung.wishboard.databinding.DialogOneButtonBinding import com.hyeeyoung.wishboard.presentation.base.screen.BaseDialogFragment +import com.hyeeyoung.wishboard.presentation.common.types.DialogButtonReplyType +import com.hyeeyoung.wishboard.util.DialogListener -class OneButtonDialogFragment( - private val title: String, - private val description: String? -) : BaseDialogFragment(R.layout.dialog_one_button) { +class OneButtonDialogFragment : + BaseDialogFragment(R.layout.dialog_one_button) { + private lateinit var listener: DialogListener override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - binding.title.text = title - binding.description.text = description + + arguments?.let { + binding.title.text = it.getString(ARG_TITLE) + binding.description.text = it.getString(ARG_DESCRIPTION) + binding.yes.text = it.getString(ARG_BUTTON_TEXT) ?: getString(R.string.confirm) + } addListener() } private fun addListener() { binding.yes.setOnClickListener { - dismiss() + listener.onButtonClicked(DialogButtonReplyType.YES.name) + } + } + + fun setListener(listener: DialogListener) { + this.listener = listener + } + + companion object { + private const val ARG_TITLE = "title" + private const val ARG_DESCRIPTION = "description" + private const val ARG_BUTTON_TEXT = "buttonText" + + fun newInstance( + title: String, + description: String?, + buttonText: String? = null, + ): OneButtonDialogFragment { + val args = Bundle().apply { + putString(ARG_TITLE, title) + putString(ARG_DESCRIPTION, description) + putString(ARG_BUTTON_TEXT, buttonText) + } + + return OneButtonDialogFragment().apply { arguments = args } } } } \ No newline at end of file diff --git a/app/src/main/java/com/hyeeyoung/wishboard/presentation/splash/SplashActivity.kt b/app/src/main/java/com/hyeeyoung/wishboard/presentation/splash/SplashActivity.kt index 226d2c6d..190c3991 100644 --- a/app/src/main/java/com/hyeeyoung/wishboard/presentation/splash/SplashActivity.kt +++ b/app/src/main/java/com/hyeeyoung/wishboard/presentation/splash/SplashActivity.kt @@ -11,6 +11,7 @@ import com.google.android.play.core.install.model.UpdateAvailability import com.hyeeyoung.wishboard.BuildConfig import com.hyeeyoung.wishboard.R import com.hyeeyoung.wishboard.databinding.ActivitySplashBinding +import com.hyeeyoung.wishboard.presentation.common.screens.OneButtonDialogFragment import com.hyeeyoung.wishboard.presentation.common.screens.TwoButtonDialogFragment import com.hyeeyoung.wishboard.presentation.common.types.DialogButtonReplyType import com.hyeeyoung.wishboard.presentation.main.MainActivity @@ -28,7 +29,7 @@ class SplashActivity : BaseActivity(R.layout.activity_spl override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - lifecycleScope.launch() { + lifecycleScope.launch { delay(2000) checkForNewVersionUpdate() } @@ -50,7 +51,17 @@ class SplashActivity : BaseActivity(R.layout.activity_spl && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE) && appUpdateInfo.availableVersionCode() != BuildConfig.VERSION_CODE ) { - showUpdateDialog() + showOptionalUpdateDialog() + viewModel.checkForAppUpdate( + playStoreVersionCode = appUpdateInfo.availableVersionCode(), + moveToNext = { moveToNext() }, + showUpdateDialog = { isForceUpdate -> + when (isForceUpdate) { + true -> showForceUpdateDialog() + false -> showOptionalUpdateDialog() + } + } + ) } else { moveToNext() } @@ -59,7 +70,7 @@ class SplashActivity : BaseActivity(R.layout.activity_spl } } - private fun showUpdateDialog() { + private fun showOptionalUpdateDialog() { TwoButtonDialogFragment.newInstance( title = getString(R.string.app_update_dialog_title), description = getString(R.string.app_update_dialog_description), @@ -76,6 +87,22 @@ class SplashActivity : BaseActivity(R.layout.activity_spl }.show(supportFragmentManager, "UpdateDialog") } + private fun showForceUpdateDialog() { + OneButtonDialogFragment.newInstance( + title = getString(R.string.app_update_dialog_title), + description = getString(R.string.app_update_dialog_description), + buttonText = getString(R.string.app_update_dialog_yes_button_text), + ).apply { + setListener(object : DialogListener { + override fun onButtonClicked(clicked: String) { + if (clicked == DialogButtonReplyType.YES.name) { + moveToPlayStore() + } + } + }) + }.show(supportFragmentManager, "ForceUpdateDialog") + } + private fun moveToPlayStore() { Intent(Intent.ACTION_VIEW).apply { data = diff --git a/app/src/main/java/com/hyeeyoung/wishboard/presentation/splash/SplashViewModel.kt b/app/src/main/java/com/hyeeyoung/wishboard/presentation/splash/SplashViewModel.kt index 62b3b76a..1e78e937 100644 --- a/app/src/main/java/com/hyeeyoung/wishboard/presentation/splash/SplashViewModel.kt +++ b/app/src/main/java/com/hyeeyoung/wishboard/presentation/splash/SplashViewModel.kt @@ -1,13 +1,45 @@ package com.hyeeyoung.wishboard.presentation.splash import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.hyeeyoung.wishboard.BuildConfig import com.hyeeyoung.wishboard.data.local.WishBoardPreference +import com.hyeeyoung.wishboard.domain.repositories.SystemRepository import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class SplashViewModel @Inject constructor( private val localStorage: WishBoardPreference, + private val systemRepository: SystemRepository, ) : ViewModel() { fun isLogin() = localStorage.isLogin + + fun checkForAppUpdate( + playStoreVersionCode: Int, + moveToNext: () -> Unit, + showUpdateDialog: (isForceUpdate: Boolean) -> Unit + ) { + viewModelScope.launch { + systemRepository.fetchAppVersion().onSuccess { remoteVersion -> + if (remoteVersion == null) { + moveToNext() + return@launch + } + + when { + BuildConfig.VERSION_CODE < playStoreVersionCode -> { + showUpdateDialog(BuildConfig.VERSION_CODE < remoteVersion.minVersionCode) + } + + else -> { + moveToNext() + } + } + }.onFailure { + moveToNext() + } + } + } } diff --git a/app/src/main/java/com/hyeeyoung/wishboard/presentation/wishitem/screens/WishBasicFragment.kt b/app/src/main/java/com/hyeeyoung/wishboard/presentation/wishitem/screens/WishBasicFragment.kt index 25bae0ea..c0841e63 100644 --- a/app/src/main/java/com/hyeeyoung/wishboard/presentation/wishitem/screens/WishBasicFragment.kt +++ b/app/src/main/java/com/hyeeyoung/wishboard/presentation/wishitem/screens/WishBasicFragment.kt @@ -14,14 +14,20 @@ import com.hyeeyoung.wishboard.databinding.FragmentWishBinding import com.hyeeyoung.wishboard.designsystem.component.CustomSnackbar import com.hyeeyoung.wishboard.domain.model.WishItemDetail import com.hyeeyoung.wishboard.presentation.common.screens.OneButtonDialogFragment +import com.hyeeyoung.wishboard.presentation.common.types.DialogButtonReplyType import com.hyeeyoung.wishboard.presentation.common.types.ProcessStatus import com.hyeeyoung.wishboard.presentation.folder.screens.FolderListBottomDialogFragment import com.hyeeyoung.wishboard.presentation.noti.screens.NotiSettingBottomDialogFragment import com.hyeeyoung.wishboard.presentation.wishitem.WishItemStatus import com.hyeeyoung.wishboard.presentation.wishitem.viewmodels.WishItemRegistrationViewModel import com.hyeeyoung.wishboard.util.BaseFragment +import com.hyeeyoung.wishboard.util.DialogListener import com.hyeeyoung.wishboard.util.FolderListDialogListener -import com.hyeeyoung.wishboard.util.extension.* +import com.hyeeyoung.wishboard.util.extension.getParcelableValue +import com.hyeeyoung.wishboard.util.extension.requestCamera +import com.hyeeyoung.wishboard.util.extension.requestSelectPicture +import com.hyeeyoung.wishboard.util.extension.showPhotoDialog +import com.hyeeyoung.wishboard.util.extension.takePicture import com.hyeeyoung.wishboard.util.setOnSingleClickListener import dagger.hilt.android.AndroidEntryPoint @@ -128,6 +134,7 @@ class WishBasicFragment : BaseFragment(R.layout.fragment_wi moveToPrevious(WishItemStatus.ADDED) } } + else -> {} } } @@ -137,10 +144,12 @@ class WishBasicFragment : BaseFragment(R.layout.fragment_wi ProcessStatus.IDLE -> { binding.loadingLottie.visibility = View.GONE } + ProcessStatus.IN_PROGRESS -> { binding.loadingLottie.visibility = View.VISIBLE binding.loadingLottie.playAnimation() } + else -> {} } } @@ -159,11 +168,18 @@ class WishBasicFragment : BaseFragment(R.layout.fragment_wi } private fun showItemNonUpdateDialog() { - val dialog = OneButtonDialogFragment( - getString(R.string.item_non_update_dialog_title), - getString(R.string.item_non_update_dialog_description) - ) - dialog.show(parentFragmentManager, "ItemNonUpdateDialog") + OneButtonDialogFragment.newInstance( + title = getString(R.string.item_non_update_dialog_title), + description = getString(R.string.item_non_update_dialog_description) + ).apply { + setListener(object : DialogListener { + override fun onButtonClicked(clicked: String) { + if (clicked == DialogButtonReplyType.YES.name) { + dismiss() + } + } + }) + }.show(parentFragmentManager, "ItemNonUpdateDialog") } private fun showFolderListDialog() { diff --git a/app/src/main/res/layout/dialog_one_button.xml b/app/src/main/res/layout/dialog_one_button.xml index 4ae04a5a..12136c94 100644 --- a/app/src/main/res/layout/dialog_one_button.xml +++ b/app/src/main/res/layout/dialog_one_button.xml @@ -18,8 +18,8 @@ app:layout_constraintTop_toTopOf="parent"> + app:layout_constraintTop_toBottomOf="@id/description" + tools:text="@string/confirm" />