feat(character): 캐릭터 탭 UI 및 기본 기능 구현
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
package kr.co.vividnext.sodalive.chat.character
|
||||||
|
|
||||||
|
data class Character(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val description: String,
|
||||||
|
val imageUrl: String,
|
||||||
|
val ranking: Int? = null // 인기 캐릭터에서만 사용
|
||||||
|
)
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package kr.co.vividnext.sodalive.chat.character
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.LinearLayout
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.Character
|
||||||
|
|
||||||
|
class CharacterAdapter(
|
||||||
|
private var characters: List<Character> = emptyList(),
|
||||||
|
private val showRanking: Boolean = false,
|
||||||
|
private val onCharacterClick: (Character) -> Unit = {}
|
||||||
|
) : RecyclerView.Adapter<CharacterAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
val ivCharacter: ImageView = itemView.findViewById(R.id.iv_character)
|
||||||
|
val tvCharacterName: TextView = itemView.findViewById(R.id.tv_character_name)
|
||||||
|
val tvCharacterDescription: TextView = itemView.findViewById(R.id.tv_character_description)
|
||||||
|
val llRanking: LinearLayout = itemView.findViewById(R.id.ll_ranking)
|
||||||
|
val tvRanking: TextView = itemView.findViewById(R.id.tv_ranking)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
val view = LayoutInflater.from(parent.context)
|
||||||
|
.inflate(R.layout.item_character, parent, false)
|
||||||
|
return ViewHolder(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
val character = characters[position]
|
||||||
|
|
||||||
|
holder.tvCharacterName.text = character.name
|
||||||
|
holder.tvCharacterDescription.text = character.description
|
||||||
|
|
||||||
|
// 순위 표시 여부 결정
|
||||||
|
if (showRanking && character.ranking != null) {
|
||||||
|
holder.llRanking.visibility = View.VISIBLE
|
||||||
|
holder.tvRanking.text = character.ranking.toString()
|
||||||
|
} else {
|
||||||
|
holder.llRanking.visibility = View.GONE
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 이미지 로딩 라이브러리 사용 (Glide, Picasso 등)
|
||||||
|
// Glide.with(holder.itemView.context)
|
||||||
|
// .load(character.imageUrl)
|
||||||
|
// .into(holder.ivCharacter)
|
||||||
|
|
||||||
|
holder.itemView.setOnClickListener {
|
||||||
|
onCharacterClick(character)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = characters.size
|
||||||
|
|
||||||
|
fun updateCharacters(newCharacters: List<Character>) {
|
||||||
|
characters = newCharacters
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,15 +2,162 @@ package kr.co.vividnext.sodalive.chat.character
|
|||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import kr.co.vividnext.sodalive.base.BaseFragment
|
import kr.co.vividnext.sodalive.base.BaseFragment
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.curation.CurationSection
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.curation.CurationSectionAdapter
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.recent.RecentCharacter
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.recent.RecentCharacterAdapter
|
||||||
import kr.co.vividnext.sodalive.databinding.FragmentCharacterTabBinding
|
import kr.co.vividnext.sodalive.databinding.FragmentCharacterTabBinding
|
||||||
|
|
||||||
// 캐릭터 탭 프래그먼트
|
// 캐릭터 탭 프래그먼트
|
||||||
class CharacterTabFragment : BaseFragment<FragmentCharacterTabBinding>(
|
class CharacterTabFragment : BaseFragment<FragmentCharacterTabBinding>(
|
||||||
FragmentCharacterTabBinding::inflate
|
FragmentCharacterTabBinding::inflate
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
private lateinit var recentCharacterAdapter: RecentCharacterAdapter
|
||||||
|
private lateinit var popularCharacterAdapter: CharacterAdapter
|
||||||
|
private lateinit var newCharacterAdapter: CharacterAdapter
|
||||||
|
private lateinit var curationSectionAdapter: CurationSectionAdapter
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
// 캐릭터 탭 초기화 로직
|
setupRecyclerViews()
|
||||||
|
loadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupRecyclerViews() {
|
||||||
|
// 최근 대화한 캐릭터 RecyclerView 설정
|
||||||
|
recentCharacterAdapter = RecentCharacterAdapter { character ->
|
||||||
|
// 캐릭터 클릭 처리
|
||||||
|
onRecentCharacterClick(character)
|
||||||
|
}
|
||||||
|
binding.rvRecentCharacters.apply {
|
||||||
|
layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||||
|
adapter = recentCharacterAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
// 인기 캐릭터 RecyclerView 설정 (순위 표시)
|
||||||
|
popularCharacterAdapter = CharacterAdapter(
|
||||||
|
showRanking = true
|
||||||
|
) { character ->
|
||||||
|
// 캐릭터 클릭 처리
|
||||||
|
onCharacterClick(character)
|
||||||
|
}
|
||||||
|
binding.rvPopularCharacters.apply {
|
||||||
|
layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||||
|
adapter = popularCharacterAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
// 신규 캐릭터 RecyclerView 설정
|
||||||
|
newCharacterAdapter = CharacterAdapter(
|
||||||
|
showRanking = false
|
||||||
|
) { character ->
|
||||||
|
// 캐릭터 클릭 처리
|
||||||
|
onCharacterClick(character)
|
||||||
|
}
|
||||||
|
binding.rvNewCharacters.apply {
|
||||||
|
layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||||
|
adapter = newCharacterAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
// 큐레이션 섹션 RecyclerView 설정
|
||||||
|
curationSectionAdapter = CurationSectionAdapter { character ->
|
||||||
|
// 캐릭터 클릭 처리
|
||||||
|
onCharacterClick(character)
|
||||||
|
}
|
||||||
|
binding.rvCurationSections.apply {
|
||||||
|
layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
|
||||||
|
adapter = curationSectionAdapter
|
||||||
|
}
|
||||||
|
|
||||||
|
// 전체보기 버튼 클릭 리스너
|
||||||
|
binding.tvFamousCharacterAll.setOnClickListener {
|
||||||
|
// 인기 캐릭터 전체보기 처리
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.tvNewCharacterAll.setOnClickListener {
|
||||||
|
// 신규 캐릭터 전체보기 처리
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadData() {
|
||||||
|
// TODO: 실제 데이터 로딩 로직 구현
|
||||||
|
loadRecentCharacters()
|
||||||
|
loadPopularCharacters()
|
||||||
|
loadNewCharacters()
|
||||||
|
loadCurationSections()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadRecentCharacters() {
|
||||||
|
// TODO: 서버에서 최근 대화한 캐릭터 데이터 로드
|
||||||
|
val recentCharacters = listOf(
|
||||||
|
RecentCharacter("1", "Yubin...", ""),
|
||||||
|
RecentCharacter("2", "Yubin...", ""),
|
||||||
|
RecentCharacter("3", "Yubin...", ""),
|
||||||
|
RecentCharacter("4", "Yubin...", ""),
|
||||||
|
RecentCharacter("5", "Yubin...", "")
|
||||||
|
)
|
||||||
|
|
||||||
|
recentCharacterAdapter.updateCharacters(recentCharacters)
|
||||||
|
binding.tvLatestCharacterCount.text = recentCharacters.size.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadPopularCharacters() {
|
||||||
|
// TODO: 서버에서 인기 캐릭터 데이터 로드
|
||||||
|
val popularCharacters = listOf(
|
||||||
|
Character("1", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", "", 1),
|
||||||
|
Character("2", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", "", 2),
|
||||||
|
Character("3", "캐릭터 이름", "#태그#태그#태그", "", 3),
|
||||||
|
Character("4", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", "", 4),
|
||||||
|
Character("5", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", "", 5)
|
||||||
|
)
|
||||||
|
|
||||||
|
popularCharacterAdapter.updateCharacters(popularCharacters)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadNewCharacters() {
|
||||||
|
// TODO: 서버에서 신규 캐릭터 데이터 로드
|
||||||
|
val newCharacters = listOf(
|
||||||
|
Character("1", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||||
|
Character("2", "하이퍼나이프", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||||
|
Character("3", "내일", "#태그#태그", "")
|
||||||
|
)
|
||||||
|
|
||||||
|
newCharacterAdapter.updateCharacters(newCharacters)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadCurationSections() {
|
||||||
|
// TODO: 서버에서 큐레이션 섹션 데이터 로드
|
||||||
|
val curationSections = listOf(
|
||||||
|
CurationSection(
|
||||||
|
"1",
|
||||||
|
"큐레이션",
|
||||||
|
listOf(
|
||||||
|
Character("1", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||||
|
Character("2", "하이퍼나이프", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||||
|
Character("3", "내일", "#태그#태그", "")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
CurationSection(
|
||||||
|
"2",
|
||||||
|
"큐레이션",
|
||||||
|
listOf(
|
||||||
|
Character("4", "캐릭터 이름", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||||
|
Character("5", "하이퍼나이프", "캐릭터 한줄 소개인데 2줄까", ""),
|
||||||
|
Character("6", "내일", "#태그#태그", "")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
curationSectionAdapter.updateSections(curationSections)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onRecentCharacterClick(character: RecentCharacter) {
|
||||||
|
// TODO: 최근 대화한 캐릭터 클릭 처리
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onCharacterClick(character: Character) {
|
||||||
|
// TODO: 캐릭터 클릭 처리
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package kr.co.vividnext.sodalive.chat.character.curation
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.Character
|
||||||
|
|
||||||
|
data class CurationSection(
|
||||||
|
val id: String,
|
||||||
|
val title: String,
|
||||||
|
val characters: List<Character>
|
||||||
|
)
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package kr.co.vividnext.sodalive.chat.character.curation
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.CharacterAdapter
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.Character
|
||||||
|
import kr.co.vividnext.sodalive.chat.character.curation.CurationSection
|
||||||
|
|
||||||
|
class CurationSectionAdapter(
|
||||||
|
private var sections: List<CurationSection> = emptyList(),
|
||||||
|
private val onCharacterClick: (Character) -> Unit = {}
|
||||||
|
) : RecyclerView.Adapter<CurationSectionAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
val tvSectionTitle: TextView = itemView.findViewById(R.id.tv_section_title)
|
||||||
|
val rvCharacters: RecyclerView = itemView.findViewById(R.id.rv_characters)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
val view = LayoutInflater.from(parent.context)
|
||||||
|
.inflate(R.layout.item_curation_section, parent, false)
|
||||||
|
return ViewHolder(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
val section = sections[position]
|
||||||
|
|
||||||
|
holder.tvSectionTitle.text = section.title
|
||||||
|
|
||||||
|
// 캐릭터 리스트 설정
|
||||||
|
val characterAdapter = CharacterAdapter(
|
||||||
|
characters = section.characters,
|
||||||
|
showRanking = false,
|
||||||
|
onCharacterClick = onCharacterClick
|
||||||
|
)
|
||||||
|
|
||||||
|
holder.rvCharacters.apply {
|
||||||
|
layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
|
||||||
|
adapter = characterAdapter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = sections.size
|
||||||
|
|
||||||
|
fun updateSections(newSections: List<CurationSection>) {
|
||||||
|
sections = newSections
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package kr.co.vividnext.sodalive.chat.character.recent
|
||||||
|
|
||||||
|
data class RecentCharacter(
|
||||||
|
val id: String,
|
||||||
|
val name: String,
|
||||||
|
val profileImageUrl: String
|
||||||
|
)
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package kr.co.vividnext.sodalive.chat.character.recent
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.ImageView
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import kr.co.vividnext.sodalive.R
|
||||||
|
|
||||||
|
class RecentCharacterAdapter(
|
||||||
|
private var characters: List<RecentCharacter> = emptyList(),
|
||||||
|
private val onCharacterClick: (RecentCharacter) -> Unit = {}
|
||||||
|
) : RecyclerView.Adapter<RecentCharacterAdapter.ViewHolder>() {
|
||||||
|
|
||||||
|
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
val ivProfile: ImageView = itemView.findViewById(R.id.iv_profile)
|
||||||
|
val tvName: TextView = itemView.findViewById(R.id.tv_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||||
|
val view = LayoutInflater.from(parent.context)
|
||||||
|
.inflate(R.layout.item_recent_character, parent, false)
|
||||||
|
return ViewHolder(view)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||||
|
val character = characters[position]
|
||||||
|
|
||||||
|
holder.tvName.text = character.name
|
||||||
|
|
||||||
|
// TODO: 이미지 로딩 라이브러리 사용 (Glide, Picasso 등)
|
||||||
|
// Glide.with(holder.itemView.context)
|
||||||
|
// .load(character.profileImageUrl)
|
||||||
|
// .into(holder.ivProfile)
|
||||||
|
|
||||||
|
holder.itemView.setOnClickListener {
|
||||||
|
onCharacterClick(character)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getItemCount(): Int = characters.size
|
||||||
|
|
||||||
|
@SuppressLint("NotifyDataSetChanged")
|
||||||
|
fun updateCharacters(newCharacters: List<RecentCharacter>) {
|
||||||
|
characters = newCharacters
|
||||||
|
notifyDataSetChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
14
app/src/main/res/drawable/gradient_ranking_bg.xml
Normal file
14
app/src/main/res/drawable/gradient_ranking_bg.xml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<gradient
|
||||||
|
android:angle="135"
|
||||||
|
android:startColor="#80000000"
|
||||||
|
android:centerColor="#99000000"
|
||||||
|
android:endColor="#CC000000"
|
||||||
|
android:type="linear" />
|
||||||
|
<corners
|
||||||
|
android:bottomLeftRadius="16dp"
|
||||||
|
android:bottomRightRadius="0dp"
|
||||||
|
android:topLeftRadius="0dp"
|
||||||
|
android:topRightRadius="0dp" />
|
||||||
|
</shape>
|
||||||
@@ -1,19 +1,183 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@color/black">
|
android:background="@color/color_131313"
|
||||||
|
android:fillViewport="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- 배너 섹션 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_banner"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="48dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<com.zhpan.bannerview.BannerViewPager
|
||||||
|
android:id="@+id/event_banner_slider"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false" />
|
||||||
|
|
||||||
|
<com.zhpan.indicator.IndicatorView
|
||||||
|
android:id="@+id/indicator_event_banner"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginTop="28dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 최근 대화한 캐릭터 섹션 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="48dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- 제목 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="24dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="캐릭터 탭"
|
android:fontFamily="@font/pretendard_bold"
|
||||||
|
android:text="최근 대화한 캐릭터"
|
||||||
android:textColor="@color/white"
|
android:textColor="@color/white"
|
||||||
android:textSize="20sp"
|
android:textSize="20sp" />
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
<TextView
|
||||||
|
android:id="@+id/tv_latest_character_count"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:fontFamily="@font/pretendard_bold"
|
||||||
|
android:textColor="@color/color_fdca2f"
|
||||||
|
android:textSize="20sp"
|
||||||
|
tools:text="14" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 프로필 리스트 -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv_recent_characters"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingHorizontal="24dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 인기 캐릭터 섹션 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="48dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- 제목과 전체보기 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="24dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:fontFamily="@font/pretendard_bold"
|
||||||
|
android:text="인기 캐릭터"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="24sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_famous_character_all"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/pretendard_regular"
|
||||||
|
android:text="전체보기"
|
||||||
|
android:textColor="#90A4AE"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 캐릭터 카드 리스트 -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv_popular_characters"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingStart="24dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 신규 캐릭터 섹션 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="48dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- 제목과 전체보기 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="24dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:fontFamily="@font/pretendard_bold"
|
||||||
|
android:text="신규 캐릭터"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="24sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_new_character_all"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/pretendard_regular"
|
||||||
|
android:text="전체보기"
|
||||||
|
android:textColor="#90A4AE"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 캐릭터 카드 리스트 -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv_new_characters"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingStart="24dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 큐레이션 섹션들 -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv_curation_sections"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="24dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
71
app/src/main/res/layout/item_character.xml
Normal file
71
app/src/main/res/layout/item_character.xml
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="168dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_character"
|
||||||
|
android:layout_width="168dp"
|
||||||
|
android:layout_height="168dp"
|
||||||
|
android:background="@color/color_777777"
|
||||||
|
android:scaleType="centerCrop" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_character_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/pretendard_regular"
|
||||||
|
android:textColor="@color/color_b0bec5"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_character_description"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:fontFamily="@font/pretendard_regular"
|
||||||
|
android:textColor="#78909C"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 순위 표시 (인기 캐릭터에서만 보임) -->
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/ll_ranking"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:background="@drawable/gradient_ranking_bg"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:paddingVertical="8dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_ranking"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="@font/pretendard_bold"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="72sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
36
app/src/main/res/layout/item_curation_section.xml
Normal file
36
app/src/main/res/layout/item_curation_section.xml
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="48dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<!-- 제목 -->
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingHorizontal="24dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_section_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:fontFamily="@font/pretendard_bold"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="24sp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- 캐릭터 카드 리스트 -->
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/rv_characters"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingStart="24dp" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
27
app/src/main/res/layout/item_recent_character.xml
Normal file
27
app/src/main/res/layout/item_recent_character.xml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="76dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_profile"
|
||||||
|
android:layout_width="76dp"
|
||||||
|
android:layout_height="76dp"
|
||||||
|
android:background="@color/color_777777"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:scaleType="centerCrop" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="6dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:fontFamily="@font/pretendard_regular"
|
||||||
|
android:gravity="center"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
</LinearLayout>
|
||||||
Reference in New Issue
Block a user