Skip to content
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

[AN-UI] 상성 페이지 UI 구현 #8

Merged
merged 20 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".presentation.type.TypeActivity"
android:exported="false" />
</application>

</manifest>
</manifest>
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package poke.rogue.helper.data.model

enum class MatchedResult {
NORMAL,
STRONG,
WEAK,
INEFFECTIVE,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package poke.rogue.helper.data.model

data class TypeInfo(
val id: Int,
val name: String,
)
27 changes: 27 additions & 0 deletions android/app/src/main/java/poke/rogue/helper/local/dao/TypeDao.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package poke.rogue.helper.local.dao

import poke.rogue.helper.data.model.TypeInfo

object TypeDao {
val allTypes =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

추가하느라 고생하셨습니다 👍

listOf(
TypeInfo(0, "노말"),
TypeInfo(1, "불꽃"),
TypeInfo(2, "물"),
TypeInfo(3, "전기"),
TypeInfo(4, "풀"),
TypeInfo(5, "얼음"),
TypeInfo(6, "격투"),
TypeInfo(7, "독"),
TypeInfo(8, "땅"),
TypeInfo(9, "비행"),
TypeInfo(10, "에스퍼"),
TypeInfo(11, "벌레"),
TypeInfo(12, "바위"),
TypeInfo(13, "고스트"),
TypeInfo(14, "드래곤"),
TypeInfo(15, "악"),
TypeInfo(16, "강철"),
TypeInfo(17, "페어리"),
)
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package poke.rogue.helper.presentation.home

import android.content.Intent
import android.os.Bundle
import poke.rogue.helper.R
import poke.rogue.helper.databinding.ActivityHomeBinding
import poke.rogue.helper.presentation.base.BindingActivity
import poke.rogue.helper.presentation.type.TypeActivity

class HomeActivity : BindingActivity<ActivityHomeBinding>(R.layout.activity_home) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding.tvTmp.setOnClickListener {
Intent(this, TypeActivity::class.java).apply {
startActivity(this)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package poke.rogue.helper.presentation.type

import android.os.Bundle
import poke.rogue.helper.R
import poke.rogue.helper.databinding.ActivityTypeBinding
import poke.rogue.helper.local.dao.TypeDao
import poke.rogue.helper.presentation.base.BindingActivity
import poke.rogue.helper.presentation.type.mapper.toResultUiModel
import poke.rogue.helper.presentation.type.model.TypeMatchedResultUiModel
import poke.rogue.helper.presentation.type.typeselection.TypeSelectionBottomSheetFragment

class TypeActivity : BindingActivity<ActivityTypeBinding>(R.layout.activity_type) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding.ivTypeMyTypeContent.setOnClickListener {
displayBottomSheet()
}
val dummy =
TypeMatchedResultUiModel("페어리", R.drawable.img_property_tmp_2, true, "강한 타입", TypeDao.allTypes.map { it.toResultUiModel() })
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사소한 부분이지만, 저는 개인적으로 멤버 참조를 사용하는 게 읽기 좋아서 그렇게 사용하고 있기는 합니다.
TypeDao.allTypes.map(TypeInfo::toResultUiModel)

binding.typeResult = dummy
}

private fun displayBottomSheet() {
TypeSelectionBottomSheetFragment().show(
supportFragmentManager,
TypeSelectionBottomSheetFragment.TAG,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package poke.rogue.helper.presentation.type

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import poke.rogue.helper.databinding.ItemTypeNameBinding
import poke.rogue.helper.presentation.type.model.TypeUiModel

class TypeResultAdapter(private val types: List<TypeUiModel> = listOf()) :
RecyclerView.Adapter<TypeResultViewHolder>() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ListAdapter 가 아닌 RecyclerView.Adapter 를 사용한 이유가 따로 있을까요?
리사이클러뷰가 필요한 다른 화면에서는 대부분 ListAdapter 를 사용할 것 같아요

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#8 (comment)
해당 코멘트와 동일합니다!

override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int,
): TypeResultViewHolder {
val view = ItemTypeNameBinding.inflate(LayoutInflater.from(parent.context))
return TypeResultViewHolder(view)
}

override fun onBindViewHolder(
holder: TypeResultViewHolder,
position: Int,
) {
val item = types[position]
holder.bind(item)
}

override fun getItemCount(): Int {
return types.size
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package poke.rogue.helper.presentation.type

import android.content.Context
import android.graphics.Color
import android.text.SpannableStringBuilder
import android.text.Spanned
import android.text.style.ForegroundColorSpan
import android.util.AttributeSet
import android.view.LayoutInflater
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.databinding.BindingAdapter
import com.google.android.flexbox.FlexDirection
import com.google.android.flexbox.FlexWrap
import com.google.android.flexbox.FlexboxLayoutManager
import com.google.android.flexbox.JustifyContent
import poke.rogue.helper.databinding.ItemTypeResultBinding
import poke.rogue.helper.presentation.type.model.TypeMatchedResultUiModel

class TypeResultView(context: Context, attrs: AttributeSet) :
ConstraintLayout(context, attrs) {
private val binding: ItemTypeResultBinding by lazy {
ItemTypeResultBinding.inflate(LayoutInflater.from(context), this, true)
}
private val flexboxLayoutManager: FlexboxLayoutManager by lazy {
FlexboxLayoutManager(context).apply {
flexWrap = FlexWrap.WRAP
flexDirection = FlexDirection.ROW
justifyContent = JustifyContent.FLEX_START
}
}

fun bind(typeResult: TypeMatchedResultUiModel) {
binding.typeResult = typeResult
binding.tvResultMyTypeStrength.text =
SpannableStringBuilder(typeResult.matchedResult).apply {
setSpan(
ForegroundColorSpan(Color.RED),
0,
2,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE,
)
}
binding.ivResultMyType.setImageResource(typeResult.typeIconResId)
binding.rvResultMatchedTypes.layoutManager = flexboxLayoutManager
binding.rvResultMatchedTypes.adapter = TypeResultAdapter(typeResult.matchedItem)
}

companion object {
@JvmStatic
@BindingAdapter("typeResult")
fun setTypeResult(
view: TypeResultView,
typeResult: TypeMatchedResultUiModel,
) {
view.bind(typeResult)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package poke.rogue.helper.presentation.type

import androidx.recyclerview.widget.RecyclerView
import poke.rogue.helper.databinding.ItemTypeNameBinding
import poke.rogue.helper.presentation.type.model.TypeUiModel

class TypeResultViewHolder(
private val binding: ItemTypeNameBinding,
) : RecyclerView.ViewHolder(binding.root) {
fun bind(typeItem: TypeUiModel) {
binding.type = typeItem
binding.ivTypeNameIcon.setImageResource(typeItem.iconResId)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 imageRes 는 바인딩 어뎁터를 추가 설정을 안했군요..

// CommonBIndingAdapter
@BindingAdapter("imageRes")
fun ImageView.setImageRes(imageRes: Int) {
    setImageResource(imageRes)
}

추가하도록 하겠습니다

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package poke.rogue.helper.presentation.type.mapper

import poke.rogue.helper.R
import poke.rogue.helper.data.model.TypeInfo
import poke.rogue.helper.presentation.type.model.TypeUiModel

fun TypeInfo.toSelectionUiModel(): TypeUiModel {
val imageResId =
when (this.id) {
0 -> R.drawable.img_type_tmp_1
1 -> R.drawable.img_type_tmp_1
2 -> R.drawable.img_type_tmp_1
3 -> R.drawable.img_type_tmp_1
4 -> R.drawable.img_type_tmp_1
5 -> R.drawable.img_type_tmp_1
6 -> R.drawable.img_type_tmp_1
7 -> R.drawable.img_type_tmp_1
8 -> R.drawable.img_type_tmp_1
9 -> R.drawable.img_type_tmp_1
10 -> R.drawable.img_type_tmp_1
11 -> R.drawable.img_type_tmp_1
12 -> R.drawable.img_type_tmp_1
13 -> R.drawable.img_type_tmp_1
14 -> R.drawable.img_type_tmp_1
15 -> R.drawable.img_type_tmp_1
16 -> R.drawable.img_type_tmp_1
17 -> R.drawable.img_type_tmp_1
else -> throw IllegalArgumentException("Unknown type ID")
}
return TypeUiModel(this.id, this.name, imageResId)
}

fun TypeInfo.toResultUiModel(): TypeUiModel {
val imageResId =
when (this.id) {
0 -> R.drawable.img_property_tmp_1
1 -> R.drawable.img_property_tmp_1
2 -> R.drawable.img_property_tmp_1
3 -> R.drawable.img_property_tmp_1
4 -> R.drawable.img_property_tmp_1
5 -> R.drawable.img_property_tmp_1
6 -> R.drawable.img_property_tmp_1
7 -> R.drawable.img_property_tmp_1
8 -> R.drawable.img_property_tmp_1
9 -> R.drawable.img_property_tmp_1
10 -> R.drawable.img_property_tmp_1
11 -> R.drawable.img_property_tmp_1
12 -> R.drawable.img_property_tmp_1
13 -> R.drawable.img_property_tmp_1
14 -> R.drawable.img_property_tmp_1
15 -> R.drawable.img_property_tmp_1
16 -> R.drawable.img_property_tmp_1
17 -> R.drawable.img_property_tmp_1
else -> throw IllegalArgumentException("Unknown type ID")
}
return TypeUiModel(this.id, this.name, imageResId)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package poke.rogue.helper.presentation.type.mapper

import poke.rogue.helper.R
import poke.rogue.helper.data.model.MatchedResult

fun MatchedResult.displayName(): String {
return when (this) {
MatchedResult.STRONG -> "강한"
MatchedResult.WEAK -> "약한"
MatchedResult.INEFFECTIVE -> "무효한"
MatchedResult.NORMAL -> throw IllegalStateException("")
}
}

fun MatchedResult.displayColor(): Int {
return when (this) {
MatchedResult.STRONG -> R.color.white
MatchedResult.WEAK -> R.color.white
MatchedResult.INEFFECTIVE -> R.color.white
MatchedResult.NORMAL -> throw IllegalStateException("")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package poke.rogue.helper.presentation.type.model

import androidx.annotation.DrawableRes

data class TypeMatchedResultUiModel(
val typeName: String,
@DrawableRes val typeIconResId: Int,
val isMyType: Boolean,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isMyType 이 필요한 이유가 있나요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

내 타입만 선택 or 상대 타입만 선택에 따라서 보여지는 텍스트의 위치가 달라지는데, 이를 처리하기 위해서 넣었습니다!
네이밍을 수정해도 좋을 것 같다는 생각이 드네요 🙃

val matchedResult: String,
val matchedItem: List<TypeUiModel>,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package poke.rogue.helper.presentation.type.model

import androidx.annotation.DrawableRes

data class TypeUiModel(
val id: Int,
val name: String,
@DrawableRes val iconResId: Int,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DrawableRes 애노테이션 좋아요 👍

)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package poke.rogue.helper.presentation.type.typeselection

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import poke.rogue.helper.databinding.ItemTypeChoiceBinding
import poke.rogue.helper.presentation.type.model.TypeUiModel

class TypeSelectionAdapter(private val types: List<TypeUiModel> = listOf()) :
RecyclerView.Adapter<TypeSelectionViewHolder>() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ViewModel 작업할 때 ListAdapter 로 바꿔주시는건가요?!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


데이터에 변화(추가, 삭제 등)가 있는 부분도 아니고, 바텀 시트를 매번 생성하게 되면 어차피 Adapter도 새로 생성되는 거라
굳이 ListAdapter를 사용하지 않아도 될 거라고 생각했었는데 어떻게 생각하시나요!

override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int,
): TypeSelectionViewHolder {
val view = ItemTypeChoiceBinding.inflate(LayoutInflater.from(parent.context))
return TypeSelectionViewHolder(view)
}

override fun getItemCount(): Int {
return types.size
}

override fun onBindViewHolder(
holder: TypeSelectionViewHolder,
position: Int,
) {
val item = types[position]
holder.bind(item)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package poke.rogue.helper.presentation.type.typeselection

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import poke.rogue.helper.databinding.FragmentTypeChoiceBottomSheetBinding
import poke.rogue.helper.local.dao.TypeDao
import poke.rogue.helper.presentation.type.mapper.toSelectionUiModel
import poke.rogue.helper.presentation.util.view.GridSpacingItemDecoration
import poke.rogue.helper.presentation.util.view.dp

class TypeSelectionBottomSheetFragment : BottomSheetDialogFragment() {
private var _binding: FragmentTypeChoiceBottomSheetBinding? = null
private val binding get() = requireNotNull(_binding)
private val adapter by lazy {
TypeSelectionAdapter(TypeDao.allTypes.map { it.toSelectionUiModel() })
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View {
_binding = FragmentTypeChoiceBottomSheetBinding.inflate(inflater, container, false)
return binding.root
}

override fun onViewCreated(
view: View,
savedInstanceState: Bundle?,
) {
super.onViewCreated(view, savedInstanceState)
initAdapter()
}

private fun initAdapter() {
binding.rvTypeChoice.adapter = adapter
val decoration =
GridSpacingItemDecoration(spanCount = 4, spacing = 19.dp, includeEdge = false)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 👍 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아하 spacing 에 Int.dp 확장함수를 이렇게 작성해야 하는군요!!! :)

binding.rvTypeChoice.addItemDecoration(decoration)
}

override fun onDestroyView() {
super.onDestroyView()
_binding = null
}

companion object {
const val TAG = "type_selection_bottom_sheet_fragment"
}
}
Loading
Loading