diff --git a/app/src/main/java/org/sopt/pingle/data/datasource/local/PingleLocalDataSource.kt b/app/src/main/java/org/sopt/pingle/data/datasource/local/PingleLocalDataSource.kt index b83ed88fd..594dda2fb 100644 --- a/app/src/main/java/org/sopt/pingle/data/datasource/local/PingleLocalDataSource.kt +++ b/app/src/main/java/org/sopt/pingle/data/datasource/local/PingleLocalDataSource.kt @@ -1,6 +1,9 @@ package org.sopt.pingle.data.datasource.local +import android.content.SharedPreferences + interface PingleLocalDataSource { + val sharedPreference: SharedPreferences var isLogin: Boolean var userName: String var accessToken: String diff --git a/app/src/main/java/org/sopt/pingle/data/datasourceimpl/local/PingleLocalDataSourceImpl.kt b/app/src/main/java/org/sopt/pingle/data/datasourceimpl/local/PingleLocalDataSourceImpl.kt index f8b9cd91d..b12ed707c 100644 --- a/app/src/main/java/org/sopt/pingle/data/datasourceimpl/local/PingleLocalDataSourceImpl.kt +++ b/app/src/main/java/org/sopt/pingle/data/datasourceimpl/local/PingleLocalDataSourceImpl.kt @@ -31,6 +31,9 @@ class PingleLocalDataSourceImpl @Inject constructor( ) } + override val sharedPreference: SharedPreferences + get() = pref + override var isLogin: Boolean get() = pref.getBoolean(AUTO_LOGIN, false) set(value) = pref.edit { putBoolean(AUTO_LOGIN, value) } diff --git a/app/src/main/java/org/sopt/pingle/presentation/model/PingleFilterModel.kt b/app/src/main/java/org/sopt/pingle/presentation/model/PingleFilterModel.kt new file mode 100644 index 000000000..561b4d4e9 --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/presentation/model/PingleFilterModel.kt @@ -0,0 +1,12 @@ +package org.sopt.pingle.presentation.model + +import org.sopt.pingle.presentation.type.CategoryType +import org.sopt.pingle.presentation.type.HomeViewType +import org.sopt.pingle.presentation.type.MainListOrderType + +data class PingleFilterModel( + val category: CategoryType? = null, + val searchWord: String? = null, + val mainListOrderType: MainListOrderType = MainListOrderType.NEW, + val homeViewType: HomeViewType = HomeViewType.MAP +) diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/auth/AuthActivity.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/auth/AuthActivity.kt index b038f0fcb..d0fe57244 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/auth/AuthActivity.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/auth/AuthActivity.kt @@ -13,8 +13,11 @@ import org.sopt.pingle.R import org.sopt.pingle.data.service.KakaoAuthService import org.sopt.pingle.databinding.ActivityAuthBinding import org.sopt.pingle.presentation.ui.main.MainActivity +import org.sopt.pingle.presentation.ui.main.more.MoreFragment.Companion.MORE_FRAGMENT import org.sopt.pingle.presentation.ui.onboarding.onboarding.OnboardingActivity +import org.sopt.pingle.presentation.ui.onboarding.onboarding.OnboardingActivity.Companion.FROM_ACTIVITY import org.sopt.pingle.util.AmplitudeUtils +import org.sopt.pingle.util.activity.setDoubleBackPressToExit import org.sopt.pingle.util.base.BindingActivity import org.sopt.pingle.util.view.UiState import timber.log.Timber @@ -28,10 +31,18 @@ class AuthActivity : BindingActivity(R.layout.activity_auth override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + initLayout() addListeners() collectData() } + private fun initLayout() { + when (intent.getStringExtra(FROM_ACTIVITY)) { + MORE_FRAGMENT -> setDoubleBackPressToExit(binding.root) + else -> Unit + } + } + private fun addListeners() { binding.btnAuthKakao.setOnClickListener { kakaoAuthService.loginKakao(viewModel::login, viewModel::saveAccount) diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/HomeFragment.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/HomeFragment.kt index 2bc5e6711..63398540b 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/HomeFragment.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/HomeFragment.kt @@ -12,32 +12,37 @@ import androidx.fragment.app.activityViewModels import androidx.lifecycle.flowWithLifecycle import androidx.lifecycle.lifecycleScope import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import org.sopt.pingle.R import org.sopt.pingle.databinding.FragmentHomeBinding import org.sopt.pingle.presentation.model.SearchModel import org.sopt.pingle.presentation.type.CategoryType import org.sopt.pingle.presentation.type.HomeViewType +import org.sopt.pingle.presentation.type.SnackbarType import org.sopt.pingle.presentation.ui.main.home.mainlist.MainListFragment import org.sopt.pingle.presentation.ui.main.home.map.MapFragment import org.sopt.pingle.presentation.ui.search.SearchActivity import org.sopt.pingle.presentation.ui.search.SearchActivity.Companion.SEARCH_WORD import org.sopt.pingle.util.AmplitudeUtils +import org.sopt.pingle.util.activity.FINISH_INTERVAL_TIME +import org.sopt.pingle.util.activity.INIT_BACK_PRESSED_TIME import org.sopt.pingle.util.base.BindingFragment import org.sopt.pingle.util.component.PingleChip +import org.sopt.pingle.util.component.PingleSnackbar +import org.sopt.pingle.util.fragment.stringOf import org.sopt.pingle.util.view.PingleFragmentStateAdapter import org.sopt.pingle.util.view.UiState @AndroidEntryPoint class HomeFragment : BindingFragment(R.layout.fragment_home) { private val homeViewModel: HomeViewModel by activityViewModels() + private var backPressedTime = INIT_BACK_PRESSED_TIME private lateinit var fragmentList: ArrayList private lateinit var fragmentStateAdapter: PingleFragmentStateAdapter private lateinit var resultLauncher: ActivityResultLauncher - private lateinit var stopSearchCallback: OnBackPressedCallback override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -47,11 +52,12 @@ class HomeFragment : BindingFragment(R.layout.fragment_home collectData() setFragmentStateAdapter() setResultLauncher() - setStopSearchCallback() } override fun onResume() { super.onResume() + + setOnBackPressedCallback() initChip() } @@ -76,8 +82,6 @@ class HomeFragment : BindingFragment(R.layout.fragment_home navigateToSearch() } } - - initChip() } private fun addListeners() { @@ -85,7 +89,7 @@ class HomeFragment : BindingFragment(R.layout.fragment_home ivHomeSearch.setOnClickListener { navigateToSearch() - when (homeViewModel.homeViewType.value) { + when (homeViewModel.pingleFilter.value.homeViewType) { HomeViewType.MAP -> AmplitudeUtils.trackEvent(CLICK_SEARCH_MAP) HomeViewType.MAIN_LIST -> AmplitudeUtils.trackEvent(CLICK_SEARCH_LIST) } @@ -100,7 +104,7 @@ class HomeFragment : BindingFragment(R.layout.fragment_home checkedIds.getOrNull(SINGLE_SELECTION) ?.let { group.findViewById(it).categoryType.let { categoryType -> - when (homeViewModel.homeViewType.value) { + when (homeViewModel.pingleFilter.value.homeViewType) { HomeViewType.MAP -> AmplitudeUtils.trackEventWithProperty( eventName = CLICK_CATEGORY_MAP, propertyName = CATEGORY, @@ -119,7 +123,7 @@ class HomeFragment : BindingFragment(R.layout.fragment_home fabHomeChange.setOnClickListener { with(homeViewModel) { - when (homeViewType.value) { + when (pingleFilter.value.homeViewType) { HomeViewType.MAP -> { AmplitudeUtils.trackEvent(CLICK_LIST_MAP) setHomeViewType(HomeViewType.MAIN_LIST) @@ -136,38 +140,39 @@ class HomeFragment : BindingFragment(R.layout.fragment_home } private fun collectData() { - combine( - homeViewModel.category.flowWithLifecycle(viewLifecycleOwner.lifecycle).distinctUntilChanged(), - homeViewModel.searchWord.flowWithLifecycle(viewLifecycleOwner.lifecycle).distinctUntilChanged(), - homeViewModel.mainListOrderType.flowWithLifecycle(viewLifecycleOwner.lifecycle).distinctUntilChanged(), - homeViewModel.homeViewType.flowWithLifecycle(viewLifecycleOwner.lifecycle).distinctUntilChanged() - ) { _, _, _, homeViewType -> - homeViewType - }.onEach { homeViewType -> - when (homeViewType) { - HomeViewType.MAIN_LIST -> homeViewModel.getMainListPingleList() - HomeViewType.MAP -> homeViewModel.getPinListWithoutFilter() - } - }.launchIn(viewLifecycleOwner.lifecycleScope) + homeViewModel.pingleFilter.flowWithLifecycle(viewLifecycleOwner.lifecycle) + .distinctUntilChanged() + .onEach { pingleFilter -> + with(pingleFilter) { + when (homeViewType) { + HomeViewType.MAIN_LIST -> homeViewModel.getMainListPingleList() + HomeViewType.MAP -> homeViewModel.getPinListWithoutFilter(isSearching = searchWord != homeViewModel.lastSearchWord) + } + homeViewModel.setLastSearchWord(searchWord) + } + }.launchIn(viewLifecycleOwner.lifecycleScope) - homeViewModel.homeViewType.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { - with(binding) { - vpHome.setCurrentItem(homeViewModel.homeViewType.value.index, false) - fabHomeChange.setImageResource(homeViewModel.homeViewType.value.fabDrawableRes) - } - }.launchIn(viewLifecycleOwner.lifecycleScope) + homeViewModel.pingleFilter.map { pingleFilter -> pingleFilter.homeViewType } + .distinctUntilChanged() + .flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { homeViewType -> + with(binding) { + vpHome.setCurrentItem(homeViewType.index, false) + fabHomeChange.setImageResource(homeViewType.fabDrawableRes) + } + }.launchIn(viewLifecycleOwner.lifecycleScope) - homeViewModel.searchWord.flowWithLifecycle(viewLifecycleOwner.lifecycle) + homeViewModel.pingleFilter.map { pingleFilter -> pingleFilter.searchWord } + .distinctUntilChanged() + .flowWithLifecycle(viewLifecycleOwner.lifecycle) .onEach { searchWord -> with(binding) { - pingleSearchHomeSearch.binding.etSearchPingleEditText.setText(homeViewModel.searchWord.value) + pingleSearchHomeSearch.binding.etSearchPingleEditText.setText(searchWord) (!searchWord.isNullOrEmpty()).let { isSearching -> pingleSearchHomeSearch.visibility = if (isSearching) View.VISIBLE else View.INVISIBLE tvHomeGroup.visibility = if (isSearching) View.INVISIBLE else View.VISIBLE ivHomeSearch.visibility = if (isSearching) View.INVISIBLE else View.VISIBLE - if (isSearching) setStopSearchCallback() else stopSearchCallback.remove() } } }.launchIn(viewLifecycleOwner.lifecycleScope) @@ -205,7 +210,6 @@ class HomeFragment : BindingFragment(R.layout.fragment_home resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult -> if (activityResult.resultCode == RESULT_OK) { - homeViewModel.clearCategory() homeViewModel.setSearchWord( activityResult.data?.getStringExtra(SEARCH_WORD) ) @@ -213,24 +217,35 @@ class HomeFragment : BindingFragment(R.layout.fragment_home } } - private fun setStopSearchCallback() { - stopSearchCallback = - object : OnBackPressedCallback(!homeViewModel.searchWord.value.isNullOrEmpty()) { + private fun setOnBackPressedCallback() { + requireActivity().onBackPressedDispatcher.addCallback( + this.viewLifecycleOwner, + object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { - homeViewModel.clearSearchWord() - navigateToSearch() + if (homeViewModel.pingleFilter.value.searchWord.isNullOrEmpty()) { + if (System.currentTimeMillis() - backPressedTime <= FINISH_INTERVAL_TIME) { + requireActivity().finish() + } else { + backPressedTime = System.currentTimeMillis() + PingleSnackbar.makeSnackbar( + view = requireView(), + message = stringOf(R.string.all_on_back_pressed_snackbar), + bottomMarin = org.sopt.pingle.util.activity.SNACKBAR_BOTTOM_MARGIN, + snackbarType = SnackbarType.GUIDE + ) + } + } else { + homeViewModel.clearSearchWord() + navigateToSearch() + } } } - - requireActivity().onBackPressedDispatcher.addCallback( - viewLifecycleOwner, - stopSearchCallback ) } private fun initChip() { with(binding) { - homeViewModel.category.value.let { selectedCategory -> + homeViewModel.pingleFilter.value.category.let { selectedCategory -> chipHomeCategoryPlay.isChecked = selectedCategory == CategoryType.PLAY chipHomeCategoryStudy.isChecked = selectedCategory == CategoryType.STUDY chipHomeCategoryMulti.isChecked = selectedCategory == CategoryType.MULTI @@ -241,13 +256,15 @@ class HomeFragment : BindingFragment(R.layout.fragment_home private fun navigateToSearch() { Intent(requireContext(), SearchActivity::class.java).apply { - putExtra( - SEARCH_MODEL, - SearchModel( - homeViewType = homeViewModel.homeViewType.value, - searchWord = homeViewModel.searchWord.value + with(homeViewModel.pingleFilter.value) { + putExtra( + SEARCH_MODEL, + SearchModel( + homeViewType = homeViewType, + searchWord = searchWord + ) ) - ) + } resultLauncher.launch(this) } } diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/HomeViewModel.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/HomeViewModel.kt index 5bcc40d25..d740f9c60 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/HomeViewModel.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/HomeViewModel.kt @@ -1,5 +1,6 @@ package org.sopt.pingle.presentation.ui.main.home +import android.content.SharedPreferences import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel @@ -8,6 +9,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import kotlinx.serialization.json.Json import org.sopt.pingle.data.datasource.local.PingleLocalDataSource @@ -22,6 +24,7 @@ import org.sopt.pingle.domain.usecase.PostPingleJoinUseCase import org.sopt.pingle.presentation.mapper.toMainListPingleModel import org.sopt.pingle.presentation.model.MainListPingleModel import org.sopt.pingle.presentation.model.MarkerModel +import org.sopt.pingle.presentation.model.PingleFilterModel import org.sopt.pingle.presentation.type.CategoryType import org.sopt.pingle.presentation.type.HomeViewType import org.sopt.pingle.presentation.type.MainListOrderType @@ -39,16 +42,36 @@ class HomeViewModel @Inject constructor( private val getPinListWithoutFilteringUseCase: GetPinListWithoutFilteringUseCase, private val postPingleJoinUseCase: PostPingleJoinUseCase ) : ViewModel() { - private val _category = MutableStateFlow(null) - val category get() = _category.asStateFlow() + private val sharedPreferenceChangeListener = + SharedPreferences.OnSharedPreferenceChangeListener { _, key -> + if (key == GROUP_ID) { + clearPingleFilter() + clearMarkerModelData() + clearSelectedMarkerPosition() + } + } + + init { + localStorage.sharedPreference.registerOnSharedPreferenceChangeListener( + sharedPreferenceChangeListener + ) + } + + override fun onCleared() { + localStorage.sharedPreference.unregisterOnSharedPreferenceChangeListener( + sharedPreferenceChangeListener + ) + super.onCleared() + } - private val _homeViewType = MutableStateFlow(HomeViewType.MAP) - val homeViewType get() = _homeViewType.asStateFlow() + private var _pingleFilter = MutableStateFlow(PingleFilterModel()) + val pingleFilter get() = _pingleFilter.asStateFlow() - private var _searchWord = MutableStateFlow(null) - val searchWord get() = _searchWord.asStateFlow() + private var _lastSearchWord: String? = null + val lastSearchWord get() = _lastSearchWord - private val _pinEntityListState = MutableStateFlow>>(UiState.Empty) + private val _pinEntityListState = + MutableStateFlow>>>(UiState.Empty) val pinEntityListState get() = _pinEntityListState.asStateFlow() private var _markerModelData = @@ -70,30 +93,46 @@ class HomeViewModel @Inject constructor( private val _pingleDeleteState = MutableSharedFlow>() val pingleDeleteState get() = _pingleDeleteState.asSharedFlow() - private val _mainListOrderType = MutableStateFlow(MainListOrderType.NEW) - val mainListOrderType get() = _mainListOrderType.asStateFlow() - private val _mainListPingleListState = MutableSharedFlow>>() val mainListPingleListState get() = _mainListPingleListState.asSharedFlow() - fun setCategory(category: CategoryType?) { - _category.value = category + private fun clearPingleFilter() { + _pingleFilter.value = PingleFilterModel() } - fun clearCategory() { - _category.value = null + fun setCategory(category: CategoryType?) { + _pingleFilter.update { pingleFilter -> + pingleFilter.copy(category = category) + } } fun setHomeViewType(homeViewType: HomeViewType) { - _homeViewType.value = homeViewType + _pingleFilter.update { pingleFilter -> + pingleFilter.copy(homeViewType = homeViewType) + } } fun setSearchWord(searchWord: String?) { - _searchWord.value = searchWord + _pingleFilter.update { pingleFilter -> + pingleFilter.copy(category = null, searchWord = searchWord) + } } fun clearSearchWord() { - _searchWord.value = null + _pingleFilter.update { pingleFilter -> + pingleFilter.copy(searchWord = null) + } + _lastSearchWord = null + } + + fun setMainListOrderType(mainListOrderType: MainListOrderType) { + _pingleFilter.update { pingleFilter -> + pingleFilter.copy(mainListOrderType = mainListOrderType) + } + } + + fun setLastSearchWord(searchWord: String?) { + _lastSearchWord = searchWord } private fun setMarkerModelListIsSelected(position: Int) { @@ -148,10 +187,6 @@ class HomeViewModel @Inject constructor( } } - fun setMainListOrderType(mainListOrderType: MainListOrderType) { - _mainListOrderType.value = mainListOrderType - } - fun getGroupName(): String = localStorage.groupName fun deletePingleCancel(meetingId: Long) { @@ -193,16 +228,17 @@ class HomeViewModel @Inject constructor( } fun getMainListPingleList() { + _pingleFilter.value.searchWord viewModelScope.launch { _mainListPingleListState.emit(UiState.Loading) - if (_searchWord.value?.isBlank() == true) { + if (_pingleFilter.value.searchWord?.isBlank() == true) { _mainListPingleListState.emit(UiState.Success(emptyList())) } else { getMainListPingleListUseCase( - searchWord = _searchWord.value, - category = _category.value?.name, + searchWord = _pingleFilter.value.searchWord, + category = _pingleFilter.value.category?.name, teamId = localStorage.groupId.toLong(), - order = _mainListOrderType.value.name + order = _pingleFilter.value.mainListOrderType.name ).onSuccess { mainListPingleList -> _mainListPingleListState.emit(UiState.Success(mainListPingleList.map { pingleEntity -> pingleEntity.toMainListPingleModel() })) }.onFailure { throwable -> @@ -219,7 +255,7 @@ class HomeViewModel @Inject constructor( getMapPingleListUseCase( teamId = localStorage.groupId.toLong(), pinId = pinId, - category = _category.value?.name + category = _pingleFilter.value.category?.name ).collect() { mapPingleList -> _mapPingleListState.emit(UiState.Success(Pair(pinId, mapPingleList))) } @@ -229,19 +265,19 @@ class HomeViewModel @Inject constructor( } } - fun getPinListWithoutFilter() { + fun getPinListWithoutFilter(isSearching: Boolean = false) { viewModelScope.launch { _pinEntityListState.value = UiState.Loading - if (_searchWord.value?.isBlank() == true) { - _pinEntityListState.emit(UiState.Success(emptyList())) + if (_pingleFilter.value.searchWord?.isBlank() == true) { + _pinEntityListState.emit(UiState.Success(Pair(isSearching, emptyList()))) } else { runCatching { getPinListWithoutFilteringUseCase( teamId = localStorage.groupId.toLong(), - category = _category.value?.name, - searchWord = _searchWord.value + category = _pingleFilter.value.category?.name, + searchWord = _pingleFilter.value.searchWord ).collect() { pinList -> - _pinEntityListState.value = UiState.Success(pinList) + _pinEntityListState.value = UiState.Success(Pair(isSearching, pinList)) } }.onFailure { exception: Throwable -> _pinEntityListState.value = UiState.Error(exception.message) @@ -277,6 +313,7 @@ class HomeViewModel @Inject constructor( } companion object { + private const val GROUP_ID = "GroupId" const val DEFAULT_SELECTED_MARKER_POSITION = -1 } } diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/mainlist/MainListFragment.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/mainlist/MainListFragment.kt index d1deadca6..a56a0739a 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/mainlist/MainListFragment.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/mainlist/MainListFragment.kt @@ -137,13 +137,13 @@ class MainListFragment : BindingFragment(R.layout.fragm } binding.tvMainListOrderType.text = - stringOf(homeViewModel.mainListOrderType.value.mainListOrderStringRes) + stringOf(homeViewModel.pingleFilter.value.mainListOrderType.mainListOrderStringRes) - (!homeViewModel.searchWord.value.isNullOrEmpty()).let { isSearching -> + (!homeViewModel.pingleFilter.value.searchWord.isNullOrEmpty()).let { isSearching -> AmplitudeUtils.trackEventWithProperty( eventName = COMPLETE_SEARCH_LIST, propertyName = KEYWORD, - propertyValue = homeViewModel.searchWord.value + propertyValue = homeViewModel.pingleFilter.value.searchWord ) with(binding.tvMainListSearchCount) { visibility = if (isSearching) View.VISIBLE else View.INVISIBLE diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapFragment.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapFragment.kt index 597dc8462..b57d3e5f9 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapFragment.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapFragment.kt @@ -209,20 +209,25 @@ class MapFragment : BindingFragment(R.layout.fragment_map), when (uiState) { is UiState.Success -> { if (::naverMap.isInitialized) { - makeMarkers(uiState.data) + makeMarkers(uiState.data.second) mapCardAdapter.clearData() homeViewModel.clearSelectedMarkerPosition() } - homeViewModel.searchWord.value?.let { searchWord -> - AmplitudeUtils.trackEventWithProperty( - eventName = COMPLETE_SEARCH_MAP, - propertyName = KEYWORD, - propertyValue = searchWord - ) - when { - uiState.data.isEmpty() -> homeViewModel.setHomeViewType(HomeViewType.MAIN_LIST) - else -> moveMapCamera(homeViewModel.markerModelData.value.second[FIRST_INDEX].marker.position) + if (uiState.data.first) { + homeViewModel.pingleFilter.value.searchWord?.let { searchWord -> + AmplitudeUtils.trackEventWithProperty( + eventName = COMPLETE_SEARCH_MAP, + propertyName = KEYWORD, + propertyValue = searchWord + ) + when { + uiState.data.second.isEmpty() -> homeViewModel.setHomeViewType( + HomeViewType.MAIN_LIST + ) + + else -> moveMapCamera(homeViewModel.markerModelData.value.second[FIRST_INDEX].marker.position) + } } } } diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/more/MoreFragment.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/more/MoreFragment.kt index d34f16d49..ac333c66a 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/more/MoreFragment.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/more/MoreFragment.kt @@ -15,8 +15,9 @@ import org.sopt.pingle.R import org.sopt.pingle.data.service.KakaoAuthService import org.sopt.pingle.databinding.FragmentMoreBinding import org.sopt.pingle.presentation.type.SnackbarType +import org.sopt.pingle.presentation.ui.auth.AuthActivity import org.sopt.pingle.presentation.ui.mygroup.MyGroupActivity -import org.sopt.pingle.presentation.ui.onboarding.onboardingexplanation.OnboardingExplanationActivity +import org.sopt.pingle.presentation.ui.onboarding.onboarding.OnboardingActivity.Companion.FROM_ACTIVITY import org.sopt.pingle.util.AmplitudeUtils import org.sopt.pingle.util.base.BindingFragment import org.sopt.pingle.util.component.AllModalDialogFragment @@ -76,47 +77,49 @@ class MoreFragment : BindingFragment(R.layout.fragment_more } private fun collectData() { - moreViewModel.logoutState.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { logoutState -> - when (logoutState) { - is UiState.Success -> { - AmplitudeUtils.trackEvent(LOGOUT_APP) - navigateToOnboardingExplanation() - } - - is UiState.Error -> { - Timber.d(FAILURE_LOGOUT) - } + moreViewModel.logoutState.flowWithLifecycle(viewLifecycleOwner.lifecycle) + .onEach { logoutState -> + when (logoutState) { + is UiState.Success -> { + AmplitudeUtils.trackEvent(LOGOUT_APP) + navigateToAuth() + } - else -> {} - } - }.launchIn(viewLifecycleOwner.lifecycleScope) + is UiState.Error -> { + Timber.d(FAILURE_LOGOUT) + } - moreViewModel.withDrawState.flowWithLifecycle(viewLifecycleOwner.lifecycle).onEach { withDrawState -> - when (withDrawState) { - is UiState.Success -> { - AmplitudeUtils.trackEvent(WITHDRAW_APP) - kakaoAuthService.withdrawKakao() - navigateToOnboardingExplanation() + else -> {} } + }.launchIn(viewLifecycleOwner.lifecycleScope) - is UiState.Error -> { - when (withDrawState.code) { - FAILURE_OWNER -> { - PingleSnackbar.makeSnackbar( - requireView(), - stringOf(R.string.more_snackbar_failure), - SNACKBAR_BOTTOM_MARGIN, - SnackbarType.WARNING - ) - } + moreViewModel.withDrawState.flowWithLifecycle(viewLifecycleOwner.lifecycle) + .onEach { withDrawState -> + when (withDrawState) { + is UiState.Success -> { + AmplitudeUtils.trackEvent(WITHDRAW_APP) + kakaoAuthService.withdrawKakao() + navigateToAuth() + } - else -> Timber.d("$FAILURE_LOGOUT : ${withDrawState.message}") + is UiState.Error -> { + when (withDrawState.code) { + FAILURE_OWNER -> { + PingleSnackbar.makeSnackbar( + requireView(), + stringOf(R.string.more_snackbar_failure), + SNACKBAR_BOTTOM_MARGIN, + SnackbarType.WARNING + ) + } + + else -> Timber.d("$FAILURE_LOGOUT : ${withDrawState.message}") + } } - } - else -> {} - } - }.launchIn(viewLifecycleOwner.lifecycleScope) + else -> {} + } + }.launchIn(viewLifecycleOwner.lifecycleScope) moreViewModel.userInfoState.flowWithLifecycle(viewLifecycleOwner.lifecycle) .onEach { userInfoState -> @@ -130,9 +133,10 @@ class MoreFragment : BindingFragment(R.layout.fragment_more }.launchIn(viewLifecycleOwner.lifecycleScope) } - private fun navigateToOnboardingExplanation() { - Intent(requireContext(), OnboardingExplanationActivity::class.java).apply { + private fun navigateToAuth() { + Intent(requireContext(), AuthActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK + putExtra(FROM_ACTIVITY, MORE_FRAGMENT) startActivity(this) } } @@ -184,5 +188,7 @@ class MoreFragment : BindingFragment(R.layout.fragment_more private const val WITHDRAW_APP = "withdraw_app" private const val START_MYGROUP = "start_mygroup" + + const val MORE_FRAGMENT = "MoreFragment" } } diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/ranking/RankingFragment.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/ranking/RankingFragment.kt index ef9415827..6dc436110 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/ranking/RankingFragment.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/ranking/RankingFragment.kt @@ -42,7 +42,7 @@ class RankingFragment : BindingFragment(R.layout.fragmen addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { super.onScrollStateChanged(recyclerView, newState) - if (newState == RecyclerView.SCROLL_STATE_IDLE) { + if (newState == RecyclerView.SCROLL_STATE_DRAGGING) { AmplitudeUtils.trackEvent(SCROLL_RANKING) } } diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/onboarding/onboardingexplanation/OnboardingExplanationActivity.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/onboarding/onboardingexplanation/OnboardingExplanationActivity.kt index 31b5944e3..a0f5af0f6 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/onboarding/onboardingexplanation/OnboardingExplanationActivity.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/onboarding/onboardingexplanation/OnboardingExplanationActivity.kt @@ -18,6 +18,7 @@ import org.sopt.pingle.presentation.type.SnackbarType import org.sopt.pingle.presentation.ui.auth.AuthActivity import org.sopt.pingle.presentation.ui.auth.AuthViewModel import org.sopt.pingle.presentation.ui.main.MainActivity +import org.sopt.pingle.presentation.ui.onboarding.onboarding.OnboardingActivity import org.sopt.pingle.presentation.ui.onboarding.onboardingexplanation.OnboardingExplanationAdapter.Companion.ONBOARDING_SIZE import org.sopt.pingle.presentation.ui.onboarding.onboardingexplanation.OnboardingExplanationAdapter.Companion.POSITION_MINUS import org.sopt.pingle.util.activity.FINISH_INTERVAL_TIME @@ -54,7 +55,12 @@ class OnboardingExplanationActivity : private fun initLayout() { if (authViewModel.isLocalToken()) { - if (authViewModel.isLocalGroupId()) navigateToMain() else authViewModel.getUserInfo() + if (authViewModel.isLocalGroupId()) { + navigateToMain() + } else { + authViewModel.getUserInfo() + navigateToOnboarding() + } } initAdapter() @@ -148,4 +154,11 @@ class OnboardingExplanationActivity : startActivity(this) } } + + private fun navigateToOnboarding() { + Intent(this, OnboardingActivity::class.java).apply { + flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK + startActivity(this) + } + } } diff --git a/app/src/main/java/org/sopt/pingle/util/component/PingleSearch.kt b/app/src/main/java/org/sopt/pingle/util/component/PingleSearch.kt index e3e30cd68..f36514628 100644 --- a/app/src/main/java/org/sopt/pingle/util/component/PingleSearch.kt +++ b/app/src/main/java/org/sopt/pingle/util/component/PingleSearch.kt @@ -44,6 +44,10 @@ class PingleSearch @JvmOverloads constructor( if (text.isNullOrEmpty()) View.GONE else View.VISIBLE } + etSearchPingleEditText.setOnEditorActionListener { textView, _, _ -> + textView.text.isEmpty() + } + ivSearchPingleClear.setOnClickListener { _binding.etSearchPingleEditText.text.clear() } diff --git a/app/src/main/res/layout/dialog_my_group_modal.xml b/app/src/main/res/layout/dialog_my_group_modal.xml index df07204ff..58940c1ea 100644 --- a/app/src/main/res/layout/dialog_my_group_modal.xml +++ b/app/src/main/res/layout/dialog_my_group_modal.xml @@ -37,7 +37,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" - app:layout_constraintGuide_end="@dimen/dialog_all_modal_horizontal_margin" /> + app:layout_constraintGuide_end="@dimen/dialog_my_group_modal_horizontal_margin" /> 24dp 34dp 24dp - 34dp + 26dp 24dp