Skip to content

Commit

Permalink
Merge pull request #140 from Team-Motivoo/feat/#117-change-exercise
Browse files Browse the repository at this point in the history
[QA] 운동 뷰 QA 1차 수정
  • Loading branch information
l2zh committed Apr 8, 2024
2 parents bb65eec + 2f25755 commit 15f0ddb
Show file tree
Hide file tree
Showing 18 changed files with 246 additions and 160 deletions.
6 changes: 6 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,12 @@ dependencies {
// dataStore
implementation 'androidx.datastore:datastore-preferences:1.0.0'

//coil
implementation("io.coil-kt:coil:2.0.0-rc03")

//tooltip
implementation "com.github.skydoves:balloon:1.4.6"

// test
androidTestImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.4'
androidTestImplementation 'com.squareup.okhttp3:mockwebserver:4.10.0'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ data class ResponseExerciseDto(
@Serializable
data class ExerciseHistoryData(
@SerialName("user_type") val userType: String,
@SerialName("opponent_user_type") val opponentUserType: String,
@SerialName("today_mission") val todayMission: MissionContent?,
@SerialName("mission_history") val missionHistory: List<MissionHistory>?,
) {
Expand All @@ -39,8 +40,11 @@ data class ResponseExerciseDto(
}

fun toExerciseData(): ExerciseData {
fun String.removeDayOfTheWeek(): String = this.removeRange(length - 4 until length)
val list: MutableList<ExerciseItemInfo> =
if (data.todayMission == null && data.missionHistory?.isEmpty() == true) {
if (data.todayMission == null && data.missionHistory!!.isEmpty()) {
mutableListOf()
} else if (data.todayMission == null && data.missionHistory!!.size == 1 && data.missionHistory[0].date.removeDayOfTheWeek() == LocalDate.now().prettyString) {
mutableListOf()
} else if (data.todayMission == null) {
mutableListOf(
Expand Down Expand Up @@ -68,7 +72,6 @@ data class ResponseExerciseDto(
}

data.missionHistory?.forEach {
fun String.removeDayOfTheWeek(): String = this.removeRange(length - 4 until length)
if (it.date.removeDayOfTheWeek() != LocalDate.now().prettyString) {
list.add(
ExerciseItemInfo.EachDateItemInfo(
Expand All @@ -83,6 +86,6 @@ data class ResponseExerciseDto(
)
}
}
return ExerciseData(data.userType, list)
return ExerciseData(data.userType, data.opponentUserType, list)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package sopt.motivoo.domain.entity.exercise

class ExerciseData(
val userType: String,
val opponentUserType: String,
val exerciseItemInfoList: List<ExerciseItemInfo>,
) {
sealed class ExerciseItemInfo {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import sopt.motivoo.databinding.ItemExerciseBinding
import sopt.motivoo.databinding.ItemExerciseNoticeBinding
import sopt.motivoo.databinding.ItemExerciseTodayBinding
import sopt.motivoo.domain.entity.exercise.ExerciseData.ExerciseItemInfo

class ExerciseAdapter(private val userType: String) :
class ExerciseAdapter(private val userType: String, private val opponentUserType: String) :
RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private var exerciseItemInfoList: List<ExerciseItemInfo> = emptyList()

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
NOTICE_INFO_TYPE -> {
val binding = ItemExerciseNoticeBinding.inflate(inflater, parent, false)
val binding = ItemExerciseTodayBinding.inflate(inflater, parent, false)
ExerciseNoticeViewHolder(binding)
}

Expand All @@ -30,12 +30,19 @@ class ExerciseAdapter(private val userType: String) :
when (holder) {
is ExerciseNoticeViewHolder -> {
val noticeInfo = exerciseItemInfoList[position]
holder.onBind(noticeInfo as ExerciseItemInfo.NoticeItemInfo, userType)
holder.onBind(
noticeInfo as ExerciseItemInfo.NoticeItemInfo,
userType,
opponentUserType,
itemCount
)
}

is ExerciseEachDateInfoViewHolder -> {
val dateExerciseInfo = exerciseItemInfoList[position]
holder.onBind(dateExerciseInfo as ExerciseItemInfo.EachDateItemInfo, userType, itemCount)
holder.onBind(
dateExerciseInfo as ExerciseItemInfo.EachDateItemInfo, opponentUserType
)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ class ExerciseFragment : BindingFragment<FragmentExerciseBinding>(R.layout.fragm
}

private fun initAdapter(exerciseData: ExerciseData) {
val adapter = ExerciseAdapter(userType = exerciseData.userType)
val adapter = ExerciseAdapter(
userType = exerciseData.userType,
opponentUserType = exerciseData.opponentUserType
)
adapter.updateItemList(exerciseList = exerciseData.exerciseItemInfoList)
binding.rvExerciseEachDateExercise.adapter = adapter
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import androidx.core.content.ContextCompat
import androidx.navigation.findNavController
import androidx.recyclerview.widget.RecyclerView
import coil.load
import coil.transform.RoundedCornersTransformation
import com.skydoves.balloon.ArrowPositionRules
import com.skydoves.balloon.Balloon
import com.skydoves.balloon.BalloonSizeSpec
import sopt.motivoo.R
import sopt.motivoo.databinding.ItemExerciseBinding
import sopt.motivoo.databinding.ItemExerciseNoticeBinding
import sopt.motivoo.databinding.ItemExerciseTodayBinding
import sopt.motivoo.domain.entity.exercise.ExerciseData.ExerciseItemInfo
import sopt.motivoo.presentation.exercise.ExerciseFragment.Companion.CHILD
import sopt.motivoo.util.extension.prettyString
import java.time.LocalDate

class ExerciseEachDateInfoViewHolder(
private val binding: ItemExerciseBinding,
Expand All @@ -21,39 +23,27 @@ class ExerciseEachDateInfoViewHolder(

fun onBind(
exerciseItemInfoData: ExerciseItemInfo.EachDateItemInfo,
userType: String,
itemSize: Int,
opponentUserType: String,
) {
setHistoryOrNot(exerciseItemInfoData, userType, itemSize)
setHistory(exerciseItemInfoData, opponentUserType)
}

private fun setHistoryOrNot(
private fun setHistory(
exerciseItemInfoData: ExerciseItemInfo.EachDateItemInfo,
userType: String,
itemSize: Int,
opponentUserType: String,
) {
with(binding) {
fun String.removeDayOfTheWeek(): String = this.removeRange(length - 4 until length)
if (itemSize == 2 && exerciseItemInfoData.date!!.removeDayOfTheWeek() == LocalDate.now().prettyString) {
ivExerciseEmptyHistory.visibility = View.VISIBLE
ivItemExerciseLeftImage.visibility = View.GONE
tvItemExerciseMyExercise.visibility = View.GONE
tvItemExerciseOpponentExercise.visibility = View.GONE
ivItemExerciseRightImage.visibility = View.GONE
} else {
ivExerciseEmptyHistory.visibility = View.GONE
initText(exerciseItemInfoData, binding, userType)
initImage(exerciseItemInfoData, binding)
val context = binding.root.context
checkStatus(exerciseItemInfoData, binding, context)
}
initText(exerciseItemInfoData, binding, opponentUserType)
val context = binding.root.context
initImage(context, exerciseItemInfoData, binding)
checkStatus(exerciseItemInfoData, binding, context)
}
}

private fun initText(
exerciseItemInfoData: ExerciseItemInfo.EachDateItemInfo,
binding: ItemExerciseBinding,
userType: String,
opponentUserType: String,
) {
with(binding) {
tvItemExerciseDate.text = exerciseItemInfoData.date
Expand All @@ -62,26 +52,36 @@ class ExerciseEachDateInfoViewHolder(
tvItemExerciseMyState.text = exerciseItemInfoData.myMissionStatus
tvItemExerciseParentState.text = exerciseItemInfoData.opponentMissionStatus
tvItemExerciseOpponentExercise.text =
if (userType == CHILD) root.context.getString(R.string.exercise_parent_exercise) else root.context.getString(
R.string.exercise_child_exercise
if (opponentUserType == CHILD) root.context.getString(R.string.exercise_child_exercise) else root.context.getString(
R.string.exercise_parent_exercise
)
}
}

private fun dpToPx(context: Context, dp: Float): Float {
return dp * (context.resources.displayMetrics.density)
}

private fun initImage(
context: Context,
exerciseItemInfoData: ExerciseItemInfo.EachDateItemInfo,
binding: ItemExerciseBinding,
) {
val pxValue = dpToPx(context, 8f)
with(binding) {
if (exerciseItemInfoData.myMissionImgUrl != null) {
ivItemExerciseLeftImage.load(exerciseItemInfoData.myMissionImgUrl)
ivItemExerciseLeftImage.load(exerciseItemInfoData.myMissionImgUrl) {
transformations(RoundedCornersTransformation(pxValue))
}
} else if (exerciseItemInfoData.myMissionStatus == "없음") {
ivItemExerciseLeftImage.setImageResource(R.drawable.img_choose_exercise)
} else {
ivItemExerciseLeftImage.setImageResource(R.drawable.img_success_next_exercise)
}
if (exerciseItemInfoData.opponentMissionImgUrl != null) {
ivItemExerciseRightImage.load(exerciseItemInfoData.opponentMissionImgUrl)
ivItemExerciseRightImage.load(exerciseItemInfoData.opponentMissionImgUrl) {
transformations(RoundedCornersTransformation(pxValue))
}
} else if (exerciseItemInfoData.opponentMissionStatus == "없음") {
ivItemExerciseRightImage.setImageResource(R.drawable.img_choose_exercise)
} else {
Expand Down Expand Up @@ -126,23 +126,58 @@ class ExerciseEachDateInfoViewHolder(
}
}

class ExerciseNoticeViewHolder(private val binding: ItemExerciseNoticeBinding) :
class ExerciseNoticeViewHolder(private val binding: ItemExerciseTodayBinding) :
RecyclerView.ViewHolder(binding.root) {
fun onBind(exerciseNoticeData: ExerciseItemInfo.NoticeItemInfo, userType: String) {
setCharacterIcon(userType)
fun onBind(
exerciseNoticeData: ExerciseItemInfo.NoticeItemInfo,
userType: String,
opponentUserType: String,
itemCount: Int,
) {
clickQuestionMark()
setCharacterIcon(userType, opponentUserType)
setText(exerciseNoticeData)
setEmptyHistory(itemCount)
}

private fun setCharacterIcon(userType: String) {
if (userType == CHILD) {
binding.ivExerciseTodayIconLeft.setImageResource(R.drawable.ic_child_left)
binding.ivExerciseTodayIconRight.setImageResource(R.drawable.ic_parent_right)
} else {
binding.ivExerciseTodayIconLeft.setImageResource(R.drawable.ic_parent_left)
binding.ivExerciseTodayIconRight.setImageResource(R.drawable.ic_child_right)
private fun clickQuestionMark() {
val context = binding.root.context
val balloon = Balloon.Builder(context)
.setHeight(BalloonSizeSpec.WRAP)
.setWidth(BalloonSizeSpec.WRAP)
.setTextResource(R.string.exercise_today_question_notice)
.setArrowColorResource(R.color.white_FFFFFF)
.setBackgroundColorResource(R.color.white_FFFFFF)
.setTextColorResource(R.color.gray_800_303031)
.setTextSize(15f)
.setTextTypeface(R.font.pretendard)
.setPaddingLeft(11)
.setPaddingRight(15)
.setPaddingTop(14)
.setPaddingBottom(15)
.setMarginTop(3)
.setArrowPositionRules(ArrowPositionRules.ALIGN_ANCHOR)
.setIconDrawableResource(R.drawable.ic_notice)
.setCornerRadius(6f)
.setArrowPosition(0.5f)
.setElevation(5)
.setArrowSize(13)
.build()

binding.ivExerciseTodayIconQuestion.setOnClickListener {
balloon.showAlignTop(binding.ivExerciseTodayIconQuestion)
}
}

private fun setCharacterIcon(userType: String, opponentUserType: String) {
if (userType == CHILD) binding.ivExerciseTodayIconLeft.setImageResource(R.drawable.ic_child_left) else binding.ivExerciseTodayIconLeft.setImageResource(
R.drawable.ic_parent_left
)
if (opponentUserType == CHILD) binding.ivExerciseTodayIconRight.setImageResource(R.drawable.ic_child_right) else binding.ivExerciseTodayIconRight.setImageResource(
R.drawable.ic_parent_right
)
}

private fun setText(exerciseNoticeData: ExerciseItemInfo.NoticeItemInfo) {
val context = binding.root.context
if (exerciseNoticeData.missionContent == null) {
Expand All @@ -156,7 +191,7 @@ class ExerciseNoticeViewHolder(private val binding: ItemExerciseNoticeBinding) :
with(binding) {
tvExerciseTodayExercise.text =
context.getString(R.string.exercise_please_select_today_mission)
clExerciseSelectTodayMission.visibility = View.VISIBLE
clExerciseTodaySelectTodayMission.visibility = View.VISIBLE
tvExerciseTodayMission.visibility = View.GONE
ivExerciseTodayBubbleLeft.visibility = View.GONE
ivExerciseTodayBubbleRight.visibility = View.GONE
Expand All @@ -165,7 +200,7 @@ class ExerciseNoticeViewHolder(private val binding: ItemExerciseNoticeBinding) :
}

private fun setClickEvents() {
binding.clExerciseSelectTodayMission.setOnClickListener {
binding.clExerciseTodaySelectTodayMission.setOnClickListener {
it.findNavController().navigate(R.id.action_exerciseFragment_to_homeFragment)
}
}
Expand All @@ -176,28 +211,44 @@ class ExerciseNoticeViewHolder(private val binding: ItemExerciseNoticeBinding) :
) {
with(binding) {
tvExerciseTodayExercise.text = context.getString(R.string.exercise_today_exercise)
clExerciseSelectTodayMission.visibility = View.GONE
clExerciseTodaySelectTodayMission.visibility = View.GONE
tvExerciseTodayMission.text = exerciseNoticeData.missionContent
}
setTodayImageAndBubble(exerciseNoticeData)
setTodayImageAndBubble(context, exerciseNoticeData)
}

private fun dpToPx(context: Context, dp: Float): Float {
return dp * (context.resources.displayMetrics.density)
}

private fun setTodayImageAndBubble(
context: Context,
exerciseNoticeData: ExerciseItemInfo.NoticeItemInfo,
) {
val pxValue = dpToPx(context, 8f)
if (exerciseNoticeData.missionDate == exerciseNoticeData.todayDate) {
if (exerciseNoticeData.myMissionStatus == ExerciseEachDateInfoViewHolder.STATE_SUCCESS_TYPE) {
binding.ivExerciseTodayBubbleLeft.setImageResource(R.drawable.ic_bubble_success)
binding.ivExerciseTodayImageLeft.load(exerciseNoticeData.myMissionImgUrl)
binding.ivExerciseTodayImageLeft.load(exerciseNoticeData.myMissionImgUrl) {
transformations(RoundedCornersTransformation(pxValue))
}
} else {
binding.ivExerciseTodayBubbleLeft.setImageResource(R.drawable.ic_bubble_exercising)
}
if (exerciseNoticeData.opponentMissionStatus == ExerciseEachDateInfoViewHolder.STATE_SUCCESS_TYPE) {
binding.ivExerciseTodayBubbleRight.setImageResource(R.drawable.ic_bubble_success)
binding.ivExerciseTodayImageRight.load(exerciseNoticeData.opponentMissionImgUrl)
binding.ivExerciseTodayImageRight.load(exerciseNoticeData.opponentMissionImgUrl) {
transformations(RoundedCornersTransformation(pxValue))
}
} else {
binding.ivExerciseTodayBubbleRight.setImageResource(R.drawable.ic_bubble_exercising)
}
}
}

private fun setEmptyHistory(itemCount: Int) {
if (itemCount >= 2) {
binding.ivExerciseTodayEmptyHistory.visibility = View.GONE
}
}
}
2 changes: 1 addition & 1 deletion app/src/main/res/drawable/background_exercise.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
<corners
android:bottomRightRadius="12dp"
android:bottomLeftRadius="12dp" />
<solid android:color="@color/red_50_FFEDEC" />
<solid android:color="@color/red_50_FFF4F2" />
</shape>
4 changes: 2 additions & 2 deletions app/src/main/res/drawable/ic_bubble_exercising.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
android:viewportHeight="34">
<path
android:pathData="M13.883,0L56.117,0A13.883,13.883 0,0 1,70 13.883L70,13.883A13.883,13.883 0,0 1,56.117 27.767L13.883,27.767A13.883,13.883 0,0 1,0 13.883L0,13.883A13.883,13.883 0,0 1,13.883 0z"
android:fillColor="#F5F5F5"/>
android:fillColor="#F4F5F9"/>
<path
android:pathData="M25.313,14.227V15.43H19.766V18.149H18.266V15.43H12.5V14.227H25.313ZM13.906,10.383C13.898,8.633 15.883,7.547 18.891,7.54C21.898,7.547 23.867,8.633 23.859,10.383C23.867,12.125 21.898,13.212 18.891,13.212C15.883,13.212 13.898,12.125 13.906,10.383ZM14.109,20.915V16.805H15.594V19.696H23.891V20.915H14.109ZM15.5,10.383C15.484,11.391 16.844,12.008 18.891,12.008C20.945,12.008 22.289,11.391 22.297,10.383C22.289,9.344 20.945,8.735 18.891,8.727C16.844,8.735 15.484,9.344 15.5,10.383ZM39.125,14.024V15.212H26.344V14.024H32.016V12.54H27.938V7.852H37.547V9.024H29.406V11.352H37.641V12.54H33.453V14.024H39.125ZM27.859,18.665C27.859,17.04 29.68,16.125 32.719,16.118C35.734,16.125 37.539,17.04 37.547,18.665C37.539,20.29 35.734,21.204 32.719,21.212C29.68,21.204 27.859,20.29 27.859,18.665ZM29.359,18.665C29.352,19.563 30.578,20.055 32.719,20.04C34.828,20.055 36.063,19.563 36.063,18.665C36.063,17.782 34.828,17.274 32.719,17.274C30.578,17.274 29.352,17.782 29.359,18.665ZM56.844,13.696V14.899H51.188V16.243C53.75,16.383 55.273,17.243 55.281,18.712C55.273,20.297 53.461,21.188 50.453,21.18C47.406,21.188 45.594,20.297 45.594,18.712C45.594,17.243 47.117,16.375 49.719,16.243V14.899H44.078V13.696H56.844ZM44.75,11.79C47.266,11.532 49.25,10.391 49.453,9.04H45.25V7.852H55.703V9.04H51.453C51.656,10.399 53.625,11.532 56.188,11.79L55.656,12.962C53.227,12.68 51.219,11.657 50.461,10.172C49.688,11.657 47.695,12.68 45.266,12.962L44.75,11.79ZM47.094,18.712C47.086,19.563 48.313,20.055 50.453,20.04C52.563,20.055 53.797,19.563 53.797,18.712C53.797,17.844 52.563,17.375 50.453,17.368C48.313,17.375 47.086,17.844 47.094,18.712Z"
android:fillColor="#464747"/>
<path
android:pathData="M34.535,33.24C34.117,33.66 33.437,33.66 33.018,33.24L27.648,27.86C26.974,27.184 27.453,26.031 28.407,26.031L39.147,26.031C40.101,26.031 40.579,27.184 39.905,27.86L34.535,33.24Z"
android:fillColor="#F5F5F5"/>
android:fillColor="#F4F5F9"/>
</vector>
Loading

0 comments on commit 15f0ddb

Please sign in to comment.