diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 569480f88..431a8cae7 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/java/com/eatssu/android/alarm/NotificationReceiver.kt b/app/src/main/java/com/eatssu/android/alarm/NotificationReceiver.kt index feb9f2cab..95a8166f0 100644 --- a/app/src/main/java/com/eatssu/android/alarm/NotificationReceiver.kt +++ b/app/src/main/java/com/eatssu/android/alarm/NotificationReceiver.kt @@ -10,7 +10,7 @@ import android.os.Build import androidx.annotation.RequiresApi import androidx.core.app.NotificationCompat import com.eatssu.android.R -import com.eatssu.android.presentation.main.MainActivity +import com.eatssu.android.presentation.main.cafeteria.CafeteriaFragment import java.time.DayOfWeek import java.time.LocalDateTime @@ -44,7 +44,7 @@ class NotificationReceiver : BroadcastReceiver() { } - val intent = Intent(context, MainActivity::class.java).apply { + val intent = Intent(context, CafeteriaFragment::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } 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 index ce8a22824..eed904b0a 100644 --- a/app/src/main/java/com/eatssu/android/presentation/main/MainActivity.kt +++ b/app/src/main/java/com/eatssu/android/presentation/main/MainActivity.kt @@ -1,61 +1,47 @@ package com.eatssu.android.presentation.main +import android.Manifest import android.annotation.SuppressLint import android.content.Intent import android.content.pm.PackageManager import android.os.Build import android.os.Bundle +import android.util.Log 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.navigation.findNavController +import androidx.navigation.fragment.NavHostFragment +import androidx.navigation.ui.NavigationUI 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.login.LoginActivity +import com.eatssu.android.presentation.main.cafeteria.CafeteriaFragment 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 com.google.android.material.bottomnavigation.BottomNavigationView 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 { +class MainActivity : BaseActivity(ActivityMainBinding::inflate){ 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?) { @@ -63,111 +49,45 @@ class MainActivity : BaseActivity(ActivityMainBinding::infl 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 { - // 권한이 이미 있어 - } - } + checkAlarmPermission() checkNicknameIsNull() + collectLogoutState() - // 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 - } + setNavigation() - @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 + private fun setNavigation() { + val navHostFragment = supportFragmentManager + .findFragmentById(R.id.nav_host_fragment) as NavHostFragment + val navController = navHostFragment.navController - val viewpagerFragmentAdapter = ViewPager2Adapter(this) - - viewPager.adapter = viewpagerFragmentAdapter - viewPager.setCurrentItem(viewpagerFragmentAdapter.getDefaultFragmentPosition(), false) + binding.bottomNaviBar.setOnItemSelectedListener { item -> + when (item.itemId) { + R.id.cafeteria_menu -> { + navController.navigate(R.id.homeFragment) + true + } - val tabTitles = listOf("아침", "점심", "저녁") + R.id.map_menu -> { + navController.navigate(R.id.mapFragment) + true + } - TabLayoutMediator(tabLayout, viewPager) { tab, position -> tab.text = tabTitles[position] }.attach() + R.id.mypage_menu -> { + navController.navigate(R.id.myPageFragment) + true + } - binding.btnSetting.setOnClickListener { - startActivity() + else -> { + false + } + } } - - initWidgets() - setWeekView() } + // set UI -- private fun setupNoToolbar() { // 툴바 사용하지 않도록 설정 toolbar.let { @@ -179,43 +99,24 @@ class MainActivity : BaseActivity(ActivityMainBinding::infl } } - - 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 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) +// } +// } + + // Permission -- // 권한 요청 결과 처리 override fun onRequestPermissionsResult( requestCode: Int, @@ -238,4 +139,57 @@ class MainActivity : BaseActivity(ActivityMainBinding::infl } } } + + // 알림 퍼미션 있는지 자가 진단 + 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() + } + } + } + } } \ 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/main/MainViewModel.kt index 266448446..1e61540d8 100644 --- a/app/src/main/java/com/eatssu/android/presentation/main/MainViewModel.kt +++ b/app/src/main/java/com/eatssu/android/presentation/main/MainViewModel.kt @@ -1,10 +1,14 @@ package com.eatssu.android.presentation.main 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 = "로그아웃 되었습니다.", + isLoggedOut = true + ) + } + } + } + private val data = MutableLiveData() + + fun setData(dataToSend: LocalDate) { + data.value = dataToSend + + Log.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/main/MainViewPager2Adapter.kt b/app/src/main/java/com/eatssu/android/presentation/main/MainViewPager2Adapter.kt new file mode 100644 index 000000000..dfa7a03d7 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/presentation/main/MainViewPager2Adapter.kt @@ -0,0 +1,25 @@ +package com.eatssu.android.presentation.main + +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.cafeteria.CafeteriaFragment +import com.eatssu.android.presentation.main.map.MapFragment +import com.eatssu.android.presentation.main.menu.MenuFragment +import com.eatssu.android.presentation.mypage.MyPageFragment + +class MainViewPager2Adapter(activity: FragmentActivity) : FragmentStateAdapter(activity) { + + private val mainFragmentList = listOf( + CafeteriaFragment(), + //MapFragment(), + MyPageFragment(), + ) + + override fun getItemCount(): Int = mainFragmentList.count() + + override fun createFragment(position: Int): Fragment { + return mainFragmentList[position] + } +} diff --git a/app/src/main/java/com/eatssu/android/presentation/main/cafeteria/CafeteriaFragment.kt b/app/src/main/java/com/eatssu/android/presentation/main/cafeteria/CafeteriaFragment.kt new file mode 100644 index 000000000..d8820fc45 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/presentation/main/cafeteria/CafeteriaFragment.kt @@ -0,0 +1,98 @@ +package com.eatssu.android.presentation.main.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.main.MainViewModel +import com.eatssu.android.presentation.main.calendar.CalendarAdapter +import com.eatssu.android.presentation.main.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/main/cafeteria/CafeteriaViewPagerAdapter.kt similarity index 93% rename from app/src/main/java/com/eatssu/android/presentation/main/ViewPager2Adapter.kt rename to app/src/main/java/com/eatssu/android/presentation/main/cafeteria/CafeteriaViewPagerAdapter.kt index 691b055cc..5b6c8315d 100644 --- a/app/src/main/java/com/eatssu/android/presentation/main/ViewPager2Adapter.kt +++ b/app/src/main/java/com/eatssu/android/presentation/main/cafeteria/CafeteriaViewPagerAdapter.kt @@ -1,4 +1,4 @@ -package com.eatssu.android.presentation.main +package com.eatssu.android.presentation.main.cafeteria import android.os.Build import androidx.annotation.RequiresApi @@ -9,7 +9,7 @@ import com.eatssu.android.data.enums.Time import com.eatssu.android.presentation.main.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/CalendarViewModel.kt b/app/src/main/java/com/eatssu/android/presentation/main/calendar/CalendarViewModel.kt index 6d6b910a3..550a2243c 100644 --- 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 @@ -7,15 +7,15 @@ 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 - } +// 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/map/MapFragment.kt b/app/src/main/java/com/eatssu/android/presentation/main/map/MapFragment.kt new file mode 100644 index 000000000..da1f584d3 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/presentation/main/map/MapFragment.kt @@ -0,0 +1,34 @@ +package com.eatssu.android.presentation.main.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.R +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/main/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/main/map/MapFragmentComposeView.kt index ddc780809..b5a2da9b5 100644 --- a/app/src/main/java/com/eatssu/android/presentation/ComposeExample.kt +++ b/app/src/main/java/com/eatssu/android/presentation/main/map/MapFragmentComposeView.kt @@ -1,14 +1,13 @@ -package com.eatssu.android.presentation +package com.eatssu.android.presentation.main.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/main/menu/MenuFragment.kt b/app/src/main/java/com/eatssu/android/presentation/main/menu/MenuFragment.kt index a970a6acd..e2b8bea06 100644 --- 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 @@ -23,7 +23,7 @@ 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 com.eatssu.android.presentation.main.MainViewModel import java.time.DayOfWeek import java.time.LocalDate import java.time.LocalDateTime @@ -33,7 +33,9 @@ class MenuFragment : Fragment() { private var _binding: FragmentMenuBinding? = null private val binding get() = _binding!! - private lateinit var calendarViewModel: CalendarViewModel + // private lateinit var calendarViewModel: CalendarViewModel + private val mainViewModel by activityViewModels() + private lateinit var menuViewModel: MenuViewModel private lateinit var menuService: MenuService @@ -101,14 +103,14 @@ class MenuFragment : Fragment() { )[MenuViewModel::class.java] // ViewModel에서 데이터 가져오기 - calendarViewModel = ViewModelProvider(requireActivity())[CalendarViewModel::class.java] + // 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 -> + mainViewModel.getData().observe(viewLifecycleOwner) { dataReceived -> val parsedDate = LocalDate.parse(dataReceived.toString(), DateTimeFormatter.ofPattern("yyyy-MM-dd")) 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..f5ffe1480 --- /dev/null +++ b/app/src/main/java/com/eatssu/android/presentation/mypage/MyPageFragment.kt @@ -0,0 +1,206 @@ +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.main.MainViewModel +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() // 로그아웃은 메인 액티비티에서 처리하도록 수정 + } + .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/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/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_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/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 88b20d40d..764131a2f 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -2,156 +2,37 @@ - - - - - - - - - - - - - - - + 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/fragment_cafeteria.xml b/app/src/main/res/layout/fragment_cafeteria.xml new file mode 100644 index 000000000..2fee2a6e3 --- /dev/null +++ b/app/src/main/res/layout/fragment_cafeteria.xml @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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..8744a8118 --- /dev/null +++ b/app/src/main/res/layout/fragment_map.xml @@ -0,0 +1,14 @@ + + + + + + + \ 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..cf1131001 --- /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 947e5f0ab..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" }