Andorid

[Android]Firebase로 채팅 앱 만들기(5)

CoBool 2022. 3. 31. 14:58

이번에는 새로 채팅할 상대를 추가할 수 있는 검색창을 만들어보도록 하겠다.

class AddChatRoomActivity : AppCompatActivity() {
    lateinit var binding:ActivityAddChatroomBinding
    lateinit var btn_exit: ImageButton
    lateinit var edt_opponent:EditText
    lateinit var firebaseDatabase:DatabaseReference
    lateinit var recycler_people:RecyclerView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityAddChatroomBinding.inflate(layoutInflater)
        setContentView(binding.root)
        initializeView()
        initializeListener()
        setupRecycler()
    }

    fun initializeView()   //뷰 초기화
    {
        firebaseDatabase = FirebaseDatabase.getInstance().reference!!
        btn_exit = binding.imgbtnBack
        edt_opponent = binding.edtOpponentName
        recycler_people = binding.recyclerPeoples
    }
    fun initializeListener()   //버튼 클릭 시 리스너 초기화
    {
        btn_exit.setOnClickListener()
        {
            startActivity(Intent(this@AddChatRoomActivity, MainActivity::class.java))
        }

        edt_opponent.addTextChangedListener(object :TextWatcher                  //검색 창에 입력된 글자가 변경될 때마다 검색 내용 업데이트
        {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            }

            override fun afterTextChanged(s: Editable?) {
                var adapter = recycler_people?.adapter as RecyclerUsersAdapter
                adapter.searchItem(s.toString())                  //입력된 검색어로 검색 진행 및 업데이트
            }
        })
    }
    fun setupRecycler()   //사용자 목록 초기화 및 업데이트
    {
       recycler_people.layoutManager = LinearLayoutManager(this)
        recycler_people.adapter = RecyclerUsersAdapter(this)
    }
}

새롭게 대화를 시작할 친구를 검색할 액티비티의 전체 코드이다.

해당 화면에 필요한 뷰들을 초기화한 후,

edt_opponent.addTextChangedListener(object :TextWatcher                  //검색 창에 입력된 글자가 변경될 때마다 검색 내용 업데이트
        {
            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            }

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            }

            override fun afterTextChanged(s: Editable?) {
                var adapter = recycler_people?.adapter as RecyclerUsersAdapter
                adapter.searchItem(s.toString())                  //입력된 검색어로 검색 진행 및 업데이트
            }
        })

검색어 입력란에 단어와 일치하는 사용자를 바로 검색하게 하기 위해 리스너를 추가하였다.

다음으로 각 사용자들의 목록을 불러올 Recycler를 만들어야 한다.

class RecyclerUsersAdapter(val context: Context) :
    RecyclerView.Adapter<RecyclerUsersAdapter.ViewHolder>() {
    var users: ArrayList<User> =arrayListOf()        //검색어로 일치한 사용자 목록
    val allUsers: ArrayList<User> =arrayListOf()    //전체 사용자 목록
    lateinit var currnentUser: User

    init {
        setupAllUserList()
    }

    fun setupAllUserList() {        //전체 사용자 목록 불러오기
        val myUid = FirebaseAuth.getInstance().currentUser?.uid.toString()        //현재 사용자 아이디
        FirebaseDatabase.getInstance().getReference("User").child("users")   //사용자 데이터 요청
            .addValueEventListener(object : ValueEventListener {
                override fun onCancelled(error: DatabaseError) {
                }

                override fun onDataChange(snapshot: DataSnapshot) {
                    users.clear()
                    for (data in snapshot.children) {
                        val item = data.getValue<User>()
                        if (item?.uid.equals(myUid)) {
                            currnentUser = item!!             //전체 사용자 목록에서 현재 사용자는 제외
                            continue
                        }
                        allUsers.add(item!!)              //전체 사용자 목록에 추가
                    }
                    users = allUsers.clone() as ArrayList<User>
                    notifyDataSetChanged()              //화면 업데이트
                }
            })
    }

    fun searchItem(target: String) {            //검색
        if (target.equals("")) {      //검색어 없는 경우 전체 목록 표시
            users = allUsers.clone() as ArrayList<User>
        } else {
            var matchedList = allUsers.filter{ it.name!!.contains(target)}//검색어 포함된 항목 불러오기
            users.clear()
            matchedList.forEach{users.add(it)}
}
        notifyDataSetChanged()          //화면 업데이트
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(context).inflate(R.layout.list_person_item, parent, false)
        return ViewHolder(ListPersonItemBinding.bind(view))
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.txt_name.text= users[position].name
        holder.txt_email.text= users[position].email

        holder.background.setOnClickListener()
{
addChatRoom(position)        //해당 사용자 선택 시
}
}

    fun addChatRoom(position: Int) {     //채팅방 추가
        val opponent = users[position]   //채팅할 상대방 정보
        var database = FirebaseDatabase.getInstance().getReference("ChatRoom")    //넣을 database reference 세팅
        var chatRoom = ChatRoom(         //추가할 채팅방 정보 세팅
mapOf(currnentUser.uid!!totrue, opponent.uid!!totrue),
            null
        )
        var myUid = FirebaseAuth.getInstance().uid//내 Uid
        database.child("chatRooms")
            .orderByChild("users/${opponent.uid}").equalTo(true)       //상대방 Uid가 포함된 채팅방이 있는 지 확인
            .addListenerForSingleValueEvent(object : ValueEventListener {
                override fun onCancelled(error: DatabaseError) {}
                override fun onDataChange(snapshot: DataSnapshot) {
                    if (snapshot.value== null) {              //채팅방이 없는 경우
                        database.child("chatRooms").push().setValue(chatRoom).addOnSuccessListener{// 채팅방 새로 생성 후 이동
                            goToChatRoom(chatRoom, opponent)
}
} else {
                        context.startActivity(Intent(context, MainActivity::class.java))
                        goToChatRoom(chatRoom, opponent)                    //해당 채팅방으로 이동
                    }

                }
            })
    }

    fun goToChatRoom(chatRoom: ChatRoom, opponentUid: User) {       //채팅방으로 이동
        var intent = Intent(context, ChatRoomActivity::class.java)
        intent.putExtra("ChatRoom", chatRoom)       //채팅방 정보
        intent.putExtra("Opponent", opponentUid)    //상대방 정보
        intent.putExtra("ChatRoomKey", "")   //채팅방 키
        context.startActivity(intent)
        (context as AppCompatActivity).finish()
    }

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

    inner class ViewHolder(itemView: ListPersonItemBinding) :
        RecyclerView.ViewHolder(itemView.root) {
        var background = itemView.background
        var txt_name = itemView.txtName
        var txt_email = itemView.txtEmail
    }

}

