From 9e2cfe1d65633cb6dcc86614489d4dded582cafa Mon Sep 17 00:00:00 2001 From: MunJangHun <105299421+moondev03@users.noreply.github.com> Date: Wed, 2 Oct 2024 13:07:27 +0900 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8F=20=EA=B0=95=EC=A0=9C=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EA=B8=B0=EB=8A=A5=20=20?= =?UTF-8?q?(#47)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add ForceUpdate Min Version API * Add DI Modules | Repository & Datasource & Service * Add ForceUpdateDialog * Add UseCase | GetForceUpdateMinVersionUseCase * Apply ForceUpdate Check --- .../data/datasource/VersionDataSource.kt | 12 +++ .../datasourceImpl/VersionDataSourceImpl.kt | 20 +++++ .../com/neverland/data/di/DataSourceModule.kt | 5 ++ .../com/neverland/data/di/RepositoryModule.kt | 6 ++ .../com/neverland/data/di/ServiceModule.kt | 6 ++ .../model/ForceUpdateMinVersionResponse.kt | 10 +++ .../data/remote/service/VersionService.kt | 12 +++ .../data/repository/VersionRepositoryImpl.kt | 23 ++++++ .../domain/repository/VersionRepository.kt | 8 ++ .../GetForceUpdateMinVersionUseCase.kt | 13 +++ .../view/home/ForceUpdateDialog.kt | 82 +++++++++++++++++++ .../thinkerbell/view/splash/StartActivity.kt | 17 ++++ .../thinkerbell/view/splash/StartViewModel.kt | 20 ++++- .../main/res/layout/dialog_force_update.xml | 59 +++++++++++++ 14 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 ThinkerBell/data/src/main/java/com/neverland/data/datasource/VersionDataSource.kt create mode 100644 ThinkerBell/data/src/main/java/com/neverland/data/datasourceImpl/VersionDataSourceImpl.kt create mode 100644 ThinkerBell/data/src/main/java/com/neverland/data/remote/model/ForceUpdateMinVersionResponse.kt create mode 100644 ThinkerBell/data/src/main/java/com/neverland/data/remote/service/VersionService.kt create mode 100644 ThinkerBell/data/src/main/java/com/neverland/data/repository/VersionRepositoryImpl.kt create mode 100644 ThinkerBell/domain/src/main/java/com/neverland/domain/repository/VersionRepository.kt create mode 100644 ThinkerBell/domain/src/main/java/com/neverland/domain/usecase/version/GetForceUpdateMinVersionUseCase.kt create mode 100644 ThinkerBell/presentation/src/main/java/com/neverland/thinkerbell/view/home/ForceUpdateDialog.kt create mode 100644 ThinkerBell/presentation/src/main/res/layout/dialog_force_update.xml diff --git a/ThinkerBell/data/src/main/java/com/neverland/data/datasource/VersionDataSource.kt b/ThinkerBell/data/src/main/java/com/neverland/data/datasource/VersionDataSource.kt new file mode 100644 index 0000000..ad44cb1 --- /dev/null +++ b/ThinkerBell/data/src/main/java/com/neverland/data/datasource/VersionDataSource.kt @@ -0,0 +1,12 @@ +package com.neverland.data.datasource + +import com.neverland.data.remote.model.BaseResponse +import com.neverland.data.remote.model.ForceUpdateMinVersionResponse +import com.neverland.data.remote.model.alarm.AlarmDTO +import retrofit2.Response +import retrofit2.http.PATCH + +interface VersionDataSource { + + suspend fun getForceUpdateMinVersion(): Response> +} \ No newline at end of file diff --git a/ThinkerBell/data/src/main/java/com/neverland/data/datasourceImpl/VersionDataSourceImpl.kt b/ThinkerBell/data/src/main/java/com/neverland/data/datasourceImpl/VersionDataSourceImpl.kt new file mode 100644 index 0000000..136f6d2 --- /dev/null +++ b/ThinkerBell/data/src/main/java/com/neverland/data/datasourceImpl/VersionDataSourceImpl.kt @@ -0,0 +1,20 @@ +package com.neverland.data.datasourceImpl + +import com.neverland.data.datasource.AlarmDataSource +import com.neverland.data.datasource.VersionDataSource +import com.neverland.data.remote.model.BaseResponse +import com.neverland.data.remote.model.ForceUpdateMinVersionResponse +import com.neverland.data.remote.model.alarm.AlarmDTO +import com.neverland.data.remote.service.AlarmService +import com.neverland.data.remote.service.VersionService +import retrofit2.Response +import javax.inject.Inject + +class VersionDataSourceImpl @Inject constructor( + private val service: VersionService +): VersionDataSource { + + override suspend fun getForceUpdateMinVersion(): Response> { + return service.getForceUpdateMinVersion() + } +} \ No newline at end of file diff --git a/ThinkerBell/data/src/main/java/com/neverland/data/di/DataSourceModule.kt b/ThinkerBell/data/src/main/java/com/neverland/data/di/DataSourceModule.kt index 1f15efd..4d1f182 100644 --- a/ThinkerBell/data/src/main/java/com/neverland/data/di/DataSourceModule.kt +++ b/ThinkerBell/data/src/main/java/com/neverland/data/di/DataSourceModule.kt @@ -7,6 +7,7 @@ import com.neverland.data.datasource.NoticeDataSource import com.neverland.data.datasource.ReportDataSource import com.neverland.data.datasource.UnivDataSource import com.neverland.data.datasource.UserDataSource +import com.neverland.data.datasource.VersionDataSource import com.neverland.data.datasourceImpl.AlarmDataSourceImpl import com.neverland.data.datasourceImpl.BookmarkDataSourceImpl import com.neverland.data.datasourceImpl.KeywordDataSourceImpl @@ -14,6 +15,7 @@ import com.neverland.data.datasourceImpl.NoticeDataSourceImpl import com.neverland.data.datasourceImpl.ReportDataSourceImpl import com.neverland.data.datasourceImpl.UnivDataSourceImpl import com.neverland.data.datasourceImpl.UserDataSourceImpl +import com.neverland.data.datasourceImpl.VersionDataSourceImpl import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -51,4 +53,7 @@ abstract class DataSourceModule { @Binds @Singleton abstract fun bindsReportDataSource(impl: ReportDataSourceImpl): ReportDataSource + + @Binds + abstract fun bindsVersionDataSource(impl: VersionDataSourceImpl): VersionDataSource } \ No newline at end of file diff --git a/ThinkerBell/data/src/main/java/com/neverland/data/di/RepositoryModule.kt b/ThinkerBell/data/src/main/java/com/neverland/data/di/RepositoryModule.kt index fb209f2..8697a18 100644 --- a/ThinkerBell/data/src/main/java/com/neverland/data/di/RepositoryModule.kt +++ b/ThinkerBell/data/src/main/java/com/neverland/data/di/RepositoryModule.kt @@ -7,6 +7,7 @@ import com.neverland.data.repository.NoticeRepositoryImpl import com.neverland.data.repository.ReportRepositoryImpl import com.neverland.data.repository.UnivRepositoryImpl import com.neverland.data.repository.UserRepositoryImpl +import com.neverland.data.repository.VersionRepositoryImpl import com.neverland.domain.repository.AlarmRepository import com.neverland.domain.repository.BookmarkRepository import com.neverland.domain.repository.KeywordRepository @@ -14,6 +15,7 @@ import com.neverland.domain.repository.NoticeRepository import com.neverland.domain.repository.ReportRepository import com.neverland.domain.repository.UnivRepository import com.neverland.domain.repository.UserRepository +import com.neverland.domain.repository.VersionRepository import dagger.Binds import dagger.Module import dagger.hilt.InstallIn @@ -51,4 +53,8 @@ abstract class RepositoryModule { @Binds @Singleton abstract fun bindsReportRepository(impl: ReportRepositoryImpl): ReportRepository + + @Binds + @Singleton + abstract fun bindsVersionRepository(impl: VersionRepositoryImpl): VersionRepository } \ No newline at end of file diff --git a/ThinkerBell/data/src/main/java/com/neverland/data/di/ServiceModule.kt b/ThinkerBell/data/src/main/java/com/neverland/data/di/ServiceModule.kt index 69e6edb..f32ed4c 100644 --- a/ThinkerBell/data/src/main/java/com/neverland/data/di/ServiceModule.kt +++ b/ThinkerBell/data/src/main/java/com/neverland/data/di/ServiceModule.kt @@ -7,6 +7,8 @@ import com.neverland.data.remote.service.NoticeService import com.neverland.data.remote.service.ReportService import com.neverland.data.remote.service.UnivService import com.neverland.data.remote.service.UserService +import com.neverland.data.remote.service.VersionService +import com.neverland.domain.repository.VersionRepository import dagger.Module import dagger.Provides import dagger.hilt.InstallIn @@ -44,4 +46,8 @@ internal class ServiceModule { @Provides fun providesReportService(client: Retrofit): ReportService = client.create(ReportService::class.java) + + @Provides + fun providesVersionService(client: Retrofit): VersionService = + client.create(VersionService::class.java) } \ No newline at end of file diff --git a/ThinkerBell/data/src/main/java/com/neverland/data/remote/model/ForceUpdateMinVersionResponse.kt b/ThinkerBell/data/src/main/java/com/neverland/data/remote/model/ForceUpdateMinVersionResponse.kt new file mode 100644 index 0000000..30bc733 --- /dev/null +++ b/ThinkerBell/data/src/main/java/com/neverland/data/remote/model/ForceUpdateMinVersionResponse.kt @@ -0,0 +1,10 @@ +package com.neverland.data.remote.model + +import com.google.gson.annotations.SerializedName + +data class ForceUpdateMinVersionResponse( + @SerializedName("versionCode") + val versionCode: String, + @SerializedName("versionName") + val versionName: String +) diff --git a/ThinkerBell/data/src/main/java/com/neverland/data/remote/service/VersionService.kt b/ThinkerBell/data/src/main/java/com/neverland/data/remote/service/VersionService.kt new file mode 100644 index 0000000..e44698e --- /dev/null +++ b/ThinkerBell/data/src/main/java/com/neverland/data/remote/service/VersionService.kt @@ -0,0 +1,12 @@ +package com.neverland.data.remote.service + +import com.neverland.data.remote.model.BaseResponse +import com.neverland.data.remote.model.ForceUpdateMinVersionResponse +import retrofit2.Response +import retrofit2.http.GET + +interface VersionService { + + @GET("/api/version") + suspend fun getForceUpdateMinVersion(): Response> +} \ No newline at end of file diff --git a/ThinkerBell/data/src/main/java/com/neverland/data/repository/VersionRepositoryImpl.kt b/ThinkerBell/data/src/main/java/com/neverland/data/repository/VersionRepositoryImpl.kt new file mode 100644 index 0000000..0764993 --- /dev/null +++ b/ThinkerBell/data/src/main/java/com/neverland/data/repository/VersionRepositoryImpl.kt @@ -0,0 +1,23 @@ +package com.neverland.data.repository + +import com.neverland.data.datasource.AlarmDataSource +import com.neverland.data.datasource.VersionDataSource +import com.neverland.data.utils.handleResponse +import com.neverland.domain.model.alarm.Alarm +import com.neverland.domain.repository.AlarmRepository +import com.neverland.domain.repository.VersionRepository +import javax.inject.Inject + +class VersionRepositoryImpl @Inject constructor( + private val datasource: VersionDataSource +) : VersionRepository { + + override suspend fun getForceUpdateMinVersion(): Result { + return handleResponse( + call = { datasource.getForceUpdateMinVersion() }, + onSuccess = { data -> + data?.versionCode ?: "0" + } + ) + } +} diff --git a/ThinkerBell/domain/src/main/java/com/neverland/domain/repository/VersionRepository.kt b/ThinkerBell/domain/src/main/java/com/neverland/domain/repository/VersionRepository.kt new file mode 100644 index 0000000..ddfeb76 --- /dev/null +++ b/ThinkerBell/domain/src/main/java/com/neverland/domain/repository/VersionRepository.kt @@ -0,0 +1,8 @@ +package com.neverland.domain.repository + +import com.neverland.domain.model.alarm.Alarm + +interface VersionRepository { + + suspend fun getForceUpdateMinVersion(): Result +} \ No newline at end of file diff --git a/ThinkerBell/domain/src/main/java/com/neverland/domain/usecase/version/GetForceUpdateMinVersionUseCase.kt b/ThinkerBell/domain/src/main/java/com/neverland/domain/usecase/version/GetForceUpdateMinVersionUseCase.kt new file mode 100644 index 0000000..9384714 --- /dev/null +++ b/ThinkerBell/domain/src/main/java/com/neverland/domain/usecase/version/GetForceUpdateMinVersionUseCase.kt @@ -0,0 +1,13 @@ +package com.neverland.domain.usecase.version + +import com.neverland.domain.repository.VersionRepository +import javax.inject.Inject + +class GetForceUpdateMinVersionUseCase @Inject constructor( + private val repository: VersionRepository +) { + + suspend operator fun invoke(): Result { + return repository.getForceUpdateMinVersion() + } +} \ No newline at end of file diff --git a/ThinkerBell/presentation/src/main/java/com/neverland/thinkerbell/view/home/ForceUpdateDialog.kt b/ThinkerBell/presentation/src/main/java/com/neverland/thinkerbell/view/home/ForceUpdateDialog.kt new file mode 100644 index 0000000..9eab2d4 --- /dev/null +++ b/ThinkerBell/presentation/src/main/java/com/neverland/thinkerbell/view/home/ForceUpdateDialog.kt @@ -0,0 +1,82 @@ +package com.neverland.thinkerbell.view.home + +import android.content.ActivityNotFoundException +import android.content.ClipData +import android.content.ClipboardManager +import android.content.Context +import android.content.Intent +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.net.Uri +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.ViewGroup.LayoutParams.WRAP_CONTENT +import androidx.fragment.app.DialogFragment +import com.neverland.domain.model.univ.DeptContact +import com.neverland.thinkerbell.BuildConfig +import com.neverland.thinkerbell.custom.CustomToast +import com.neverland.thinkerbell.databinding.DialogContactBinding +import com.neverland.thinkerbell.databinding.DialogForceUpdateBinding +import com.neverland.thinkerbell.utils.DisplayUtils + +class ForceUpdateDialog : DialogFragment() { + + companion object { + fun newInstance(): ForceUpdateDialog { + return ForceUpdateDialog() + } + } + + private var mBinding: DialogForceUpdateBinding? = null + private val binding get() = mBinding!! + + override fun onStart() { + super.onStart() + + dialog?.let { + it.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) + + val widthInDp = 304f + + val widthInPx = DisplayUtils.dpToPx(requireContext(), widthInDp).toInt() + + it.window?.setLayout(widthInPx, WRAP_CONTENT) + } + + isCancelable = false + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + mBinding = DialogForceUpdateBinding.inflate(requireActivity().layoutInflater) + return binding.root + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.btnDialogUpdate.setOnClickListener { + moveToPlayStore() + } + } + + private fun moveToPlayStore() { + val intent = Intent(Intent.ACTION_VIEW).apply { + data = Uri.parse("https://play.google.com/store/apps/details?id=${BuildConfig.APPLICATION_ID}") + setPackage("com.android.vending") + } + try { + startActivity(intent) + } catch (e: ActivityNotFoundException) { + val webIntent = Intent(Intent.ACTION_VIEW).apply { + data = Uri.parse("https://play.google.com/store/apps/details?id=${BuildConfig.APPLICATION_ID}") + } + startActivity(webIntent) + } + } +} diff --git a/ThinkerBell/presentation/src/main/java/com/neverland/thinkerbell/view/splash/StartActivity.kt b/ThinkerBell/presentation/src/main/java/com/neverland/thinkerbell/view/splash/StartActivity.kt index c174efd..3738304 100644 --- a/ThinkerBell/presentation/src/main/java/com/neverland/thinkerbell/view/splash/StartActivity.kt +++ b/ThinkerBell/presentation/src/main/java/com/neverland/thinkerbell/view/splash/StartActivity.kt @@ -3,11 +3,13 @@ package com.neverland.thinkerbell.view.splash import android.content.Intent import androidx.activity.viewModels import com.google.firebase.messaging.FirebaseMessaging +import com.neverland.thinkerbell.BuildConfig import com.neverland.thinkerbell.R import com.neverland.thinkerbell.base.BaseActivity import com.neverland.thinkerbell.databinding.ActivityStartBinding import com.neverland.thinkerbell.utils.UiState import com.neverland.thinkerbell.view.HomeActivity +import com.neverland.thinkerbell.view.home.ForceUpdateDialog import dagger.hilt.android.AndroidEntryPoint @AndroidEntryPoint @@ -20,11 +22,26 @@ class StartActivity : BaseActivity() { } setStatusBarColor(R.color.primary2, false) + viewModel.checkForceUpdate(BuildConfig.VERSION_CODE) } override fun setObserver() { super.setObserver() + viewModel.update.observe(this) { state -> + when(state){ + is UiState.Loading -> {} + is UiState.Success -> { + if(state.data){ + ForceUpdateDialog.newInstance().show(supportFragmentManager, "") + } + } + + is UiState.Error -> {} + is UiState.Empty -> {} + } + } + viewModel.fcmState.observe(this) { when (it) { is UiState.Loading -> {} diff --git a/ThinkerBell/presentation/src/main/java/com/neverland/thinkerbell/view/splash/StartViewModel.kt b/ThinkerBell/presentation/src/main/java/com/neverland/thinkerbell/view/splash/StartViewModel.kt index 17e1144..3d2e63d 100644 --- a/ThinkerBell/presentation/src/main/java/com/neverland/thinkerbell/view/splash/StartViewModel.kt +++ b/ThinkerBell/presentation/src/main/java/com/neverland/thinkerbell/view/splash/StartViewModel.kt @@ -7,6 +7,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.neverland.core.utils.LoggerUtil import com.neverland.domain.usecase.user.PostUserInfoUseCase +import com.neverland.domain.usecase.version.GetForceUpdateMinVersionUseCase import com.neverland.thinkerbell.base.ThinkerBellApplication.Companion.application import com.neverland.thinkerbell.utils.UiState import dagger.hilt.android.lifecycle.HiltViewModel @@ -15,12 +16,16 @@ import javax.inject.Inject @HiltViewModel class StartViewModel @Inject constructor( - private val postUserInfoUseCase: PostUserInfoUseCase + private val postUserInfoUseCase: PostUserInfoUseCase, + private val getForceUpdateMinVersionUseCase: GetForceUpdateMinVersionUseCase ) : ViewModel() { private val _fcmState = MutableLiveData>(UiState.Loading) val fcmState: LiveData> get() = _fcmState + private val _update = MutableLiveData>() + val update: LiveData> get() = _update + @SuppressLint("HardwareIds") fun saveDeviceInfo(token: String) { _fcmState.value = UiState.Loading @@ -37,4 +42,17 @@ class StartViewModel @Inject constructor( } } + fun checkForceUpdate(currentVersion: Int){ + _update.value = UiState.Loading + + viewModelScope.launch { + getForceUpdateMinVersionUseCase.invoke() + .onSuccess { + LoggerUtil.i("현재 버전: $currentVersion | 최소 업데이트 필요 버전: $it") + _update.value = UiState.Success(currentVersion < it.toInt()) + } + .onFailure { _update.value = UiState.Success(false) } + } + } + } \ No newline at end of file diff --git a/ThinkerBell/presentation/src/main/res/layout/dialog_force_update.xml b/ThinkerBell/presentation/src/main/res/layout/dialog_force_update.xml new file mode 100644 index 0000000..053c05b --- /dev/null +++ b/ThinkerBell/presentation/src/main/res/layout/dialog_force_update.xml @@ -0,0 +1,59 @@ + + + + + + + + + + \ No newline at end of file