-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feat] 메인 지도 뷰 카드 구현 #40
Changes from 20 commits
1becc47
331424d
8f07327
d9610da
75f45d1
c4291fc
50163a8
9319ca9
8fd9ada
ba4c6a1
cc74003
ce97cb0
7e1ac86
694a46b
6281026
cbff2be
6c8b03c
ba4b11e
58071f2
a945e52
9233886
69b5994
ca39761
f500d7c
ef95fe8
4216c4a
2404efa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package org.sopt.pingle.domain.model | ||
|
||
data class PingleEntity( | ||
val id: Long, | ||
val category: String, | ||
val name: String, | ||
val ownerName: String, | ||
val location: String, | ||
val date: String, | ||
val startAt: String, | ||
val endAt: String, | ||
val maxParticipants: Int, | ||
val curParticipants: Int, | ||
val isParticipating: Boolean, | ||
val chatLink: String | ||
) |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 카테고리 타입 쓰는 거 진짜 좋은 것 같아요 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,11 +35,16 @@ enum class CategoryType( | |
backgroundBadgeColor = R.color.badge_yellow, | ||
categoryNameRes = R.string.category_multi | ||
), | ||
OTHER( | ||
OTHERS( | ||
textColor = R.color.g_01, | ||
activatedOutLinedColor = R.color.g_01, | ||
backgroundChipColor = R.color.g_10, | ||
backgroundBadgeColor = R.color.g_07, | ||
categoryNameRes = R.string.category_others | ||
) | ||
); | ||
|
||
companion object { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 우앙 이렇게두 되는군욤 이런건 보통 어떤 경우에 이렇게 상ㅇ하낭? |
||
fun fromString(categoryName: String) = | ||
CategoryType.values().first() { it.name == categoryName } | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,9 +28,13 @@ import org.sopt.pingle.R | |
import org.sopt.pingle.databinding.FragmentMapBinding | ||
import org.sopt.pingle.presentation.mapper.toMarker | ||
import org.sopt.pingle.presentation.type.CategoryType | ||
import org.sopt.pingle.presentation.ui.common.AllModalDialogFragment | ||
import org.sopt.pingle.util.base.BindingFragment | ||
import org.sopt.pingle.util.component.OnPingleCardClickListener | ||
import org.sopt.pingle.util.component.PingleChip | ||
import org.sopt.pingle.util.fragment.navigateToWebView | ||
import org.sopt.pingle.util.fragment.showToast | ||
import org.sopt.pingle.util.fragment.stringOf | ||
|
||
class MapFragment : BindingFragment<FragmentMapBinding>(R.layout.fragment_map), OnMapReadyCallback { | ||
private val mapViewModel by viewModels<MapViewModel>() | ||
|
@@ -79,7 +83,20 @@ class MapFragment : BindingFragment<FragmentMapBinding>(R.layout.fragment_map), | |
chipMapCategoryPlay.setChipCategoryType(CategoryType.PLAY) | ||
chipMapCategoryStudy.setChipCategoryType(CategoryType.STUDY) | ||
chipMapCategoryMulti.setChipCategoryType(CategoryType.MULTI) | ||
chipMapCategoryOthers.setChipCategoryType(CategoryType.OTHER) | ||
chipMapCategoryOthers.setChipCategoryType(CategoryType.OTHERS) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OTHERS로 다 바꾼거 완전 꼼꼼핑 |
||
cardMap.initLayout(mapViewModel.dummyPingle) | ||
cardMap.listener = object : OnPingleCardClickListener { | ||
override fun onPingleCardChatBtnClickListener() { | ||
startActivity(navigateToWebView(mapViewModel.dummyPingle.chatLink)) | ||
} | ||
|
||
override fun onPingleCardParticipateBtnClickListener() { | ||
when (mapViewModel.dummyPingle.isParticipating) { | ||
true -> showMapCancelModalDialogFragment() | ||
false -> showMapModalDialogFragment() | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
|
@@ -168,12 +185,38 @@ class MapFragment : BindingFragment<FragmentMapBinding>(R.layout.fragment_map), | |
} | ||
} | ||
|
||
private fun showMapCancelModalDialogFragment() { | ||
AllModalDialogFragment( | ||
title = stringOf(R.string.map_cancel_modal_title), | ||
detail = stringOf(R.string.map_cancel_modal_detail), | ||
buttonText = stringOf(R.string.map_cancel_modal_button_text), | ||
textButtonText = stringOf(R.string.map_cancel_modal_text_button_text), | ||
clickBtn = { mapViewModel.cancelPingle() }, | ||
clickTextBtn = { }, | ||
onDialogClosed = { binding.cardMap.initLayout(mapViewModel.dummyPingle) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 프래그먼트 이런 식으로 쓰는거 진짜 깔끔하구 좋당.. |
||
).show(childFragmentManager, MAP_CANCEL_MODAL) | ||
} | ||
|
||
private fun showMapModalDialogFragment() { | ||
with(mapViewModel.dummyPingle) { | ||
MapModalDialogFragment( | ||
category = CategoryType.fromString(categoryName = category), | ||
name = name, | ||
ownerName = ownerName, | ||
clickBtn = { mapViewModel.joinPingle() }, | ||
onDialogClosed = { binding.cardMap.initLayout(mapViewModel.dummyPingle) } | ||
).show(childFragmentManager, MAP_MODAL) | ||
} | ||
} | ||
|
||
companion object { | ||
private const val LOCATION_PERMISSION_REQUEST_CODE = 1000 | ||
private val LOCATION_PERMISSIONS = arrayOf( | ||
Manifest.permission.ACCESS_FINE_LOCATION, | ||
Manifest.permission.ACCESS_COARSE_LOCATION | ||
) | ||
private const val SINGLE_SELECTION = 0 | ||
private const val MAP_CANCEL_MODAL = "mapCancelModal" | ||
private const val MAP_MODAL = "mapModal" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel | |
import kotlinx.coroutines.flow.MutableStateFlow | ||
import kotlinx.coroutines.flow.asStateFlow | ||
import org.sopt.pingle.domain.model.PinEntity | ||
import org.sopt.pingle.domain.model.PingleEntity | ||
import org.sopt.pingle.presentation.type.CategoryType | ||
|
||
class MapViewModel() : ViewModel() { | ||
|
@@ -38,10 +39,59 @@ class MapViewModel() : ViewModel() { | |
) | ||
) | ||
|
||
var dummyPingle = PingleEntity( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 더미데이터 댕기욥다 ㅋㅅㅋ |
||
id = 1, | ||
category = "PLAY", | ||
name = "핑글핑글핑글 ~", | ||
ownerName = "배지현", | ||
location = "길음역", | ||
date = "2023-01-06", | ||
startAt = "10:30:00", | ||
endAt = "22:34:00", | ||
maxParticipants = 5, | ||
curParticipants = 4, | ||
isParticipating = false, | ||
chatLink = "https://github.com/TeamPINGLE/PINGLE-ANDROID" | ||
) | ||
|
||
private val _category = MutableStateFlow<CategoryType?>(null) | ||
val category get() = _category.asStateFlow() | ||
|
||
fun setCategory(category: CategoryType?) { | ||
_category.value = category | ||
} | ||
|
||
fun cancelPingle() { | ||
dummyPingle = PingleEntity( | ||
id = 1, | ||
category = "PLAY", | ||
name = "핑글핑글핑글 ~", | ||
ownerName = "배지현", | ||
location = "길음역", | ||
date = "2023-01-06", | ||
startAt = "10:30:00", | ||
endAt = "22:34:00", | ||
maxParticipants = 5, | ||
curParticipants = 4, | ||
isParticipating = false, | ||
chatLink = "https://github.com/TeamPINGLE/PINGLE-ANDROID" | ||
) | ||
} | ||
|
||
fun joinPingle() { | ||
dummyPingle = PingleEntity( | ||
id = 1, | ||
category = "PLAY", | ||
name = "핑글핑글핑글 ~", | ||
ownerName = "배지현", | ||
location = "길음역", | ||
date = "2023-01-06", | ||
startAt = "10:30:00", | ||
endAt = "22:34:00", | ||
maxParticipants = 5, | ||
curParticipants = 5, | ||
isParticipating = true, | ||
chatLink = "https://github.com/TeamPINGLE/PINGLE-ANDROID" | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
package org.sopt.pingle.util.component | ||
|
||
import android.annotation.SuppressLint | ||
import android.content.Context | ||
import android.text.Spannable | ||
import android.text.SpannableString | ||
import android.text.style.ForegroundColorSpan | ||
import android.text.style.TextAppearanceSpan | ||
import android.util.AttributeSet | ||
import android.view.LayoutInflater | ||
import androidx.constraintlayout.widget.ConstraintLayout | ||
import java.time.LocalDate | ||
import java.time.LocalTime | ||
import java.time.format.DateTimeFormatter | ||
import org.sopt.pingle.R | ||
import org.sopt.pingle.databinding.CardPingleBinding | ||
import org.sopt.pingle.domain.model.PingleEntity | ||
import org.sopt.pingle.presentation.type.CategoryType | ||
import org.sopt.pingle.util.view.colorOf | ||
import org.sopt.pingle.util.view.stringOf | ||
|
||
@SuppressLint("CustomViewStyleable") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 오호이 현재 프로젝트에 설정된 minSdkVersion 버젼 이후에 나온 API를 사용할때 warning을 없애고 사용할 수 있게 합니다.. 라고 하는데 그게 여기서 머길래 SuppressLint를 사용하신건가요? |
||
class PingleCard @JvmOverloads constructor( | ||
context: Context, | ||
attrs: AttributeSet? = null, | ||
defStyleAttr: Int = 0 | ||
) : ConstraintLayout(context, attrs, defStyleAttr) { | ||
private val binding: CardPingleBinding | ||
var listener: OnPingleCardClickListener? = null | ||
|
||
init { | ||
binding = CardPingleBinding.inflate(LayoutInflater.from(context), this, true) | ||
|
||
addListeners() | ||
} | ||
|
||
private fun addListeners() { | ||
binding.btnCardBottomMapChat.setOnClickListener { | ||
listener?.onPingleCardChatBtnClickListener() | ||
} | ||
|
||
binding.btnCardBottomMapParticipate.setOnClickListener { | ||
listener?.onPingleCardParticipateBtnClickListener() | ||
} | ||
} | ||
|
||
fun initLayout(pingleEntity: PingleEntity) { | ||
val category: CategoryType = CategoryType.fromString(pingleEntity.category) | ||
|
||
with(binding) { | ||
badgeCardTopInfo.setBadgeCategoryType(category) | ||
tvCardTopInfoName.text = pingleEntity.name | ||
tvCardTopInfoName.setTextColor(colorOf(category.textColor)) | ||
tvCardTopInfoOwnerName.text = pingleEntity.ownerName | ||
tvCardBottomCalenderDetail.text = pingleEntity.convertToCalenderDetail() | ||
tvCardBottomMapDetail.text = pingleEntity.location | ||
btnCardBottomMapChat.isEnabled = pingleEntity.isParticipating | ||
btnCardBottomMapParticipate.text = when (pingleEntity.isParticipating) { | ||
true -> stringOf(R.string.map_card_cancel) | ||
false -> stringOf(R.string.map_card_participate) | ||
} | ||
btnCardBottomMapParticipate.isEnabled = | ||
pingleEntity.isParticipating || !pingleEntity.isCompleted() | ||
|
||
if (pingleEntity.isCompleted()) { | ||
with(tvCardTopInfoParticipantDetail) { | ||
text = stringOf(R.string.map_card_completed) | ||
setTextAppearance(R.style.TextAppearance_Pingle_Sub_Semi_16) | ||
} | ||
} else { | ||
with(tvCardTopInfoParticipantDetail) { | ||
val participantDetail = context.getString( | ||
R.string.map_card_participant_detail, | ||
pingleEntity.curParticipants, | ||
pingleEntity.maxParticipants | ||
) | ||
text = SpannableString(participantDetail).apply { | ||
setSpan( | ||
ForegroundColorSpan( | ||
colorOf(category.textColor) | ||
), | ||
CUR_PARTICIPANTS_START, | ||
pingleEntity.curParticipants.toString().length, | ||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | ||
) | ||
setSpan( | ||
TextAppearanceSpan( | ||
context, | ||
R.style.TextAppearance_Pingle_Title_Semi_30 | ||
), | ||
CUR_PARTICIPANTS_START, | ||
pingleEntity.curParticipants.toString().length + 1, | ||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | ||
) | ||
setSpan( | ||
TextAppearanceSpan( | ||
context, | ||
R.style.TextAppearance_Pingle_Title_Semi_20 | ||
), | ||
pingleEntity.curParticipants.toString().length + 1, | ||
participantDetail.length, | ||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE | ||
) | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
companion object { | ||
const val CUR_PARTICIPANTS_START = 0 | ||
} | ||
} | ||
|
||
interface OnPingleCardClickListener { | ||
fun onPingleCardChatBtnClickListener() | ||
fun onPingleCardParticipateBtnClickListener() | ||
} | ||
|
||
fun PingleEntity.isCompleted() = maxParticipants == curParticipants | ||
|
||
fun PingleEntity.convertToCalenderDetail(): String { | ||
val localDate = LocalDate.parse(date, DateTimeFormatter.ISO_LOCAL_DATE) | ||
val startTime = LocalTime.parse(startAt, DateTimeFormatter.ISO_LOCAL_TIME) | ||
val endTime = LocalTime.parse(endAt, DateTimeFormatter.ISO_LOCAL_TIME) | ||
|
||
return buildString { | ||
append("${localDate.year}년 ${localDate.monthValue}월 ${localDate.dayOfMonth}일\n") | ||
append("${startTime.format(DateTimeFormatter.ofPattern("HH:mm"))} ~ ") | ||
append("${endTime.format(DateTimeFormatter.ofPattern("HH:mm"))}") | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<selector xmlns:android="http://schemas.android.com/apk/res/android"> | ||
<item android:color="@color/g_01" android:state_enabled="true" /> | ||
<item android:color="@color/g_07" android:state_enabled="false" /> | ||
</selector> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<selector xmlns:android="http://schemas.android.com/apk/res/android"> | ||
<item android:color="@color/white" android:state_enabled="true" /> | ||
<item android:color="@color/g_06" android:state_enabled="false" /> | ||
</selector> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<shape xmlns:android="http://schemas.android.com/apk/res/android" | ||
android:shape="oval"> | ||
<stroke android:width="1dp" android:color="@color/g_06"/> | ||
</shape> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
네이밍이 어떤 엔티티인지 잘 알아보기 어려운거 같은데 수정하는건 어떨까염!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저도 이 부분 알아보기 좀 힘들다구 느꼈어여ㅜ,ㅜ