사용자 목록을 불러오는 Recycler의 전체 코드다.

 fun setupAllUserList() {        //전체 사용자 목록 불러오기
        val myUid = FirebaseAuth.getInstance().currentUser?.uid.toString()        //현재 사용자 아이디
        FirebaseDatabase.getInstance().getReference("User").child("users")   //사용자 데이터 요청
            .addValueEventListener(object : ValueEventListener {
                override fun onCancelled(error: DatabaseError) {
                }

                override fun onDataChange(snapshot: DataSnapshot) {
                    users.clear()
                    for (data in snapshot.children) {
                        val item = data.getValue<User>()
                        if (item?.uid.equals(myUid)) {
                            currnentUser = item!!             //전체 사용자 목록에서 현재 사용자는 제외
                            continue
                        }
                        allUsers.add(item!!)              //전체 사용자 목록에 추가
                    }
                    users = allUsers.clone() as ArrayList<User>
                    notifyDataSetChanged()              //화면 업데이트
                }
            })
    }

사용자들의 정보가 포함된 데이터베이스인 User 데이터베이스에 접근하여 목록을 가져와 저장한 뒤,

현재 사용자의 uid와 비교하여 자신은 제외한다.

 fun searchItem(target: String) {            //검색
        if (target.equals("")) {      //검색어 없는 경우 전체 목록 표시
            users = allUsers.clone() as ArrayList<User>
        } else {
            var matchedList = allUsers.filter{ it.name!!.contains(target)}//검색어 포함된 항목 불러오기
            users.clear()
            matchedList.forEach{users.add(it)}
}
        notifyDataSetChanged()          //화면 업데이트
    }

사용자가 입력란에 검색어를 넣는 경우 위 코드를 실행하여 불러온 전체 목록에서 검색어를 포함하는 목록만 남겨 리스트를 업데이트 한다.

 override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.txt_name.text= users[position].name
        holder.txt_email.text= users[position].email

        holder.background.setOnClickListener()
{
addChatRoom(position)        //해당 사용자 선택 시
}
}

    fun addChatRoom(position: Int) {     //채팅방 추가
        val opponent = users[position]   //채팅할 상대방 정보
        var database = FirebaseDatabase.getInstance().getReference("ChatRoom")    //넣을 database reference 세팅
        var chatRoom = ChatRoom(         //추가할 채팅방 정보 세팅
mapOf(currnentUser.uid!!totrue, opponent.uid!!totrue),
            null
        )
        var myUid = FirebaseAuth.getInstance().uid//내 Uid
        database.child("chatRooms")
            .orderByChild("users/${opponent.uid}").equalTo(true)       //상대방 Uid가 포함된 채팅방이 있는 지 확인
            .addListenerForSingleValueEvent(object : ValueEventListener {
                override fun onCancelled(error: DatabaseError) {}
                override fun onDataChange(snapshot: DataSnapshot) {
                    if (snapshot.value== null) {              //채팅방이 없는 경우
                        database.child("chatRooms").push().setValue(chatRoom).addOnSuccessListener{// 채팅방 새로 생성 후 이동
                            goToChatRoom(chatRoom, opponent)
}
} else {
                        context.startActivity(Intent(context, MainActivity::class.java))
                        goToChatRoom(chatRoom, opponent)                    //해당 채팅방으로 이동
                    }

                }
            })
    }

항목을 선택 시 채팅방 목록 중에서 해당 사용자의 Uid가 포함된 채팅방을 찾아 해당 채팅방 화면으로 이동하고, 없으면 새로 데이터베이스에 채팅방을 삽입한다.

완성된 화면이다.

참조

https://m.blog.naver.com/zoown13/222094002924https://cionman.tistory.com/72https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=traeumen927&logNo=221493556497https://lasbe.tistory.com/19