[Android / Kotlin] SNS 앱 팀 프로젝트 (1)

Subeen·2023년 12월 27일
0

Android

목록 보기
25/73

오늘부터 본격적으로 앱개발 기초 팀프로젝트가 시작 됐다. 주제는 SNS 앱 만들기로 예시로 인스타그램이 주어졌지만 팀원들과 여러 SNS를 얘기하며 결정한 주제는 게임 커뮤니티 앱이다. 구현 하고 싶은 기능은 많지만 비교적 짧은 기간으로 인해 최소한의 기능으로 디테일을 높이려고 한다. 앞으로 약 일주일간 프로젝트를 진행하며 프로젝트 개발 현황을 정리하고자 한다. 📝

프로젝트 제목/설명

  • 프로젝트 명칭 : 아크마스터(ArkMaster)
    • 플레이어들이 게임에서 마스터하고자 하는 능력을 의미한다.
  • 서비스의 핵심적인 목적 또는 기능
    • 로스트아크 게임의 캐릭터를 소개하고 캐릭터에 대한 플레이 팁을 공유하는 서비스이다.

와이어 프레임

Figma

개발 기능 정리

  • 로그인 화면
    • 이메일, 비밀번호 텍스트 필드 빈값 체크
    • 비밀번호 입력시 *** 표시
    • 회원가입 버튼 클릭시 회원가입 화면으로 이동
    • 로그인 버튼 클릭시 메인 화면으로 이동
  • 회원가입 화면
    • 유효성 검사 (비밀번호 조합, 이메일, 닉네임 중복 체크 등)
    • 스피너를 사용해 이메일 서비스 제공사 목록을 보여줌
    • 텍스트 필드 빈값 체크
    • 비밀번호 입력시 *** 표시
  • 메인 화면
    • 캐릭터 리스트 RecyclerView 사용
    • 캐릭터 이미지를 모서리가 둥근 이미지로 출력
    • 캐릭터 클릭 시 해당 캐릭터의 디테일 화면으로 이동
    • 디테일 화면으로 이동시 animation 구현
    • bottom navigation bar
  • 디테일 화면
    • 메인 화면에서 전달받은 id값에 해당하는 캐릭터 정보 출력
    • 캐릭터에 대해 모든 사용자가 작성한 댓글 목록 출력
  • 마이 페이지 화면
    • 대표 캐릭터를 설정했을 경우에만 프로필 사진 출력
    • 팝업, 스피너를 사용해 대표 캐릭터 설정
    • 사용자가 작성한 댓글 목록 출력

메인 화면

  • 내가 맡은 기능은 메인 화면 구현이다.

Character

data class Character(
    val id: Int, // 고유값
    val profileImage: Int, // 캐릭터 이미지
    val korName: String, // 한글 이름
    val engName: String, // 영어 이름
    val type: String, // 계열
    val explainType: String, // 계열 설명
    val weapon: String, // 대표 무기
    val identification: String, // 아이덴티티
    val explainIdentity: String // 아이덴티티 설명
)

CharacterManager

class CharacterManager {
    companion object {
        fun getItems(): List<Character> = listOf(
            Character(0, R.drawable.character_breaker, "브레이커", "Breaker", "무도가", "", "헤비 건틀릿", "기력/충격/투지 에너지", ""),
            Character(1, R.drawable.character_sorceress, "소서리스", "Sorceress", "마법사", "", "롱 스태프", "마력 방출/점멸", ""),
            Character(2, R.drawable.character_striker, "스트라이커", "Striker", "무도가", "", "엘리멘탈 건틀렛", "엘리멘탈 버블", ""),
            Character(3, R.drawable.character_reaper, "리퍼", "Reaper", "암살자", "", "대거", "페르소나", ""),
            Character(4, R.drawable.character_gunslinger, "건슬링어", "Gunslinger", "헌터(여)", "", "샷건, 더블 핸드건, 라이플", "퀵 스탠스", ""),
            Character(5, R.drawable.character_bard, "바드", "Bard", "마법사", "", "리아네 하프", "세레나데", ""),
            Character(6, R.drawable.character_summoner, "서머너", "Summoner", "마법사", "", "매직 스태프", "고대정령 소환", ""),
            Character(7, R.drawable.character_blade, "블레이드", "Blade", "암살자", "", "검", "블레이드 아츠", ""),
            Character(8, R.drawable.character_lance_master, "창술사", "Lance Master", "무도가", "", "창", "듀얼 스탠스", ""),
            Character(9, R.drawable.character_arcana, "아르카나", "Arcana", "마법사", "", "마법덱", "카드 덱", ""),
            Character(10, R.drawable.character_holyknight, "홀리나이트", "Holyknight", "전사", "", "한손검", "신앙게이지", "")
        )
    }

