diff --git a/app/src/main/java/org/sopt/pingle/presentation/type/MainListOrderType.kt b/app/src/main/java/org/sopt/pingle/presentation/type/MainListOrderType.kt new file mode 100644 index 00000000..366c76e8 --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/presentation/type/MainListOrderType.kt @@ -0,0 +1,11 @@ +package org.sopt.pingle.presentation.type + +import androidx.annotation.StringRes +import org.sopt.pingle.R + +enum class MainListOrderType( + @StringRes val mainListOrderStringRes: Int +) { + NEW(mainListOrderStringRes = R.string.main_list_order_new), + UPCOMING(mainListOrderStringRes = R.string.main_list_order_upcoming) +} diff --git a/app/src/main/java/org/sopt/pingle/presentation/type/PingleCardType.kt b/app/src/main/java/org/sopt/pingle/presentation/type/PingleCardType.kt new file mode 100644 index 00000000..e544c01d --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/presentation/type/PingleCardType.kt @@ -0,0 +1,15 @@ +package org.sopt.pingle.presentation.type + +import androidx.annotation.ColorRes +import org.sopt.pingle.R + +enum class PingleCardType( + @ColorRes val participationStatusColorRes: Int +) { + MAP( + participationStatusColorRes = R.color.g_10 + ), + MAINLIST( + participationStatusColorRes = R.color.g_09 + ) +} diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/HomeViewModel.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/HomeViewModel.kt index c46cae03..3867c62f 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/HomeViewModel.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/HomeViewModel.kt @@ -19,6 +19,7 @@ import org.sopt.pingle.domain.usecase.GetPingleListUseCase import org.sopt.pingle.domain.usecase.PostPingleJoinUseCase import org.sopt.pingle.presentation.model.MarkerModel import org.sopt.pingle.presentation.type.CategoryType +import org.sopt.pingle.presentation.type.MainListOrderType import org.sopt.pingle.util.view.UiState @HiltViewModel @@ -55,6 +56,9 @@ class HomeViewModel @Inject constructor( private val _pingleDeleteState = MutableSharedFlow>() val pingleDeleteState get() = _pingleDeleteState.asSharedFlow() + private val _mainListOrderType = MutableStateFlow(MainListOrderType.NEW) + val mainListOrderType get() = _mainListOrderType.asStateFlow() + fun setCategory(category: CategoryType?) { _category.value = category } @@ -105,6 +109,10 @@ class HomeViewModel @Inject constructor( } } + fun setMainListOrderType(mainListOrderType: MainListOrderType) { + _mainListOrderType.value = mainListOrderType + } + fun getGroupName(): String = localStorage.groupName fun getPinListWithoutFilter() { @@ -183,6 +191,99 @@ class HomeViewModel @Inject constructor( } } + val dummyPingleList = listOf( + PingleEntity( + id = 1L, + category = "STUDY", + name = "강남 모각작팟을 구합니다!!!!", + ownerName = "박소현", + location = "하얀집 2호점", + date = "2023-12-31", + startAt = "17:00:00", + endAt = "23:00:00", + maxParticipants = 99, + curParticipants = 11, + isParticipating = false, + chatLink = "https://github.com/TeamPINGLE/PINGLE-ANDROID", + isOwner = false + ), + PingleEntity( + id = 2L, + category = "MULTI", + name = "모각공하고 곱창먹자", + ownerName = "하지은", + location = "푸지미곱창", + date = "2024-02-23", + startAt = "14:00:00", + endAt = "23:00:00", + maxParticipants = 12, + curParticipants = 4, + isParticipating = true, + chatLink = "https://github.com/TeamPINGLE/PINGLE-ANDROID", + isOwner = false + ), + PingleEntity( + id = 3L, + category = "OTHERS", + name = "국민대 졸업하는 김승연 축하하러 올사람", + ownerName = "김승연", + location = "국민대학교", + date = "2024-02-14", + startAt = "14:30:00", + endAt = "21:30:00", + maxParticipants = 14, + curParticipants = 14, + isParticipating = false, + chatLink = "https://github.com/TeamPINGLE/PINGLE-ANDROID", + isOwner = false + ), + PingleEntity( + id = 4L, + category = "PLAY", + name = "건빵 QA", + ownerName = "배지현", + location = "서울역", + date = "2024-02-23", + startAt = "18:30:00", + endAt = "21:30:00", + maxParticipants = 13, + curParticipants = 13, + isParticipating = true, + chatLink = "https://github.com/TeamPINGLE/PINGLE-ANDROID", + isOwner = false + ), + PingleEntity( + id = 5L, + category = "PLAY", + name = "안핑이들 집합 ㅋ.ㅋ", + ownerName = "배지현", + location = "포어플랜", + date = "2024-02-27", + startAt = "19:00:00", + endAt = "23:00:00", + maxParticipants = 4, + curParticipants = 4, + isParticipating = true, + chatLink = "https://github.com/TeamPINGLE/PINGLE-ANDROID", + isOwner = true + ), + PingleEntity( + id = 6L, + category = "OTHERS", + name = "핑글", + ownerName = "배지현", + location = "핑글핑글", + date = "2024-02-29", + startAt = "01:00:00", + endAt = "03:00:00", + maxParticipants = 24, + curParticipants = 13, + isParticipating = true, + chatLink = "https://github.com/TeamPINGLE/PINGLE-ANDROID", + isOwner = true + ) + ) + companion object { const val DEFAULT_SELECTED_MARKER_POSITION = -1 } diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/mainlist/MainListAdapter.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/mainlist/MainListAdapter.kt new file mode 100644 index 00000000..dd9a283e --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/mainlist/MainListAdapter.kt @@ -0,0 +1,40 @@ +package org.sopt.pingle.presentation.ui.main.home.mainlist + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.ListAdapter +import org.sopt.pingle.databinding.ItemMainListPingleCardBinding +import org.sopt.pingle.domain.model.PingleEntity +import org.sopt.pingle.util.view.ItemDiffCallback + +class MainListAdapter( + private val navigateToParticipant: (Long) -> Unit, + private val navigateToWebViewWithChatLink: (String) -> Unit, + private val showPingleJoinModalDialogFragment: (PingleEntity) -> Unit, + private val showPingleCancelModalDialogFragment: (PingleEntity) -> Unit, + private val showPingleDeleteModalDialogFragment: (PingleEntity) -> Unit +) : ListAdapter( + ItemDiffCallback( + onContentsTheSame = { old, new -> old == new }, + onItemsTheSame = { old, new -> old.id == new.id } + ) +) { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainListViewHolder = + MainListViewHolder( + binding = ItemMainListPingleCardBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ), + context = parent.context, + navigateToParticipant = navigateToParticipant, + navigateToWebViewWithChatLink = navigateToWebViewWithChatLink, + showPingleJoinModalDialogFragment = showPingleJoinModalDialogFragment, + showPingleCancelModalDialogFragment = showPingleCancelModalDialogFragment, + showPingleDeleteModalDialogFragment = showPingleDeleteModalDialogFragment + ) + + override fun onBindViewHolder(holder: MainListViewHolder, position: Int) { + holder.onBind(pingleEntity = currentList[position]) + } +} diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/mainlist/MainListFragment.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/mainlist/MainListFragment.kt index e83157a2..9d4c0e4b 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/mainlist/MainListFragment.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/mainlist/MainListFragment.kt @@ -2,12 +2,110 @@ package org.sopt.pingle.presentation.ui.main.home.mainlist import android.os.Bundle import android.view.View +import androidx.fragment.app.activityViewModels +import androidx.lifecycle.flowWithLifecycle +import androidx.lifecycle.lifecycleScope +import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach import org.sopt.pingle.R import org.sopt.pingle.databinding.FragmentMainListBinding +import org.sopt.pingle.presentation.type.MainListOrderType +import org.sopt.pingle.presentation.ui.main.home.HomeViewModel import org.sopt.pingle.util.base.BindingFragment +import org.sopt.pingle.util.fragment.navigateToWebView +import org.sopt.pingle.util.fragment.stringOf +import org.sopt.pingle.util.view.PingleCardUtils +@AndroidEntryPoint class MainListFragment : BindingFragment(R.layout.fragment_main_list) { + private val homeViewModel: HomeViewModel by activityViewModels() + private lateinit var mainListAdapter: MainListAdapter + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + + initLayout() + addListeners() + collectData() + } + + override fun onDestroyView() { + binding.rvMainList.adapter = null + super.onDestroyView() + } + + private fun initLayout() { + mainListAdapter = MainListAdapter( + navigateToParticipant = { id -> + context?.let { + PingleCardUtils.navigateToParticipant( + it, + id + ) + } + }, + navigateToWebViewWithChatLink = { chatLink -> startActivity(navigateToWebView(chatLink)) }, + showPingleJoinModalDialogFragment = { pingleEntity -> + PingleCardUtils.showPingleJoinModalDialogFragment( + fragment = this, + postPingleJoin = { homeViewModel.postPingleJoin(pingleEntity.id) }, + pingleEntity = pingleEntity + ) + }, + showPingleCancelModalDialogFragment = { pingleEntity -> + PingleCardUtils.showPingleCancelModalDialogFragment( + fragment = this, + deletePingleCancel = { homeViewModel.deletePingleCancel(pingleEntity.id) } + ) + }, + showPingleDeleteModalDialogFragment = { pingleEntity -> + PingleCardUtils.showMapDeleteModalDialogFragment( + fragment = this, + deletePingleDelete = { homeViewModel.deletePingleDelete(pingleEntity.id) } + ) + } + ) + binding.rvMainList.adapter = mainListAdapter + mainListAdapter.submitList(homeViewModel.dummyPingleList) + + // TODO 서버통신 구현 후 collectData 함수로 해당 로직 이동 + with(homeViewModel.dummyPingleList) { + binding.tvMainListEmpty.visibility = if (isEmpty()) View.VISIBLE else View.INVISIBLE + binding.tvMainListEmpty.text = stringOf(R.string.main_list_empty_pingle) + } + } + + private fun addListeners() { + with(binding) { + layoutMainListOrder.setOnClickListener { + (layoutMainListOrderMenu.visibility == View.VISIBLE).let { isVisible -> + layoutMainListOrderMenu.visibility = + if (isVisible) View.INVISIBLE else View.VISIBLE + } + } + + tvMainListOrderMenuNew.setOnClickListener { + homeViewModel.setMainListOrderType( + MainListOrderType.NEW + ) + layoutMainListOrderMenu.visibility = View.INVISIBLE + } + + tvMainListOrderMenuUpcoming.setOnClickListener { + homeViewModel.setMainListOrderType( + MainListOrderType.UPCOMING + ) + layoutMainListOrderMenu.visibility = View.INVISIBLE + } + } + } + + private fun collectData() { + homeViewModel.mainListOrderType.flowWithLifecycle(viewLifecycleOwner.lifecycle) + .onEach { mainListOrderType -> + binding.tvMainListOrderType.text = + stringOf(mainListOrderType.mainListOrderStringRes) + }.launchIn(viewLifecycleOwner.lifecycleScope) } } diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/mainlist/MainListViewHolder.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/mainlist/MainListViewHolder.kt new file mode 100644 index 00000000..9f989fe4 --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/mainlist/MainListViewHolder.kt @@ -0,0 +1,70 @@ +package org.sopt.pingle.presentation.ui.main.home.mainlist + +import android.content.Context +import android.view.View +import androidx.appcompat.content.res.AppCompatResources +import androidx.recyclerview.widget.RecyclerView +import org.sopt.pingle.R +import org.sopt.pingle.databinding.ItemMainListPingleCardBinding +import org.sopt.pingle.domain.model.PingleEntity +import org.sopt.pingle.presentation.type.PingleCardType + +class MainListViewHolder( + private val binding: ItemMainListPingleCardBinding, + private val context: Context, + private val navigateToParticipant: (Long) -> Unit, + private val navigateToWebViewWithChatLink: (String) -> Unit, + private val showPingleJoinModalDialogFragment: (PingleEntity) -> Unit, + private val showPingleCancelModalDialogFragment: (PingleEntity) -> Unit, + private val showPingleDeleteModalDialogFragment: (PingleEntity) -> Unit +) : RecyclerView.ViewHolder(binding.root) { + init { + with(binding) { + ivMainListPingleCardBottomArrowUp.setOnClickListener { + setCardExpandable(isExpanded = false) + } + + ivMainListPingleCardBottomArrowDown.setOnClickListener { + setCardExpandable(isExpanded = true) + } + } + } + + private fun setCardExpandable(isExpanded: Boolean) { + with(binding) { + ivMainListPingleCardBottomArrowUp.visibility = + if (isExpanded) View.VISIBLE else View.GONE + pingleCardBottomMainListPingleCard.visibility = + if (isExpanded) View.VISIBLE else View.GONE + ivMainListPingleCardBottomArrowDown.visibility = + if (isExpanded) View.GONE else View.VISIBLE + layoutMainListPingleCardBottom.background = AppCompatResources.getDrawable( + context, + if (isExpanded) R.drawable.shape_border_radius_15 else R.drawable.shape_border_radius_8 + ) + } + } + + fun onBind(pingleEntity: PingleEntity) { + with(binding.pingleCardTopMainListPingleCard) { + initLayout(pingleEntity = pingleEntity, pingleCardType = PingleCardType.MAINLIST) + setOnParticipationStatusLayoutClick { + navigateToParticipant(pingleEntity.id) + } + } + + with(binding.pingleCardBottomMainListPingleCard) { + initLayout(pingleEntity) + setOnChatButtonClick { + navigateToWebViewWithChatLink(pingleEntity.chatLink) + } + setOnParticipateButtonClick { + when { + pingleEntity.isOwner -> showPingleDeleteModalDialogFragment(pingleEntity) + pingleEntity.isParticipating -> showPingleCancelModalDialogFragment(pingleEntity) + else -> showPingleJoinModalDialogFragment(pingleEntity) + } + } + } + } +} diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapCardAdapter.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapCardAdapter.kt index fd177210..92c53f79 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapCardAdapter.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapCardAdapter.kt @@ -10,9 +10,9 @@ import org.sopt.pingle.util.view.ItemDiffCallback class MapCardAdapter( private val navigateToParticipant: (Long) -> Unit, private val navigateToWebViewWithChatLink: (String) -> Unit, - private val showMapJoinModalDialogFragment: (PingleEntity) -> Unit, - private val showMapCancelModalDialogFragment: (PingleEntity) -> Unit, - private val showMapDeleteModalDialogFragment: (PingleEntity) -> Unit + private val showPingleJoinModalDialogFragment: (PingleEntity) -> Unit, + private val showPingleCancelModalDialogFragment: (PingleEntity) -> Unit, + private val showPingleDeleteModalDialogFragment: (PingleEntity) -> Unit ) : ListAdapter( ItemDiffCallback( onContentsTheSame = { old, new -> old == new }, @@ -31,9 +31,9 @@ class MapCardAdapter( ), navigateToParticipant = navigateToParticipant, navigateToWebViewWithChatLink = navigateToWebViewWithChatLink, - showMapJoinModalDialogFragment = showMapJoinModalDialogFragment, - showMapCancelModalDialogFragment = showMapCancelModalDialogFragment, - showMapDeleteModalDialogFragment = showMapDeleteModalDialogFragment + showPingleJoinModalDialogFragment = showPingleJoinModalDialogFragment, + showPingleCancelModalDialogFragment = showPingleCancelModalDialogFragment, + showPingleDeleteModalDialogFragment = showPingleDeleteModalDialogFragment ) override fun onBindViewHolder(holder: MapCardViewHolder, position: Int) { diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapCardViewHolder.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapCardViewHolder.kt index 1784bcfb..1e713625 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapCardViewHolder.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapCardViewHolder.kt @@ -3,18 +3,19 @@ package org.sopt.pingle.presentation.ui.main.home.map import androidx.recyclerview.widget.RecyclerView import org.sopt.pingle.databinding.ItemMapPingleCardBinding import org.sopt.pingle.domain.model.PingleEntity +import org.sopt.pingle.presentation.type.PingleCardType class MapCardViewHolder( private val binding: ItemMapPingleCardBinding, private val navigateToParticipant: (Long) -> Unit, private val navigateToWebViewWithChatLink: (String) -> Unit, - private val showMapJoinModalDialogFragment: (PingleEntity) -> Unit, - private val showMapCancelModalDialogFragment: (PingleEntity) -> Unit, - private val showMapDeleteModalDialogFragment: (PingleEntity) -> Unit + private val showPingleJoinModalDialogFragment: (PingleEntity) -> Unit, + private val showPingleCancelModalDialogFragment: (PingleEntity) -> Unit, + private val showPingleDeleteModalDialogFragment: (PingleEntity) -> Unit ) : RecyclerView.ViewHolder(binding.root) { fun onBind(pinId: Long, pingleEntity: PingleEntity) { with(binding.pingleCardTopMapPingleCard) { - initLayout(pingleEntity) + initLayout(pingleEntity = pingleEntity, pingleCardType = PingleCardType.MAP) setOnParticipationStatusLayoutClick { navigateToParticipant(pingleEntity.id) } @@ -28,9 +29,9 @@ class MapCardViewHolder( } setOnParticipateButtonClick { when { - pingleEntity.isOwner -> showMapDeleteModalDialogFragment(pingleEntity) - pingleEntity.isParticipating -> showMapCancelModalDialogFragment(pingleEntity) - else -> showMapJoinModalDialogFragment(pingleEntity) + pingleEntity.isOwner -> showPingleDeleteModalDialogFragment(pingleEntity) + pingleEntity.isParticipating -> showPingleCancelModalDialogFragment(pingleEntity) + else -> showPingleJoinModalDialogFragment(pingleEntity) } } } diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapFragment.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapFragment.kt index a1957850..f612fd61 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapFragment.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapFragment.kt @@ -1,7 +1,6 @@ package org.sopt.pingle.presentation.ui.main.home.map import android.Manifest -import android.content.Intent import android.content.pm.PackageManager import android.graphics.Rect import android.os.Bundle @@ -31,17 +30,13 @@ import kotlinx.coroutines.flow.onEach import org.sopt.pingle.R import org.sopt.pingle.databinding.FragmentMapBinding import org.sopt.pingle.domain.model.PinEntity -import org.sopt.pingle.domain.model.PingleEntity import org.sopt.pingle.presentation.mapper.toMarkerModel -import org.sopt.pingle.presentation.type.CategoryType import org.sopt.pingle.presentation.ui.main.home.HomeViewModel import org.sopt.pingle.presentation.ui.main.home.HomeViewModel.Companion.DEFAULT_SELECTED_MARKER_POSITION -import org.sopt.pingle.presentation.ui.participant.ParticipantActivity import org.sopt.pingle.util.base.BindingFragment -import org.sopt.pingle.util.component.AllModalDialogFragment import org.sopt.pingle.util.fragment.navigateToWebView -import org.sopt.pingle.util.fragment.stringOf import org.sopt.pingle.util.toPx +import org.sopt.pingle.util.view.PingleCardUtils import org.sopt.pingle.util.view.UiState @AndroidEntryPoint @@ -110,11 +105,34 @@ class MapFragment : BindingFragment(R.layout.fragment_map), private fun initLayout() { mapCardAdapter = MapCardAdapter( - navigateToParticipant = ::navigateToParticipant, - navigateToWebViewWithChatLink = ::navigateToWebViewWithChatLink, - showMapJoinModalDialogFragment = ::showMapJoinModalDialogFragment, - showMapCancelModalDialogFragment = ::showMapCancelModalDialogFragment, - showMapDeleteModalDialogFragment = ::showMapDeleteModalDialogFragment + navigateToParticipant = { id -> + context?.let { + PingleCardUtils.navigateToParticipant( + it, + id + ) + } + }, + navigateToWebViewWithChatLink = { chatLink -> startActivity(navigateToWebView(chatLink)) }, + showPingleJoinModalDialogFragment = { pingleEntity -> + PingleCardUtils.showPingleJoinModalDialogFragment( + fragment = this, + postPingleJoin = { homeViewModel.postPingleJoin(pingleEntity.id) }, + pingleEntity = pingleEntity + ) + }, + showPingleCancelModalDialogFragment = { pingleEntity -> + PingleCardUtils.showPingleCancelModalDialogFragment( + fragment = this, + deletePingleCancel = { homeViewModel.deletePingleCancel(pingleEntity.id) } + ) + }, + showPingleDeleteModalDialogFragment = { pingleEntity -> + PingleCardUtils.showMapDeleteModalDialogFragment( + fragment = this, + deletePingleDelete = { homeViewModel.deletePingleDelete(pingleEntity.id) } + ) + } ) with(binding.vpMapCard) { @@ -279,50 +297,6 @@ class MapFragment : BindingFragment(R.layout.fragment_map), } } - private fun navigateToParticipant(pingleEntityId: Long) { - Intent(context, ParticipantActivity::class.java).apply { - putExtra(MEETING_ID, pingleEntityId) - startActivity(this) - } - } - - private fun navigateToWebViewWithChatLink(chatLink: String) { - startActivity(navigateToWebView(chatLink)) - } - - private fun showMapCancelModalDialogFragment(pingleEntity: PingleEntity) { - AllModalDialogFragment( - title = stringOf(R.string.cancel_modal_title), - detail = stringOf(R.string.cancel_modal_detail), - buttonText = stringOf(R.string.cancel_modal_button_text), - textButtonText = stringOf(R.string.cancel_modal_text_button_text), - clickBtn = { homeViewModel.deletePingleCancel(meetingId = pingleEntity.id) }, - clickTextBtn = { } - ).show(childFragmentManager, MAP_CANCEL_MODAL) - } - - private fun showMapJoinModalDialogFragment(pingleEntity: PingleEntity) { - with(pingleEntity) { - MapModalDialogFragment( - category = CategoryType.fromString(categoryName = category), - name = name, - ownerName = ownerName, - clickBtn = { homeViewModel.postPingleJoin(meetingId = pingleEntity.id) } - ).show(childFragmentManager, MAP_JOIN_MODAL) - } - } - - private fun showMapDeleteModalDialogFragment(pingleEntity: PingleEntity) { - AllModalDialogFragment( - title = stringOf(R.string.delete_modal_title), - detail = stringOf(R.string.delete_modal_detail), - buttonText = stringOf(R.string.delete_modal_button_text), - textButtonText = stringOf(R.string.delete_modal_text_button_text), - clickBtn = { homeViewModel.deletePingleDelete(meetingId = pingleEntity.id) }, - clickTextBtn = {} - ).show(childFragmentManager, MAP_DELETE_MODAL) - } - companion object { private const val LOCATION_PERMISSION_REQUEST_CODE = 1000 private val LOCATION_PERMISSIONS = arrayOf( @@ -330,10 +304,6 @@ class MapFragment : BindingFragment(R.layout.fragment_map), Manifest.permission.ACCESS_COARSE_LOCATION ) - private const val MAP_CANCEL_MODAL = "mapCancelModal" - private const val MAP_JOIN_MODAL = "mapJoinModal" - private const val MAP_DELETE_MODAL = "mapDeleteModal" - val OVERLAY_IMAGE_PIN_PLAY_DEFAULT = OverlayImage.fromResource(R.drawable.ic_pin_play_default) val OVERLAY_IMAGE_PIN_STUDY_DEFAULT = diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/mypingle/MyPingleViewHolder.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/main/mypingle/MyPingleViewHolder.kt index f5aca99e..e023643d 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/mypingle/MyPingleViewHolder.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/main/mypingle/MyPingleViewHolder.kt @@ -10,7 +10,7 @@ import org.sopt.pingle.presentation.type.CategoryType import org.sopt.pingle.util.context.colorOf import org.sopt.pingle.util.context.navigateToWebView import org.sopt.pingle.util.context.stringOf -import org.sopt.pingle.util.convertToCalenderDetail +import org.sopt.pingle.util.view.DateTimeUtils import org.sopt.pingle.util.view.setBackgroundTint class MyPingleViewHolder( @@ -40,7 +40,7 @@ class MyPingleViewHolder( context.colorOf(CategoryType.fromString(myPingleEntity.category).textColor) ) tvMyPingleCalenderDetail.text = - convertToCalenderDetail( + DateTimeUtils.convertToCalenderDetail( date = myPingleEntity.date, startAt = myPingleEntity.startAt, endAt = myPingleEntity.endAt diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/plan/PlanViewModel.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/plan/PlanViewModel.kt index fb86fe51..983f5781 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/plan/PlanViewModel.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/plan/PlanViewModel.kt @@ -22,7 +22,7 @@ import org.sopt.pingle.domain.usecase.GetUserInfoUseCase import org.sopt.pingle.domain.usecase.PostPlanMeetingUseCase import org.sopt.pingle.presentation.type.CategoryType import org.sopt.pingle.presentation.type.PlanType -import org.sopt.pingle.util.combineAll +import org.sopt.pingle.util.flow.combineAll import org.sopt.pingle.util.view.UiState @HiltViewModel diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/plan/plansummaryconfirmation/PlanSummaryConfirmationFragment.kt b/app/src/main/java/org/sopt/pingle/presentation/ui/plan/plansummaryconfirmation/PlanSummaryConfirmationFragment.kt index 93040f88..cd6dc275 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/plan/plansummaryconfirmation/PlanSummaryConfirmationFragment.kt +++ b/app/src/main/java/org/sopt/pingle/presentation/ui/plan/plansummaryconfirmation/PlanSummaryConfirmationFragment.kt @@ -12,8 +12,8 @@ import org.sopt.pingle.R import org.sopt.pingle.databinding.FragmentPlanSummaryConfirmationBinding import org.sopt.pingle.presentation.ui.plan.PlanViewModel import org.sopt.pingle.util.base.BindingFragment -import org.sopt.pingle.util.convertToCalenderDetailWithNewLine import org.sopt.pingle.util.fragment.colorOf +import org.sopt.pingle.util.view.DateTimeUtils import org.sopt.pingle.util.view.UiState @AndroidEntryPoint @@ -36,7 +36,7 @@ class PlanSummaryConfirmationFragment : tvPlanSummaryConfirmationName.setTextColor(colorOf((category.textColor))) } tvPlanSummaryConfirmationName.text = viewModel.planTitle.value - tvPlanSummaryConfirmationCalenderDetail.text = convertToCalenderDetailWithNewLine( + tvPlanSummaryConfirmationCalenderDetail.text = DateTimeUtils.convertToCalenderDetailWithNewLine( date = viewModel.planDate.value, startAt = viewModel.startTime.value, endAt = viewModel.endTime.value diff --git a/app/src/main/java/org/sopt/pingle/util/ExtensionUtils.kt b/app/src/main/java/org/sopt/pingle/util/ExtensionUtils.kt index f44ca682..13d532b2 100644 --- a/app/src/main/java/org/sopt/pingle/util/ExtensionUtils.kt +++ b/app/src/main/java/org/sopt/pingle/util/ExtensionUtils.kt @@ -1,53 +1,5 @@ package org.sopt.pingle.util import android.content.res.Resources -import java.time.LocalDate -import java.time.LocalTime -import java.time.format.DateTimeFormatter -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.combineTransform -import kotlinx.coroutines.flow.flowOf - -inline fun List>.combineAll(): Flow> { - return when (size) { - 0 -> flowOf(emptyList()) - else -> combineTransform(this) { flows -> - emit(flows.toList()) - } - } -} fun Int.toPx(): Int = (this * Resources.getSystem().displayMetrics.density).toInt() - -fun convertToDateFormat(localDate: LocalDate): String = localDate.format( - DateTimeFormatter.ofPattern( - DATE_FORMAT - ) -) - -fun convertToTimeFormat(localTime: LocalTime): String = localTime.format( - DateTimeFormatter.ofPattern(TIME_FORMAT) -) - -fun convertToCalenderDetailWithNewLine(date: String, startAt: String, endAt: String): String = - buildString { - append(convertToDateFormat(LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE))) - append(NEW_LINE) - append(convertToTimeFormat(LocalTime.parse(startAt, DateTimeFormatter.ISO_LOCAL_TIME))) - append(TIME_SEPARATOR) - append(convertToTimeFormat(LocalTime.parse(endAt, DateTimeFormatter.ISO_LOCAL_TIME))) - } - -fun convertToCalenderDetail(date: String, startAt: String, endAt: String): String = buildString { - append(convertToDateFormat(LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE))) - append(WIDTH_BAR) - append(convertToTimeFormat(LocalTime.parse(startAt, DateTimeFormatter.ISO_LOCAL_TIME))) - append(TIME_SEPARATOR) - append(convertToTimeFormat(LocalTime.parse(endAt, DateTimeFormatter.ISO_LOCAL_TIME))) -} - -const val DATE_FORMAT = "yyyy년 M월 d일" -const val TIME_FORMAT = "HH:mm" -const val NEW_LINE = "\n" -const val TIME_SEPARATOR = " ~ " -const val WIDTH_BAR = " | " diff --git a/app/src/main/java/org/sopt/pingle/util/component/PingleCardBottom.kt b/app/src/main/java/org/sopt/pingle/util/component/PingleCardBottom.kt index bd8a7282..f43540d3 100644 --- a/app/src/main/java/org/sopt/pingle/util/component/PingleCardBottom.kt +++ b/app/src/main/java/org/sopt/pingle/util/component/PingleCardBottom.kt @@ -9,7 +9,7 @@ import org.sopt.pingle.R import org.sopt.pingle.databinding.BottomCardPingleBinding import org.sopt.pingle.domain.model.PingleEntity import org.sopt.pingle.presentation.mapper.isCompleted -import org.sopt.pingle.util.convertToCalenderDetailWithNewLine +import org.sopt.pingle.util.view.DateTimeUtils import org.sopt.pingle.util.view.stringOf @SuppressLint("CustomViewStyleable") @@ -42,7 +42,7 @@ class PingleCardBottom @JvmOverloads constructor( fun initLayout(pingleEntity: PingleEntity) { with(binding) { - tvCardBottomCalenderDetail.text = convertToCalenderDetailWithNewLine( + tvCardBottomCalenderDetail.text = DateTimeUtils.convertToCalenderDetailWithNewLine( date = pingleEntity.date, startAt = pingleEntity.startAt, endAt = pingleEntity.endAt diff --git a/app/src/main/java/org/sopt/pingle/util/component/PingleCardTop.kt b/app/src/main/java/org/sopt/pingle/util/component/PingleCardTop.kt index 6a2234c4..0b53d338 100644 --- a/app/src/main/java/org/sopt/pingle/util/component/PingleCardTop.kt +++ b/app/src/main/java/org/sopt/pingle/util/component/PingleCardTop.kt @@ -2,6 +2,7 @@ package org.sopt.pingle.util.component import android.annotation.SuppressLint import android.content.Context +import android.content.res.ColorStateList import android.util.AttributeSet import android.view.LayoutInflater import android.view.View @@ -10,6 +11,7 @@ import org.sopt.pingle.databinding.TopCardPingleBinding import org.sopt.pingle.domain.model.PingleEntity import org.sopt.pingle.presentation.mapper.isCompleted import org.sopt.pingle.presentation.type.CategoryType +import org.sopt.pingle.presentation.type.PingleCardType import org.sopt.pingle.util.view.colorOf @SuppressLint("CustomViewStyleable") @@ -25,8 +27,11 @@ class PingleCardTop @JvmOverloads constructor( binding = TopCardPingleBinding.inflate(LayoutInflater.from(context), this, true) } - fun initLayout(pingleEntity: PingleEntity) { + fun initLayout(pingleEntity: PingleEntity, pingleCardType: PingleCardType) { with(binding) { + layoutCardTopParticipationStatus.backgroundTintList = + ColorStateList.valueOf(colorOf(pingleCardType.participationStatusColorRes)) + (CategoryType.fromString(pingleEntity.category)).let { category -> badgeCardTopInfo.setBadgeCategoryType(category) tvCardTopInfoParticipationStatusCurrentParticipants.setTextColor(colorOf(category.textColor)) diff --git a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapModalDialogFragment.kt b/app/src/main/java/org/sopt/pingle/util/component/PingleModalDialogFragment.kt similarity index 61% rename from app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapModalDialogFragment.kt rename to app/src/main/java/org/sopt/pingle/util/component/PingleModalDialogFragment.kt index d85e5a13..d3e2edd1 100644 --- a/app/src/main/java/org/sopt/pingle/presentation/ui/main/home/map/MapModalDialogFragment.kt +++ b/app/src/main/java/org/sopt/pingle/util/component/PingleModalDialogFragment.kt @@ -1,21 +1,21 @@ -package org.sopt.pingle.presentation.ui.main.home.map +package org.sopt.pingle.util.component import android.content.DialogInterface import android.os.Bundle import android.view.View import org.sopt.pingle.R -import org.sopt.pingle.databinding.DialogMapModalBinding +import org.sopt.pingle.databinding.DialogPingleModalBinding import org.sopt.pingle.presentation.type.CategoryType import org.sopt.pingle.util.base.BindingDialogFragment import org.sopt.pingle.util.fragment.colorOf -class MapModalDialogFragment( +class PingleModalDialogFragment( private val category: CategoryType, private val name: String, private val ownerName: String, private val clickBtn: () -> Unit, private val onDialogClosed: () -> Unit = {} -) : BindingDialogFragment(R.layout.dialog_map_modal) { +) : BindingDialogFragment(R.layout.dialog_pingle_modal) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -31,20 +31,20 @@ class MapModalDialogFragment( private fun initLayout() { with(binding) { - badgeMapModalPingleInfoCategory.setBadgeCategoryType(category) - tvMapModalPingleInfoName.text = name - tvMapModalPingleInfoName.setTextColor(colorOf(category.textColor)) - tvMapModalPingleInfoOwnerName.text = ownerName + badgePingleModalPingleInfoCategory.setBadgeCategoryType(category) + tvPingleModalPingleInfoName.text = name + tvPingleModalPingleInfoName.setTextColor(colorOf(category.textColor)) + tvPingleModalPingleInfoOwnerName.text = ownerName } } private fun addListeners() { - binding.btnMapModal.setOnClickListener { + binding.btnPingleModal.setOnClickListener { clickBtn() dismiss() } - binding.layoutMapModalBackground.setOnClickListener { + binding.layoutPingleModalBackground.setOnClickListener { dismiss() } } diff --git a/app/src/main/java/org/sopt/pingle/util/flow/FlowExt.kt b/app/src/main/java/org/sopt/pingle/util/flow/FlowExt.kt new file mode 100644 index 00000000..c5c66130 --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/util/flow/FlowExt.kt @@ -0,0 +1,14 @@ +package org.sopt.pingle.util.flow + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combineTransform +import kotlinx.coroutines.flow.flowOf + +inline fun List>.combineAll(): Flow> { + return when (size) { + 0 -> flowOf(emptyList()) + else -> combineTransform(this) { flows -> + emit(flows.toList()) + } + } +} diff --git a/app/src/main/java/org/sopt/pingle/util/view/DateTimeUtils.kt b/app/src/main/java/org/sopt/pingle/util/view/DateTimeUtils.kt new file mode 100644 index 00000000..9eb6ba19 --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/util/view/DateTimeUtils.kt @@ -0,0 +1,41 @@ +package org.sopt.pingle.util.view + +import java.time.LocalDate +import java.time.LocalTime +import java.time.format.DateTimeFormatter + +object DateTimeUtils { + private const val DATE_FORMAT = "yyyy년 M월 d일" + private const val TIME_FORMAT = "HH:mm" + private const val NEW_LINE = "\n" + private const val TIME_SEPARATOR = " ~ " + private const val WIDTH_BAR = " | " + + private fun convertToDateFormat(localDate: LocalDate): String = localDate.format( + DateTimeFormatter.ofPattern( + DATE_FORMAT + ) + ) + + private fun convertToTimeFormat(localTime: LocalTime): String = localTime.format( + DateTimeFormatter.ofPattern(TIME_FORMAT) + ) + + fun convertToCalenderDetailWithNewLine(date: String, startAt: String, endAt: String): String = + buildString { + append(convertToDateFormat(LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE))) + append(NEW_LINE) + append(convertToTimeFormat(LocalTime.parse(startAt, DateTimeFormatter.ISO_LOCAL_TIME))) + append(TIME_SEPARATOR) + append(convertToTimeFormat(LocalTime.parse(endAt, DateTimeFormatter.ISO_LOCAL_TIME))) + } + + fun convertToCalenderDetail(date: String, startAt: String, endAt: String): String = + buildString { + append(convertToDateFormat(LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE))) + append(WIDTH_BAR) + append(convertToTimeFormat(LocalTime.parse(startAt, DateTimeFormatter.ISO_LOCAL_TIME))) + append(TIME_SEPARATOR) + append(convertToTimeFormat(LocalTime.parse(endAt, DateTimeFormatter.ISO_LOCAL_TIME))) + } +} diff --git a/app/src/main/java/org/sopt/pingle/util/view/ItemDiffCallback.kt b/app/src/main/java/org/sopt/pingle/util/view/ItemDiffCallback.kt new file mode 100644 index 00000000..f951b268 --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/util/view/ItemDiffCallback.kt @@ -0,0 +1,12 @@ +package org.sopt.pingle.util.view + +import androidx.recyclerview.widget.DiffUtil + +class ItemDiffCallback( + val onItemsTheSame: (T, T) -> Boolean, + val onContentsTheSame: (T, T) -> Boolean +) : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: T, newItem: T): Boolean = onItemsTheSame(oldItem, newItem) + override fun areContentsTheSame(oldItem: T, newItem: T): Boolean = + onContentsTheSame(oldItem, newItem) +} diff --git a/app/src/main/java/org/sopt/pingle/util/view/PingleCardUtils.kt b/app/src/main/java/org/sopt/pingle/util/view/PingleCardUtils.kt new file mode 100644 index 00000000..b58664e3 --- /dev/null +++ b/app/src/main/java/org/sopt/pingle/util/view/PingleCardUtils.kt @@ -0,0 +1,75 @@ +package org.sopt.pingle.util.view + +import android.content.Context +import android.content.Intent +import androidx.fragment.app.Fragment +import org.sopt.pingle.R +import org.sopt.pingle.domain.model.PingleEntity +import org.sopt.pingle.presentation.type.CategoryType +import org.sopt.pingle.presentation.ui.main.home.map.MapFragment +import org.sopt.pingle.presentation.ui.participant.ParticipantActivity +import org.sopt.pingle.util.component.AllModalDialogFragment +import org.sopt.pingle.util.component.PingleModalDialogFragment +import org.sopt.pingle.util.fragment.stringOf + +object PingleCardUtils { + private const val PINGLE_CANCEL_MODAL = "pingleCancelModal" + private const val PINGLE_JOIN_MODAL = "pingleJoinModal" + private const val PINGLE_DELETE_MODAL = "pingleDeleteModal" + + fun navigateToParticipant(context: Context, pingleEntityId: Long) { + with(context) { + Intent(this, ParticipantActivity::class.java).apply { + putExtra(MapFragment.MEETING_ID, pingleEntityId) + startActivity(this) + } + } + } + + fun showPingleJoinModalDialogFragment( + fragment: Fragment, + postPingleJoin: () -> Unit, + pingleEntity: PingleEntity + ) { + with(pingleEntity) { + PingleModalDialogFragment( + category = CategoryType.fromString(categoryName = category), + name = name, + ownerName = ownerName, + clickBtn = { postPingleJoin() } + ).show(fragment.childFragmentManager, PINGLE_JOIN_MODAL) + } + } + + fun showPingleCancelModalDialogFragment( + fragment: Fragment, + deletePingleCancel: () -> Unit + ) { + with(fragment) { + AllModalDialogFragment( + title = stringOf(R.string.cancel_modal_title), + detail = stringOf(R.string.cancel_modal_detail), + buttonText = stringOf(R.string.cancel_modal_button_text), + textButtonText = stringOf(R.string.cancel_modal_text_button_text), + clickBtn = { deletePingleCancel() }, + clickTextBtn = { } + ).show(childFragmentManager, PINGLE_CANCEL_MODAL) + } + } + + fun showMapDeleteModalDialogFragment( + fragment: Fragment, + deletePingleDelete: () -> Unit + ) { + with(fragment) { + AllModalDialogFragment( + title = stringOf(R.string.delete_modal_title), + detail = stringOf(R.string.delete_modal_detail), + buttonText = stringOf(R.string.delete_modal_button_text), + textButtonText = stringOf(R.string.delete_modal_text_button_text), + clickBtn = { deletePingleDelete() }, + clickTextBtn = {} + ).show(childFragmentManager, PINGLE_DELETE_MODAL) + } + } +} diff --git a/app/src/main/java/org/sopt/pingle/util/view/ViewExt.kt b/app/src/main/java/org/sopt/pingle/util/view/ViewExt.kt index c164540b..94c1a3de 100644 --- a/app/src/main/java/org/sopt/pingle/util/view/ViewExt.kt +++ b/app/src/main/java/org/sopt/pingle/util/view/ViewExt.kt @@ -6,7 +6,6 @@ import androidx.annotation.StringRes import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat.getString import androidx.core.view.ViewCompat -import androidx.recyclerview.widget.DiffUtil fun View.stringOf(@StringRes resId: Int) = getString(context, resId) @@ -14,12 +13,3 @@ fun View.colorOf(@ColorRes resId: Int) = ContextCompat.getColor(context, resId) fun View.setBackgroundTint(@ColorRes resId: Int) = ViewCompat.setBackgroundTintList(this, ContextCompat.getColorStateList(context, resId)) - -class ItemDiffCallback( - val onItemsTheSame: (T, T) -> Boolean, - val onContentsTheSame: (T, T) -> Boolean -) : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: T, newItem: T): Boolean = onItemsTheSame(oldItem, newItem) - override fun areContentsTheSame(oldItem: T, newItem: T): Boolean = - onContentsTheSame(oldItem, newItem) -} diff --git a/app/src/main/res/layout/dialog_map_modal.xml b/app/src/main/res/layout/dialog_pingle_modal.xml similarity index 82% rename from app/src/main/res/layout/dialog_map_modal.xml rename to app/src/main/res/layout/dialog_pingle_modal.xml index beaae00a..10c4b578 100644 --- a/app/src/main/res/layout/dialog_map_modal.xml +++ b/app/src/main/res/layout/dialog_pingle_modal.xml @@ -8,7 +8,7 @@ @@ -40,7 +40,7 @@ app:layout_constraintGuide_end="@dimen/dialog_map_modal_horizontal_margin" /> + app:layout_constraintTop_toBottomOf="@id/layout_pingle_modal_pingle_info" /> + app:layout_constraintTop_toBottomOf="@id/tv_pingle_modal_description" /> diff --git a/app/src/main/res/layout/fragment_main_list.xml b/app/src/main/res/layout/fragment_main_list.xml index bcf661ac..f21d9974 100644 --- a/app/src/main/res/layout/fragment_main_list.xml +++ b/app/src/main/res/layout/fragment_main_list.xml @@ -12,41 +12,140 @@ android:layout_height="match_parent" tools:context=".presentation.ui.main.home.mainlist.MainListFragment"> - + android:orientation="vertical" + app:layout_constraintGuide_begin="@dimen/spacing16" /> + + + android:textColor='@color/g_02' + app:layout_constraintStart_toStartOf="@id/gl_start" + app:layout_constraintTop_toTopOf="parent" + tools:text="총 5건" /> + + + + + + + + - + + + + + + + + + + + + + android:gravity="center" + android:textAppearance="@style/TextAppearance.Pingle.Sub.Semi.18" + android:textColor="@color/g_06" + android:visibility="invisible" + app:layout_constraintBottom_toBottomOf="@id/rv_main_list" + app:layout_constraintEnd_toStartOf="@id/gl_end" + app:layout_constraintStart_toStartOf="@id/gl_start" + app:layout_constraintTop_toTopOf="@id/rv_main_list" + tools:text="현재 개최된 핑글이 없어요\n핑글을 직접 개최해 보세요!" /> \ No newline at end of file diff --git a/app/src/main/res/layout/item_main_list_pingle_card.xml b/app/src/main/res/layout/item_main_list_pingle_card.xml new file mode 100644 index 00000000..c6f08c1d --- /dev/null +++ b/app/src/main/res/layout/item_main_list_pingle_card.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/item_map_pingle_card.xml b/app/src/main/res/layout/item_map_pingle_card.xml index 399c3c5c..8a39cd1e 100644 --- a/app/src/main/res/layout/item_map_pingle_card.xml +++ b/app/src/main/res/layout/item_map_pingle_card.xml @@ -58,7 +58,7 @@ diff --git a/app/src/main/res/layout/top_card_pingle.xml b/app/src/main/res/layout/top_card_pingle.xml index c6fb03fc..75b43bd3 100644 --- a/app/src/main/res/layout/top_card_pingle.xml +++ b/app/src/main/res/layout/top_card_pingle.xml @@ -61,7 +61,6 @@ android:layout_width="@dimen/card_participant_size" android:layout_height="0dp" android:background="@drawable/shape_oval" - android:backgroundTint="@color/g_10" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintDimensionRatio="1" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a5f3d130..05d8cf43 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -14,6 +14,10 @@ 놀 땐 놀고, 일할 땐 일하자! 다른 활동이 하고 싶다면? + + 최신순 + 날짜임박순 + 랭킹 @@ -68,8 +72,8 @@ 참여하기 - - 이 핑글에 참여할까요? + + 이 핑글에 참여할까요? 참여를 취소하시겠어요? @@ -83,6 +87,11 @@ 삭제하기 돌아가기 + + 총 %d건 + 현재 개최된 핑글이 없어요\n핑글을 직접 개최해보세요! + 검색 결과가 없어요 + 나중에 만드시겠어요? 나가기