코틀린 개인 과제

연락처 리스트앱 구현

songyooho 2024. 7. 18. 19:49

1. 구현기능 

-연락처 불러오기

-여러 뷰홀더를 이용하여 즐겨찾기 여부에 따라 다른 아이템뷰로 연락처 리스트 나타내기

-리사이클러뷰 어댑터를 리스트 어댑터 사용하기

-전화 걸기

 

2. 구현

1)Contact

data class Contact(val name:String, val num:String, val img: Bitmap?, val starred:Int)

-연락처 정보를 담는 데이터 클래스

 

2)CustomAdapter

class CustomAdapter() : ListAdapter<Contact,ViewHolder>(diffUtil){

    interface ItemClick{
        fun onClick(tel:String)
    }

    var itemClick : ItemClick? = null

    override fun getItemViewType(position: Int): Int {
        return currentList[position].starred
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return when(viewType){
            0 -> normalViewHolder(ItemNormalBinding.inflate(inflater,parent,false))
            else -> likeViewHolder(ItemLikeBinding.inflate(inflater,parent,false))
        }
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {

        val contact:Contact = currentList[position]
        if(holder is normalViewHolder){
            holder.binding.root.setOnClickListener{
                itemClick?.onClick(contact.num)
            }

            if(contact.img!=null){
                holder.img.setImageBitmap(contact.img)
            }

            holder.num.text=contact.num
            holder.name.text=contact.name
        }else if(holder is likeViewHolder){
            holder.binding.root.setOnClickListener{
                itemClick?.onClick(contact.num)
            }

            if(contact.img!=null){
                holder.img.setImageBitmap(contact.img)
            }
            holder.num.text=contact.num
            holder.name.text=contact.name
        }
    }


    companion object{
        val diffUtil = object :DiffUtil.ItemCallback<Contact>(){
            override fun areItemsTheSame(oldItem: Contact, newItem: Contact) = oldItem == newItem
            override fun areContentsTheSame(oldItem: Contact, newItem: Contact) = oldItem == newItem
        }
    }

    inner class normalViewHolder(val binding: ItemNormalBinding) : RecyclerView.ViewHolder(binding.root){
        val img=binding.normalImg
        val name=binding.normalName
        val num=binding.normalNum
    }

    inner class likeViewHolder(val binding: ItemLikeBinding) : RecyclerView.ViewHolder(binding.root){
        val img=binding.likeImg
        val name=binding.likeName
        val num= binding.likeNum
    }
}

-diffUtil을 인자로 받아 아이템 비교에 관한 콜백 메소드를 작성

-즐겨찾기 여부에 따라 두가지의 뷰홀더 이너클래스 작성

-getItemViewType으로 뷰타입을 설정하는 함수 오버라이드

 

 

3)MainActivity

class MainActivity : AppCompatActivity() {

    private val binding:ActivityMainBinding by lazy {
        ActivityMainBinding.inflate(layoutInflater)
    }

    val adapter:CustomAdapter by lazy {
        CustomAdapter()
    }

    val contacts = ArrayList<Contact>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContentView(binding.root)
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
            val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
            insets
        }
        initRecyclerView()
        getPermission()


    }

    fun getPermission(){
        if(Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return
        val permissions = arrayOf(android.Manifest.permission.READ_CONTACTS, android.Manifest.permission.CALL_PHONE)
        var flag=false
        for(i in permissions){
            if(checkSelfPermission(i)==PackageManager.PERMISSION_DENIED){
                flag=true
            }
        }
        if(flag) requestPermissions(permissions,0)
        else initContact()

    }

    fun initContact(){
        if(checkSelfPermission(android.Manifest.permission.READ_CONTACTS)==PackageManager.PERMISSION_DENIED) return
        contacts.clear()
        val projection = arrayOf<String>(ContactsContract.CommonDataKinds.Phone.CONTACT_ID, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
            ContactsContract.CommonDataKinds.Phone.NUMBER,ContactsContract.CommonDataKinds.Photo.PHOTO_URI, ContactsContract.Contacts.STARRED)

        val cursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,projection,null,null,null)
        if(cursor==null) return

        while (cursor.moveToNext()){
            val nameidx=cursor.getColumnIndex(projection[1])
            val numberidx=cursor.getColumnIndex(projection[2])
            val photoidx=cursor.getColumnIndex(projection[3])
            val starredidx=cursor.getColumnIndex(projection[4])

            val name = cursor.getString(nameidx)
            val number = cursor.getString(numberidx)

            val photoUri = cursor.getString(photoidx)?.toUri()
            println(photoUri)
            val photo = photoUri?.let{
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                    ImageDecoder.decodeBitmap(ImageDecoder.createSource(contentResolver, photoUri))
                } else {
                    MediaStore.Images.Media.getBitmap(contentResolver, photoUri)
                }
            }

            val starred = cursor.getInt(starredidx)

            contacts+=Contact(name,number,photo,starred)

        }
        println("contacts:${contacts.size}")
        adapter.submitList(contacts)

    }

    fun initRecyclerView(){
        binding.recyclerView.apply{
            layoutManager=LinearLayoutManager(this@MainActivity,LinearLayoutManager.VERTICAL,false)
            this@MainActivity.adapter.itemClick = object : CustomAdapter.ItemClick{
                override fun onClick(tel:String) {
                    startActivity(Intent("android.intent.action.CALL", Uri.parse("tel:"+tel.replace("-",""))))
                }
            }
            this.adapter=this@MainActivity.adapter
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if(requestCode == 0){
            if(grantResults[0]==PackageManager.PERMISSION_GRANTED){
                initContact()
            }
        }
    }


}

-itemClick에 ItemClick을 오버라이드한 오브젝트를 할당하여 클릭시 전화가 가능하도록 함

-Cursor을 이용해 연락처 정보를 가져옴

-permission체크후 Contact정보를 가져오도록 함

'코틀린 개인 과제' 카테고리의 다른 글

이미지 검색앱 만들기  (0) 2024.08.08
뉴스 리더 앱  (0) 2024.07.18
AppleMarket 구현 과제  (0) 2024.07.15
회원가입 MVVM 과제  (0) 2024.07.14
챌린지반 3주차 첫번째 과제: 디자인 패턴 구현  (0) 2024.07.09