diff --git a/core/common/src/main/java/com/teamwable/common/util/AmplitudeTag.kt b/core/common/src/main/java/com/teamwable/common/util/AmplitudeTag.kt index bd0a25a4..7580cee5 100644 --- a/core/common/src/main/java/com/teamwable/common/util/AmplitudeTag.kt +++ b/core/common/src/main/java/com/teamwable/common/util/AmplitudeTag.kt @@ -10,7 +10,7 @@ object AmplitudeSignUpTag { const val CLICK_DETOUR_TEAM_SIGNUP = "click_detour_team_signup" const val CLICK_NEXT_TEAM_SIGNUP = "click_next_team_signup" const val CLICK_CHANGE_PICTURE_PROFILE_SIGNUP = "click_change_picture_profile_signup" - const val CLICK_ADD_PICTURE_PROFILE_SIGNUP = "k_add_picture_profile_signup" + const val CLICK_ADD_PICTURE_PROFILE_SIGNUP = "click_add_picture_profile_signup" const val CLICK_NEXT_PROFILE_SIGNUP = "click_next_profile_signup" const val CLICK_COMPLETE_TNC_SIGNUP = "click_complete_tnc_signup" const val CLICK_JOIN_POPUP_SIGNUP = "click_join_popup_signup" diff --git a/core/ui/src/main/java/com/teamwable/ui/extensions/ContextExt.kt b/core/ui/src/main/java/com/teamwable/ui/extensions/ContextExt.kt index 08c0b5dc..c430e78e 100644 --- a/core/ui/src/main/java/com/teamwable/ui/extensions/ContextExt.kt +++ b/core/ui/src/main/java/com/teamwable/ui/extensions/ContextExt.kt @@ -124,3 +124,22 @@ fun Context.restartApp() { intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) startActivity(intent) } + +fun Context.showAlertDialog( + title: String, + message: String, + positiveButtonText: String, + negativeButtonText: String, + onPositiveClick: () -> Unit, +) { + val builder = AlertDialog.Builder(this) + builder.setTitle(title) + .setMessage(message) + .setPositiveButton(positiveButtonText) { dialog, _ -> + dialog.dismiss() + onPositiveClick() + } + .setNegativeButton(negativeButtonText) { dialog, _ -> dialog.dismiss() } + + builder.create().show() +} diff --git a/core/ui/src/main/java/com/teamwable/ui/util/SingleEventHandler.kt b/core/ui/src/main/java/com/teamwable/ui/util/SingleEventHandler.kt index 25100984..72a1a05d 100644 --- a/core/ui/src/main/java/com/teamwable/ui/util/SingleEventHandler.kt +++ b/core/ui/src/main/java/com/teamwable/ui/util/SingleEventHandler.kt @@ -21,7 +21,7 @@ class SingleEventHandler private constructor() { } companion object { - private const val DEBOUNCE_DELAY = 500L + private const val DEBOUNCE_DELAY = 200L fun from(): SingleEventHandler = SingleEventHandler() } diff --git a/feature/main/src/main/java/com/teamwable/main/AppUpdateHandler.kt b/feature/main/src/main/java/com/teamwable/main/AppUpdateHandler.kt index e403374c..cc69081f 100644 --- a/feature/main/src/main/java/com/teamwable/main/AppUpdateHandler.kt +++ b/feature/main/src/main/java/com/teamwable/main/AppUpdateHandler.kt @@ -1,63 +1,28 @@ package com.teamwable.main -import android.content.Context import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.IntentSenderRequest -import androidx.appcompat.app.AlertDialog 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.UpdateAvailability -class AppUpdateHandler(private val context: Context) { - private lateinit var appUpdateManager: AppUpdateManager - - fun checkForAppUpdate(activityResultLauncher: ActivityResultLauncher) { - appUpdateManager = AppUpdateManagerFactory.create(context) +class AppUpdateHandler(private val appUpdateManager: AppUpdateManager) { + fun checkForAppUpdate(onUpdateAvailable: (AppUpdateInfo) -> Unit) { val appUpdateInfoTask = appUpdateManager.appUpdateInfo appUpdateInfoTask.addOnSuccessListener { appUpdateInfo -> if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE) - showUpdateDialog(appUpdateInfo, activityResultLauncher) + onUpdateAvailable(appUpdateInfo) } } - private fun showUpdateDialog(appUpdateInfo: AppUpdateInfo, activityResultLauncher: ActivityResultLauncher) { - val builder = AlertDialog.Builder(context) - builder.setTitle(context.getString(R.string.label_in_app_update_title)) - .setMessage(context.getString(R.string.label_in_app_update_content)) - .setPositiveButton(context.getString(R.string.label_in_app_update_yes)) { dialog, _ -> - dialog.dismiss() - startUpdate(appUpdateInfo, activityResultLauncher) - } - .setNegativeButton(context.getString(R.string.label_in_app_update_next)) { dialog, _ -> - dialog.dismiss() - } - - val dialog = builder.create() - dialog.show() - } - - private fun startUpdate(appUpdateInfo: AppUpdateInfo, activityResultLauncher: ActivityResultLauncher) { + fun startUpdate(appUpdateInfo: AppUpdateInfo, activityResultLauncher: ActivityResultLauncher) { appUpdateManager.startUpdateFlowForResult( appUpdateInfo, activityResultLauncher, AppUpdateOptions.newBuilder(AppUpdateType.FLEXIBLE).build(), ) } - - fun resumeUpdateIfNeeded(activityResultLauncher: ActivityResultLauncher) { - appUpdateManager.appUpdateInfo.addOnSuccessListener { appUpdateInfo -> - if (appUpdateInfo.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) { - // In-app update가 이미 실행 중이면, 업데이트를 다시 시작 - appUpdateManager.startUpdateFlowForResult( - appUpdateInfo, - activityResultLauncher, - AppUpdateOptions.newBuilder(AppUpdateType.FLEXIBLE).build(), - ) - } - } - } } diff --git a/feature/main/src/main/java/com/teamwable/main/MainActivity.kt b/feature/main/src/main/java/com/teamwable/main/MainActivity.kt index e208b0d1..2bf687b3 100644 --- a/feature/main/src/main/java/com/teamwable/main/MainActivity.kt +++ b/feature/main/src/main/java/com/teamwable/main/MainActivity.kt @@ -15,6 +15,11 @@ import androidx.navigation.NavDestination import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.onNavDestinationSelected import androidx.navigation.ui.setupWithNavController +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.install.InstallStateUpdatedListener +import com.google.android.play.core.install.model.InstallStatus import com.teamwable.common.uistate.UiState import com.teamwable.common.util.AmplitudeHomeTag.CLICK_HOME_BOTNAVI import com.teamwable.common.util.AmplitudeHomeTag.CLICK_MYPROFILE_BOTNAVI @@ -24,6 +29,7 @@ import com.teamwable.common.util.AmplitudeUtil.trackEvent import com.teamwable.home.HomeFragment import com.teamwable.main.databinding.ActivityMainBinding import com.teamwable.ui.extensions.colorOf +import com.teamwable.ui.extensions.showAlertDialog import com.teamwable.ui.extensions.toast import com.teamwable.ui.extensions.visible import com.teamwable.ui.util.Navigation @@ -39,6 +45,7 @@ class MainActivity : AppCompatActivity(), Navigation { private lateinit var binding: ActivityMainBinding private val viewModel: MainViewModel by viewModels() private lateinit var appUpdateHelper: AppUpdateHandler + private val appUpdateManager: AppUpdateManager by lazy { AppUpdateManagerFactory.create(this) } private val activityResultLauncher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { result -> @@ -49,6 +56,16 @@ class MainActivity : AppCompatActivity(), Navigation { } } + private val installStateUpdatedListener = InstallStateUpdatedListener { state -> + if (state.installStatus() == InstallStatus.DOWNLOADED) { + Timber.i("Download Complete") + lifecycleScope.launch { + delay(5000) + appUpdateManager.completeUpdate() + } + } + } + @SuppressLint("SourceLockedOrientationActivity") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -59,19 +76,28 @@ class MainActivity : AppCompatActivity(), Navigation { requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT } - override fun onResume() { - super.onResume() - appUpdateHelper.resumeUpdateIfNeeded(activityResultLauncher) + override fun onDestroy() { + super.onDestroy() + appUpdateManager.unregisterListener(installStateUpdatedListener) } private fun setInAppUpdate() { - appUpdateHelper = AppUpdateHandler(this) - appUpdateHelper.checkForAppUpdate(activityResultLauncher) + appUpdateManager.registerListener(installStateUpdatedListener) + appUpdateHelper = AppUpdateHandler(appUpdateManager).apply { + checkForAppUpdate { appUpdateInfo -> showUpdateDialog(appUpdateInfo) } + } } + private fun showUpdateDialog(appUpdateInfo: AppUpdateInfo) = showAlertDialog( + title = getString(R.string.label_in_app_update_title), + message = getString(R.string.label_in_app_update_content), + positiveButtonText = getString(R.string.label_in_app_update_yes), + negativeButtonText = getString(R.string.label_in_app_update_next), + onPositiveClick = { appUpdateHelper.startUpdate(appUpdateInfo, activityResultLauncher) }, + ) + private fun initView() { setBottomNavigation() - setupNumberObserve() } diff --git a/feature/main/src/main/res/values/strings.xml b/feature/main/src/main/res/values/strings.xml index 8815d008..22e5444a 100644 --- a/feature/main/src/main/res/values/strings.xml +++ b/feature/main/src/main/res/values/strings.xml @@ -18,5 +18,5 @@ 와블이 새롭게 업그레이드 되었어요. 업데이트를 통해 최신 버전으로 즐겨보세요. 업데이트 하기 다음에 - 업데이트되었습니다. 앱을 재시작 해주세요. + 업데이트 진행 중 : 화면 이탈 시 업데이트가 취소 될 수 있습니다. diff --git a/feature/profile/src/main/java/com/teamwable/profile/profile/BindingProfileFragment.kt b/feature/profile/src/main/java/com/teamwable/profile/profile/BindingProfileFragment.kt index 2839d381..c9464406 100644 --- a/feature/profile/src/main/java/com/teamwable/profile/profile/BindingProfileFragment.kt +++ b/feature/profile/src/main/java/com/teamwable/profile/profile/BindingProfileFragment.kt @@ -8,6 +8,7 @@ import android.view.ViewGroup import androidx.annotation.ColorRes import androidx.core.content.ContextCompat import androidx.fragment.app.Fragment +import com.google.android.material.appbar.AppBarLayout import com.teamwable.model.Profile import com.teamwable.profile.R import com.teamwable.profile.databinding.FragmentProfileBinding @@ -23,6 +24,8 @@ abstract class BindingProfileFragment : Fragment() { protected val binding: FragmentProfileBinding get() = requireNotNull(_binding) { "ViewBinding is not initialized" } + private lateinit var offsetChangedListener: AppBarLayout.OnOffsetChangedListener + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -34,6 +37,8 @@ abstract class BindingProfileFragment : Fragment() { override fun onDestroyView() { super.onDestroyView() + if (this::offsetChangedListener.isInitialized) + binding.appbarProfileInfo.removeOnOffsetChangedListener(offsetChangedListener) _binding = null } @@ -43,9 +48,17 @@ abstract class BindingProfileFragment : Fragment() { tvProfileNickname.text = data.nickName tvProfileInfo.text = getString(R.string.label_profile_info, data.teamTag.ifBlank { TeamTag.LCK.name }, data.lckYears) tvProfileGhostPercentage.text = getString(R.string.label_ghost_percentage, data.ghost) + setSwipeLayout() setGhostProgress(data.ghost) } + private fun setSwipeLayout() { + offsetChangedListener = AppBarLayout.OnOffsetChangedListener { _, verticalOffset -> + binding.layoutProfileSwipe.isEnabled = verticalOffset == 0 + } + binding.appbarProfileInfo.addOnOffsetChangedListener(offsetChangedListener) + } + private fun setGhostProgress(percentage: Int) { animateProgress(abs(100 + percentage)) if (percentage < -50) setGhostProgressColor(com.teamwable.ui.R.color.sky_50) else setGhostProgressColor(com.teamwable.ui.R.color.purple_50) diff --git a/feature/profile/src/main/java/com/teamwable/profile/profile/ProfileAuthFragment.kt b/feature/profile/src/main/java/com/teamwable/profile/profile/ProfileAuthFragment.kt index 4e273825..0f21f7ef 100644 --- a/feature/profile/src/main/java/com/teamwable/profile/profile/ProfileAuthFragment.kt +++ b/feature/profile/src/main/java/com/teamwable/profile/profile/ProfileAuthFragment.kt @@ -6,7 +6,6 @@ import androidx.fragment.app.setFragmentResultListener import androidx.fragment.app.viewModels import androidx.lifecycle.flowWithLifecycle import androidx.navigation.fragment.findNavController -import com.google.android.material.appbar.AppBarLayout import com.google.android.material.tabs.TabLayoutMediator import com.teamwable.model.Profile import com.teamwable.model.profile.MemberInfoEditModel @@ -14,6 +13,7 @@ import com.teamwable.profile.hamburger.ProfileHamburgerBottomSheet import com.teamwable.profile.profiletabs.ProfilePagerStateAdapter import com.teamwable.profile.profiletabs.ProfileTabType import com.teamwable.ui.extensions.parcelable +import com.teamwable.ui.extensions.setOnDuplicateBlockClick import com.teamwable.ui.extensions.stringOf import com.teamwable.ui.extensions.viewLifeCycle import com.teamwable.ui.extensions.viewLifeCycleScope @@ -45,7 +45,7 @@ class ProfileAuthFragment : BindingProfileFragment() { } private fun initAppbarHamburgerClickListener() { - binding.viewProfileAppbar.btnProfileAppbarHamburger.setOnClickListener { + binding.viewProfileAppbar.btnProfileAppbarHamburger.setOnDuplicateBlockClick { ProfileHamburgerBottomSheet().show(childFragmentManager, PROFILE_HAMBURGER_BOTTOM_SHEET) } } @@ -81,12 +81,6 @@ class ProfileAuthFragment : BindingProfileFragment() { } private fun setSwipeLayout() { - binding.appbarProfileInfo.addOnOffsetChangedListener( - AppBarLayout.OnOffsetChangedListener { _, verticalOffset -> - binding.layoutProfileSwipe.isEnabled = verticalOffset == 0 - }, - ) - binding.layoutProfileSwipe.setOnRefreshListener { binding.layoutProfileSwipe.isRefreshing = false viewModel.fetchAuthId() diff --git a/feature/profile/src/main/java/com/teamwable/profile/profile/ProfileMemberFragment.kt b/feature/profile/src/main/java/com/teamwable/profile/profile/ProfileMemberFragment.kt index 1912dacf..f111cc17 100644 --- a/feature/profile/src/main/java/com/teamwable/profile/profile/ProfileMemberFragment.kt +++ b/feature/profile/src/main/java/com/teamwable/profile/profile/ProfileMemberFragment.kt @@ -5,7 +5,6 @@ import android.view.View import androidx.fragment.app.viewModels import androidx.lifecycle.flowWithLifecycle import androidx.navigation.fragment.findNavController -import com.google.android.material.appbar.AppBarLayout import com.google.android.material.tabs.TabLayoutMediator import com.teamwable.model.Profile import com.teamwable.profile.profiletabs.ProfilePagerStateAdapter @@ -63,12 +62,6 @@ class ProfileMemberFragment : BindingProfileFragment() { } private fun setSwipeLayout() { - binding.appbarProfileInfo.addOnOffsetChangedListener( - AppBarLayout.OnOffsetChangedListener { _, verticalOffset -> - binding.layoutProfileSwipe.isEnabled = verticalOffset == 0 - }, - ) - binding.layoutProfileSwipe.setOnRefreshListener { binding.layoutProfileSwipe.isRefreshing = false viewModel.fetchProfileInfo(userId)