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" }