From ee4d686439c00acd25bb78f9becab2bc688a3660 Mon Sep 17 00:00:00 2001 From: HyeseonBaek Date: Mon, 19 Feb 2024 16:31:24 +0900 Subject: [PATCH 1/9] =?UTF-8?q?[ui]=20#244=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B7=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/layout/activity_setting.xml | 287 +++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 app/src/main/res/layout/activity_setting.xml diff --git a/app/src/main/res/layout/activity_setting.xml b/app/src/main/res/layout/activity_setting.xml new file mode 100644 index 00000000..6ce03d97 --- /dev/null +++ b/app/src/main/res/layout/activity_setting.xml @@ -0,0 +1,287 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 8257758f68027a800c8157602420724f4d91f03c Mon Sep 17 00:00:00 2001 From: HyeseonBaek Date: Mon, 19 Feb 2024 16:33:21 +0900 Subject: [PATCH 2/9] =?UTF-8?q?[feat]=20#244=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 권환 확인, 알림 토글, 원온원, 약관, 로그아웃, 탈퇴 --- app/src/main/AndroidManifest.xml | 4 + .../main/mypage/MyPageFragment.kt | 12 ++ .../main/mypage/setting/SettingActivity.kt | 141 ++++++++++++++++++ app/src/main/res/layout/fragment_my_page.xml | 1 + 4 files changed, 158 insertions(+) create mode 100644 app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e95cc344..938f7c14 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -82,6 +82,10 @@ android:name=".presentation.main.notification.NotificationActivity" android:exported="false" android:screenOrientation="portrait" /> + diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt index faba564a..75915a41 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt @@ -29,6 +29,7 @@ import org.go.sopt.winey.domain.entity.User import org.go.sopt.winey.domain.repository.DataStoreRepository import org.go.sopt.winey.presentation.main.MainViewModel import org.go.sopt.winey.presentation.main.mypage.myfeed.MyFeedFragment +import org.go.sopt.winey.presentation.main.mypage.setting.SettingActivity import org.go.sopt.winey.presentation.main.notification.NotificationActivity import org.go.sopt.winey.presentation.nickname.NicknameActivity import org.go.sopt.winey.presentation.onboarding.guide.GuideActivity @@ -38,6 +39,7 @@ import org.go.sopt.winey.util.fragment.snackBar import org.go.sopt.winey.util.fragment.viewLifeCycle import org.go.sopt.winey.util.fragment.viewLifeCycleScope import org.go.sopt.winey.util.view.UiState +import org.go.sopt.winey.util.view.setOnSingleClickListener import javax.inject.Inject @AndroidEntryPoint @@ -65,6 +67,10 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ setupDeleteUserState() checkFromWineyFeed() + + binding.ivMypageSetting.setOnSingleClickListener { + navigateToSettingScreen() + } } private fun initCheckNotificationPermission() { @@ -203,6 +209,12 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ } } + private fun navigateToSettingScreen() { + Intent(requireContext(), SettingActivity::class.java).apply { + startActivity(this) + } + } + private fun setupGetUserState() { mainViewModel.getUserState.flowWithLifecycle(lifecycle).onEach { state -> when (state) { diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt new file mode 100644 index 00000000..30ee7900 --- /dev/null +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt @@ -0,0 +1,141 @@ +package org.go.sopt.winey.presentation.main.mypage.setting + +import android.Manifest +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.os.Build +import android.os.Bundle +import androidx.activity.viewModels +import androidx.core.content.ContextCompat +import androidx.core.view.isGone +import androidx.core.view.isVisible +import dagger.hilt.android.AndroidEntryPoint +import org.go.sopt.winey.R +import org.go.sopt.winey.databinding.ActivitySettingBinding +import org.go.sopt.winey.presentation.main.MainViewModel +import org.go.sopt.winey.presentation.model.WineyDialogLabel +import org.go.sopt.winey.util.amplitude.AmplitudeUtils +import org.go.sopt.winey.util.binding.BindingActivity +import org.go.sopt.winey.util.context.stringOf +import org.go.sopt.winey.util.fragment.WineyDialogFragment +import javax.inject.Inject + +@AndroidEntryPoint +class SettingActivity : BindingActivity(R.layout.activity_setting) { + private val settingViewModel by viewModels() + private val mainViewModel by viewModels() + + @Inject + lateinit var amplitudeUtils: AmplitudeUtils + private var isNotificationPermissionAllowed = true + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + addListener() + addObserver() + initNotificationPermissionState() + } + + override fun onStart() { + super.onStart() + initNotificationPermissionState() + updateNotificationToggleByPermission() + } + + private fun addListener() { + init1On1ButtonClickListener() + initLogoutButtonClickListener() + initTermsButtonClickListener() + initWithdrawButtonClickListener() + } + + private fun addObserver() { + + } + + private fun initNotificationPermissionState() { + isNotificationPermissionAllowed = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + ContextCompat.checkSelfPermission( + this, + Manifest.permission.POST_NOTIFICATIONS + ) == PackageManager.PERMISSION_GRANTED + } else { + true + } + } + + private fun updateNotificationToggleByPermission() { + if (isNotificationPermissionAllowed) { + binding.ivSettingAgree.isVisible = true + + binding.llSettingAgreePermissionChange.isGone = true + binding.tvSettingAgreePermission.isGone = true + } else { + binding.ivSettingAgree.isGone = true + + binding.llSettingAgreePermissionChange.isVisible = true + binding.tvSettingAgreePermission.isVisible = true + } + } + + private fun init1On1ButtonClickListener() { + binding.clSettingTo1on1.setOnClickListener { + val url = ONE_ON_ONE_URL + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + startActivity(intent) + } + } + + private fun initTermsButtonClickListener() { + binding.clSettingToTerms.setOnClickListener { + val url = TERMS_URL + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) + startActivity(intent) + } + } + + private fun initLogoutButtonClickListener() { + binding.clSettingLogout.setOnClickListener { + amplitudeUtils.logEvent("click_logout") + val dialog = WineyDialogFragment.newInstance( + WineyDialogLabel( + stringOf(R.string.mypage_logout_dialog_title), + stringOf(R.string.mypage_logout_dialog_subtitle), + stringOf(R.string.mypage_logout_dialog_negative_button), + stringOf(R.string.mypage_logout_dialog_positive_button) + ), + handleNegativeButton = {}, + handlePositiveButton = { mainViewModel.postLogout() } + ) + dialog.show(supportFragmentManager, TAG_LOGOUT_DIALOG) + } + } + + private fun initWithdrawButtonClickListener() { + binding.clSettingWithdraw.setOnClickListener { + val dialog = WineyDialogFragment.newInstance( + WineyDialogLabel( + stringOf(R.string.mypage_withdraw_dialog_title), + stringOf(R.string.mypage_withdraw_dialog_subtitle), + stringOf(R.string.mypage_withdraw_dialog_negative_button), + stringOf(R.string.mypage_withdraw_dialog_positive_button) + ), + handleNegativeButton = { settingViewModel.deleteUser() }, + handlePositiveButton = {} + ) + dialog.show(supportFragmentManager, TAG_WITHDRAW_DIALOG) + } + } + + companion object { + + private const val ONE_ON_ONE_URL = "https://open.kakao.com/o/s751Susf" + private const val TERMS_URL = + "https://empty-weaver-a9f.notion.site/iney-9dbfe130c7df4fb9a0903481c3e377e6?pvs=4" + + private const val TAG_LOGOUT_DIALOG = "LOGOUT_DIALOG" + private const val TAG_WITHDRAW_DIALOG = "WITHDRAW_DIALOG" + } +} diff --git a/app/src/main/res/layout/fragment_my_page.xml b/app/src/main/res/layout/fragment_my_page.xml index 3f802198..508f3d0e 100644 --- a/app/src/main/res/layout/fragment_my_page.xml +++ b/app/src/main/res/layout/fragment_my_page.xml @@ -26,6 +26,7 @@ app:layout_constraintTop_toTopOf="parent" /> Date: Mon, 19 Feb 2024 16:33:51 +0900 Subject: [PATCH 3/9] =?UTF-8?q?[feat]=20#244=20=ED=83=88=ED=87=B4=20?= =?UTF-8?q?=EC=84=9C=EB=B2=84=20=EC=97=B0=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/mypage/setting/SettingViewModel.kt | 46 +++++++++++++++++++ .../xml/mypage_noti_agree_motion_scene.xml | 18 ++++---- 2 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt new file mode 100644 index 00000000..1563bc0a --- /dev/null +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt @@ -0,0 +1,46 @@ +package org.go.sopt.winey.presentation.main.mypage.setting + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import org.go.sopt.winey.domain.repository.AuthRepository +import org.go.sopt.winey.domain.repository.DataStoreRepository +import org.go.sopt.winey.util.view.UiState +import retrofit2.HttpException +import timber.log.Timber +import javax.inject.Inject + +@HiltViewModel +class SettingViewModel @Inject constructor( + private val authRepository: AuthRepository, + private val dataStoreRepository: DataStoreRepository +) : ViewModel() { + + private val _deleteUserState = MutableStateFlow>(UiState.Empty) + val deleteUserState: StateFlow> = _deleteUserState.asStateFlow() + + fun deleteUser() { + viewModelScope.launch { + authRepository.deleteUser() + .onSuccess { response -> + Timber.d("SUCCESS DELETE USER") + _deleteUserState.value = UiState.Success(response) + } + .onFailure { t -> + _deleteUserState.value = UiState.Failure(t.message.toString()) + + if (t is HttpException) { + Timber.e("HTTP FAIL DELETE USER: ${t.code()} ${t.message}") + return@onFailure + } + + Timber.e("FAIL DELETE USER: ${t.message}") + } + } + } + +} diff --git a/app/src/main/res/xml/mypage_noti_agree_motion_scene.xml b/app/src/main/res/xml/mypage_noti_agree_motion_scene.xml index 3a56fd20..835624b8 100644 --- a/app/src/main/res/xml/mypage_noti_agree_motion_scene.xml +++ b/app/src/main/res/xml/mypage_noti_agree_motion_scene.xml @@ -24,12 +24,12 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="4dp" - motion:layout_constraintBottom_toBottomOf="@+id/iv_mypage_switch" - motion:layout_constraintStart_toStartOf="@+id/iv_mypage_switch" - motion:layout_constraintTop_toTopOf="@+id/iv_mypage_switch"/> + motion:layout_constraintBottom_toBottomOf="@+id/iv_setting_switch" + motion:layout_constraintStart_toStartOf="@+id/iv_setting_switch" + motion:layout_constraintTop_toTopOf="@+id/iv_setting_switch"/> + motion:layout_constraintBottom_toBottomOf="@+id/iv_setting_switch" + motion:layout_constraintEnd_toEndOf="@+id/iv_setting_switch" + motion:layout_constraintTop_toTopOf="@+id/iv_setting_switch" /> Date: Wed, 21 Feb 2024 15:57:39 +0900 Subject: [PATCH 4/9] =?UTF-8?q?[feat]=20#244=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=97=AC=EB=B6=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/mypage/MyPageFragment.kt | 20 --- .../main/mypage/MyPageViewModel.kt | 27 --- .../main/mypage/setting/SettingActivity.kt | 163 ++++++++++++++++-- .../main/mypage/setting/SettingViewModel.kt | 32 ++++ 4 files changed, 181 insertions(+), 61 deletions(-) diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt index 75915a41..006008a9 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt @@ -36,7 +36,6 @@ import org.go.sopt.winey.presentation.onboarding.guide.GuideActivity import org.go.sopt.winey.util.amplitude.AmplitudeUtils import org.go.sopt.winey.util.binding.BindingFragment import org.go.sopt.winey.util.fragment.snackBar -import org.go.sopt.winey.util.fragment.viewLifeCycle import org.go.sopt.winey.util.fragment.viewLifeCycleScope import org.go.sopt.winey.util.view.UiState import org.go.sopt.winey.util.view.setOnSingleClickListener @@ -64,7 +63,6 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ registerBackPressedCallback() setupGetUserState() - setupDeleteUserState() checkFromWineyFeed() @@ -176,24 +174,6 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ } } - private fun setupDeleteUserState() { - myPageViewModel.deleteUserState.flowWithLifecycle(viewLifeCycle) - .onEach { state -> - when (state) { - is UiState.Success -> { - myPageViewModel.clearDataStore() - navigateToGuideScreen() - } - - is UiState.Failure -> { - snackBar(binding.root) { state.msg } - } - - else -> { - } - } - }.launchIn(viewLifeCycleScope) - } private fun navigateToGuideScreen() { Intent(requireContext(), GuideActivity::class.java).apply { diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageViewModel.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageViewModel.kt index 6346e006..db894610 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageViewModel.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageViewModel.kt @@ -22,9 +22,6 @@ class MyPageViewModel @Inject constructor( private val _deleteUserState = MutableStateFlow>(UiState.Empty) val deleteUserState: StateFlow> = _deleteUserState.asStateFlow() - private val _patchAllowedNotificationState = MutableStateFlow>(UiState.Empty) - val patchAllowedNotificationState: StateFlow> = _patchAllowedNotificationState.asStateFlow() - fun deleteUser() { viewModelScope.launch { authRepository.deleteUser() @@ -45,29 +42,5 @@ class MyPageViewModel @Inject constructor( } } - fun patchAllowedNotification(isAllowed: Boolean) { - viewModelScope.launch { - authRepository.patchAllowedNotification(!isAllowed) - .onSuccess { response -> - Timber.d("SUCCESS PATCH ALLOWED NOTI") - _patchAllowedNotificationState.value = UiState.Success(response) - } - .onFailure { t -> - _patchAllowedNotificationState.value = UiState.Failure(t.message.toString()) - - if (t is HttpException) { - Timber.e("HTTP FAIL ALLOWED NOTI : ${t.code()} ${t.message}") - return@onFailure - } - - Timber.e("FAIL ALLOWED NOTI : ${t.message}") - } - } - } - fun clearDataStore() { - viewModelScope.launch { - dataStoreRepository.clearDataStore() - } - } } diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt index 30ee7900..32c93607 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt @@ -6,19 +6,30 @@ import android.content.pm.PackageManager import android.net.Uri import android.os.Build import android.os.Bundle +import android.provider.Settings import androidx.activity.viewModels import androidx.core.content.ContextCompat import androidx.core.view.isGone import androidx.core.view.isVisible +import androidx.lifecycle.flowWithLifecycle +import androidx.lifecycle.lifecycleScope import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.launch import org.go.sopt.winey.R import org.go.sopt.winey.databinding.ActivitySettingBinding +import org.go.sopt.winey.domain.entity.User +import org.go.sopt.winey.domain.repository.DataStoreRepository import org.go.sopt.winey.presentation.main.MainViewModel import org.go.sopt.winey.presentation.model.WineyDialogLabel import org.go.sopt.winey.util.amplitude.AmplitudeUtils import org.go.sopt.winey.util.binding.BindingActivity +import org.go.sopt.winey.util.context.snackBar import org.go.sopt.winey.util.context.stringOf import org.go.sopt.winey.util.fragment.WineyDialogFragment +import org.go.sopt.winey.util.view.UiState import javax.inject.Inject @AndroidEntryPoint @@ -26,6 +37,9 @@ class SettingActivity : BindingActivity(R.layout.activit private val settingViewModel by viewModels() private val mainViewModel by viewModels() + @Inject + lateinit var dataStoreRepository: DataStoreRepository + @Inject lateinit var amplitudeUtils: AmplitudeUtils private var isNotificationPermissionAllowed = true @@ -40,7 +54,6 @@ class SettingActivity : BindingActivity(R.layout.activit override fun onStart() { super.onStart() initNotificationPermissionState() - updateNotificationToggleByPermission() } private fun addListener() { @@ -48,38 +61,114 @@ class SettingActivity : BindingActivity(R.layout.activit initLogoutButtonClickListener() initTermsButtonClickListener() initWithdrawButtonClickListener() + initNotiPermissionButtonClickListener() } private fun addObserver() { } - private fun initNotificationPermissionState() { - isNotificationPermissionAllowed = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - ContextCompat.checkSelfPermission( - this, - Manifest.permission.POST_NOTIFICATIONS - ) == PackageManager.PERMISSION_GRANTED - } else { - true - } + private fun switchOnNotification() { + binding.ivSettingAgree.transitionToState(R.id.end, -1) + patchUserInfo() + settingViewModel.patchAllowedNotification(isAllowed = false) + } + + private fun switchOffNotification() { + binding.ivSettingAgree.transitionToState(R.id.start, -1) + patchUserInfo() + settingViewModel.patchAllowedNotification(isAllowed = true) + } + + private fun initNotiPermissionButtonClickListener() { + binding.llSettingAgreePermissionChange.setOnClickListener { + showSystemNotificationSetting() + } + } + + private fun showSystemNotificationSetting() { + Intent().apply { + action = Settings.ACTION_APP_NOTIFICATION_SETTINGS + putExtra(Settings.EXTRA_APP_PACKAGE, this) + flags = Intent.FLAG_ACTIVITY_NEW_TASK + startActivity(this) + } + } + + private fun showNotificationOffConfirmDialog() { + val dialog = WineyDialogFragment.newInstance( + WineyDialogLabel( + stringOf(R.string.notification_off_dialog_title), + stringOf(R.string.notification_off_dialog_subtitle), + stringOf(R.string.notification_off_dialog_negative_button), + stringOf(R.string.notification_off_dialog_positive_button) + ), + handleNegativeButton = {}, + handlePositiveButton = { switchOffNotification() } + ) + dialog.show( + supportFragmentManager, + TAG_NOTIFICATION_OFF_DIALOG + ) } - private fun updateNotificationToggleByPermission() { + private fun updateNotificationAllowSwitchState(data: User) { if (isNotificationPermissionAllowed) { binding.ivSettingAgree.isVisible = true - binding.llSettingAgreePermissionChange.isGone = true binding.tvSettingAgreePermission.isGone = true + when (data.fcmIsAllowed) { + true -> { + binding.ivSettingAgree.transitionToState(R.id.end, 1) + } + + false -> { + binding.ivSettingAgree.transitionToState(R.id.start, 1) + } + } } else { binding.ivSettingAgree.isGone = true - binding.llSettingAgreePermissionChange.isVisible = true binding.tvSettingAgreePermission.isVisible = true } } + private fun patchUserInfo() { + lifecycleScope.launch { + val data = dataStoreRepository.getUserInfo().first() + val newData = data?.copy(fcmIsAllowed = false) + dataStoreRepository.saveUserInfo(newData) + } + } + + private fun initNotiToggleButtonClickListener() { + binding.ivSettingSwitch.setOnClickListener { + val isAllowed = when (binding.ivSettingAgree.currentState) { + R.id.start -> false + R.id.end -> true + else -> false + } + + if (!isAllowed) { + switchOnNotification() + } else { + showNotificationOffConfirmDialog() + } + } + } + + private fun initNotificationPermissionState() { + isNotificationPermissionAllowed = + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + ContextCompat.checkSelfPermission( + this, + Manifest.permission.POST_NOTIFICATIONS + ) == PackageManager.PERMISSION_GRANTED + } else { + true + } + } + private fun init1On1ButtonClickListener() { binding.clSettingTo1on1.setOnClickListener { val url = ONE_ON_ONE_URL @@ -129,6 +218,50 @@ class SettingActivity : BindingActivity(R.layout.activit } } + private fun setupDeleteUserState() { + settingViewModel.deleteUserState.flowWithLifecycle(lifecycle) + .onEach { state -> + when (state) { + is UiState.Success -> { + settingViewModel.clearDataStore() + //navigateToGuideScreen() + } + + is UiState.Failure -> { + snackBar(binding.root) { state.msg } + } + + else -> { + } + } + }.launchIn(lifecycleScope) + } + + private fun setupPatchAllowedNotificationState() { + settingViewModel.patchAllowedNotificationState.flowWithLifecycle(lifecycle) + .onEach { state -> + when (state) { + is UiState.Success -> { + when (state.data) { + true -> { + binding.ivSettingAgree.transitionToState(R.id.end, -1) + } + + false -> { + binding.ivSettingAgree.transitionToState(R.id.start, -1) + } + + null -> { + binding.ivSettingAgree.transitionToState(R.id.start, -1) + } + } + } + + else -> {} + } + } + } + companion object { private const val ONE_ON_ONE_URL = "https://open.kakao.com/o/s751Susf" @@ -137,5 +270,7 @@ class SettingActivity : BindingActivity(R.layout.activit private const val TAG_LOGOUT_DIALOG = "LOGOUT_DIALOG" private const val TAG_WITHDRAW_DIALOG = "WITHDRAW_DIALOG" + + private const val TAG_NOTIFICATION_OFF_DIALOG = "offNotification" } } diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt index 1563bc0a..ff473a7a 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt @@ -23,6 +23,11 @@ class SettingViewModel @Inject constructor( private val _deleteUserState = MutableStateFlow>(UiState.Empty) val deleteUserState: StateFlow> = _deleteUserState.asStateFlow() + + private val _patchAllowedNotificationState = MutableStateFlow>(UiState.Empty) + val patchAllowedNotificationState: StateFlow> = + _patchAllowedNotificationState.asStateFlow() + fun deleteUser() { viewModelScope.launch { authRepository.deleteUser() @@ -43,4 +48,31 @@ class SettingViewModel @Inject constructor( } } + fun patchAllowedNotification(isAllowed: Boolean) { + viewModelScope.launch { + authRepository.patchAllowedNotification(!isAllowed) + .onSuccess { response -> + Timber.d("SUCCESS PATCH ALLOWED NOTI") + _patchAllowedNotificationState.value = UiState.Success(response) + } + .onFailure { t -> + _patchAllowedNotificationState.value = UiState.Failure(t.message.toString()) + + if (t is HttpException) { + Timber.e("HTTP FAIL ALLOWED NOTI : ${t.code()} ${t.message}") + return@onFailure + } + + Timber.e("FAIL ALLOWED NOTI : ${t.message}") + } + } + } + + + fun clearDataStore() { + viewModelScope.launch { + dataStoreRepository.clearDataStore() + } + } + } From 7b572468fa6c185dde004e6d234668ed99546bc4 Mon Sep 17 00:00:00 2001 From: HyeseonBaek Date: Fri, 23 Feb 2024 15:58:12 +0900 Subject: [PATCH 5/9] =?UTF-8?q?[feat]=20#244=20=EB=92=A4=EB=A1=9C=EA=B0=80?= =?UTF-8?q?=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../winey/presentation/main/MainViewModel.kt | 2 +- .../main/mypage/MyPageFragment.kt | 55 +++---------------- .../main/mypage/MyPageViewModel.kt | 2 - .../main/mypage/setting/SettingActivity.kt | 45 +++++++++++++-- .../main/mypage/setting/SettingViewModel.kt | 3 - 5 files changed, 48 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/MainViewModel.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/MainViewModel.kt index 269da462..9c360126 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/MainViewModel.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/MainViewModel.kt @@ -58,7 +58,7 @@ class MainViewModel @Inject constructor( } } - private fun postLogout() { + fun postLogout() { viewModelScope.launch { _logoutState.value = UiState.Loading diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt index d09511b2..5db45c08 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageFragment.kt @@ -1,13 +1,10 @@ package org.go.sopt.winey.presentation.main.mypage import android.Manifest -import android.content.ActivityNotFoundException -import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.os.Build import android.os.Bundle -import android.provider.Settings import android.view.View import androidx.activity.OnBackPressedCallback import androidx.core.content.ContextCompat @@ -29,7 +26,6 @@ import org.go.sopt.winey.domain.entity.UserV2 import org.go.sopt.winey.domain.repository.DataStoreRepository import org.go.sopt.winey.presentation.main.MainViewModel import org.go.sopt.winey.presentation.main.mypage.myfeed.MyFeedActivity -import org.go.sopt.winey.presentation.main.mypage.myfeed.MyFeedFragment import org.go.sopt.winey.presentation.main.mypage.setting.SettingActivity import org.go.sopt.winey.presentation.main.notification.NotificationActivity import org.go.sopt.winey.presentation.nickname.NicknameActivity @@ -71,6 +67,7 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ private fun addListener() { initEditNicknameButtonClickListener() initMyFeedButtonClickListener() + initSettingButtonClickListener() registerBackPressedCallback() } @@ -92,44 +89,6 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ } } - private fun navigateToNotificationSetting(context: Context) { - val intent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - setNotificationIntentActionOreo(context) - } else { - setNorificationIntentActionOreoLess(context) - } - try { - context.startActivity(intent) - } catch (e: ActivityNotFoundException) { - e.printStackTrace() - } - } - - private fun setNotificationIntentActionOreo(context: Context): Intent { - return Intent().also { intent -> - intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS - intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK - } - } - - private fun setNorificationIntentActionOreoLess(context: Context): Intent { - return Intent().also { intent -> - intent.action = "android.settings.APP_NOTIFICATION_SETTINGS" - intent.putExtra("app_package", context.packageName) - intent.putExtra("app_uid", context.applicationInfo?.uid) - intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK - } - } - - private fun patchUserInfo() { - lifecycleScope.launch { - val data = dataStoreRepository.getUserInfo().first() - val newData = data?.copy(fcmIsAllowed = false) - dataStoreRepository.saveUserInfo(newData) - } - } - // 닉네임 액티비티 갔다가 다시 돌아왔을 때 유저 데이터 갱신하도록 override fun onStart() { super.onStart() @@ -156,6 +115,12 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ } } + private fun initSettingButtonClickListener() { + binding.ivMypageSetting.setOnClickListener { + navigateToSettingScreen() + } + } + // 마이페이지 왔다가 다시 알림 화면으로 돌아가도록 private fun registerBackPressedCallback() { val callback = object : OnBackPressedCallback(true) { @@ -195,7 +160,6 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ } } - private fun navigateToGuideScreen() { Intent(requireContext(), GuideActivity::class.java).apply { addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) @@ -249,11 +213,6 @@ class MyPageFragment : BindingFragment(R.layout.fragment_ amplitudeUtils.logEvent("view_goalsetting") } - private fun showTargetNotOverDialog() { - val dialog = MyPageNotOverDialogFragment() - dialog.show(parentFragmentManager, dialog.tag) - } - private inline fun navigateAndBackStack() { parentFragmentManager.commit { replace(R.id.fcv_main, T::class.simpleName) diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageViewModel.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageViewModel.kt index db894610..6bf730d8 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageViewModel.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/MyPageViewModel.kt @@ -41,6 +41,4 @@ class MyPageViewModel @Inject constructor( } } } - - } diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt index 32c93607..6c24ef05 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt @@ -20,7 +20,7 @@ import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch import org.go.sopt.winey.R import org.go.sopt.winey.databinding.ActivitySettingBinding -import org.go.sopt.winey.domain.entity.User +import org.go.sopt.winey.domain.entity.UserV2 import org.go.sopt.winey.domain.repository.DataStoreRepository import org.go.sopt.winey.presentation.main.MainViewModel import org.go.sopt.winey.presentation.model.WineyDialogLabel @@ -30,6 +30,7 @@ import org.go.sopt.winey.util.context.snackBar import org.go.sopt.winey.util.context.stringOf import org.go.sopt.winey.util.fragment.WineyDialogFragment import org.go.sopt.winey.util.view.UiState +import org.go.sopt.winey.util.view.setOnSingleClickListener import javax.inject.Inject @AndroidEntryPoint @@ -49,11 +50,13 @@ class SettingActivity : BindingActivity(R.layout.activit addListener() addObserver() initNotificationPermissionState() + initUserData() } override fun onStart() { super.onStart() initNotificationPermissionState() + updateNotificationButtonByPermission() } private fun addListener() { @@ -61,11 +64,14 @@ class SettingActivity : BindingActivity(R.layout.activit initLogoutButtonClickListener() initTermsButtonClickListener() initWithdrawButtonClickListener() - initNotiPermissionButtonClickListener() + initNotificationPermissionButtonClickListener() + initNotiToggleButtonClickListener() + initBackButtonClickListener() } private fun addObserver() { - + setupDeleteUserState() + setupPatchAllowedNotificationState() } private fun switchOnNotification() { @@ -80,7 +86,7 @@ class SettingActivity : BindingActivity(R.layout.activit settingViewModel.patchAllowedNotification(isAllowed = true) } - private fun initNotiPermissionButtonClickListener() { + private fun initNotificationPermissionButtonClickListener() { binding.llSettingAgreePermissionChange.setOnClickListener { showSystemNotificationSetting() } @@ -112,7 +118,16 @@ class SettingActivity : BindingActivity(R.layout.activit ) } - private fun updateNotificationAllowSwitchState(data: User) { + private fun initUserData() { + lifecycleScope.launch { + val data = dataStoreRepository.getUserInfo().first() + if (data != null) { + updateNotificationAllowSwitchState(data) + } + } + } + + private fun updateNotificationAllowSwitchState(data: UserV2) { if (isNotificationPermissionAllowed) { binding.ivSettingAgree.isVisible = true binding.llSettingAgreePermissionChange.isGone = true @@ -133,6 +148,20 @@ class SettingActivity : BindingActivity(R.layout.activit } } + private fun updateNotificationButtonByPermission() { + if (isNotificationPermissionAllowed) { + binding.ivSettingAgree.isVisible = true + + binding.llSettingAgreePermissionChange.isGone = true + binding.tvSettingAgreePermission.isGone = true + } else { + binding.ivSettingAgree.isGone = true + + binding.llSettingAgreePermissionChange.isVisible = true + binding.tvSettingAgreePermission.isVisible = true + } + } + private fun patchUserInfo() { lifecycleScope.launch { val data = dataStoreRepository.getUserInfo().first() @@ -185,6 +214,12 @@ class SettingActivity : BindingActivity(R.layout.activit } } + private fun initBackButtonClickListener() { + binding.ivSettingBack.setOnSingleClickListener { + finish() + } + } + private fun initLogoutButtonClickListener() { binding.clSettingLogout.setOnClickListener { amplitudeUtils.logEvent("click_logout") diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt index ff473a7a..f6ae5b5e 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt @@ -23,7 +23,6 @@ class SettingViewModel @Inject constructor( private val _deleteUserState = MutableStateFlow>(UiState.Empty) val deleteUserState: StateFlow> = _deleteUserState.asStateFlow() - private val _patchAllowedNotificationState = MutableStateFlow>(UiState.Empty) val patchAllowedNotificationState: StateFlow> = _patchAllowedNotificationState.asStateFlow() @@ -68,11 +67,9 @@ class SettingViewModel @Inject constructor( } } - fun clearDataStore() { viewModelScope.launch { dataStoreRepository.clearDataStore() } } - } From 4789e3dcc0ce3b165aa51e9867ed9a6d5900a693 Mon Sep 17 00:00:00 2001 From: HyeseonBaek Date: Mon, 26 Feb 2024 22:15:53 +0900 Subject: [PATCH 6/9] =?UTF-8?q?[feat]=20#244=20=EB=A1=9C=EA=B7=B8=EC=95=84?= =?UTF-8?q?=EC=9B=83,=20=ED=83=88=ED=87=B4=20=EC=8B=9C=20=ED=99=94?= =?UTF-8?q?=EB=A9=B4=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/mypage/setting/SettingActivity.kt | 41 ++++++++++++++++++- .../main/mypage/setting/SettingViewModel.kt | 1 + 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt index 6c24ef05..98b7264f 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt @@ -8,6 +8,7 @@ import android.os.Build import android.os.Bundle import android.provider.Settings import androidx.activity.viewModels +import androidx.core.content.ContentProviderCompat.requireContext import androidx.core.content.ContextCompat import androidx.core.view.isGone import androidx.core.view.isVisible @@ -24,6 +25,8 @@ import org.go.sopt.winey.domain.entity.UserV2 import org.go.sopt.winey.domain.repository.DataStoreRepository import org.go.sopt.winey.presentation.main.MainViewModel import org.go.sopt.winey.presentation.model.WineyDialogLabel +import org.go.sopt.winey.presentation.onboarding.guide.GuideActivity +import org.go.sopt.winey.presentation.onboarding.login.LoginActivity import org.go.sopt.winey.util.amplitude.AmplitudeUtils import org.go.sopt.winey.util.binding.BindingActivity import org.go.sopt.winey.util.context.snackBar @@ -72,6 +75,7 @@ class SettingActivity : BindingActivity(R.layout.activit private fun addObserver() { setupDeleteUserState() setupPatchAllowedNotificationState() + setupLogoutState() } private fun switchOnNotification() { @@ -259,7 +263,7 @@ class SettingActivity : BindingActivity(R.layout.activit when (state) { is UiState.Success -> { settingViewModel.clearDataStore() - //navigateToGuideScreen() + navigateToGuideScreen() } is UiState.Failure -> { @@ -296,6 +300,41 @@ class SettingActivity : BindingActivity(R.layout.activit } } } + private fun setupLogoutState() { + mainViewModel.logoutState.flowWithLifecycle(lifecycle).onEach { state -> + when (state) { + is UiState.Loading -> { + } + + is UiState.Success -> { + navigateToLoginScreen() + } + + is UiState.Failure -> { + snackBar(binding.root) { state.msg } + } + + is UiState.Empty -> { + } + } + }.launchIn(lifecycleScope) + } + + private fun navigateToLoginScreen() { + Intent(this, LoginActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + startActivity(this) + finish() + } + } + + private fun navigateToGuideScreen() { + Intent(this, GuideActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) + startActivity(this) + } + } + companion object { diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt index f6ae5b5e..ab13085d 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt @@ -7,6 +7,7 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch +import org.go.sopt.winey.data.model.remote.response.ResponseLogoutDto import org.go.sopt.winey.domain.repository.AuthRepository import org.go.sopt.winey.domain.repository.DataStoreRepository import org.go.sopt.winey.util.view.UiState From 22dc4b4b9664ca9872be8618e02d725bf979a386 Mon Sep 17 00:00:00 2001 From: HyeseonBaek Date: Mon, 26 Feb 2024 22:30:36 +0900 Subject: [PATCH 7/9] =?UTF-8?q?[fix]=20#244=20=EC=8B=9C=EC=8A=A4=ED=85=9C?= =?UTF-8?q?=20=EC=84=A4=EC=A0=95=20=EC=9D=B4=EB=8F=99=EC=8B=9C=20=ED=81=AC?= =?UTF-8?q?=EB=9E=98=EC=8B=9C=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../presentation/main/mypage/setting/SettingActivity.kt | 5 ++--- .../presentation/main/mypage/setting/SettingViewModel.kt | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt index 98b7264f..f6c237ef 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingActivity.kt @@ -8,7 +8,6 @@ import android.os.Build import android.os.Bundle import android.provider.Settings import androidx.activity.viewModels -import androidx.core.content.ContentProviderCompat.requireContext import androidx.core.content.ContextCompat import androidx.core.view.isGone import androidx.core.view.isVisible @@ -99,7 +98,7 @@ class SettingActivity : BindingActivity(R.layout.activit private fun showSystemNotificationSetting() { Intent().apply { action = Settings.ACTION_APP_NOTIFICATION_SETTINGS - putExtra(Settings.EXTRA_APP_PACKAGE, this) + putExtra(Settings.EXTRA_APP_PACKAGE, packageName) flags = Intent.FLAG_ACTIVITY_NEW_TASK startActivity(this) } @@ -300,6 +299,7 @@ class SettingActivity : BindingActivity(R.layout.activit } } } + private fun setupLogoutState() { mainViewModel.logoutState.flowWithLifecycle(lifecycle).onEach { state -> when (state) { @@ -335,7 +335,6 @@ class SettingActivity : BindingActivity(R.layout.activit } } - companion object { private const val ONE_ON_ONE_URL = "https://open.kakao.com/o/s751Susf" diff --git a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt index ab13085d..f6ae5b5e 100644 --- a/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt +++ b/app/src/main/java/org/go/sopt/winey/presentation/main/mypage/setting/SettingViewModel.kt @@ -7,7 +7,6 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch -import org.go.sopt.winey.data.model.remote.response.ResponseLogoutDto import org.go.sopt.winey.domain.repository.AuthRepository import org.go.sopt.winey.domain.repository.DataStoreRepository import org.go.sopt.winey.util.view.UiState From 11e797112dc8e9e34e53b0ebd65bd3664583a604 Mon Sep 17 00:00:00 2001 From: HyeseonBaek Date: Mon, 26 Feb 2024 22:42:03 +0900 Subject: [PATCH 8/9] =?UTF-8?q?[mod]=20#244=20=EB=92=A4=EB=A1=9C=EA=B0=80?= =?UTF-8?q?=EA=B8=B0=20=EB=B2=84=ED=8A=BC=20=ED=86=B5=EC=9D=BC=20=EB=B0=98?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/layout/activity_setting.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_setting.xml b/app/src/main/res/layout/activity_setting.xml index 6ce03d97..7a62a270 100644 --- a/app/src/main/res/layout/activity_setting.xml +++ b/app/src/main/res/layout/activity_setting.xml @@ -24,7 +24,7 @@ android:layout_height="wrap_content" android:layout_marginVertical="4dp" android:padding="12dp" - android:src="@drawable/ic_myfeed_back" + android:src="@drawable/ic_all_back" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> From 4ebd0f6b5c7a855f988faa28a70f167f29872077 Mon Sep 17 00:00:00 2001 From: HyeseonBaek Date: Fri, 1 Mar 2024 14:18:57 +0900 Subject: [PATCH 9/9] =?UTF-8?q?[mod]=20#244=20overScrollMode=20never=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/res/layout/fragment_my_page.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/fragment_my_page.xml b/app/src/main/res/layout/fragment_my_page.xml index c92467bf..eadbd331 100644 --- a/app/src/main/res/layout/fragment_my_page.xml +++ b/app/src/main/res/layout/fragment_my_page.xml @@ -45,6 +45,7 @@