diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a585db97c..692658615 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -107,6 +107,7 @@ dependencies { implementation(libs.transport.runtime) implementation(libs.activity) implementation(libs.fragment) + implementation(libs.androidx.activity) // Testing libraries testImplementation(libs.junit) @@ -178,6 +179,9 @@ dependencies { androidTestImplementation(libs.compose.bom) debugImplementation(libs.androidx.ui.test.manifest) + // navigation + implementation ("androidx.navigation:navigation-fragment:2.8.9") + implementation ("androidx.navigation:navigation-ui:2.8.9") } kapt { diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c6d1c24d2..4392c5aad 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -73,14 +73,14 @@ (ActivityMainBinding::inflate){ + + private val mainViewModel: MainViewModel by viewModels() + private val myPageViewModel: MyPageViewModel by viewModels() + + @RequiresApi(Build.VERSION_CODES.O) + @SuppressLint("SuspiciousIndentation") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + setupNoToolbar() + setNavigation() + + checkAlarmPermission() + checkNicknameIsNull() + + collectLogoutState() + } + + private fun setNavigation() { + val navHostFragment = supportFragmentManager + .findFragmentById(R.id.nav_host_fragment) as NavHostFragment + val navController = navHostFragment.navController + + binding.bottomNaviBar.setOnSingleItemSelectedListener { item -> + when (item.itemId) { + R.id.cafeteria_menu -> { + navController.navigate(R.id.homeFragment) + true + } + +// R.id.map_menu -> { +// navController.navigate(R.id.mapFragment) +// true +// } + + R.id.mypage_menu -> { + navController.navigate(R.id.myPageFragment) + true + } + + else -> { + false + } + } + } + } + + // set UI -- + private fun setupNoToolbar() { + // 툴바 사용하지 않도록 설정 + toolbar.let { + toolbar.visibility = View.GONE + toolbarTitle.visibility = View.GONE + setSupportActionBar(it) + supportActionBar?.setDisplayHomeAsUpEnabled(false) + supportActionBar?.setDisplayShowTitleEnabled(false) + } + } + + // Permission -- + // 권한 요청 결과 처리 + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults) + + val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()) + + if (requestCode == 1000) { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + // 권한이 승인됨 + showToast("EAT-SSU 알림 수신을 동의하였습니다.") + myPageViewModel.setNotificationOn() //바로 알림 받도록 설정 + } else { + // 권한이 거부됨 + showToast("EAT-SSU 알림 수신을 거부하였습니다.\n$dateFormat") + myPageViewModel.setNotificationOff() //바로 알림 받도록 설정 + } + } + } + + // 알림 퍼미션 있는지 자가 진단 + private fun checkAlarmPermission() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + if (ContextCompat.checkSelfPermission( + this, + Manifest.permission.POST_NOTIFICATIONS + ) != PackageManager.PERMISSION_GRANTED + ) { + // 권한이 없다면 요청 + ActivityCompat.requestPermissions( + this, + arrayOf(Manifest.permission.POST_NOTIFICATIONS), + 1000 + ) + } else { + // 권한이 이미 있어 + } + } + } + + // CollectState -- + private fun checkNicknameIsNull() { + Timber.d("관찰 시작") + mainViewModel.checkNameNull() + + lifecycleScope.launch { + mainViewModel.uiState.collectLatest { + if (it.isNicknameNull) { + //닉네임이 null일 때는 닉네임 설정을 안하면 서비스를 못쓰게 막아야함 + intent.putExtra("force", true) + startActivity() + showToast(it.toastMessage) + } else { + showToast(it.toastMessage) //Todo 이게 누구님 반갑습니다. 인데 두번 뜸 + } + } + } + } + + // 로그아웃 처리 + private fun collectLogoutState() { + lifecycleScope.launch { + mainViewModel.uiState.collectLatest { state -> + if (state.isLoggedOut) { + showToast(state.toastMessage) + startActivity() + finishAffinity() + } + } + } + } + + // 아래 함수를 View 에서는 사용이 어려워 util 로 빼지 않음 + private fun BottomNavigationView.setOnSingleItemSelectedListener( + minInterval: Long = 2000L, + onSingleItemSelected: (item: MenuItem) -> Boolean + ) { + var lastClickTime = 0L + + setOnItemSelectedListener { item -> + val currentClickTime = SystemClock.uptimeMillis() + if (currentClickTime - lastClickTime > minInterval) { + lastClickTime = currentClickTime + onSingleItemSelected(item) + } else { + false // 너무 빠른 클릭 무시 + } + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/main/MainViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/MainViewModel.kt similarity index 75% rename from app/src/main/java/com/eatssu/android/presentation/main/MainViewModel.kt rename to app/src/main/java/com/eatssu/android/presentation/MainViewModel.kt index 266448446..1988bd734 100644 --- a/app/src/main/java/com/eatssu/android/presentation/main/MainViewModel.kt +++ b/app/src/main/java/com/eatssu/android/presentation/MainViewModel.kt @@ -1,10 +1,14 @@ -package com.eatssu.android.presentation.main +package com.eatssu.android.presentation import android.content.Context +import android.util.Log +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.eatssu.android.R import com.eatssu.android.domain.usecase.auth.GetUserInfoUseCase +import com.eatssu.android.domain.usecase.auth.LogoutUseCase import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.flow.MutableStateFlow @@ -17,10 +21,12 @@ import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import timber.log.Timber +import java.time.LocalDate import javax.inject.Inject @HiltViewModel class MainViewModel @Inject constructor( + private val logoutUseCase: LogoutUseCase, private val getUserInfoUseCase: GetUserInfoUseCase, @ApplicationContext private val context: Context ) : ViewModel() { @@ -70,16 +76,40 @@ class MainViewModel @Inject constructor( } } } + } + + fun logOut() { + viewModelScope.launch { + logoutUseCase() //Todo 반환값이 쓰이는게 아니면 이렇게 해도 되나? + + _uiState.update { + it.copy( + toastMessage = context.getString(R.string.logout_description), + isLoggedOut = true + ) + } + } + } + private val data = MutableLiveData() + + fun setData(dataToSend: LocalDate) { + data.value = dataToSend + + Timber.d("setdata", dataToSend.toString()) + } + + fun getData(): LiveData { + return data } + } data class MainState( var loading: Boolean = true, var error: Boolean = false, - var toastMessage: String = "", - var isNicknameNull: Boolean = false, + var isLoggedOut: Boolean = false, ) \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/cafeteria/CafeteriaFragment.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/CafeteriaFragment.kt new file mode 100644 index 000000000..88f85cbf9 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/CafeteriaFragment.kt @@ -0,0 +1,98 @@ +package com.eatssu.android.presentation.cafeteria + +import android.os.Build +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.widget.TextView +import androidx.annotation.RequiresApi +import androidx.fragment.app.activityViewModels +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.viewpager2.widget.ViewPager2 +import com.eatssu.android.databinding.FragmentCafeteriaBinding +import com.eatssu.android.presentation.base.BaseFragment +import com.eatssu.android.presentation.MainViewModel +import com.eatssu.android.presentation.cafeteria.calendar.CalendarAdapter +import com.eatssu.android.presentation.cafeteria.calendar.CalendarAdapter.OnItemListener +import com.eatssu.android.presentation.util.CalendarUtil +import com.eatssu.android.presentation.util.CalendarUtil.daysInWeekArray +import com.eatssu.android.presentation.util.CalendarUtil.monthYearFromDate +import com.google.android.material.tabs.TabLayout +import com.google.android.material.tabs.TabLayoutMediator +import dagger.hilt.android.AndroidEntryPoint +import java.time.LocalDate + +@AndroidEntryPoint +class CafeteriaFragment : BaseFragment(), OnItemListener { + + private val mainViewModel by activityViewModels() + + private var monthYearText: TextView? = null + private var calendarRecyclerView: RecyclerView? = null + private var mainPosition: Int = -1 + + override fun setBinding(layoutInflater: LayoutInflater): FragmentCafeteriaBinding { + return FragmentCafeteriaBinding.inflate(layoutInflater) + } + + @RequiresApi(Build.VERSION_CODES.O) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val viewPager: ViewPager2 = binding.vpMain + val tabLayout: TabLayout = binding.tabLayout + + val viewpagerFragmentAdapter = CafeteriaViewPagerAdapter(requireActivity()) + viewPager.adapter = viewpagerFragmentAdapter + viewPager.setCurrentItem(viewpagerFragmentAdapter.getDefaultFragmentPosition(), false) + + val tabTitles = listOf("아침", "점심", "저녁") + TabLayoutMediator(tabLayout, viewPager) { tab, position -> tab.text = tabTitles[position] }.attach() + + initWidgets() + CalendarUtil.selectedDate = LocalDate.now() + mainViewModel.setData(CalendarUtil.selectedDate) + setWeekView() + setCalendarWeekClickListener() + } + + private fun initWidgets() { + calendarRecyclerView = binding.weekRecycler + monthYearText = binding.monthYearTV + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun setWeekView() { + monthYearText?.text = CalendarUtil.selectedDate?.let { monthYearFromDate(it) } + val days = CalendarUtil.selectedDate?.let { daysInWeekArray(it) } + val calendarAdapter = days?.let { CalendarAdapter(it, this) } + val gridLayoutManager = GridLayoutManager(requireContext(), 7) + + calendarRecyclerView?.layoutManager = gridLayoutManager + calendarRecyclerView?.adapter = calendarAdapter + } + + @RequiresApi(Build.VERSION_CODES.O) + fun setCalendarWeekClickListener() { + binding.btnPreviousWeek.setOnClickListener { + CalendarUtil.selectedDate = CalendarUtil.selectedDate.minusWeeks(1) + onItemClick(mainPosition, CalendarUtil.selectedDate) + setWeekView() + } + + binding.btnNextWeek.setOnClickListener { + CalendarUtil.selectedDate = CalendarUtil.selectedDate.plusWeeks(1) + onItemClick(mainPosition, CalendarUtil.selectedDate) + setWeekView() + } + } + + @RequiresApi(Build.VERSION_CODES.O) + override fun onItemClick(position: Int, date: LocalDate) { + CalendarUtil.selectedDate = date + mainViewModel.setData(date) + mainPosition = position + setWeekView() + } +} diff --git a/app/src/main/java/com/eatssu/android/presentation/main/ViewPager2Adapter.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/CafeteriaViewPagerAdapter.kt similarity index 89% rename from app/src/main/java/com/eatssu/android/presentation/main/ViewPager2Adapter.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/CafeteriaViewPagerAdapter.kt index 691b055cc..ef7279195 100644 --- a/app/src/main/java/com/eatssu/android/presentation/main/ViewPager2Adapter.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/CafeteriaViewPagerAdapter.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.main +package com.eatssu.android.presentation.cafeteria import android.os.Build import androidx.annotation.RequiresApi @@ -6,10 +6,10 @@ import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity import androidx.viewpager2.adapter.FragmentStateAdapter import com.eatssu.android.data.enums.Time -import com.eatssu.android.presentation.main.menu.MenuFragment +import com.eatssu.android.presentation.cafeteria.menu.MenuFragment import java.time.LocalTime -class ViewPager2Adapter(fragmentActivity: FragmentActivity) : +class CafeteriaViewPagerAdapter(fragmentActivity: FragmentActivity) : FragmentStateAdapter(fragmentActivity) { // 1. ViewPager2에 연결할 Fragment 들을 생성 diff --git a/app/src/main/java/com/eatssu/android/presentation/main/calendar/CalendarAdapter.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/calendar/CalendarAdapter.kt similarity index 97% rename from app/src/main/java/com/eatssu/android/presentation/main/calendar/CalendarAdapter.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/calendar/CalendarAdapter.kt index d1bff85ce..8e3c7a005 100644 --- a/app/src/main/java/com/eatssu/android/presentation/main/calendar/CalendarAdapter.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/calendar/CalendarAdapter.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.main.calendar +package com.eatssu.android.presentation.cafeteria.calendar import android.os.Build import android.view.LayoutInflater diff --git a/app/src/main/java/com/eatssu/android/presentation/main/calendar/CalendarViewHolder.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/calendar/CalendarViewHolder.kt similarity index 94% rename from app/src/main/java/com/eatssu/android/presentation/main/calendar/CalendarViewHolder.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/calendar/CalendarViewHolder.kt index 96efac8a6..e8985a03a 100644 --- a/app/src/main/java/com/eatssu/android/presentation/main/calendar/CalendarViewHolder.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/calendar/CalendarViewHolder.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.main.calendar +package com.eatssu.android.presentation.cafeteria.calendar import android.view.View import android.widget.TextView diff --git a/app/src/main/java/com/eatssu/android/presentation/info/InfoBottomSheetFragment.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/info/InfoBottomSheetFragment.kt similarity index 97% rename from app/src/main/java/com/eatssu/android/presentation/info/InfoBottomSheetFragment.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/info/InfoBottomSheetFragment.kt index 26aab87f0..e73a3c94e 100644 --- a/app/src/main/java/com/eatssu/android/presentation/info/InfoBottomSheetFragment.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/info/InfoBottomSheetFragment.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.info +package com.eatssu.android.presentation.cafeteria.info import android.os.Bundle import android.view.LayoutInflater diff --git a/app/src/main/java/com/eatssu/android/presentation/info/InfoViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/info/InfoViewModel.kt similarity index 95% rename from app/src/main/java/com/eatssu/android/presentation/info/InfoViewModel.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/info/InfoViewModel.kt index c71dded0c..64e1cc665 100644 --- a/app/src/main/java/com/eatssu/android/presentation/info/InfoViewModel.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/info/InfoViewModel.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.info +package com.eatssu.android.presentation.cafeteria.info import androidx.lifecycle.ViewModel import com.eatssu.android.data.enums.Restaurant diff --git a/app/src/main/java/com/eatssu/android/presentation/main/menu/MenuAdapter.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuAdapter.kt similarity index 94% rename from app/src/main/java/com/eatssu/android/presentation/main/menu/MenuAdapter.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuAdapter.kt index b7dc4cd55..0fa1932c6 100644 --- a/app/src/main/java/com/eatssu/android/presentation/main/menu/MenuAdapter.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuAdapter.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.main.menu +package com.eatssu.android.presentation.cafeteria.menu import android.util.Log import android.view.LayoutInflater @@ -10,7 +10,7 @@ import androidx.recyclerview.widget.RecyclerView import com.eatssu.android.R import com.eatssu.android.databinding.ItemCafeteriaSectionBinding import com.eatssu.android.domain.model.Section -import com.eatssu.android.presentation.info.InfoBottomSheetFragment +import com.eatssu.android.presentation.cafeteria.info.InfoBottomSheetFragment class MenuAdapter( private val fragmentManager: FragmentManager, diff --git a/app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuFragment.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuFragment.kt new file mode 100644 index 000000000..4d332664c --- /dev/null +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuFragment.kt @@ -0,0 +1,253 @@ +package com.eatssu.android.presentation.cafeteria.menu + +import android.os.Build +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.annotation.RequiresApi +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.recyclerview.widget.LinearLayoutManager +import com.eatssu.android.data.dto.response.mapFixedMenuResponseToMenu +import com.eatssu.android.data.dto.response.mapTodayMenuResponseToMenu +import com.eatssu.android.data.enums.MenuType +import com.eatssu.android.data.enums.Restaurant +import com.eatssu.android.data.enums.Time +import com.eatssu.android.databinding.FragmentMenuBinding +import com.eatssu.android.domain.model.Section +import com.eatssu.android.presentation.UiState +import com.eatssu.android.presentation.cafeteria.info.InfoViewModel +import com.eatssu.android.presentation.MainViewModel +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import java.time.DayOfWeek +import java.time.format.DateTimeFormatter + +@AndroidEntryPoint +class MenuFragment : Fragment() { + private var _binding: FragmentMenuBinding? = null + private val binding get() = _binding!! + + private val mainViewModel by activityViewModels() + private val infoViewModel by activityViewModels() + private val menuViewModel by viewModels() + + val foodCourtDataLoaded = MutableLiveData() + val snackCornerDataLoaded = MutableLiveData() + val haksikDataLoaded = MutableLiveData() + val dodamDataLoaded = MutableLiveData() + val dormitoryDataLoaded = MutableLiveData() + + private val totalMenuList = ArrayList
() + + companion object { + fun newInstance(time: Time): MenuFragment { + val fragment = MenuFragment() + val args = Bundle() + args.putSerializable("TIME", time) + fragment.arguments = args + return fragment + } + } + + private val time: Time + get() = arguments?.getSerializable("TIME") as Time //Todo deprecated + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + _binding = FragmentMenuBinding.inflate(inflater, container, false) + return binding.root + } + + @RequiresApi(Build.VERSION_CODES.O) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + // StateFlow 수집은 단 1번만 실행 + collectMealData() + collectFixedMenuData() + collectUiState() + + // 날짜 바뀔 때마다 ViewModel API 호출 + observeViewModel() + } + + @RequiresApi(Build.VERSION_CODES.O) + fun observeViewModel() { + mainViewModel.getData().observe(viewLifecycleOwner) { dataReceived -> + + val menuDate = dataReceived.format(DateTimeFormatter.ofPattern("yyyyMMdd")) + val dayOfWeek = dataReceived.dayOfWeek + + if (dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY && time == Time.LUNCH) { + menuViewModel.loadFixedMenu(Restaurant.FOOD_COURT) + menuViewModel.loadFixedMenu(Restaurant.SNACK_CORNER) + } else { + foodCourtDataLoaded.value = true + snackCornerDataLoaded.value = true + checkDataLoaded() + } + + if (time != Time.LUNCH) { + foodCourtDataLoaded.value = true + snackCornerDataLoaded.value = true + checkDataLoaded() + } + + menuViewModel.loadTodayMeal(menuDate, Restaurant.HAKSIK, time) + menuViewModel.loadTodayMeal(menuDate, Restaurant.DODAM, time) + menuViewModel.loadTodayMeal(menuDate, Restaurant.DORMITORY, time) + } + } + + private fun collectMealData() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + menuViewModel.todayMealDataHaksik.collect { result -> + totalMenuList.removeAll { it.cafeteria == Restaurant.HAKSIK } + if (result.isNotEmpty()) { + totalMenuList.add( + Section(MenuType.VARIABLE, Restaurant.HAKSIK, + result.mapTodayMenuResponseToMenu(), + infoViewModel.getRestaurantInfo(Restaurant.HAKSIK)?.location ?: "" + ) + ) + } + haksikDataLoaded.value = true + checkDataLoaded() + } + } + } + + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + menuViewModel.todayMealDataDodam.collect { result -> + totalMenuList.removeAll { it.cafeteria == Restaurant.DODAM } + if (result.isNotEmpty()) { + totalMenuList.add( + Section(MenuType.VARIABLE, Restaurant.DODAM, + result.mapTodayMenuResponseToMenu(), + infoViewModel.getRestaurantInfo(Restaurant.DODAM)?.location ?: "" + ) + ) + } + dodamDataLoaded.value = true + checkDataLoaded() + } + } + } + + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + menuViewModel.todayMealDataDormitory.collect { result -> + totalMenuList.removeAll { it.cafeteria == Restaurant.DORMITORY } + if (result.isNotEmpty()) { + totalMenuList.add( + Section(MenuType.VARIABLE, Restaurant.DORMITORY, + result.mapTodayMenuResponseToMenu(), + infoViewModel.getRestaurantInfo(Restaurant.DORMITORY)?.location ?: "" + ) + ) + } + dormitoryDataLoaded.value = true + checkDataLoaded() + } + } + } + } + + private fun collectFixedMenuData() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + menuViewModel.fixedMenuDataFood.collect { result -> + totalMenuList.removeAll { it.cafeteria == Restaurant.FOOD_COURT } + if (result.mapFixedMenuResponseToMenu().isNotEmpty()) { + totalMenuList.add( + Section(MenuType.FIXED, Restaurant.FOOD_COURT, + result.mapFixedMenuResponseToMenu(), + infoViewModel.getRestaurantInfo(Restaurant.FOOD_COURT)?.location ?: "" + ) + ) + } + foodCourtDataLoaded.value = true + checkDataLoaded() + } + } + } + + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + menuViewModel.fixedMenuDataSnack.collect { result -> + totalMenuList.removeAll { it.cafeteria == Restaurant.SNACK_CORNER } + if (result.mapFixedMenuResponseToMenu().isNotEmpty()) { + totalMenuList.add( + Section(MenuType.FIXED, Restaurant.SNACK_CORNER, + result.mapFixedMenuResponseToMenu(), + infoViewModel.getRestaurantInfo(Restaurant.SNACK_CORNER)?.location ?: "" + ) + ) + } + snackCornerDataLoaded.value = true + checkDataLoaded() + } + } + } + } + + private fun setupTodayRecyclerView() { + binding.rv.apply { + setHasFixedSize(true) + layoutManager = LinearLayoutManager(context) + adapter = fragmentManager?.let { MenuAdapter(it, totalMenuList) } + } + } + + private fun checkDataLoaded() { + if (foodCourtDataLoaded.value == true && + snackCornerDataLoaded.value == true && + haksikDataLoaded.value == true && + dodamDataLoaded.value == true && + dormitoryDataLoaded.value == true + ) { + totalMenuList.sortBy { it.cafeteria.ordinal } + setupTodayRecyclerView() + } + } + + private fun collectUiState() { + lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + menuViewModel.uiState.collect { state -> + when (state) { + is UiState.Init -> { + // init + } + is UiState.Loading -> { + // Loading + } + is UiState.Success -> { + // Success + } + is UiState.Error -> { + // Error + } + } + } + } + } + } + + override fun onDestroyView() { + super.onDestroyView() + _binding = null + } +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/main/menu/MenuSubAdapter.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuSubAdapter.kt similarity index 95% rename from app/src/main/java/com/eatssu/android/presentation/main/menu/MenuSubAdapter.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuSubAdapter.kt index c211f40ba..72984efd5 100644 --- a/app/src/main/java/com/eatssu/android/presentation/main/menu/MenuSubAdapter.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuSubAdapter.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.main.menu +package com.eatssu.android.presentation.cafeteria.menu import android.content.Intent import android.util.Log @@ -9,7 +9,7 @@ import androidx.recyclerview.widget.RecyclerView import com.eatssu.android.data.enums.MenuType import com.eatssu.android.databinding.ItemMenuBinding import com.eatssu.android.domain.model.Menu -import com.eatssu.android.presentation.review.list.ReviewActivity +import com.eatssu.android.presentation.cafeteria.review.list.ReviewActivity class MenuSubAdapter( diff --git a/app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuViewModel.kt new file mode 100644 index 000000000..b30a717ac --- /dev/null +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/menu/MenuViewModel.kt @@ -0,0 +1,154 @@ +package com.eatssu.android.presentation.cafeteria.menu + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.eatssu.android.data.dto.response.BaseResponse +import com.eatssu.android.data.dto.response.GetFixedMenuResponse +import com.eatssu.android.data.dto.response.GetMealResponse +import com.eatssu.android.data.enums.Restaurant +import com.eatssu.android.data.enums.Time +import com.eatssu.android.data.service.MealService +import com.eatssu.android.data.service.MenuService +import com.eatssu.android.domain.model.MenuMini +import com.eatssu.android.presentation.UiState +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 retrofit2.Call +import retrofit2.Callback +import retrofit2.Response +import timber.log.Timber +import javax.inject.Inject + +@HiltViewModel +class MenuViewModel @Inject constructor( + private val menuService: MenuService, + private val mealService: MealService, +) :ViewModel() { + + private val _todayMealDataDodam = MutableStateFlow>(arrayListOf()) + val todayMealDataDodam: StateFlow> = _todayMealDataDodam + + private val _todayMealDataHaksik = MutableStateFlow>(arrayListOf()) + val todayMealDataHaksik: StateFlow> = _todayMealDataHaksik + + private val _todayMealDataDormitory = + MutableStateFlow>(arrayListOf()) + val todayMealDataDormitory: StateFlow> = _todayMealDataDormitory + + private val _fixedMenuDataSnack = + MutableStateFlow(GetFixedMenuResponse(arrayListOf())) + val fixedMenuDataSnack: StateFlow = _fixedMenuDataSnack + + private val _fixedMenuDataKitchen = + MutableStateFlow(GetFixedMenuResponse(arrayListOf())) + val fixedMenuDataKitchen: StateFlow = _fixedMenuDataKitchen + + private val _fixedMenuDataFood = + MutableStateFlow(GetFixedMenuResponse(arrayListOf())) + val fixedMenuDataFood: StateFlow = _fixedMenuDataFood + + private val _uiState: MutableStateFlow> = MutableStateFlow(UiState.Init) + val uiState: StateFlow> = _uiState.asStateFlow() + + + fun loadTodayMeal( + menuDate: String, + restaurantType: Restaurant, + time: Time, + ) { + _uiState.value = UiState.Loading + Timber.d("Debug", "loadTodayMeal called with type: $restaurantType") + + viewModelScope.launch { + mealService.getTodayMeal(menuDate, restaurantType.toString(), time.toString()) + .enqueue(object : Callback>> { + override fun onResponse( + call: Call>>, + response: Response>>, + ) { + val restaurantMenuData = response.body()?.result ?: arrayListOf() + + if (response.isSuccessful) { + Timber.d("onResponse 성공" + response.body()) + + when (restaurantType) { + Restaurant.HAKSIK -> _todayMealDataHaksik.value = restaurantMenuData + Restaurant.DODAM -> _todayMealDataDodam.value = restaurantMenuData + Restaurant.DORMITORY -> _todayMealDataDormitory.value = restaurantMenuData + else -> Timber.d("onResponse 실패. 잘못된 식당입니다.") + } + _uiState.value = UiState.Success(MenuState()) + + } else { + Timber.d("onResponse 실패 투데이밀" + response.code() + response.message()) + _uiState.value = UiState.Error + } + } + + override fun onFailure( + call: Call>>, + t: Throwable, + ) { + Timber.d("onFailure 에러: 나다${t.message}+ ${call}" + "ddd") + _uiState.value = UiState.Error + } + }) + } + } + + // Fixed Menu 데이터 로드도 유사한 방식으로 구현 + fun loadFixedMenu(restaurantType: Restaurant) { + Timber.d("Debug", "loadFixedMenu called with type: $restaurantType") + + _uiState.value = UiState.Loading + + viewModelScope.launch { + menuService.getFixMenu(restaurantType.toString()) + .enqueue(object : Callback> { + override fun onResponse( + call: Call>, + response: Response>, + ) { + if (response.isSuccessful) { + Timber.d("onResponse 성공" + response.body()) + val data = + response.body()?.result ?: GetFixedMenuResponse(arrayListOf()) + when (restaurantType) { + Restaurant.THE_KITCHEN -> _fixedMenuDataKitchen.value = data + Restaurant.FOOD_COURT -> _fixedMenuDataFood.value = data + Restaurant.SNACK_CORNER -> _fixedMenuDataSnack.value = data + + else -> { + Timber.d("onResponse 실패. 잘못된 식당 입니다.") + } + } + _uiState.value = UiState.Success(MenuState()) + } else { + Timber.d("onResponse 실패") + _uiState.value = UiState.Error + } + } + + override fun onFailure( + call: Call>, + t: Throwable, + ) { + Timber.d("onFailure 에러: ${t.message}") + _uiState.value = UiState.Error + } + }) + } + } +} + +data class MenuState( + var haksikMeal: ArrayList? = null, + var dodamMeal: ArrayList? = null, + var dormitoryMeal: ArrayList? = null, + var snackMenu: GetFixedMenuResponse? = null, + var foodcourtMenu: GetFixedMenuResponse? = null, + var menuOfMeal: List? = null, +) \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewActivity.kt similarity index 96% rename from app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewActivity.kt index 428c66e21..b028a0960 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewActivity.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.review.list +package com.eatssu.android.presentation.cafeteria.review.list import android.content.Intent import android.os.Bundle @@ -14,8 +14,8 @@ import com.eatssu.android.domain.model.Review import com.eatssu.android.presentation.base.BaseActivity import com.eatssu.android.presentation.common.MyReviewBottomSheetFragment import com.eatssu.android.presentation.common.OthersBottomSheetFragment -import com.eatssu.android.presentation.review.write.ReviewWriteRateActivity -import com.eatssu.android.presentation.review.write.menu.ReviewWriteMenuActivity +import com.eatssu.android.presentation.cafeteria.review.write.ReviewWriteRateActivity +import com.eatssu.android.presentation.cafeteria.review.write.menu.ReviewWriteMenuActivity import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewAdapter.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewAdapter.kt similarity index 98% rename from app/src/main/java/com/eatssu/android/presentation/review/list/ReviewAdapter.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewAdapter.kt index f6948f8ad..0f904f401 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewAdapter.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewAdapter.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.review.list +package com.eatssu.android.presentation.cafeteria.review.list import android.view.LayoutInflater import android.view.View diff --git a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewViewModel.kt similarity index 99% rename from app/src/main/java/com/eatssu/android/presentation/review/list/ReviewViewModel.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewViewModel.kt index 86e423624..01e136aea 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/list/ReviewViewModel.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/list/ReviewViewModel.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.review.list +package com.eatssu.android.presentation.cafeteria.review.list import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope diff --git a/app/src/main/java/com/eatssu/android/presentation/review/modify/ModifyReviewActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/modify/ModifyReviewActivity.kt similarity index 97% rename from app/src/main/java/com/eatssu/android/presentation/review/modify/ModifyReviewActivity.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/review/modify/ModifyReviewActivity.kt index 127214d8c..521c38a00 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/modify/ModifyReviewActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/modify/ModifyReviewActivity.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.review.modify +package com.eatssu.android.presentation.cafeteria.review.modify import android.os.Bundle import androidx.activity.viewModels diff --git a/app/src/main/java/com/eatssu/android/presentation/review/modify/ModifyViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/modify/ModifyViewModel.kt similarity index 97% rename from app/src/main/java/com/eatssu/android/presentation/review/modify/ModifyViewModel.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/review/modify/ModifyViewModel.kt index 3861fafa8..04c3a85f0 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/modify/ModifyViewModel.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/modify/ModifyViewModel.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.review.modify +package com.eatssu.android.presentation.cafeteria.review.modify import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope diff --git a/app/src/main/java/com/eatssu/android/presentation/review/report/ReportActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/report/ReportActivity.kt similarity index 97% rename from app/src/main/java/com/eatssu/android/presentation/review/report/ReportActivity.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/review/report/ReportActivity.kt index 27f4e30d1..7c3c97396 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/report/ReportActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/report/ReportActivity.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.review.report +package com.eatssu.android.presentation.cafeteria.review.report import android.os.Bundle import android.text.Editable diff --git a/app/src/main/java/com/eatssu/android/presentation/review/report/ReportViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/report/ReportViewModel.kt similarity index 96% rename from app/src/main/java/com/eatssu/android/presentation/review/report/ReportViewModel.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/review/report/ReportViewModel.kt index 1e98e91e8..ca60a399d 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/report/ReportViewModel.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/report/ReportViewModel.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.review.report +package com.eatssu.android.presentation.cafeteria.review.report import android.util.Log import androidx.lifecycle.ViewModel diff --git a/app/src/main/java/com/eatssu/android/presentation/review/write/ImageViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/ImageViewModel.kt similarity index 98% rename from app/src/main/java/com/eatssu/android/presentation/review/write/ImageViewModel.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/ImageViewModel.kt index c485934c3..f5878bc18 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/write/ImageViewModel.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/ImageViewModel.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.review.write +package com.eatssu.android.presentation.cafeteria.review.write import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope diff --git a/app/src/main/java/com/eatssu/android/presentation/review/write/ReviewWriteRateActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/ReviewWriteRateActivity.kt similarity index 99% rename from app/src/main/java/com/eatssu/android/presentation/review/write/ReviewWriteRateActivity.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/ReviewWriteRateActivity.kt index e310528f7..ad64bcfac 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/write/ReviewWriteRateActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/ReviewWriteRateActivity.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.review.write +package com.eatssu.android.presentation.cafeteria.review.write import android.Manifest import android.content.Intent diff --git a/app/src/main/java/com/eatssu/android/presentation/review/write/ReviewWriteViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/ReviewWriteViewModel.kt similarity index 97% rename from app/src/main/java/com/eatssu/android/presentation/review/write/ReviewWriteViewModel.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/ReviewWriteViewModel.kt index 0438797e1..b013b6394 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/write/ReviewWriteViewModel.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/ReviewWriteViewModel.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.review.write +package com.eatssu.android.presentation.cafeteria.review.write import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope diff --git a/app/src/main/java/com/eatssu/android/presentation/review/write/menu/ReviewWriteMenuActivity.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/menu/ReviewWriteMenuActivity.kt similarity index 95% rename from app/src/main/java/com/eatssu/android/presentation/review/write/menu/ReviewWriteMenuActivity.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/menu/ReviewWriteMenuActivity.kt index b6e305da3..f400b8ff5 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/write/menu/ReviewWriteMenuActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/menu/ReviewWriteMenuActivity.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.review.write.menu +package com.eatssu.android.presentation.cafeteria.review.write.menu import android.content.Intent import android.os.Build @@ -9,7 +9,7 @@ import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import com.eatssu.android.databinding.ActivityReviewWriteMenuBinding import com.eatssu.android.presentation.base.BaseActivity -import com.eatssu.android.presentation.review.write.ReviewWriteRateActivity +import com.eatssu.android.presentation.cafeteria.review.write.ReviewWriteRateActivity import dagger.hilt.android.AndroidEntryPoint import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch diff --git a/app/src/main/java/com/eatssu/android/presentation/review/write/menu/VariableMenuPickAdapter.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/menu/VariableMenuPickAdapter.kt similarity index 96% rename from app/src/main/java/com/eatssu/android/presentation/review/write/menu/VariableMenuPickAdapter.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/menu/VariableMenuPickAdapter.kt index e10b2b307..6dec55316 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/write/menu/VariableMenuPickAdapter.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/menu/VariableMenuPickAdapter.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.review.write.menu +package com.eatssu.android.presentation.cafeteria.review.write.menu import android.view.LayoutInflater import android.view.ViewGroup diff --git a/app/src/main/java/com/eatssu/android/presentation/review/write/menu/VariableMenuViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/menu/VariableMenuViewModel.kt similarity index 97% rename from app/src/main/java/com/eatssu/android/presentation/review/write/menu/VariableMenuViewModel.kt rename to app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/menu/VariableMenuViewModel.kt index 516cdb10e..751523ce7 100644 --- a/app/src/main/java/com/eatssu/android/presentation/review/write/menu/VariableMenuViewModel.kt +++ b/app/src/main/java/com/eatssu/android/presentation/cafeteria/review/write/menu/VariableMenuViewModel.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.review.write.menu +package com.eatssu.android.presentation.cafeteria.review.write.menu import androidx.lifecycle.ViewModel diff --git a/app/src/main/java/com/eatssu/android/presentation/common/MyReviewBottomSheetFragment.kt b/app/src/main/java/com/eatssu/android/presentation/common/MyReviewBottomSheetFragment.kt index 2026f72a0..2d4220c59 100644 --- a/app/src/main/java/com/eatssu/android/presentation/common/MyReviewBottomSheetFragment.kt +++ b/app/src/main/java/com/eatssu/android/presentation/common/MyReviewBottomSheetFragment.kt @@ -12,7 +12,7 @@ import com.eatssu.android.App import com.eatssu.android.R import com.eatssu.android.databinding.FragmentBottomsheetMyReviewBinding import com.eatssu.android.presentation.mypage.myreview.MyReviewViewModel -import com.eatssu.android.presentation.review.modify.ModifyReviewActivity +import com.eatssu.android.presentation.cafeteria.review.modify.ModifyReviewActivity import com.eatssu.android.presentation.util.showToast import com.google.android.material.bottomsheet.BottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint diff --git a/app/src/main/java/com/eatssu/android/presentation/common/OthersBottomSheetFragment.kt b/app/src/main/java/com/eatssu/android/presentation/common/OthersBottomSheetFragment.kt index b117e81b5..501482877 100644 --- a/app/src/main/java/com/eatssu/android/presentation/common/OthersBottomSheetFragment.kt +++ b/app/src/main/java/com/eatssu/android/presentation/common/OthersBottomSheetFragment.kt @@ -6,7 +6,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import com.eatssu.android.databinding.FragmentBottomsheetOthersBinding -import com.eatssu.android.presentation.review.report.ReportActivity +import com.eatssu.android.presentation.cafeteria.review.report.ReportActivity import com.google.android.material.bottomsheet.BottomSheetDialogFragment import dagger.hilt.android.AndroidEntryPoint import timber.log.Timber diff --git a/app/src/main/java/com/eatssu/android/presentation/login/IntroActivity.kt b/app/src/main/java/com/eatssu/android/presentation/login/IntroActivity.kt index 9ad17a90b..d3b38585d 100644 --- a/app/src/main/java/com/eatssu/android/presentation/login/IntroActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/login/IntroActivity.kt @@ -7,7 +7,7 @@ import androidx.lifecycle.lifecycleScope import com.eatssu.android.databinding.ActivityIntroBinding import com.eatssu.android.presentation.UiEvent import com.eatssu.android.presentation.UiState -import com.eatssu.android.presentation.main.MainActivity +import com.eatssu.android.presentation.MainActivity import com.eatssu.android.presentation.util.showToast import com.eatssu.android.presentation.util.startActivity import dagger.hilt.android.AndroidEntryPoint diff --git a/app/src/main/java/com/eatssu/android/presentation/login/LoginActivity.kt b/app/src/main/java/com/eatssu/android/presentation/login/LoginActivity.kt index 323649261..5a7745365 100644 --- a/app/src/main/java/com/eatssu/android/presentation/login/LoginActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/login/LoginActivity.kt @@ -11,7 +11,7 @@ import com.eatssu.android.databinding.ActivityLoginBinding import com.eatssu.android.presentation.UiEvent import com.eatssu.android.presentation.UiState import com.eatssu.android.presentation.base.BaseActivity -import com.eatssu.android.presentation.main.MainActivity +import com.eatssu.android.presentation.MainActivity import com.eatssu.android.presentation.util.showToast import com.eatssu.android.presentation.util.startActivity import com.kakao.sdk.common.model.ClientError diff --git a/app/src/main/java/com/eatssu/android/presentation/main/MainActivity.kt b/app/src/main/java/com/eatssu/android/presentation/main/MainActivity.kt deleted file mode 100644 index ce8a22824..000000000 --- a/app/src/main/java/com/eatssu/android/presentation/main/MainActivity.kt +++ /dev/null @@ -1,241 +0,0 @@ -package com.eatssu.android.presentation.main - -import android.annotation.SuppressLint -import android.content.Intent -import android.content.pm.PackageManager -import android.os.Build -import android.os.Bundle -import android.view.Menu -import android.view.MenuItem -import android.view.View -import android.widget.TextView -import androidx.activity.viewModels -import androidx.annotation.RequiresApi -import androidx.core.app.ActivityCompat -import androidx.core.content.ContextCompat -import androidx.lifecycle.ViewModelProvider -import androidx.lifecycle.lifecycleScope -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.RecyclerView -import androidx.viewpager2.widget.ViewPager2 -import com.eatssu.android.R -import com.eatssu.android.databinding.ActivityMainBinding -import com.eatssu.android.presentation.base.BaseActivity -import com.eatssu.android.presentation.main.calendar.CalendarAdapter -import com.eatssu.android.presentation.main.calendar.CalendarAdapter.OnItemListener -import com.eatssu.android.presentation.main.calendar.CalendarViewModel -import com.eatssu.android.presentation.mypage.MyPageActivity -import com.eatssu.android.presentation.mypage.MyPageViewModel -import com.eatssu.android.presentation.mypage.usernamechange.UserNameChangeActivity -import com.eatssu.android.presentation.util.CalendarUtil -import com.eatssu.android.presentation.util.CalendarUtil.daysInWeekArray -import com.eatssu.android.presentation.util.CalendarUtil.monthYearFromDate -import com.eatssu.android.presentation.util.showToast -import com.eatssu.android.presentation.util.startActivity -import com.google.android.material.tabs.TabLayout -import com.google.android.material.tabs.TabLayoutMediator -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch -import timber.log.Timber -import java.text.SimpleDateFormat -import java.time.LocalDate -import java.util.Locale - -@AndroidEntryPoint -class MainActivity : BaseActivity(ActivityMainBinding::inflate), OnItemListener { - - private val mainViewModel: MainViewModel by viewModels() - private val myPageViewModel: MyPageViewModel by viewModels() - - - private lateinit var calendarViewModel: CalendarViewModel - - private var monthYearText: TextView? = null - private var calendarRecyclerView: RecyclerView? = null - - private var mainPosition: Int = -1 - - @RequiresApi(Build.VERSION_CODES.O) - @SuppressLint("SuspiciousIndentation") - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - - setupNoToolbar() - - // 알림 퍼미션 있는지 자가 진단 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - if (ContextCompat.checkSelfPermission( - this, - android.Manifest.permission.POST_NOTIFICATIONS - ) != PackageManager.PERMISSION_GRANTED - ) { - // 권한이 없다면 요청 - ActivityCompat.requestPermissions( - this, - arrayOf(android.Manifest.permission.POST_NOTIFICATIONS), - 1000 - ) - } else { - // 권한이 이미 있어 - } - } - - checkNicknameIsNull() - - // 1) ViewPager2 참조 - val viewPager: ViewPager2 = binding.vpMain - val tabLayout: TabLayout = binding.tabLayout - - // 2) FragmentStateAdapter 생성 : Fragment 여러개를 ViewPager2에 연결해주는 역할 - val viewpagerFragmentAdapter = ViewPager2Adapter(this) - - // 3) ViewPager2의 adapter에 설정 - viewPager.adapter = viewpagerFragmentAdapter - viewPager.setCurrentItem(viewpagerFragmentAdapter.getDefaultFragmentPosition(), false) - - // ###### TabLayout과 ViewPager2를 연결 - // 1. 탭메뉴의 이름을 리스트로 생성해둔다. - val tabTitles = listOf("아침", "점심", "저녁") - - // 2. TabLayout과 ViewPager2를 연결하고, TabItem의 메뉴명을 설정한다. - TabLayoutMediator(tabLayout, viewPager) { tab, position -> tab.text = tabTitles[position] }.attach() - - binding.btnSetting.setOnClickListener { - startActivity(); - } - - initWidgets() - CalendarUtil.selectedDate = LocalDate.now() - calendarViewModel.setData(LocalDate.now()) - setWeekView() - } - - private fun initWidgets() { - calendarRecyclerView = binding.weekRecycler - monthYearText = binding.monthYearTV - calendarViewModel = ViewModelProvider(this)[CalendarViewModel::class.java] - } - - @RequiresApi(Build.VERSION_CODES.O) - private fun setWeekView() { - monthYearText?.setText(CalendarUtil.selectedDate?.let { monthYearFromDate(it) }) - val days: ArrayList? = CalendarUtil.selectedDate?.let { daysInWeekArray(it) } - val calendarAdapter = days?.let { CalendarAdapter(it, this) } - val gridLayoutManager = GridLayoutManager(applicationContext, 7) - - calendarRecyclerView!!.layoutManager = gridLayoutManager - calendarRecyclerView!!.adapter = calendarAdapter - } - - @RequiresApi(Build.VERSION_CODES.O) - fun previousWeekAction(view: View?) { - CalendarUtil.selectedDate = CalendarUtil.selectedDate.minusWeeks(1) - onItemClick(mainPosition, CalendarUtil.selectedDate) - setWeekView() - } - - @RequiresApi(Build.VERSION_CODES.O) - fun nextWeekAction(view: View?) { - CalendarUtil.selectedDate = CalendarUtil.selectedDate.plusWeeks(1) - onItemClick(mainPosition, CalendarUtil.selectedDate) - setWeekView() - } - - @RequiresApi(Build.VERSION_CODES.O) - override fun onItemClick(position: Int, date: LocalDate) { - CalendarUtil.selectedDate = date - calendarViewModel.setData(date) - mainPosition = position - - val viewPager: ViewPager2 = binding.vpMain - val tabLayout: TabLayout = binding.tabLayout - - val viewpagerFragmentAdapter = ViewPager2Adapter(this) - - viewPager.adapter = viewpagerFragmentAdapter - viewPager.setCurrentItem(viewpagerFragmentAdapter.getDefaultFragmentPosition(), false) - - val tabTitles = listOf("아침", "점심", "저녁") - - TabLayoutMediator(tabLayout, viewPager) { tab, position -> tab.text = tabTitles[position] }.attach() - - binding.btnSetting.setOnClickListener { - startActivity() - } - - initWidgets() - setWeekView() - } - - private fun setupNoToolbar() { - // 툴바 사용하지 않도록 설정 - toolbar.let { - toolbar.visibility = View.GONE - toolbarTitle.visibility = View.GONE - setSupportActionBar(it) - supportActionBar?.setDisplayHomeAsUpEnabled(false) - supportActionBar?.setDisplayShowTitleEnabled(false) - } - } - - - private fun checkNicknameIsNull() { - Timber.d("관찰 시작") - mainViewModel.checkNameNull() - - lifecycleScope.launch { - mainViewModel.uiState.collectLatest { - if (it.isNicknameNull) { - //닉네임이 null일 때는 닉네임 설정을 안하면 서비스를 못쓰게 막아야함 - intent.putExtra("force", true) - startActivity() - showToast(it.toastMessage) - } else { - showToast(it.toastMessage) //Todo 이게 누구님 반갑습니다. 인데 두번 뜸 - } - } - } - } - - - override fun onCreateOptionsMenu(menu: Menu?): Boolean { - menuInflater.inflate(R.menu.menu_main, menu) - return true - } - - override fun onOptionsItemSelected(item: MenuItem): Boolean { - return when (item.itemId) { - R.id.action_setting -> { - val intent = Intent(this, MyPageActivity::class.java) // 인텐트를 생성해줌, - startActivity(intent) // 화면 전환을 시켜줌 - true - } - - else -> super.onOptionsItemSelected(item) - } - } - - // 권한 요청 결과 처리 - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray - ) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - - val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.getDefault()) - - if (requestCode == 1000) { - if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { - // 권한이 승인됨 - showToast("EAT-SSU 알림 수신을 동의하였습니다.") - myPageViewModel.setNotificationOn() //바로 알림 받도록 설정 - } else { - // 권한이 거부됨 - showToast("EAT-SSU 알림 수신을 거부하였습니다.\n$dateFormat") - myPageViewModel.setNotificationOff() //바로 알림 받도록 설정 - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/main/calendar/CalendarViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/main/calendar/CalendarViewModel.kt deleted file mode 100644 index 6d6b910a3..000000000 --- a/app/src/main/java/com/eatssu/android/presentation/main/calendar/CalendarViewModel.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.eatssu.android.presentation.main.calendar - -import android.util.Log -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import java.time.LocalDate - -class CalendarViewModel : ViewModel() { - private val data = MutableLiveData() - - fun setData(dataToSend: LocalDate) { - data.value = dataToSend - - Log.d("setdata", dataToSend.toString()) - } - - fun getData(): LiveData { - return data - } -} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/main/menu/MenuFragment.kt b/app/src/main/java/com/eatssu/android/presentation/main/menu/MenuFragment.kt deleted file mode 100644 index b23a64666..000000000 --- a/app/src/main/java/com/eatssu/android/presentation/main/menu/MenuFragment.kt +++ /dev/null @@ -1,250 +0,0 @@ -package com.eatssu.android.presentation.main.menu - -import android.os.Build -import android.os.Bundle -import android.util.Log -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import androidx.annotation.RequiresApi -import androidx.fragment.app.Fragment -import androidx.fragment.app.activityViewModels -import androidx.fragment.app.viewModels -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModelProvider -import androidx.recyclerview.widget.LinearLayoutManager -import com.eatssu.android.data.dto.response.mapFixedMenuResponseToMenu -import com.eatssu.android.data.dto.response.mapTodayMenuResponseToMenu -import com.eatssu.android.data.enums.MenuType -import com.eatssu.android.data.enums.Restaurant -import com.eatssu.android.data.enums.Time -import com.eatssu.android.data.service.MealService -import com.eatssu.android.data.service.MenuService -import com.eatssu.android.databinding.FragmentMenuBinding -import com.eatssu.android.domain.model.Section -import com.eatssu.android.presentation.info.InfoViewModel -import com.eatssu.android.presentation.main.calendar.CalendarViewModel -import dagger.hilt.android.AndroidEntryPoint -import java.time.DayOfWeek -import java.time.LocalDate -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter - -@AndroidEntryPoint -class MenuFragment : Fragment() { - private var _binding: FragmentMenuBinding? = null - private val binding get() = _binding!! - - private lateinit var calendarViewModel: CalendarViewModel - private val menuViewModel: MenuViewModel by viewModels() - - private lateinit var menuDate: String - private lateinit var cafeteriaLocation: String - - val foodCourtDataLoaded = MutableLiveData() - val snackCornerDataLoaded = MutableLiveData() - val haksikDataLoaded = MutableLiveData() - val dodamDataLoaded = MutableLiveData() - val dormitoryDataLoaded = MutableLiveData() - - private val totalMenuList = ArrayList
() - - private lateinit var restaurantType: Restaurant - - private val infoViewModel: InfoViewModel by activityViewModels() - - - companion object { - fun newInstance(time: Time): MenuFragment { - val fragment = MenuFragment() - val args = Bundle() - args.putSerializable("TIME", time) - fragment.arguments = args - return fragment - } - } - - private val time: Time - get() = arguments?.getSerializable("TIME") as Time //Todo deprecated - - override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle?, - ): View { - _binding = FragmentMenuBinding.inflate(inflater, container, false) - return binding.root - } - - @RequiresApi(Build.VERSION_CODES.O) - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - observeViewModel() - } - - @RequiresApi(Build.VERSION_CODES.O) - fun observeViewModel() { - - val calendardate = this.arguments?.getString("calendardata") - Log.d("lunchdate", "$calendardate") - - // ViewModel에서 데이터 가져오기 - calendarViewModel = ViewModelProvider(requireActivity())[CalendarViewModel::class.java] - retainInstance = true - - val dayFormat = DateTimeFormatter.ofPattern("dd") - val todayDate = LocalDateTime.now().format(dayFormat) - - // ViewModel에서 데이터 가져오기 - calendarViewModel.getData().observe(viewLifecycleOwner) { dataReceived -> - - val parsedDate = - LocalDate.parse(dataReceived.toString(), DateTimeFormatter.ofPattern("yyyy-MM-dd")) - menuDate = parsedDate.format(DateTimeFormatter.ofPattern("yyyyMMdd")) - - // Assuming menuDate is a String in the format "yyyyMMdd" - val formattedDate = LocalDate.parse(menuDate, DateTimeFormatter.BASIC_ISO_DATE) - - val dayOfWeek = formattedDate.dayOfWeek - Log.d("menudate", menuDate) - - if (dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY && time == Time.LUNCH) { - // The date is not on a weekend - //푸드코트 - menuViewModel.loadFixedMenu(Restaurant.FOOD_COURT) - menuViewModel.fixedMenuDataFood.observe(viewLifecycleOwner) { result -> - if (result.mapFixedMenuResponseToMenu().isNotEmpty()) { - Log.d("menu", result.categoryMenuListCollection.toString()) - totalMenuList.add( - Section( - MenuType.FIXED, - Restaurant.FOOD_COURT, - result.mapFixedMenuResponseToMenu(), - infoViewModel.getRestaurantInfo(Restaurant.FOOD_COURT)?.location - ?: "" - ) - ) - } - foodCourtDataLoaded.value = true - checkDataLoaded() -// - } - - //스낵코너 - menuViewModel.loadFixedMenu(Restaurant.SNACK_CORNER) - menuViewModel.fixedMenuDataSnack.observe(viewLifecycleOwner) { result -> - if (result.mapFixedMenuResponseToMenu().isNotEmpty()) { - totalMenuList.add( - Section( - MenuType.FIXED, - Restaurant.SNACK_CORNER, - result.mapFixedMenuResponseToMenu(), - infoViewModel.getRestaurantInfo(Restaurant.SNACK_CORNER)?.location - ?: "" - ) - ) - } - snackCornerDataLoaded.value = true - checkDataLoaded() - } - - Log.d("MenuFragment", "The date $menuDate is not on a weekend.") - } - - if ((dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY)) { - // The date is not on a weekend - foodCourtDataLoaded.value = true //푸드코트 - snackCornerDataLoaded.value = true //스낵코너 - checkDataLoaded() - Log.d("MenuFragment", "The date $menuDate is not on a weekend.") - } - - if (time != Time.LUNCH) { - foodCourtDataLoaded.value = true //푸드코트 - snackCornerDataLoaded.value = true //스낵코너 - checkDataLoaded() - } - - - //학생식당 - menuViewModel.loadTodayMeal(menuDate, Restaurant.HAKSIK, time) - menuViewModel.todayMealDataHaksik.observe(viewLifecycleOwner) { result -> - if (result.isNotEmpty()) { - totalMenuList.add( - Section( - MenuType.VARIABLE, - Restaurant.HAKSIK, - result.mapTodayMenuResponseToMenu(), - infoViewModel.getRestaurantInfo(Restaurant.HAKSIK)?.location ?: "" - ) - ) - -// setupTodayRecyclerView() - } - haksikDataLoaded.value = true - checkDataLoaded() - } - - //숭실도담 - menuViewModel.loadTodayMeal(menuDate, Restaurant.DODAM, time) - menuViewModel.todayMealDataDodam.observe(viewLifecycleOwner) { result -> - if (result.isNotEmpty()) { - totalMenuList.add( - Section( - MenuType.VARIABLE, - Restaurant.DODAM, - result.mapTodayMenuResponseToMenu(), - infoViewModel.getRestaurantInfo(Restaurant.DODAM)?.location ?: "" - ) - ) - } - dodamDataLoaded.value = true - checkDataLoaded() - } - - //기숙사식당 - menuViewModel.loadTodayMeal(menuDate, Restaurant.DORMITORY, time) - menuViewModel.todayMealDataDormitory.observe(viewLifecycleOwner) { result -> - if (result.isNotEmpty()) { - totalMenuList.add( - Section( - MenuType.VARIABLE, - Restaurant.DORMITORY, - result.mapTodayMenuResponseToMenu(), - infoViewModel.getRestaurantInfo(Restaurant.DORMITORY)?.location ?: "" - ) - ) - } - dormitoryDataLoaded.value = true - checkDataLoaded() - } - } - } - - private fun setupTodayRecyclerView() { - binding.rv.apply { - setHasFixedSize(true) - layoutManager = LinearLayoutManager(context) - adapter = fragmentManager?.let { MenuAdapter(it, totalMenuList) } - - } - } - - private fun checkDataLoaded() { - if (foodCourtDataLoaded.value == true && - snackCornerDataLoaded.value == true && - haksikDataLoaded.value == true && - dodamDataLoaded.value == true && - dormitoryDataLoaded.value == true - ) { - totalMenuList.sortBy { it.cafeteria.ordinal } - setupTodayRecyclerView() - } - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } -} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/main/menu/MenuViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/main/menu/MenuViewModel.kt deleted file mode 100644 index c5c253fe4..000000000 --- a/app/src/main/java/com/eatssu/android/presentation/main/menu/MenuViewModel.kt +++ /dev/null @@ -1,176 +0,0 @@ -package com.eatssu.android.presentation.main.menu - -import android.util.Log -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope -import com.eatssu.android.data.dto.response.BaseResponse -import com.eatssu.android.data.dto.response.GetFixedMenuResponse -import com.eatssu.android.data.dto.response.GetMealResponse -import com.eatssu.android.data.enums.Restaurant -import com.eatssu.android.data.enums.Time -import com.eatssu.android.data.service.MealService -import com.eatssu.android.data.service.MenuService -import com.eatssu.android.domain.model.MenuMini -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 retrofit2.Call -import retrofit2.Callback -import retrofit2.Response -import javax.inject.Inject - -@HiltViewModel -class MenuViewModel @Inject constructor( - private val menuService: MenuService, - private val mealService: MealService, -) :ViewModel() { - - private val _todayMealDataDodam = MutableLiveData>() - val todayMealDataDodam: LiveData> = _todayMealDataDodam - - private val _todayMealDataHaksik = MutableLiveData>() - val todayMealDataHaksik: LiveData> = _todayMealDataHaksik - - private val _todayMealDataDormitory = MutableLiveData>() - val todayMealDataDormitory: LiveData> = _todayMealDataDormitory - - private val _fixedMenuDataKitchen = MutableLiveData() - val fixedMenuDataKitchen: MutableLiveData = _fixedMenuDataKitchen - - private val _fixedMenuDataSnack = MutableLiveData() - val fixedMenuDataSnack: MutableLiveData = _fixedMenuDataSnack - - private val _fixedMenuDataFood = MutableLiveData() - val fixedMenuDataFood: MutableLiveData = _fixedMenuDataFood - - private val _uiState: MutableStateFlow = MutableStateFlow(MenuState()) - val uiState: StateFlow = _uiState.asStateFlow() - - - fun loadTodayMeal( - menuDate: String, - restaurantType: Restaurant, - time: Time, - ) { - viewModelScope.launch { - mealService.getTodayMeal(menuDate, restaurantType.toString(), time.toString()) - .enqueue(object : Callback>> { - override fun onResponse( - call: Call>>, - response: Response>>, - ) { - val data = response.body()?.result - - if (response.isSuccessful) { - Log.d("post", "onResponse 성공" + response.body()) - - when (restaurantType) { - Restaurant.HAKSIK -> _todayMealDataHaksik.postValue(data!!) - Restaurant.DODAM -> _todayMealDataDodam.postValue(data!!) - Restaurant.DORMITORY -> _todayMealDataDormitory.postValue(data!!) - - else -> { - Log.d("post", "onResponse 실패. 잘못된 식당입니다.") - } - } - } else { - Log.d( - "post", - "onResponse 실패 투데이밀" + response.code() + response.message() - ) - } - } - - override fun onFailure( - call: Call>>, - t: Throwable, - ) { - Log.d("post", "onFailure 에러: 나다${t.message}+ ${call}" + "ddd") - } - }) - } - } - - // Fixed Menu 데이터 로드도 유사한 방식으로 구현 - fun loadFixedMenu(restaurantType: Restaurant) { - viewModelScope.launch { - menuService.getFixMenu(restaurantType.toString()) - .enqueue(object : Callback> { - override fun onResponse( - call: Call>, - response: Response>, - ) { - if (response.isSuccessful) { - Log.d("post", "onResponse 성공" + response.body()) - val data = response.body()?.result!! - when (restaurantType) { - Restaurant.THE_KITCHEN -> _fixedMenuDataKitchen.postValue(data) - Restaurant.FOOD_COURT -> _fixedMenuDataFood.postValue(data) - Restaurant.SNACK_CORNER -> _fixedMenuDataSnack.postValue(data) - - else -> { - Log.d("post", "onResponse 실패. 잘못된 식당 입니다.") - } - } - } else { - Log.d("post", "onResponse 실패") - } - } - - override fun onFailure( - call: Call>, - t: Throwable, - ) { - Log.d("post", "onFailure 에러: ${t.message}") - } - }) - } - } - -// fun findMenuItemByMealId(mealId: Long) { -// viewModelScope.launch { -// mealService.getMenuInfoByMealId(mealId) -// .enqueue(object : Callback> { -// override fun onResponse( -// call: Call>, -// response: Response>, -// ) { -// if (response.isSuccessful) { -// val data = response.body()?.result -// Log.d("post", "onResponse 성공" + response.body()) -// _uiState.update { -// it.copy( -// menuOfMeal = response.body()?.result?.asMenuOfMeal() -// ) -// } -// } else { -// Log.d("post", "onResponse 실패") -// } -// } -// -// override fun onFailure( -// call: Call>, -// t: Throwable, -// ) { -// Log.d("post", "onFailure 에러: ${t.message}") -// } -// }) -// } -// } -} - -data class MenuState( - var toastMessage: String = "", - var loading: Boolean = true, - var error: Boolean = false, - var haksikMeal: ArrayList? = null, - var dodamMeal: ArrayList? = null, - var dormitoryMeal: ArrayList? = null, - var snackMenu: GetFixedMenuResponse? = null, - var foodcourtMenu: GetFixedMenuResponse? = null, - var menuOfMeal: List? = null, -) \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/main/menu/MenuViewModelFactory.kt b/app/src/main/java/com/eatssu/android/presentation/main/menu/MenuViewModelFactory.kt deleted file mode 100644 index 7e8057b31..000000000 --- a/app/src/main/java/com/eatssu/android/presentation/main/menu/MenuViewModelFactory.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.eatssu.android.presentation.main.menu - -import androidx.lifecycle.ViewModel -import androidx.lifecycle.ViewModelProvider -import com.eatssu.android.data.service.MealService -import com.eatssu.android.data.service.MenuService - -class MenuViewModelFactory( - private val menuService: MenuService, - private val mealService: MealService, -) : - ViewModelProvider.Factory { - - override fun create(modelClass: Class): T { - if (modelClass.isAssignableFrom(MenuViewModel::class.java)) { - @Suppress("UNCHECKED_CAST") - return MenuViewModel(menuService, mealService) as T - } - throw IllegalArgumentException("Unknown ViewModel class") - } -} - diff --git a/app/src/main/java/com/eatssu/android/presentation/map/MapFragment.kt b/app/src/main/java/com/eatssu/android/presentation/map/MapFragment.kt new file mode 100644 index 000000000..591a1d6a2 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/presentation/map/MapFragment.kt @@ -0,0 +1,33 @@ +package com.eatssu.android.presentation.map + +import android.os.Bundle +import androidx.fragment.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.compose.ui.platform.ComposeView +import com.eatssu.android.presentation.compose.ui.theme.EatssuTheme + +class MapFragment : Fragment() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + } + + override fun onCreateView( + inflater: LayoutInflater, container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + // Inflate the layout for this fragment + return ComposeView(requireContext()).apply { + setContent { + EatssuTheme { + MapFragmentComposeView() + } + } + } + // return inflater.inflate(R.layout.fragment_map, container, false) + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/ComposeExample.kt b/app/src/main/java/com/eatssu/android/presentation/map/MapFragmentComposeView.kt similarity index 72% rename from app/src/main/java/com/eatssu/android/presentation/ComposeExample.kt rename to app/src/main/java/com/eatssu/android/presentation/map/MapFragmentComposeView.kt index ddc780809..43d138691 100644 --- a/app/src/main/java/com/eatssu/android/presentation/ComposeExample.kt +++ b/app/src/main/java/com/eatssu/android/presentation/map/MapFragmentComposeView.kt @@ -1,14 +1,13 @@ -package com.eatssu.android.presentation +package com.eatssu.android.presentation.map import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview import com.eatssu.android.presentation.compose.ui.theme.EatssuTheme import com.eatssu.android.presentation.compose.ui.theme.Primary -import com.google.firebase.annotations.concurrent.Background @Composable -fun ComposeExample() { +fun MapFragmentComposeView() { Text( text = "Hello, Eatssu!", style = EatssuTheme.typography.body1, @@ -18,8 +17,8 @@ fun ComposeExample() { @Preview(showBackground = true) @Composable -fun ComposeExamplePreview() { +fun MapFragmentComposeViewPreview() { EatssuTheme { - ComposeExample() + MapFragmentComposeView() } } \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageActivity.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageActivity.kt deleted file mode 100644 index b75675248..000000000 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageActivity.kt +++ /dev/null @@ -1,301 +0,0 @@ -package com.eatssu.android.presentation.mypage - - -import android.app.Activity -import android.content.Context -import android.content.Intent -import android.content.pm.PackageManager -import android.graphics.Paint -import android.net.Uri -import android.os.Build -import android.os.Bundle -import android.provider.Settings -import androidx.activity.viewModels -import androidx.annotation.RequiresApi -import androidx.appcompat.app.AlertDialog -import androidx.core.app.ActivityCompat -import androidx.core.content.ContextCompat -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import com.eatssu.android.R -import com.eatssu.android.databinding.ActivityMyPageBinding -import com.eatssu.android.presentation.base.BaseActivity -import com.eatssu.android.presentation.login.LoginActivity -import com.eatssu.android.presentation.mypage.myreview.MyReviewListActivity -import com.eatssu.android.presentation.mypage.terms.WebViewActivity -import com.eatssu.android.presentation.mypage.usernamechange.UserNameChangeActivity -import com.eatssu.android.presentation.util.showToast -import com.google.android.gms.oss.licenses.OssLicensesMenuActivity -import com.eatssu.android.presentation.util.startActivity -import com.google.android.material.snackbar.Snackbar -import dagger.hilt.android.AndroidEntryPoint -import kotlinx.coroutines.flow.collectLatest -import kotlinx.coroutines.launch -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter - -@AndroidEntryPoint -class MyPageActivity : BaseActivity(ActivityMyPageBinding::inflate) { - - private val myPageViewModel: MyPageViewModel by viewModels() - - @RequiresApi(Build.VERSION_CODES.O) - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - toolbarTitle.text = "마이페이지" // 툴바 제목 설정 - - binding.tvSignout.paintFlags = Paint.UNDERLINE_TEXT_FLAG - setupObservers() - setOnClickListener() - - } - - @RequiresApi(Build.VERSION_CODES.O) - private fun setupObservers() { - lifecycleScope.launch { - repeatOnLifecycle(Lifecycle.State.STARTED) { - myPageViewModel.uiState.collect { - binding.tvAppVersion.text = it.appVersion - - if (it.nickname.isNotEmpty()) { - binding.tvNickname.text = it.nickname - } - - // Switch 상태를 설정할 때 리스너를 임시로 null로 설정 - binding.alarmSwitch.setOnCheckedChangeListener(null) - binding.alarmSwitch.isChecked = it.isAlarmOn - // 상태 설정 후에 리스너 추가 - binding.alarmSwitch.setOnCheckedChangeListener { _, isChecked -> - handleAlarmSwitchChange(isChecked) - } - } - } - } - } - - @RequiresApi(Build.VERSION_CODES.O) - private fun handleAlarmSwitchChange(isChecked: Boolean) { - val nowDatetime = LocalDateTime.now() - val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm") - val formattedDate = nowDatetime.format(formatter) - - if (isChecked) { - if (checkNotificationPermission(this)) { // 권한이 있는 상태 - myPageViewModel.setNotificationOn() - showSnackbar("EAT-SSU 알림 수신을 동의하였습니다.\n$formattedDate") - } else { // 권한이 없으면 설정 화면으로 이동 알림 - showNotificationPermissionDialog() - } - } else { - myPageViewModel.setNotificationOff() - showSnackbar("EAT-SSU 알림 수신을 거부하였습니다.\n$formattedDate") - } - } - - - @RequiresApi(Build.VERSION_CODES.O) - private fun setOnClickListener() { - binding.llNickname.setOnClickListener { - startActivity() - } - - binding.llInquire.setOnClickListener { - val intent = Intent(this, WebViewActivity::class.java) - intent.putExtra("URL", getString(R.string.kakao_talk_channel_url)) - intent.putExtra("TITLE", getString(R.string.contact)) - startActivity(intent) - } - - binding.llMyReview.setOnClickListener { - startActivity() - } - - binding.tvLogout.setOnClickListener { - showLogoutDialog() - } - - binding.llSignout.setOnClickListener { - val intent = Intent(this, SignOutActivity::class.java) - intent.putExtra("nickname", myPageViewModel.uiState.value.nickname) - startActivity(intent) - } - - binding.llDeveloper.setOnClickListener { - startActivity() - } - - binding.llOss.setOnClickListener { - startActivity() - } - - binding.llAppVersion.setOnClickListener { - moveToPlayStore() - } - - binding.llServiceRule.setOnClickListener { - val intent = Intent(this, WebViewActivity::class.java) - intent.putExtra("URL", getString(R.string.terms_url)) - intent.putExtra("TITLE", getString(R.string.terms)) - startActivity(intent) - } - - binding.llPrivateInformation.setOnClickListener { - val intent = Intent(this, WebViewActivity::class.java) - intent.putExtra("URL", getString(R.string.policy_url)) - intent.putExtra("TITLE", getString(R.string.policy)) - startActivity(intent) - } - - } - - @RequiresApi(Build.VERSION_CODES.O) - private fun showNotificationPermissionDialog() { - AlertDialog.Builder(this) - .setTitle("알림 권한 필요") - .setMessage("알림을 받으려면 알림 권한을 활성화해야 합니다. 설정 화면으로 이동하시겠습니까?") - .setPositiveButton("설정으로 이동") { _, _ -> - openAppNotificationSettings(this) - } - .setNegativeButton("취소", null) - .show() - } - - private fun checkNotificationPermission(context: Context): Boolean { - return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - ContextCompat.checkSelfPermission( - context, - android.Manifest.permission.POST_NOTIFICATIONS - ) == PackageManager.PERMISSION_GRANTED - } else { - true // Android 13 이전 버전에서는 알림 권한이 필요하지 않음 - } - } - - private fun showLogoutDialog() { - - // 다이얼로그를 생성하기 위해 Builder 클래스 생성자를 이용해 줍니다. - val builder = AlertDialog.Builder(this) - builder.setTitle("로그아웃") - .setMessage("로그아웃 하시겠습니까?") - .setPositiveButton( - "로그아웃" - ) { _, _ -> - //로그아웃 - myPageViewModel.loginOut() - - lifecycleScope.launch { - myPageViewModel.uiState.collectLatest { - if (it.isLoginOuted) { - showToast(it.toastMessage) - startActivity() - finishAffinity() - } - - } - } - } - .setNegativeButton("취소") { _, _ -> - } - // 다이얼로그를 띄워주기 - builder.show() - } - - private fun showSignoutDialog() { - - // 다이얼로그를 생성하기 위해 Builder 클래스 생성자를 이용해 줍니다. - val builder = AlertDialog.Builder(this) - builder.setTitle("탈퇴하기") - .setMessage("탈퇴 하시겠습니까?") - .setPositiveButton( - "탈퇴하기" - ) { _, _ -> - //탈퇴처리 - myPageViewModel.signOut() - - lifecycleScope.launch { - myPageViewModel.uiState.collectLatest { - if (it.isSignOuted) { - showToast(it.toastMessage) - startActivity() - finishAffinity() - } - - } - } - } - .setNegativeButton("취소") { _, _ -> - } - // 다이얼로그를 띄워주기 - builder.show() - } - - - private fun moveToPlayStore() { - val appPackageName = packageName - try { - startActivity( - Intent( - Intent.ACTION_VIEW, - Uri.parse("market://details?id=$appPackageName") - ) - ) - } catch (e: android.content.ActivityNotFoundException) { - startActivity( - Intent( - Intent.ACTION_VIEW, - Uri.parse("https://play.google.com/store/apps/details?id=$appPackageName") - ) - ) - } - } - - // 알림 권한 요청 함수 - private fun requestNotificationPermission(activity: Activity) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - ActivityCompat.requestPermissions( - activity, - arrayOf(android.Manifest.permission.POST_NOTIFICATIONS), - REQUEST_NOTIFICATION_PERMISSION - ) - } - } - - - @RequiresApi(Build.VERSION_CODES.O) - override fun onRequestPermissionsResult( - requestCode: Int, - permissions: Array, - grantResults: IntArray - ) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults) - if (requestCode == REQUEST_NOTIFICATION_PERMISSION) { - if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) { - // 권한이 허용되었을 때 알림 설정 - myPageViewModel.setNotificationOn() - } else { - // 권한이 거부되었을 때 처리 - showToast("EAT-SSU 알림 수신을 거부하였습니다.") - openAppNotificationSettings(this) - myPageViewModel.setNotificationOff() - } - } - } - - - @RequiresApi(Build.VERSION_CODES.O) - private fun openAppNotificationSettings(context: Context) { - val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { - putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) - } - context.startActivity(intent) - } - - private fun showSnackbar(message: String) { - Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show() - } - - companion object { - private const val REQUEST_NOTIFICATION_PERMISSION = 1001 - } -} \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt new file mode 100644 index 000000000..ba57b4a08 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt @@ -0,0 +1,208 @@ +package com.eatssu.android.presentation.mypage + +import android.content.Context +import android.content.Intent +import android.content.pm.PackageManager +import android.graphics.Paint +import android.net.Uri +import android.os.Build +import android.os.Bundle +import android.provider.Settings +import android.view.LayoutInflater +import android.view.View +import androidx.annotation.RequiresApi +import androidx.appcompat.app.AlertDialog +import androidx.core.content.ContextCompat +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.eatssu.android.R +import com.eatssu.android.databinding.FragmentMyPageBinding +import com.eatssu.android.presentation.base.BaseFragment +import com.eatssu.android.presentation.MainViewModel +import com.eatssu.android.presentation.login.LoginActivity +import com.eatssu.android.presentation.mypage.myreview.MyReviewListActivity +import com.eatssu.android.presentation.mypage.terms.WebViewActivity +import com.eatssu.android.presentation.mypage.usernamechange.UserNameChangeActivity +import com.google.android.gms.oss.licenses.OssLicensesMenuActivity +import com.google.android.material.snackbar.Snackbar +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.launch +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter + +@AndroidEntryPoint +class MyPageFragment : BaseFragment() { + + private val myPageViewModel: MyPageViewModel by viewModels() + private val mainViewModel: MainViewModel by activityViewModels() + + override fun setBinding(layoutInflater: LayoutInflater): FragmentMyPageBinding { + return FragmentMyPageBinding.inflate(layoutInflater) + } + + @RequiresApi(Build.VERSION_CODES.O) + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + binding.tvSignout.paintFlags = Paint.UNDERLINE_TEXT_FLAG + setupObservers() + setOnClickListener() + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun setupObservers() { + viewLifecycleOwner.lifecycleScope.launch { + repeatOnLifecycle(Lifecycle.State.STARTED) { + myPageViewModel.uiState.collect { + binding.tvAppVersion.text = it.appVersion + + if (it.nickname.isNotEmpty()) { + binding.tvNickname.text = it.nickname + } + + binding.alarmSwitch.setOnCheckedChangeListener(null) + binding.alarmSwitch.isChecked = it.isAlarmOn + binding.alarmSwitch.setOnCheckedChangeListener { _, isChecked -> + handleAlarmSwitchChange(isChecked) + } + } + } + } + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun handleAlarmSwitchChange(isChecked: Boolean) { + val nowDatetime = LocalDateTime.now() + val formattedDate = nowDatetime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")) + + if (isChecked) { + if (checkNotificationPermission(requireContext())) { + myPageViewModel.setNotificationOn() + showSnackbar("EAT-SSU 알림 수신을 동의하였습니다.\n$formattedDate") + } else { + showNotificationPermissionDialog() + } + } else { + myPageViewModel.setNotificationOff() + showSnackbar("EAT-SSU 알림 수신을 거부하였습니다.\n$formattedDate") + } + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun setOnClickListener() { + binding.llNickname.setOnClickListener { + startActivity(Intent(requireContext(), UserNameChangeActivity::class.java)) + } + + binding.llInquire.setOnClickListener { + startWebView(getString(R.string.kakao_talk_channel_url), getString(R.string.contact)) + } + + binding.llMyReview.setOnClickListener { + startActivity(Intent(requireContext(), MyReviewListActivity::class.java)) + } + + binding.tvLogout.setOnClickListener { + showLogoutDialog() + } + + binding.llSignout.setOnClickListener { + Intent(requireContext(), SignOutActivity::class.java).apply { + putExtra("nickname", myPageViewModel.uiState.value.nickname) + startActivity(this) + } + } + + binding.llDeveloper.setOnClickListener { + startActivity(Intent(requireContext(), DeveloperActivity::class.java)) + } + + binding.llOss.setOnClickListener { + startActivity(Intent(requireContext(), OssLicensesMenuActivity::class.java)) + } + + binding.llAppVersion.setOnClickListener { + moveToPlayStore() + } + + binding.llServiceRule.setOnClickListener { + startWebView(getString(R.string.terms_url), getString(R.string.terms)) + } + + binding.llPrivateInformation.setOnClickListener { + startWebView(getString(R.string.policy_url), getString(R.string.policy)) + } + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun showNotificationPermissionDialog() { + AlertDialog.Builder(requireContext()) + .setTitle("알림 권한 필요") + .setMessage("알림을 받으려면 알림 권한을 활성화해야 합니다. 설정 화면으로 이동하시겠습니까?") + .setPositiveButton("설정으로 이동") { _, _ -> + openAppNotificationSettings(requireContext()) + } + .setNegativeButton("취소", null) + .show() + } + + private fun checkNotificationPermission(context: Context): Boolean { + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + ContextCompat.checkSelfPermission( + context, + android.Manifest.permission.POST_NOTIFICATIONS + ) == PackageManager.PERMISSION_GRANTED + } else true + } + + private fun showLogoutDialog() { + AlertDialog.Builder(requireContext()) + .setTitle("로그아웃") + .setMessage("로그아웃 하시겠습니까?") + .setPositiveButton("로그아웃") { _, _ -> + mainViewModel.logOut() // 로그아웃은 메인 액티비티에서 처리하도록 수정 + startActivity(Intent(requireContext(), LoginActivity::class.java)) + } + .setNegativeButton("취소", null) + .show() + } + + private fun moveToPlayStore() { + val appPackageName = requireContext().packageName + val uri = Uri.parse("market://details?id=$appPackageName") + val fallbackUri = Uri.parse("https://play.google.com/store/apps/details?id=$appPackageName") + + try { + startActivity(Intent(Intent.ACTION_VIEW, uri)) + } catch (e: Exception) { + startActivity(Intent(Intent.ACTION_VIEW, fallbackUri)) + } + } + + @RequiresApi(Build.VERSION_CODES.O) + private fun openAppNotificationSettings(context: Context) { + val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { + putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) + } + context.startActivity(intent) + } + + private fun showSnackbar(message: String) { + Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show() + } + + private fun startWebView(url: String, title: String) { + val intent = Intent(requireContext(), WebViewActivity::class.java).apply { + putExtra("URL", url) + putExtra("TITLE", title) + } + startActivity(intent) + } + + companion object { + private const val REQUEST_NOTIFICATION_PERMISSION = 1001 + } +} diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageViewModel.kt index 10d3d009b..7caa99861 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageViewModel.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageViewModel.kt @@ -27,13 +27,8 @@ import javax.inject.Inject @HiltViewModel class MyPageViewModel @Inject constructor( - private val logoutUseCase: LogoutUseCase, - private val signOutUseCase: SignOutUseCase, private val getUserInfoUseCase: GetUserInfoUseCase, - private val setAccessTokenUseCase: SetAccessTokenUseCase, - private val setRefreshTokenUseCase: SetRefreshTokenUseCase, private val setNotificationStatusUseCase: SetDailyNotificationStatusUseCase, - private val getDailyNotificationStatusUseCase: GetDailyNotificationStatusUseCase, private val alarmUseCase: AlarmUseCase, private val preferencesRepository: PreferencesRepository // Assuming you're using DataStore here ) : ViewModel() { @@ -100,43 +95,6 @@ class MyPageViewModel @Inject constructor( } } - fun loginOut() { - viewModelScope.launch { - logoutUseCase() //Todo 반환값이 쓰이는게 아니면 이렇게 해도 되나? - - _uiState.update { - it.copy( - toastMessage = "로그아웃 되었습니다.", - isLoginOuted = true - ) - } - } - } - - fun signOut() { - viewModelScope.launch { - signOutUseCase().onStart { - _uiState.update { it.copy(loading = true) } - }.onCompletion { - _uiState.update { it.copy(loading = false, error = true) } - }.catch { e -> - _uiState.update { it.copy(error = true, toastMessage = "정보를 불러올 수 없습니다.") } - Timber.e(e.toString()) - }.collectLatest { result -> - Timber.d(result.toString()) - if (result.result == true) { - logoutUseCase() - _uiState.update { - it.copy( - isSignOuted = true, - toastMessage = "탈퇴가 완료되었습니다." - ) - } - } - } - } - } - fun setNotificationOn() { viewModelScope.launch { setNotificationStatusUseCase(true) //로컬 디비 저장 @@ -150,12 +108,6 @@ class MyPageViewModel @Inject constructor( alarmUseCase.cancelAlarm() } } - - - - companion object { - val TAG = "MyPageViewModel" - } } @@ -171,6 +123,4 @@ data class MyPageState( var appVersion: String = "0.0.0", var isNicknameNull: Boolean = false, - var isLoginOuted: Boolean = false, - var isSignOuted: Boolean = false, ) \ No newline at end of file diff --git a/app/src/main/java/com/eatssu/android/presentation/mypage/SignOutViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/mypage/SignOutViewModel.kt index f3c467195..0b9324e9a 100644 --- a/app/src/main/java/com/eatssu/android/presentation/mypage/SignOutViewModel.kt +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/SignOutViewModel.kt @@ -1,6 +1,5 @@ package com.eatssu.android.presentation.mypage -import android.util.Log import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.eatssu.android.domain.usecase.auth.GetUserInfoUseCase @@ -18,6 +17,7 @@ import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch +import timber.log.Timber import javax.inject.Inject @HiltViewModel @@ -40,10 +40,9 @@ class SignOutViewModel @Inject constructor( _uiState.update { it.copy(loading = false, error = true) } }.catch { e -> _uiState.update { it.copy(error = true, toastMessage = "정보를 불러올 수 없습니다.") } - Log.d(TAG, e.toString()) - + Timber.d(TAG, e.toString()) }.collectLatest { result -> - Log.d(TAG, result.toString()) + Timber.d(TAG, result.toString()) if (result.result == true) { logoutUseCase() _uiState.update { @@ -62,16 +61,12 @@ class SignOutViewModel @Inject constructor( } } - data class SignOutState( var loading: Boolean = true, var error: Boolean = false, - var toastMessage: String = "", - var nickname: String = "", var platform: String = "", - var isNicknameNull: Boolean = false, var isLoginOuted: Boolean = false, var isSignOuted: Boolean = false, diff --git a/app/src/main/java/com/eatssu/android/presentation/util/ContextUtil.kt b/app/src/main/java/com/eatssu/android/presentation/util/ContextUtil.kt index 60ec7845b..ebab1b5b4 100644 --- a/app/src/main/java/com/eatssu/android/presentation/util/ContextUtil.kt +++ b/app/src/main/java/com/eatssu/android/presentation/util/ContextUtil.kt @@ -2,10 +2,19 @@ package com.eatssu.android.presentation.util import android.content.Context import android.widget.Toast +import androidx.fragment.app.Fragment +// Activity fun Context.showToast(msg: String) { //Todo 앱 진입시 빈 토스트 왜 뜨는지 알아야함 if (msg.isNotEmpty()) { Toast.makeText(this, msg, Toast.LENGTH_SHORT).show() } +} + +// Fragment +fun Fragment.showToast(msg: String) { + if (msg.isNotEmpty()) { + Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show() + } } \ No newline at end of file diff --git a/app/src/main/res/color/selector_bottom_navi_item.xml b/app/src/main/res/color/selector_bottom_navi_item.xml new file mode 100644 index 000000000..5858766d5 --- /dev/null +++ b/app/src/main/res/color/selector_bottom_navi_item.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/app/src/main/res/drawable-v24/ic_dot.png b/app/src/main/res/drawable-v24/ic_dot.png deleted file mode 100644 index db4bac54f..000000000 Binary files a/app/src/main/res/drawable-v24/ic_dot.png and /dev/null differ diff --git a/app/src/main/res/drawable-v24/image_logo_none.png b/app/src/main/res/drawable-v24/image_logo_none.png deleted file mode 100644 index 5785ad74b..000000000 Binary files a/app/src/main/res/drawable-v24/image_logo_none.png and /dev/null differ diff --git a/app/src/main/res/drawable/ic_cafeteria_menu.xml b/app/src/main/res/drawable/ic_cafeteria_menu.xml new file mode 100644 index 000000000..b0771d94d --- /dev/null +++ b/app/src/main/res/drawable/ic_cafeteria_menu.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/app/src/main/res/drawable/ic_close.png b/app/src/main/res/drawable/ic_close.png deleted file mode 100644 index 5e5a3b687..000000000 Binary files a/app/src/main/res/drawable/ic_close.png and /dev/null differ diff --git a/app/src/main/res/drawable/ic_map.xml b/app/src/main/res/drawable/ic_map.xml new file mode 100644 index 000000000..e28cdef28 --- /dev/null +++ b/app/src/main/res/drawable/ic_map.xml @@ -0,0 +1,21 @@ + + + + + diff --git a/app/src/main/res/drawable/ic_mypage.xml b/app/src/main/res/drawable/ic_mypage.xml new file mode 100644 index 000000000..9fbf5fd20 --- /dev/null +++ b/app/src/main/res/drawable/ic_mypage.xml @@ -0,0 +1,12 @@ + + + + diff --git a/app/src/main/res/drawable/ic_star.png b/app/src/main/res/drawable/ic_star.png deleted file mode 100644 index d1d850789..000000000 Binary files a/app/src/main/res/drawable/ic_star.png and /dev/null differ diff --git a/app/src/main/res/drawable/img_app_bar.png b/app/src/main/res/drawable/img_app_bar.png deleted file mode 100644 index 73b39f223..000000000 Binary files a/app/src/main/res/drawable/img_app_bar.png and /dev/null differ diff --git a/app/src/main/res/drawable/img_event_splash.png b/app/src/main/res/drawable/img_event_splash.png deleted file mode 100644 index b9c062048..000000000 Binary files a/app/src/main/res/drawable/img_event_splash.png and /dev/null differ diff --git a/app/src/main/res/layout/activity_fix_menu.xml b/app/src/main/res/layout/activity_fix_menu.xml index 32397c143..3e4321d1b 100644 --- a/app/src/main/res/layout/activity_fix_menu.xml +++ b/app/src/main/res/layout/activity_fix_menu.xml @@ -5,7 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp" - tools:context=".presentation.review.modify.ModifyReviewActivity"> + tools:context=".presentation.cafeteria.review.modify.ModifyReviewActivity"> + tools:context=".presentation.MainActivity"> - - - - - - - - - - - - - - - + app:layout_constraintEnd_toEndOf="parent" + app:navGraph="@navigation/eatssu_navigation"/> - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + app:layout_constraintEnd_toEndOf="parent" + android:paddingVertical="15dp" + android:elevation="3dp" + android:background="@drawable/shape_corner_top" + app:itemRippleColor="@color/white" + android:textAlignment="center" + app:itemTextColor="@color/selector_bottom_navi_item" + app:itemIconTint="@color/selector_bottom_navi_item" + app:menu="@menu/menu_bottom_navigation" /> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_my_review_list.xml b/app/src/main/res/layout/activity_my_review_list.xml index 130a12d3e..b4f3b1947 100644 --- a/app/src/main/res/layout/activity_my_review_list.xml +++ b/app/src/main/res/layout/activity_my_review_list.xml @@ -5,7 +5,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:padding="16dp" - tools:context=".presentation.review.list.ReviewActivity"> + tools:context=".presentation.cafeteria.review.list.ReviewActivity"> + tools:context=".presentation.cafeteria.review.report.ReportActivity"> + type="com.eatssu.android.presentation.cafeteria.review.list.ReviewViewModel" /> + tools:context=".presentation.cafeteria.review.list.ReviewActivity"> + tools:context=".presentation.cafeteria.review.write.menu.ReviewWriteMenuActivity"> + type="com.eatssu.android.presentation.cafeteria.review.write.UploadReviewViewModel" /> + tools:context=".presentation.cafeteria.review.write.ReviewWriteRateActivity"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_map.xml b/app/src/main/res/layout/fragment_map.xml new file mode 100644 index 000000000..b6c44f456 --- /dev/null +++ b/app/src/main/res/layout/fragment_map.xml @@ -0,0 +1,13 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_my_page.xml b/app/src/main/res/layout/fragment_my_page.xml similarity index 95% rename from app/src/main/res/layout/activity_my_page.xml rename to app/src/main/res/layout/fragment_my_page.xml index 3c2894899..bd236ce91 100644 --- a/app/src/main/res/layout/activity_my_page.xml +++ b/app/src/main/res/layout/fragment_my_page.xml @@ -4,11 +4,34 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context=".presentation.mypage.MyPageActivity"> + tools:context=".presentation.mypage.MyPageFragment"> + + + + + + android:layout_height="0dp" + app:layout_constraintTop_toBottomOf="@+id/toolbar" + > + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/navigation/eatssu_navigation.xml b/app/src/main/res/navigation/eatssu_navigation.xml new file mode 100644 index 000000000..2b441460e --- /dev/null +++ b/app/src/main/res/navigation/eatssu_navigation.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 88f23dc44..8f9ee362e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -169,5 +169,10 @@ http://pf.kakao.com/_ZlVAn 오픈소스 라이브러리 - 로그인이 실패했습니다. + 학식 + 지도 + 마이 + 마이페이지 + + 로그인이 실패했습니다.\n \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 80b33f0a3..97f01d5bb 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -46,6 +46,7 @@ ossLicensesPlugin = "0.10.4" uiTestJunit4 = "1.7.8" uiTooling = "1.7.8" compose-material3 = "1.3.1" +activityVersion = "1.9.3" [libraries] accompanist-appcompat-theme = { module = "com.google.accompanist:accompanist-appcompat-theme", version.ref = "accompanistAppcompatTheme" } @@ -110,6 +111,7 @@ firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics" } timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" } oss-licenses = { group = "com.google.android.gms", name = "play-services-oss-licenses", version.ref = "ossLicenses" } oss-licenses-plugin = { group = "com.google.android.gms", name = "oss-licenses-plugin", version.ref = "ossLicensesPlugin" } +androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activityVersion" }