    fun getSelectedItem(id: Int) {
        getItems().find { it.id == id }?.let { item ->
            println("${item.korName}, ${item.engName}, ${item.type}, ${item.explainType}, ${item.weapon}, ${item.identification}, ${item.explainIdentity}") // TODO
        }
    }
}

RecyclerCharacterAdapter

class RecyclerCharacterAdapter(
    private val items: List<Character>,
    private val itemClickListener: (Int) -> Unit
) :
    RecyclerView.Adapter<RecyclerCharacterAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            LayoutInflater.from(parent.context).inflate(R.layout.item_rv_character, parent, false)
        )
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.itemView.setOnClickListener {
            itemClickListener.invoke(position)
        }
        holder.bindItem(items[position])
    }

    override fun getItemCount(): Int = items.size

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bindItem(item: Character) {
            val ivCharacter = itemView.findViewById<ImageView>(R.id.ivCharacter)
            val tvName = itemView.findViewById<TextView>(R.id.tvCharacterName)
            val tvComment = itemView.findViewById<TextView>(R.id.tvCharacterComment)

            ivCharacter.setImageResource(item.profileImage)
            ivCharacter.clipToOutline = true
            tvName.text = item.korName
            
            val commentsSize = "댓글 ${item.korName.getSize()}"
            tvComment.text = commentsSize
        }
    }
	// 캐릭터 이름으로 검색해 댓글 수 가져오기 
    fun String.getSize() = MyCommentsTempDatas().getCommentSize(this)
}

MainActivity

class MainActivity : AppCompatActivity() {

    private val rcCharacter: RecyclerView by lazy {
        findViewById(R.id.rcCharacter)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        initView()
    }

    private fun initView() {
        val items = CharacterManager.getItems().sortedBy { it.korName }

        val adapter = setCharacterAdapter(items) { position ->
            Toast.makeText(applicationContext, items[position].korName, Toast.LENGTH_SHORT).show()
            // TODO 디테일 화면 이동
        }

        rcCharacter.adapter = adapter
        rcCharacter.layoutManager = GridLayoutManager(this, 3)
    }

	// 어댑터 세팅 
    private fun setCharacterAdapter(
        items: List<Character>,
        onItemClick: (Int) -> Unit
    ): RecyclerCharacterAdapter {
        return RecyclerCharacterAdapter(items, onItemClick)
    }
}
class MyCommentsTempDatas {
    val dataset = arrayOf(
    ...
    ) // 댓글 리스트 

    // 리스트에서 캐릭터 이름에 해당하는 댓글 수 
    fun getCommentSize(name: String): Int = dataset.count { it.charName == name }
}

item_rv_character.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="5dp"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/ivCharacter"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:background="@drawable/iv_background_radius" />

    <TextView
        android:id="@+id/tvCharacterName"
        style="@style/ThemeTvCharacter"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/tvCharacterComment"
        style="@style/ThemeTvCharacter"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="13sp" />

</LinearLayout>

결과 화면

프로젝트 기간이 일주일도 채 안되는 기간이다보니 우선적으로 화면을 액티비티로 구성하여 화면 전환을 구현하려고 한다. 개발 현황을 보고 네비게이션 바를 사용하여 프래그먼트간 화면 전환이 이루어지도록 수정하고, Room database를 사용하여 데이터를 저장하면 좋을 것 같다 ! 🔥

profile
개발 공부 기록 🌱

0개의 댓글