Kotlin高仿微信-第8篇-单聊

news2025/1/13 10:13:26

Kotlin高仿微信-项目实践58篇详细讲解了各个功能点,包括:注册、登录、主页、单聊(文本、表情、语音、图片、小视频、视频通话、语音通话、红包、转账)、群聊、个人信息、朋友圈、支付服务、扫一扫、搜索好友、添加好友、开通VIP等众多功能。

Kotlin高仿微信-项目实践58篇,点击查看详情

效果图:

实现代码:

<?xml version="1.0" encoding="utf-8"?>
<layout>
<androidx.constraintlayout.widget.ConstraintLayout 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_height="match_parent"
    android:id="@+id/chat_main_root"
    android:background="@drawable/wc_base_bg">


    <include layout="@layout/wc_base_top_title"/>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:focusable="true"
        android:focusableInTouchMode="true"
        app:layout_constraintTop_toBottomOf="@+id/base_top_root_layout"
        app:layout_constraintBottom_toTopOf="@+id/chat_bottom_layout">

        <com.aspsine.swipetoloadlayout.SwipeToLoadLayout
            android:id="@+id/swipeToLoadLayout"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toTopOf="@+id/chat_audio"
            app:layout_constraintBottom_toBottomOf="parent"
            android:layout_marginBottom="12dp"
            android:layout_width="match_parent"
            android:layout_height="0dp">

            <com.wn.wechatclientdemo.view.ChatRefreshHeaderView
                android:id="@+id/swipe_refresh_header"
                android:layout_width="match_parent"
                android:layout_height="wrap_content" />

            <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/swipe_target"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:scrollbars="vertical" />

        </com.aspsine.swipetoloadlayout.SwipeToLoadLayout>

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/chat_audio"
            android:layout_width="38dp"
            android:layout_height="38dp"
            android:layout_marginBottom="10dp"
            android:layout_marginTop="100dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            android:src="@drawable/wc_chat_audio"/>

        <EditText
            android:id="@+id/chat_content"
            android:layout_width="0dp"
            android:layout_height="38dp"
            android:layout_marginHorizontal="10dp"
            android:paddingLeft="8dp"
            android:background="@drawable/chat_message_shap_bg"
            app:layout_constraintStart_toEndOf="@+id/chat_audio"
            app:layout_constraintEnd_toStartOf="@+id/chat_emoji"
            app:layout_constraintTop_toTopOf="@+id/chat_audio"
            app:layout_constraintBottom_toBottomOf="@+id/chat_audio"/>

        <com.wn.wechatclientdemo.view.ChatRecordButton
            android:id="@+id/chat_record_btn"
            android:layout_width="0dp"
            android:layout_height="38dp"
            android:visibility="gone"
            android:layout_marginHorizontal="10dp"
            android:background="@drawable/wc_chat_voice_selector"
            app:layout_constraintStart_toEndOf="@+id/chat_audio"
            app:layout_constraintEnd_toStartOf="@+id/chat_emoji"
            app:layout_constraintTop_toTopOf="@+id/chat_audio"
            app:layout_constraintBottom_toBottomOf="@+id/chat_audio"
            android:text="按住说话"/>

        <androidx.appcompat.widget.AppCompatImageView
            android:id="@+id/chat_emoji"
            android:layout_width="38dp"
            android:layout_height="38dp"
            android:layout_marginEnd="10dp"
            app:layout_constraintEnd_toStartOf="@+id/chat_add_or_send"
            app:layout_constraintBottom_toBottomOf="@+id/chat_content"
            app:layout_constraintTop_toTopOf="@+id/chat_content"
            android:src="@drawable/wc_chat_emoji"/>

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/chat_add_or_send"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            app:layout_constraintTop_toTopOf="@+id/chat_content"
            app:layout_constraintTop_toBottomOf="@+id/chat_content"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent">

            <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/chat_add"
                android:layout_width="38dp"
                android:layout_height="38dp"
                android:layout_marginEnd="10dp"
                android:layout_marginBottom="10dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                android:visibility="visible"
                android:src="@drawable/wc_chat_add"/>

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/chat_send"
                app:layout_constraintBottom_toBottomOf="@+id/chat_add_or_send"
                app:layout_constraintTop_toTopOf="@+id/chat_add_or_send"
                app:layout_constraintEnd_toEndOf="parent"
                android:layout_marginRight="10dp"
                android:layout_marginBottom="6dp"
                android:padding="6dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:gravity="center"
                android:visibility="gone"
                android:background="@drawable/wc_blue_light_shape"
                android:textColor="@color/blue"
                android:textStyle="bold"
                android:text="发送"/>
        </androidx.constraintlayout.widget.ConstraintLayout>


    </androidx.constraintlayout.widget.ConstraintLayout>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/chat_bottom_layout"
        android:layout_width="match_parent"
        android:layout_height="220dp"
        android:visibility="gone"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

        <include
            android:id="@+id/chat_add_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            android:visibility="gone"
            layout="@layout/wc_chat_add_layout"/>

        <include
            android:id="@+id/chat_emoji_layout"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            android:visibility="visible"
            layout="@layout/wc_chat_emoji_layout"/>

    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

/**
 * Author : wangning
 * Email : maoning20080809@163.com
 * Date : 2022/4/24 14:10
 * Description : 聊天页面
 */
class ChatFragment : BaseDataBindingFragment<WcChatMainBinding>() , OnRefreshListener{

    override fun getLayoutRes()= R.layout.wc_chat_main

    private val chatViewModel: ChatViewModel by viewModels()
    private val emojiViewModel : EmojiViewModel by viewModels()
    private val userViewModel : UserViewModel by viewModels()
    private val vipViewModel : VipManagerViewModel by viewModels()

    private val REQUEST_PICTURE_CODE = 101
    //申请权限
    private val REQUEST_PERMISSION_CODE = 102

    private var toUserId : String = ""
    private var toUserName : String = ""
    private var adapter : ChatAdapter = ChatAdapter(RedpacketClick(), OnItemLongClick())
    private var account = DataStoreUtils.get(DataStoreParams.User.DS_ACCOUNT, "") as String

    private var navController : NavController? = null
    private var isOpenRedpacketDialog = false
    private var mRedpacketBalance = 0f
    private var mRedpacketFromUser = ""

    //每页13条
    private val PAGE_SIZE = 13
    //当前页
    private var PAGE_NUM = 1
    //从那一条开始(为保证最新的先显示, 先查询最后的,并且不能用desc查询)
    private var startNum = 0
    //总共多少条
    private var CHAT_TOTAL = 0

    companion object {
        const val USER_ID = "CHAT_USER_ID"
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        TagUtils.d("ChatFragment 进入")
        //先判断是否已经注册
        if(!EventBus.getDefault().isRegistered(this)){
            EventBus.getDefault().register(this)
        }

        swipeToLoadLayout.setOnRefreshListener(this)
        //swipeToLoadLayout.setOnLoadMoreListener(this) 不适用加载更多

        handlePermission()
        ChatNotificationUtils.setChatFragment(true)
    }

    override fun onPause() {
        super.onPause()
        AudioUtils.stopChatVoice()
    }

    private fun processInit(){
        checkNetwork()
        initView()
        initListener()
        initEmoji()
        checkRenewall()
    }

    private fun processScrollToPosition(){
        //保证在主线程中进行滑动操作
        CoroutineScope(Dispatchers.Main).launch {
            delay(100)
            swipe_target.scrollToPosition(adapter.itemCount - 1)
        }
    }


    var scrollX : Float = 0f
    var scrollY : Float = 0f

    var linearLayoutManager: LinearLayoutManager? = null
    private fun initView(){
        linearLayoutManager = LinearLayoutManager(requireContext())
        linearLayoutManager?.orientation = LinearLayoutManager.VERTICAL
        swipe_target.layoutManager = linearLayoutManager
        swipe_target.adapter = adapter

        //处理点击发送消息框, 列表向上移动
        chat_content.setOnClickListener {
               if(chat_bottom_layout.visibility == View.VISIBLE){
                chat_bottom_layout.visibility = View.GONE
            }
            SoftInputUtils.showSoftInput(requireActivity(), chat_content)
            processScrollToPosition()
        }

        swipeToLoadLayout.setOnTouchListener { view, motionEvent ->
            SoftInputUtils.hideSoftInput(chat_content)
            hideBottomLayout()
            false
        }

        navController = findNavController()
        navController?.currentBackStackEntry?.savedStateHandle?.getLiveData<Float>(RedpacketFragment.REDPACKET_BALANCE)?.observe(viewLifecycleOwner){
            TagUtils.d("红包返回金额:${it}")
            if(it > 0){
                var content = CommonUtils.Chat.REDPACKET_MARK + it
                var chatBean = CommonUtils.Chat.getChatBean(account, toUserId, ChatBean.USER_TYPE_ME, content, ChatBean.CONTENT_TYPE_REDPACKET, "",0.0, 0.0)
                sendMessage(chatBean)
            }
        }
        navController?.currentBackStackEntry?.savedStateHandle?.getLiveData<Float>(CommonUtils.QRCommon.TRANSFER_BALANCE)?.observe(viewLifecycleOwner){
            TagUtils.d("转账返回金额:${it}")
            if(it > 0){
                var content = CommonUtils.Chat.TRANSFER_MARK + it
                var chatBean = CommonUtils.Chat.getChatBean(account, toUserId, ChatBean.USER_TYPE_ME, content, ChatBean.CONTENT_TYPE_TRANSFER, "",0.0, 0.0)
                sendMessage(chatBean)
            }
        }

        //录音完成回调
        chat_record_btn.setOnFinishedRecordListener(object : ChatRecordButton.OnFinishedRecordListener{
            override fun onFinishedRecord(audioPath: String, time: Int) {
                chat_content.isFocusable = false
                SoftInputUtils.hideSoftInput(chat_record_btn)
                AddFileListener.sendFile(ChatBean.CONTENT_TYPE_VOICE, audioPath, toUserId, time)
            }
        })

        userViewModel.balanceRedpacketLiveData.observe(viewLifecycleOwner){
            TagUtils.d("领取红包服务器返回:${it}")
            if(it.position >= 0){
                //ToastUtils.makeText(requireActivity(), BaseUtils.getString(R.string.wc_receive_redpacket_success))
                redPacketDialogUtils.dismissDialog()

                var position = it.position
                var chatBean = adapter.getItemObject(position)
                chatBean?.let {
                    //设置为点击状态
                    it.isClick = 1
                    adapter.chatList?.set(position, it)
                    adapter.notifyItemChanged(position)
                    chatViewModel.updateChatClickByMessageIdLocal(it.isClick, it.messageId)
                }

                if(isOpenRedpacketDialog){
                    CoroutineScope(Dispatchers.Main).launch {
                        var bundle = bundleOf(CommonUtils.QRCommon.BALANCE to mRedpacketBalance,
                            CommonUtils.QRCommon.TO_USER to mRedpacketFromUser,
                            CommonUtils.QRCommon.FROM_ACCOUNT to account)
                        navController?.navigate(R.id.action_redpacket_success, bundle)
                    }
                }
                isOpenRedpacketDialog = false
                TagUtils.d("点击的view值:${view}")
            } else {
                //ToastUtils.makeText(requireActivity(), BaseUtils.getString(R.string.wc_receive_redpacket_success))
            }
        }

    }


    fun initListener(){
        //发送文本消息
        chat_send.setOnClickListener {
            var content = chat_content.text.toString()
            var chatBean = CommonUtils.Chat.getChatBean(account, toUserId, ChatBean.USER_TYPE_ME, content, ChatBean.CONTENT_TYPE_TEXT, "",0.0, 0.0)
            sendMessage(chatBean)
            chat_emoji.setImageResource(R.drawable.wc_chat_emoji)
        }

        //相册
        chat_add_album.setOnClickListener {
            clickAddItem()
            sendPicture()
        }

        //拍摄
        chat_add_small_video.setOnClickListener {
            clickAddItem()
            var bundle = bundleOf(CameraFragment.TYPE_ENTER to CameraFragment.TYPE_CHAT)
            navController?.navigate(R.id.action_svideo_camera, bundle)
        }

        //视频通话
        chat_add_video_call.setOnClickListener {
            clickAddItem()
            showVideoPopupWindow()
        }

        //发送定位
        chat_add_location.setOnClickListener {
            clickAddItem()
            var bundle = bundleOf(CommonUtils.Chat.TO_USER_ID to toUserId)
            Navigation.findNavController(it).navigate(R.id.action_baidu_map_poi, bundle)
        }

        //录音
        chat_audio.setOnClickListener {
            if(chat_record_btn.isShown){
                hideAudioButton()
                SoftInputUtils.showSoftInput(requireActivity(), chat_content)
            } else {
                showAudioButton()
                hideEmojiLayout()
                hideBottomLayout()
                SoftInputUtils.hideSoftInput(chat_content)
                processScrollToPosition()
            }
        }

        //表情
        chat_emoji.setOnClickListener {
            showBottomLayout()
            showEmojiLayout()
            hideAddLayout()
            hideAudioButton()
            processScrollToPosition()
        }

        //加号
        chat_add.setOnClickListener {
            showBottomLayout()
            hideEmojiLayout()
            showAddLayout()
            hideAudioButton()
            processScrollToPosition()
        }

        chat_content.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) {
                if(s.length > 0){
                    chat_send.visibility = View.VISIBLE
                    chat_add.visibility = View.GONE
                } else {
                    chat_send.visibility = View.GONE
                    chat_add.visibility = View.VISIBLE
                }
            }

            override fun afterTextChanged(s: Editable?) {
            }
        })

        //红包
        chat_add_radpacket.setOnClickListener {
            clickAddItem()
            navController?.navigate(R.id.action_redpacket)
        }

        //转账
        chat_add_transfer.setOnClickListener {
            clickAddItem()
            var bundle = bundleOf(CommonUtils.QRCommon.TO_USER to toUserId)
            navController?.navigate(R.id.action_payment_transfer, bundle)
        }

        //文件
        chat_add_file.setOnClickListener {
            clickAddItem()
            ToastUtils.showBaseTip()
        }

        //收藏
        chat_add_collection.setOnClickListener {
            clickAddItem()
            ToastUtils.showBaseTip()
        }

    }

    private fun initData(){
        //先进入页面,再刷新数据。
        toUserId = arguments?.getString(USER_ID)?:""
        super.builder().setTitleContent("")
        var fromAccount: String = account
        var toAccount: String = toUserId

        CHAT_TOTAL = chatViewModel.getChatCountByAccountAsync(fromAccount, toAccount)
        startNum = CHAT_TOTAL - PAGE_SIZE * PAGE_NUM

        //先查询到我、朋友的头像
        var fromUserBean = UserRepository.getUserByAccountSync(fromAccount)
        var toUserBean = UserRepository.getUserByAccountSync(toAccount)
        adapter.addMeAtavar(fromUserBean?.avatar)
        adapter.addOtherAtavar(toUserBean?.avatar)
        toUserName = toUserBean.nickName
        var friendIsAvailable =  XmppConnectionManager.getInstance().getUserIsAvailable(toUserId)
        var titleContent = ""
        if(friendIsAvailable){
            titleContent = toUserName + BaseUtils.getString(R.string.wc_chat_online)
        } else {
            titleContent = toUserName + BaseUtils.getString(R.string.wc_chat_offline)
        }
        super.builder().setTitleContent(titleContent)
        chatViewModel.getChatListByAccountPage(fromAccount, toAccount, startNum, PAGE_SIZE)
        chatViewModel.chatListLiveData.observe(viewLifecycleOwner){
            if(PAGE_NUM == 1){
                adapter.add(it)
            } else {
                adapter.refresh(it)
            }
            //滚动到底部
            if(adapter.itemCount > 0){
                linearLayoutManager?.scrollToPositionWithOffset(adapter.getItemCount() - 1, Integer.MIN_VALUE);
            }
            if(startNum > 0){
                PAGE_NUM++
            }
            swipeToLoadLayout.isRefreshing = false
        }
    }

    //发送图片
    private fun sendPicture(){
        //单选  // 打开相册
        ImageSelector.builder()
            .useCamera(false) // 设置是否使用拍照
            .setSingle(true) //设置是否单选
            .canPreview(true) //是否点击放大图片查看,,默认为true
            .start(this,REQUEST_PICTURE_CODE)
    }

    //发送文本、红包、表情
    private fun sendMessage(chatBean: ChatBean){
        if(chatBean == null){
            ToastUtils.makeText(requireActivity(), "发送信息不能为空")
            return
        }
        var content = chatBean.content
        if(TextUtils.isEmpty(content)){
            ToastUtils.makeText(requireActivity(), "发送信息不能为空")
        } else {
            ChatManagerUtils.getInstance().sendMessage(toUserId, content)
            chat_content.setText("")
            CoroutineScope(Dispatchers.IO).launch {
                if(chatBean.contentType == ChatBean.CONTENT_TYPE_REDPACKET){
                    var content = chatBean.content
                    chatBean.content = CommonUtils.Chat.getRedpacket(content).toString()
                } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_TRANSFER){
                    var content = chatBean.content
                    chatBean.content = CommonUtils.Chat.getTransfer(content).toString()
                }
                ChatRepository.insertChat(chatBean)
            }
            refreshBase(chatBean)
        }
    }


    /**
     * 刷新发送、接收聊天信息
     * @param chatBean ChatBean
     */
    private fun refreshBase(chatBean: ChatBean){
        CoroutineScope(Dispatchers.Main).launch {
            //chatViewModel.insertChat(chatBean)
            TagUtils.d("ChatFragment refreshBase 刷新聊天信息 ")
            adapter.refresh(chatBean)
            if(chatBean.contentType == ChatBean.CONTENT_TYPE_LOCATION){
                delay(200)
            }
            swipe_target.scrollToPosition(adapter.itemCount -1)
        }
    }

    val EVERY_PAGE_SIZE = 21

    private var mListEmoji : MutableList<EmojiBean> = ArrayList()

    fun initEmoji(){

        emojiViewModel.getAllEmoji()
        emojiViewModel.emojiListLiveData.observe(viewLifecycleOwner) {
            mListEmoji = it

            val vpEmoji: ViewPager = chat_emoji_viewpage
            val indEmoji: EmojiIndicatorView = chat_emoji_iv

            val inflater = LayoutInflater.from(activity)
            val pageSize: Int = EVERY_PAGE_SIZE
            val mEmojiBean = EmojiBean(0, 0)
            val deleteCount = Math.ceil(mListEmoji.size * 1.0 / EVERY_PAGE_SIZE) .toInt() //要显示的删除键的数量

            //TagUtils.d("" + deleteCount)
            for (i in 1 until deleteCount + 1) {
                if (i == deleteCount) {
                    mListEmoji.add(mListEmoji.size, mEmojiBean)
                } else {
                    mListEmoji.add(i * EVERY_PAGE_SIZE - 1, mEmojiBean)
                }
                //TagUtils.d("添加次数$i")
            }


            val pageCount = Math.ceil(mListEmoji.size * 1.0 / pageSize).toInt() //一共的页数

            //TagUtils.d("总共的页数:$pageCount")
            val viewList: MutableList<View> = ArrayList()
            for (index in 0 until pageCount) {
                //每个页面创建一个recycleview
                val recyclerView = inflater.inflate(R.layout.wc_chat_emoji_item_vprecy, vpEmoji, false) as RecyclerView
                recyclerView.layoutManager = GridLayoutManager(activity, 7)
                var entranceAdapter: EmojiAdapter
                if (index == pageCount - 1) {
                    //最后一页的数据
                    val lastPageList: List<EmojiBean> = mListEmoji.subList(
                        index * EVERY_PAGE_SIZE,
                        mListEmoji.size
                    )
                    entranceAdapter = EmojiAdapter(lastPageList)
                } else {
                    entranceAdapter = EmojiAdapter(
                        mListEmoji.subList(
                            index * EVERY_PAGE_SIZE,
                            (index + 1) * EVERY_PAGE_SIZE
                        ))
                }
                entranceAdapter.setOnItemClickListener(object : BaseQuickAdapter.OnItemClickListener{
                    override fun onItemClick(
                        adapter: BaseQuickAdapter<*, *>,
                        view: View?,
                        position: Int
                    ) {
                        if (mEmojiBean.id === 0) {
                            //如果是删除键
                            //mEditText.dispatchKeyEvent( KeyEvent( KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL ) )
                        } else {
                            //mEditText.append((adapter.getData().get(position) as EmojiBean).getUnicodeInt() )
                        }
                    }
                })
                recyclerView.adapter = entranceAdapter
                viewList.add(recyclerView)

                entranceAdapter.setOnItemClickListener { adapter, view, position ->
                    TagUtils.d("点击表情:${position} , ${adapter.getItem(position)}")
                    var emojiBean = adapter.getItem(position) as EmojiBean
                    var content = chat_content.text.toString()
                    content += emojiBean.getEmojiStringByUnicode(emojiBean.unicode)
                    chat_content.setText(content)
                    //光标放在最后
                    chat_content?.setSelection(content.length)
                }
            }
            val adapter = EmojiVpAdapter(viewList)
            vpEmoji.adapter = adapter
            indEmoji.setIndicatorCount(vpEmoji.adapter!!.count)
            indEmoji.setCurrentIndicator(vpEmoji.currentItem)
            vpEmoji.addOnPageChangeListener(object : SimpleOnPageChangeListener() {
                override fun onPageSelected(position: Int) {
                    indEmoji.setCurrentIndicator(position)
                }
            })
            //TagUtils.d("Emoji初始化完毕")
        }

    }


    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (requestCode == REQUEST_PICTURE_CODE && data != null) {
            val images = data.getStringArrayListExtra(ImageSelector.SELECT_RESULT)
            if(images != null && images.size > 0) {
                AddFileListener.sendFile(ChatBean.CONTENT_TYPE_IMG, images[0], toUserId,0)
            }
        }
    }

    override fun onRequestPermissionsResult(requestCode: Int,permissions: Array<out String>,grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if(requestCode == REQUEST_PERMISSION_CODE && grantResults != null && grantResults.size > 0){
            if(grantResults[0] == PackageManager.PERMISSION_GRANTED){
                //录音权限, 暂时不处理
                processInit()
            }
        }
    }

    private fun handlePermission(){
        if(checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
            ||checkPermission(Manifest.permission.CAMERA)
            ||checkPermission(Manifest.permission.RECORD_AUDIO)
            ||checkPermission(Manifest.permission.ACCESS_FINE_LOCATION)
            ||checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
            ){
            var permissions = arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO,
                Manifest.permission.CAMERA,Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.ACCESS_COARSE_LOCATION)
            requestPermissions(permissions, REQUEST_PERMISSION_CODE)
        } else {
            //录音权限, 暂时不处理
            processInit()
        }
    }

    private fun checkPermission(permission: String) :Boolean {
        return ContextCompat.checkSelfPermission(requireActivity(), permission) != PackageManager.PERMISSION_GRANTED
    }

    private lateinit var redPacketDialogUtils : RedPacketDialogUtils

    //长按
    inner  class OnItemLongClick : WcOnItemLongClickInterface {
        override fun onItemLongClick(position: Int) {
            TagUtils.d("长按position:${position}");
            var chatBean = adapter.getItemObject(position);
            TagUtils.d("长按chatBean:${chatBean?.content}");
            showDeleteDialog(position)
        }
    }

    private var baseDialogUtils : BaseDialogUtils? = null

    //显示删除对话框
    fun showDeleteDialog(position : Int){
        var view = LayoutInflater.from(this.requireActivity()).inflate(R.layout.wc_chat_delete_tip, null)
        baseDialogUtils = BaseDialogUtils(this.requireActivity())
        baseDialogUtils!!.builder()
            .showView(view)
            .setCancelable(false)
            .setOnLoadingClick(object : BaseDialogUtils.OnLoadingClick{
                override fun onClickCancel() {

                }

                override fun onClickConfirm() {
                    var chatBean = adapter.getItemObject(position)
                    if(chatBean!=null){
                        chatViewModel.deleteChat(chatBean)
                    }
                    adapter.remove(position)
                }
            })
        baseDialogUtils?.show()
    }

    //聊天页面点击红包
    inner class RedpacketClick : WcOnItemClickInterface {
        override fun onItemClick(obj: Any) {
            if(!NetWorkUtils.isNetworkConnected()){
                ToastUtils.makeText(requireActivity(), BaseUtils.getString(R.string.wc_base_network_tip))
                return
            }
            TagUtils.d("点击红包打开按钮 ${obj}")
            var redPacketBean = obj as RedPacketBean
            //var redPacketBean = RedPacketBean("chaychan","https://img2.baidu.com/it/u=2059292981,3255805850&fm=253&fmt=auto&app=138&f=JPEG?w=200&h=200","大吉大利,今晚吃鸡")
            if(redPacketBean.isClick == 1){
                var bundle = bundleOf(CommonUtils.QRCommon.BALANCE to redPacketBean.balance,
                    CommonUtils.QRCommon.TO_USER to redPacketBean.account,
                    CommonUtils.QRCommon.FROM_ACCOUNT to account)
                navController?.navigate(R.id.action_redpacket_success, bundle)
            } else {
                redPacketDialogUtils = RedPacketDialogUtils()
                redPacketDialogUtils.showRedPacketDialog(requireActivity(), redPacketBean, RedpacketDialogClick())
                isOpenRedpacketDialog = true
            }
        }
    }

    //弹出红包对话框点击open按钮
    inner class RedpacketDialogClick : RedPacketDialogClickInterface {
        override fun onOpenClick(redPacketBean: RedPacketBean) {
            if(!NetWorkUtils.isNetworkConnected()){
                ToastUtils.makeText(requireActivity(), BaseUtils.getString(R.string.wc_base_network_tip))
                redPacketDialogUtils.dismissDialog()
                return
            }

            GlobalScope.launch {
                delay(2000)
                //领取红包,调用接口
                var balance = redPacketBean.balance
                TagUtils.d("点击领取红包元: ${balance}")
                if(balance > 0){
                    mRedpacketBalance = balance
                    mRedpacketFromUser = redPacketBean.account
                    var account = DataStoreUtils.getAccount()
                    userViewModel.updateBalanceRedpacketServer(redPacketBean.position, account, CommonUtils.User.OPERATOR_PLUS, balance)
                }
            }

        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onMessageCallback(obj: Any) {
        //chatBean: ChatBean
        if(obj == null){
            return
        }

        TagUtils.d("接收对象:${obj}")
        //本地小视频回调
        if(obj is SVideoBean){
            TagUtils.d("接收对象type :${obj.type} , ${obj.filePath}")
            if(obj.type == CommonUtils.Moments.TYPE_PICTURE){
                //图片
                //processSendFile(obj.filePath, toUserId)
                AddFileListener.sendFile(ChatBean.CONTENT_TYPE_IMG, obj.filePath, toUserId, 0)
            } else if(obj.type == CommonUtils.Moments.TYPE_VIDEO){
                //小视频
                //processSendVideo(obj.filePath, toUserId)
                AddFileListener.sendFile(ChatBean.CONTENT_TYPE_VIDEO, obj.filePath, toUserId,0)

            }
        }

        //接收信息
        if(obj is ChatBean){
            if(obj.isReceive){
                //接收信息, 当前聊天用户id页面才刷新
                if(obj.fromAccount.equals(toUserId)){
                    refreshBase(obj)
                }
            } else {
                refreshBase(obj)
            }
        }
    }

    private fun hideAudioButton(){
        chat_record_btn.visibility = View.GONE
        chat_audio.setImageResource(R.drawable.wc_chat_audio)
    }

    private fun showAudioButton(){
        chat_record_btn.visibility = View.VISIBLE
        chat_audio.setImageResource(R.drawable.wc_chat_keyboard)
    }

    private fun hideEmojiLayout() {
        TagUtils.d("隐藏emojiLayout")
        chat_emoji_layout.visibility = View.GONE
        chat_emoji.setImageResource(R.drawable.wc_chat_emoji)
    }

    private fun showEmojiLayout(){
        chat_content.requestFocus()
        chat_emoji_layout.visibility = View.VISIBLE
        chat_emoji.setImageResource(R.drawable.wc_chat_keyboard)
    }

    fun hideAddLayout(){
        TagUtils.d("隐藏addLayout")
        chat_add_layout.visibility = View.GONE
    }

    fun showAddLayout(){
        chat_add_layout.visibility = View.VISIBLE
    }

    fun hideBottomLayout() {
        //TagUtils.d("隐藏底部")
        chat_bottom_layout.visibility = View.GONE
    }

    fun showBottomLayout() {
        var softInputHeight: Int = BaseUtils.getDimension(R.dimen.wc_chat_emoji_height)
        SoftInputUtils.hideSoftInput(chat_content)
        chat_bottom_layout.getLayoutParams().height = softInputHeight
        chat_bottom_layout.visibility = View.VISIBLE
    }

    //点击底部按钮
    fun clickAddItem(){
        showAudioButton()
        hideEmojiLayout()
        hideBottomLayout()
        chat_content.clearFocus()
        SoftInputUtils.hideSoftInput(chat_content)
        processScrollToPosition()
    }

    override fun onDestroy() {
        super.onDestroy()
        EventBus.getDefault().unregister(this)
        ChatNotificationUtils.setChatFragment(false)
        SyncUtils.processInsertChatList()
    }

    private fun checkNetwork(){
        if(!NetWorkUtils.isNetworkConnected()){
            ToastUtils.makeText(R.string.wc_base_network_error)
        }
    }

    /**
     * 检查vip信息
     */
    private fun checkRenewall(){

        //view加载完成
        chat_main_root.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener{
            override fun onGlobalLayout() {
                if(!TextUtils.isEmpty(account)){
                    vipViewModel.getVipLocal(account)
                }
                initData()
                chat_main_root.viewTreeObserver.removeOnGlobalLayoutListener(this)
            }
        })

        vipViewModel.vipBeanLiveData.observe(viewLifecycleOwner){
            if(it == null || !CommonUtils.Vip.isVip(it)){
                showRenewalView()
            }
        }

        vipViewModel.vipBeanServerLiveData.observe(viewLifecycleOwner){
            if(it == null){
                ToastUtils.makeText(R.string.wc_vip_renewal_get_no_data)
            } else if(!CommonUtils.Vip.isVip(it)){
                ToastUtils.makeText(R.string.wc_vip_renewal_get_no_vip)
            } else {
                basePopupWindow?.baseDismiss()
                //如果是vip,更新到本地数据库
                vipViewModel.updateVipLocal(it)
            }
        }
    }

    private var basePopupWindow : BasePopupWindow? = null

    /**
     * 显示续费对话框
     */
    private fun showRenewalView(){
        var view = LayoutInflater.from(WcApp.getContext()).inflate(R.layout.wc_vip_renewal_view, null)
        basePopupWindow = BasePopupWindow(requireActivity(), view)
        basePopupWindow?.let {
            it.baseSetOnDismissListener(object : BasePopupWindow.IOnDismissListener {
                override fun onDismiss() {
                    TagUtils.d("dismiss 消失 ")
                }
            })
                .setOnCancelListener(
                    R.id.vip_renewal_cancel,
                    object : BasePopupWindow.IOnCancelListener {
                        override fun onCancelListener() {
                            it.baseDismiss()
                            System.exit(1)
                        }
                    })
                .setOnConfirmListener(
                    R.id.vip_renewal_get,
                    object : BasePopupWindow.IOnConfirmListener {
                        override fun onConfirmListener() {
                            vipViewModel.getVipServer(account)
                        }
                    })
                .baseSetFocusable(false)
                .baseShowAtLocation(chat_main_root)
        }
    }

    private var isReallyBack = false

    override fun onResume() {
        super.onResume()
        chat_main_root.isFocusableInTouchMode = true
        chat_main_root.requestFocus()
        chat_main_root.setOnKeyListener { view, i, keyEvent ->
            if (i == KeyEvent.KEYCODE_BACK && keyEvent.getAction() == KeyEvent.ACTION_DOWN) {
                onBackPressed()
            }
            !isReallyBack
        }
    }

    private var exitTime: Long = 0
    private fun onBackPressed() : Boolean {
        if(basePopupWindow != null && basePopupWindow?.isShowing!!){
            if(System.currentTimeMillis() - exitTime > 1000){
                ToastUtils.makeText(R.string.wc_two_back)
                exitTime = System.currentTimeMillis()
                isReallyBack = false
            } else {
                //连续点击2次,直接退出app
                basePopupWindow?.baseDismiss()
                isReallyBack = true
                System.exit(1)
            }
        } else {
            isReallyBack = true
        }
        return isReallyBack
    }

    //刷新是加载更多数据
    override fun onRefresh() {
        TagUtils.d("onRefresh 执行 ${startNum} , ${CHAT_TOTAL}, ${PAGE_SIZE}, ${PAGE_NUM}")
        CoroutineScope(Dispatchers.Main).launch {
            delay(200)
            swipeToLoadLayout.isRefreshing = false
            if(startNum >= PAGE_SIZE){
                startNum = CHAT_TOTAL - PAGE_SIZE * PAGE_NUM
                chatViewModel.getChatListByAccountPage(account, toUserId, startNum, PAGE_SIZE)
            } else if(startNum > 0 && startNum < PAGE_SIZE){
                //不够1页数据,查询全部,然后就不能下一页
                chatViewModel.getChatListByAccountPage(account, toUserId, 0, startNum)
                startNum = CHAT_TOTAL - PAGE_SIZE * PAGE_NUM
            }
        }
    }

    /**
     * 视频通话、语音通话
     */
    private fun showVideoPopupWindow(){
        var popupView = layoutInflater.inflate(R.layout.wc_chat_video_pop_view , moment_root, false)
        var popupWindow = PopupWindow(popupView, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, true)
        var popupRoot = popupView.findViewById<LinearLayout>(R.id.chat_video_pop_root)
        popupWindow.showAtLocation(popupRoot, Gravity.BOTTOM, 0, 0)

        var window = requireActivity().window
        //popupWindow在弹窗的时候背景半透明
        val params = window.attributes
        params.alpha = 0.5f
        window.attributes = params
        popupWindow.setOnDismissListener {
            params.alpha = 1.0f
            window.attributes = params
        }

        //视频通话
        popupView.findViewById<AppCompatTextView>(R.id.chat_pop_video_call).setOnClickListener {
            popupWindow.dismiss()
            CallSingleActivity.openActivity( requireActivity(),toUserId, true, toUserName, false, false)
        }

        //语音通话
        popupView.findViewById<AppCompatTextView>(R.id.chat_pop_voice_call).setOnClickListener {
            popupWindow.dismiss()
            CallSingleActivity.openActivity( requireActivity(),toUserId, true, toUserName, true, false)
        }

        //取消
        popupView.findViewById<AppCompatTextView>(R.id.chat_pop_cancel).setOnClickListener {
            popupWindow.dismiss()
        }

    }

}

/**
 * Author : wangning
 * Email : maoning20080809@163.com
 * Date : 2022/4/24 16:29
 * Description :
 */
class ChatAdapter(var onClickInterface: WcOnItemClickInterface, var onLongClickInterface : WcOnItemLongClickInterface ) : RecyclerView.Adapter<ChatAdapter.ChatViewHolder>() {

    //我的头像
    private var meAvatar = ""
    //我的其他人
    private var otherAvatar = ""
    var chatList : MutableList<ChatBean>? = null
    var account = DataStoreUtils.getAccount()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChatViewHolder {
        var view = LayoutInflater.from(parent.context).inflate(R.layout.wc_chat_item, parent, false)
        return ChatViewHolder(view)
    }

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

        var chatBean = chatList?.get(position)
        chatBean?.let {
            //if(chatBean.userType == ChatBean.USER_TYPE_ME){
            if(account.equals(chatBean.fromAccount)){
                //我的
                holder.meLayout.visibility = View.VISIBLE
                holder.otherLayout.visibility = View.GONE
                chatBean.avatarReally = CommonUtils.Base.getReallyImage(meAvatar)
                holder.meLayout.process(chatBean, onClickInterface)

            } else {
                //朋友
                holder.meLayout.visibility = View.GONE
                holder.otherLayout.visibility = View.VISIBLE
                chatBean.avatarReally = CommonUtils.Base.getReallyImage(otherAvatar)
                holder.otherLayout.process(chatBean, onClickInterface, position)
            }

            holder.dateTextView.text = CommonUtils.Date.getCurrentDate(chatBean.addTime)
        }
        //长按
        holder.rootLayout.setOnLongClickListener {
            onLongClickInterface.onItemLongClick(position)
            true
        }

    }

    fun addMeAtavar(meAvatar:String){
        this.meAvatar = meAvatar
    }

    fun addOtherAtavar(otherAvatar:String){
        this.otherAvatar = otherAvatar
    }

    //刷新单个
    fun refresh(chatBean: ChatBean){
        this.chatList?.add(chatBean)
        notifyItemInserted(itemCount)
    }

    //刷新多个
    fun refresh(chatList : MutableList<ChatBean>){
        //this.chatList?.addAll(chatList)
        this.chatList?.addAll(0, chatList)
        notifyItemInserted(itemCount)
    }

    fun add(chatList : MutableList<ChatBean>){
        this.chatList = chatList
        notifyDataSetChanged()
    }

    //删除某个
    fun remove(position: Int){
        this.chatList?.removeAt(position)
        notifyDataSetChanged()
    }

    fun getItemObject(position : Int) : ChatBean? = chatList?.get(position)

    override fun getItemCount() = chatList?.size?:0

    class ChatViewHolder(itemView : View) : RecyclerView.ViewHolder(itemView){
        var dateTextView = itemView.findViewById<TextView>(R.id.chat_item_date)
        var otherLayout = itemView.findViewById<ChatOtherView>(R.id.chat_item_other_layout)
        var meLayout = itemView.findViewById<ChatMeView>(R.id.chat_item_me_layout)
        var rootLayout = itemView.findViewById<ConstraintLayout>(R.id.chat_item_root_layout)
    }
}

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:id="@+id/chat_item_root_layout"
    android:layout_marginTop="16dp"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <TextView
        android:id="@+id/chat_item_date"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="聊天时间"
        android:textSize="14sp"
        android:textStyle="bold"
        android:textColor="@color/gray_hint"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <!--朋友的聊天信息-->
    <com.wn.wechatclientdemo.view.ChatOtherView
        android:id="@+id/chat_item_other_layout"
        app:layout_constraintTop_toBottomOf="@+id/chat_item_date"
        app:layout_constraintStart_toStartOf="parent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    <!--我的聊天信息-->
    <com.wn.wechatclientdemo.view.ChatMeView
        android:id="@+id/chat_item_me_layout"
        app:layout_constraintTop_toBottomOf="@+id/chat_item_date"
        app:layout_constraintEnd_toEndOf="parent"
        android:visibility="gone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

</androidx.constraintlayout.widget.ConstraintLayout>

/**
 * Author : wangning
 * Email : maoning20080809@163.com
 * Date : 2022/5/29 15:41
 * Description : 聊天内容-其他人
 */
class ChatOtherView : LinearLayout {


    constructor(context: Context) : this(context, null)
    constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0)
    constructor(context: Context, attributeSet: AttributeSet?, defStyleAttr: Int) : super(context, attributeSet, defStyleAttr){
    }

    init {
        LayoutInflater.from(context).inflate(R.layout.wc_chat_other_view, this)
    }

    fun process(chatBean: ChatBean, onClickInterface : WcOnItemClickInterface, position:Int){

        GlideUtils.load(chat_item_other_avatar,chatBean.avatarReally, R.drawable.wc_avatar_default)

        if(chatBean.contentType == ChatBean.CONTENT_TYPE_TEXT){
            //文字
            chat_item_other_img.visibility = View.GONE
            chat_item_other_content_layout.visibility = View.VISIBLE
            chat_item_other_redpacket.visibility = View.GONE
            chat_item_other_voice_layout.visibility = View.GONE
            chat_item_other_video.visibility = View.GONE
            chat_item_other_mapview.visibility = View.GONE
            chat_item_other_transfer.visibility = View.GONE
            chat_item_other_content.text = chatBean.content

        } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_IMG){
            //图片
            chat_item_other_img.visibility = View.VISIBLE
            chat_item_other_content_layout.visibility = View.GONE
            chat_item_other_redpacket.visibility = View.GONE
            chat_item_other_voice_layout.visibility = View.GONE
            chat_item_other_video.visibility = View.GONE
            chat_item_other_mapview.visibility = View.GONE
            chat_item_other_transfer.visibility = View.GONE

            var imagePath = chatBean.imgPathLocal
            if(File(imagePath).exists()){
            } else {
                imagePath = CommonUtils.Base.getReallyImage(chatBean.imgPath)
            }
            GlideUtils.load(chat_item_other_img, imagePath)

            chat_item_other_img.setOnClickListener {
                var bundle = bundleOf(CommonUtils.Moments.TYPE_IMAGE_PATH to imagePath,
                    CommonUtils.Moments.TYPE_NAME to CommonUtils.Moments.TYPE_PICTURE,
                    CommonUtils.Chat.IS_HIDE_CONFIRM to true)
                Navigation.findNavController(it).navigate(R.id.action_svideo_play, bundle)
            }

        } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_VOICE){
            //语音
            chat_item_other_img.visibility = View.GONE
            chat_item_other_content_layout.visibility = View.GONE
            chat_item_other_redpacket.visibility = View.GONE
            chat_item_other_voice_layout.visibility = View.VISIBLE
            chat_item_other_voice_second.text = "${chatBean.second}'"
            chat_item_other_video.visibility = View.GONE
            chat_item_other_mapview.visibility = View.GONE
            chat_item_other_transfer.visibility = View.GONE
            chat_item_other_voice_layout.setOnClickListener {
                var voicePath = chatBean.voiceLocal
                AudioUtils.playChatVoice(ChatBean.USER_TYPE_OTHER, voicePath, chat_item_other_voice)
            }

        } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_VIDEO){
            //小视频
            chat_item_other_img.visibility = View.GONE
            chat_item_other_content_layout.visibility = View.GONE
            chat_item_other_redpacket.visibility = View.GONE
            chat_item_other_voice_layout.visibility = View.GONE
            chat_item_other_mapview.visibility = View.GONE
            chat_item_other_video.visibility = View.VISIBLE
            chat_item_other_transfer.visibility = View.GONE
            var chatVideoUtils = ChatVideoUtils()
            chat_item_other_video.setSecond(chatBean.second)
            if(FileUtils.isFileExist(chatBean.videoLocal)){
                //如果本地小视频存在,直接显示缩略图, 不播放
                chat_item_other_video.setThumbnail(chatVideoUtils.createVideoThumbnail(chatBean.videoLocal))
                //chat_item_other_video.initData(chatBean.videoLocal, false)
            } else {
                //如果小视频不存在,显示服务器缩略图
                chat_item_other_video.setThumbnailServer(CommonUtils.Base.getReallyImage(chatBean.imgPath))
            }
            chat_item_other_video.setOnClickListener {
                //如果小视频存在,查看详情
                if(FileUtils.isFileExist(chatBean.videoLocal)){
                    var bundle = bundleOf(CommonUtils.Moments.TYPE_VIDEO_PATH to chatBean.videoLocal,
                        CommonUtils.Moments.TYPE_NAME to CommonUtils.Moments.TYPE_VIDEO,
                        CommonUtils.Chat.IS_HIDE_CONFIRM to true)
                    Navigation.findNavController(it).navigate(R.id.action_svideo_play, bundle)
                } else {
                    //如果小视频不存在,网络下载
                    chatVideoUtils.downloadVideo(chat_item_other_video, chatBean)
                }
            }

        } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_LOCATION){
            //定位
            chat_item_other_img.visibility = View.GONE
            chat_item_other_content_layout.visibility = View.GONE
            chat_item_other_redpacket.visibility = View.GONE
            chat_item_other_voice_layout.visibility = View.GONE
            chat_item_other_mapview.visibility = View.VISIBLE
            chat_item_other_video.visibility = View.GONE
            chat_item_other_transfer.visibility = View.GONE

            //点击地图
            chat_item_other_mapview.setMapOnClick(object : OnMapClickInterface {
                override fun onMapClick() {
                    var bundle = bundleOf(CommonUtils.Chat.LOCATION_LATITUDE to chatBean.latitude, CommonUtils.Chat.LOCATION_LONGITUDE to chatBean.longitude)
                    Navigation.findNavController(chat_item_other_mapview).navigate(R.id.action_baidu_map_details, bundle)
                }
            })

            chat_item_other_mapview.load(chatBean.latitude, chatBean.longitude)

        } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_REDPACKET){
            //红包
            chat_item_other_img.visibility = View.GONE
            chat_item_other_content_layout.visibility = View.GONE
            chat_item_other_redpacket.visibility = View.VISIBLE
            chat_item_other_voice_layout.visibility = View.GONE
            chat_item_other_video.visibility = View.GONE
            chat_item_other_mapview.visibility = View.GONE
            chat_item_other_transfer.visibility = View.GONE

            if(chatBean.isClick == 1){
                chat_item_other_redpacket.setBackgroundResource(R.drawable.wc_redpacket_left_click_normal)
                other_redpacket_icon.background.alpha = 100
                chat_item_other_redpacket.setOnClickListener {
                    //已经领取的只能查看红包
                    var redPacketBean = RedPacketBean(position, chatBean.fromAccount, chatBean.content.toFloat(), "恭喜发财,大吉大利", chatBean.isClick)
                    onClickInterface.onItemClick(redPacketBean)
                }
            } else {
                chat_item_other_redpacket.setBackgroundResource(R.drawable.wc_redpacket_left_normal)
                chat_item_other_redpacket.background.alpha = 255
                other_redpacket_icon.background.alpha = 255

                //还没领取红包才可以点击
                chat_item_other_redpacket.setOnClickListener {
                    TagUtils.d("领取红包:${chatBean.content} , position = ${position}")
                    //var balance = CommonUtils.Chat.getRedpacket(chatBean.content)
                    var redPacketBean = RedPacketBean(position, chatBean.fromAccount, chatBean.content.toFloat(), "恭喜发财,大吉大利", chatBean.isClick)
                    onClickInterface.onItemClick(redPacketBean)
                }
            }

        } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_TRANSFER){
            //转账
            chat_item_other_img.visibility = View.GONE
            chat_item_other_content_layout.visibility = View.GONE
            chat_item_other_redpacket.visibility = View.GONE
            chat_item_other_voice_layout.visibility = View.GONE
            chat_item_other_video.visibility = View.GONE
            chat_item_other_mapview.visibility = View.GONE
            chat_item_other_transfer.visibility = View.VISIBLE
            transfer_other_balance.text = "${chatBean.content}"

            if(chatBean.isClick == 1){
                transfer_other_content.text = "已收款"
                transfer_tip.setTextColor(BaseUtils.getColor(R.color.white88))
                chat_item_other_transfer.setBackgroundResource(R.drawable.wc_redpacket_left_click_normal)
                other_redpacket_icon.background.alpha = 126
            } else {
                chat_item_other_transfer.setBackgroundResource(R.drawable.wc_redpacket_left_normal)
                chat_item_other_transfer.background.alpha = 255
                chat_item_other_transfer.background.alpha = 255
            }

            //不管有没领取转账,点击都会进入详情
            chat_item_other_transfer.setOnClickListener {
                var bundle = bundleOf(CommonUtils.QRCommon.TO_USER to chatBean.toAccount,
                    CommonUtils.Chat.MESSAGE_ID to chatBean.messageId,
                    CommonUtils.QRCommon.TRANSFER_BALANCE to chatBean.content
                )
                Navigation.findNavController(it).navigate(R.id.action_transfer_details, bundle)
            }
        }

    }

}

/**
 * Author : wangning
 * Email : maoning20080809@163.com
 * Date : 2022/5/29 14:59
 * Description : 聊天内容-我的
 */
class ChatMeView : LinearLayout{

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attributeSet: AttributeSet?): this(context, attributeSet, 0)
    constructor(context: Context, attributeSet: AttributeSet?, defStyleAttr :Int) : super(context, attributeSet, defStyleAttr){
        init(context)
    }

    fun init(context: Context){
        LayoutInflater.from(context).inflate(R.layout.wc_chat_me_view, this)
    }

    fun process(chatBean: ChatBean, onClickInterface : WcOnItemClickInterface){

        //BaseUtils.showAvatar(chatBean.fromAccount, chat_item_me_avatar, chat_item_me_name)
        GlideUtils.load(chat_item_me_avatar,chatBean.avatarReally, R.drawable.wc_avatar_default)

        if(chatBean.contentType == ChatBean.CONTENT_TYPE_TEXT){
            //文本
            chat_item_me_img.visibility = View.GONE
            chat_item_me_content_layout.visibility = View.VISIBLE
            chat_item_me_redpacket.visibility = View.GONE
            chat_item_me_voice_layout.visibility = View.GONE
            chat_item_me_video.visibility = View.GONE
            chat_item_me_mapview.visibility = View.GONE
            chat_item_me_content.text = chatBean.content
            chat_item_me_transfer.visibility = View.GONE
        } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_IMG){
            //图片
            chat_item_me_redpacket.visibility = View.GONE
            chat_item_me_img.visibility = View.VISIBLE
            chat_item_me_content_layout.visibility = View.GONE
            chat_item_me_voice_layout.visibility = View.GONE
            chat_item_me_video.visibility = View.GONE
            chat_item_me_mapview.visibility = View.GONE
            chat_item_me_transfer.visibility = View.GONE

            var imagePath = chatBean.imgPathLocal
            if(File(imagePath).exists()){

            } else {
                imagePath = CommonUtils.Base.getReallyImage(chatBean.imgPath)
            }

            GlideUtils.load(chat_item_me_img, imagePath)

            chat_item_me_img.setOnClickListener {
                var bundle = bundleOf(CommonUtils.Moments.TYPE_IMAGE_PATH to imagePath,
                    CommonUtils.Moments.TYPE_NAME to CommonUtils.Moments.TYPE_PICTURE,
                    CommonUtils.Chat.IS_HIDE_CONFIRM to true)
                Navigation.findNavController(it).navigate(R.id.action_svideo_play, bundle)
            }

        } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_VOICE){
            //语音
            chat_item_me_img.visibility = View.GONE
            chat_item_me_content_layout.visibility = View.GONE
            chat_item_me_redpacket.visibility = View.GONE
            chat_item_me_voice_layout.visibility = View.VISIBLE
            chat_item_me_voice_second.text = "${chatBean.second}'"
            chat_item_me_video.visibility = View.GONE
            chat_item_me_mapview.visibility = View.GONE
            chat_item_me_transfer.visibility = View.GONE
            chat_item_me_voice_layout.setOnClickListener {
                var voicePath = chatBean.voiceLocal
                AudioUtils.playChatVoice(ChatBean.USER_TYPE_ME, voicePath, chat_item_me_voice)
            }

        } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_VIDEO){
            //小视频
            chat_item_me_img.visibility = View.GONE
            chat_item_me_content_layout.visibility = View.GONE
            chat_item_me_redpacket.visibility = View.GONE
            chat_item_me_voice_layout.visibility = View.GONE
            chat_item_me_video.visibility = View.VISIBLE
            chat_item_me_mapview.visibility = View.GONE
            chat_item_me_transfer.visibility = View.GONE
            var chatVideoUtils = ChatVideoUtils()
            chat_item_me_video.setSecond(chatBean.second)
            if(FileUtils.isFileExist(chatBean.videoLocal)){
                //如果本地小视频存在,直接显示缩略图, 不播放
                chat_item_me_video.setThumbnail(chatVideoUtils.createVideoThumbnail(chatBean.videoLocal))
                //chat_item_me_video.initData(chatBean.videoLocal, false)
            } else {
                //如果小视频不存在,显示服务器缩略图
                chat_item_me_video.setThumbnailServer(CommonUtils.Base.getReallyImage(chatBean.imgPath))
            }
            chat_item_me_video.setOnClickListener {
                //如果小视频存在,查看详情
                if(FileUtils.isFileExist(chatBean.videoLocal)){
                    var bundle = bundleOf(CommonUtils.Moments.TYPE_VIDEO_PATH to chatBean.videoLocal,
                        CommonUtils.Moments.TYPE_NAME to CommonUtils.Moments.TYPE_VIDEO,
                        CommonUtils.Chat.IS_HIDE_CONFIRM to true)
                    Navigation.findNavController(it).navigate(R.id.action_svideo_play, bundle)
                } else {
                    //如果小视频不存在,网络下载
                    chatVideoUtils.downloadVideo(chat_item_me_video, chatBean)
                }
            }
        } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_LOCATION){
            //定位
            chat_item_me_img.visibility = View.GONE
            chat_item_me_content_layout.visibility = View.GONE
            chat_item_me_redpacket.visibility = View.GONE
            chat_item_me_voice_layout.visibility = View.GONE
            chat_item_me_video.visibility = View.GONE
            chat_item_me_mapview.visibility = View.VISIBLE
            chat_item_me_transfer.visibility = View.GONE

            //点击地图
            chat_item_me_mapview.setMapOnClick(object : OnMapClickInterface {
                override fun onMapClick() {
                    var bundle = bundleOf(CommonUtils.Chat.LOCATION_LATITUDE to chatBean.latitude, CommonUtils.Chat.LOCATION_LONGITUDE to chatBean.longitude)
                    Navigation.findNavController(chat_item_me_mapview).navigate(R.id.action_baidu_map_details, bundle)
                }
            })

            chat_item_me_mapview.load(chatBean.latitude, chatBean.longitude)

        } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_REDPACKET){
            //红包
            chat_item_me_redpacket.visibility = View.VISIBLE
            chat_item_me_img.visibility = View.GONE
            chat_item_me_content_layout.visibility = View.GONE
            chat_item_me_voice_layout.visibility = View.GONE
            chat_item_me_video.visibility = View.GONE
            chat_item_me_mapview.visibility = View.GONE
            chat_item_me_transfer.visibility = View.GONE
            //点击红包
            TagUtils.d("查看自己发送的红包")
            chat_item_me_redpacket.setOnClickListener {
                var bundle = bundleOf(CommonUtils.QRCommon.BALANCE to chatBean.content.toFloat(),
                    CommonUtils.QRCommon.TO_USER to chatBean.toAccount,
                    CommonUtils.QRCommon.FROM_ACCOUNT to chatBean.fromAccount)
                Navigation.findNavController(it)?.navigate(R.id.action_redpacket_success, bundle)
            }
        } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_TRANSFER){
            //转账
            chat_item_me_redpacket.visibility = View.GONE
            chat_item_me_img.visibility = View.GONE
            chat_item_me_content_layout.visibility = View.GONE
            chat_item_me_voice_layout.visibility = View.GONE
            chat_item_me_video.visibility = View.GONE
            chat_item_me_mapview.visibility = View.GONE
            chat_item_me_transfer.visibility = View.VISIBLE
            transfer_me_balance.text = "${chatBean.content}"
            //点击红包
            TagUtils.d("查看自己发送的转账")
            chat_item_me_transfer.setOnClickListener {
                var bundle = bundleOf(CommonUtils.QRCommon.TO_USER to chatBean.toAccount,
                    CommonUtils.Chat.MESSAGE_ID to chatBean.messageId,
                    CommonUtils.QRCommon.TRANSFER_BALANCE to chatBean.content
                )
                Navigation.findNavController(it).navigate(R.id.action_transfer_details, bundle)
            }
        }

    }
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/45287.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

http和dubbo接口调用主动设置超时时间

http接口超时方案 方案1&#xff1a;多个resttemplate&#xff0c;不同超时时间的使用不同的template&#xff0c;优点&#xff1a;简单&#xff0c;扩展起来复制粘贴&#xff0c;缺点&#xff1a;代码冗余&#xff0c;多个template占用内存不够优雅 方案2&#xff1a;单个res…

MySQL事务和锁

目录 1、四大特性 2、事务引发的问题 3、事务控制演进 3.1、排队 3.2、排它锁 3.3、读写锁 3.4、MVCC 4、事务的隔离级别 4.1、四种隔离级别 4.2、事务隔离级别和锁的关系 4.3、MySQL隔离级别控制 5、锁机制和实战 5.1、锁分类 5.1.1、按操作粒度分类 5.1.2、按…

CDMP选修课都有什么?

大家都知道CDMP认证考试有四个级别。分别是A级&#xff08;基础级&#xff09;P级&#xff08;实践级&#xff09;M级&#xff08;专业级&#xff09;F级&#xff08;大师级&#xff09;。级别越高&#xff0c;考试难度就越大&#xff0c;分数比例要求也更高&#xff0c;相对应…

在Linux命令行中查找空目录

在 Linux 系统中&#xff0c;出现空的目录这是很正常的事情&#xff0c;而且&#xff0c;也是有办法一次性把它们都找出来的。 但是&#xff0c;仅仅列出空目录并不是我们的目的&#xff0c;我们今天了解一下如何删除这些空的目录。 在Linux中查找空目录 查找空目录&#xf…

ThinkPHP5文档学习——配置

文章目录一、配置目录二、配置格式PHP数组定义其它格式的支持二级配置三、配置加载惯例配置应用配置拓展配置场景配置四、读取配置参数五、动态配置设置配置参数六、独立配置独立配置文件V5.0.1版本已经废除该写法自动读取扩展配置七、配置作用域八、环境变量配置一、配置目录 …

语文课内外杂志语文课内外杂志社语文课内外杂志社2022年第14期目录

幼儿教育《语文课内外》投稿&#xff1a;cn7kantougao163.com 家园协同视域下幼儿心理危机的预防与干预对策 曹锭1-3 幼小衔接阶段幼儿时间观念的培养对策 陈晶晶4-6 有效支持 助力幼儿在书海中徜徉 胡玲珊7-9 东西部幼儿园结对帮扶,助力乡村教育扶贫——以广州市人民政府机关幼…

虹科分享|终端安全防护|网络安全术语列表(二)

如果你的工作或者生活与网络安全有关&#xff0c;你就知道它使用了自己独特的、不断发展的语言。术语和缩略语受到网络安全专家的喜爱。因此&#xff0c;我们创建了一个全面的网络安全词汇表&#xff0c;解释了常用的网络安全术语、短语和技术。我们设计此列表是为了揭开安全专…

[附源码]Python计算机毕业设计Django贷款申请审核管理系统论文

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;我…

你知道吗?小程序组件≠小程序插件

一直以为小程序组件和小程序插件是一回事&#xff0c;只是措辞不一样&#xff0c;导致造成乌龙&#xff0c;其实完全是两回事&#xff0c;插件是可以直接提供服务的&#xff0c;组件是给开发者提供的轮子&#xff0c;不能直接提供服务。 先看看微信是如何定义小程序插件的&…

什么是深度卷积可分离Depthwise Separable conv

假设加载进来一张GRB三通道的图片 我现在就把三个通道拆开 注意哦 传统的就是 一个卷积核filter 和三个通道channel 进行卷积 现在这个深度卷积可分离 就要用三个不同的卷积核来对每一个通道进行卷积 小细节 &#xff1a;如果是传统意义上的卷积&#xff0c;但用一个的话&a…

【SQL Server + MySQL一】数据库基本知识、关系数据模型、关系数据语言--关系代数

极其感动&#xff01;&#xff01;&#xff01;当时学数据库的时候&#xff0c;没白学&#xff01;&#xff01; 时隔很长时间回去看数据库的笔记都能看懂&#xff0c;每次都靠这份笔记巩固真的是语雀分享要花钱&#xff0c;要不一定把笔记给贴出来(;༎ຶД༎ຶ) &#xff0c;除…

详解设计模式:装饰器模式

装饰器模式&#xff08;Decorator Pattern&#xff09;也称为包装模式&#xff08;Wrapper Pattern&#xff09;&#xff0c;是 GoF 的 23 种设计模式中的一种结构型设计模式。装饰器模式 是指在不改变原有对象的基础之上&#xff0c;将功能附加到对象上&#xff0c;提供了比继…

3.7.2、IP地址(网际层)

我们日常的大多数网络应用中&#xff0c;属于数据链路层的 MAC 地址&#xff0c;和属于网络层的 IP 地址都在使用&#xff0c;它们之间存在一定的关系。这里主要介绍 IP 地址的作用 1、基本介绍 IP 地址是因特网(Internet)上的主机和路由器所使用的地址&#xff0c;用于标识两…

osgEarth示例分析——osgearth_graticule

前言 本示例最具有借鉴的功能&#xff1a;绘制网格、网格上的文字显示、拾取地球的坐标。在地球网格示例中&#xff0c;可以设置4种网格。执行命令如下&#xff1a; // --geodetic osgearth_graticuled.exe --geodetic earth_image\china-simple.earth // --utm osgearth_gr…

[附源码]Python计算机毕业设计Django大学生心理测评系统

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;我…

磁盘划分和磁盘格式化

文章目录列出装置的 UUID 等参数parted 列出磁盘的分区表类型与分区信息磁盘分区&#xff1a;gdisk、fdisk用 gdisk 新增分区槽用 gdisk 删除一个分区槽磁盘格式化&#xff08;建立文件系统&#xff09;XFS 文件系统 mkfs.xfsXFS 文件系统 for RAID 效能优化&#xff08;Option…

【Linux】环境变量

文章目录一.什么是环境变量二.常见的环境变量1.常见的环境变量和与之相关的命令2.PATH指定命令搜索路径3.env显示所有环境变量4.echo查看环境变量三.本地变量与环境变量的联系四.获取环境变量的三种方式1.getenv()函数获取环境变量2.利用命令行参数3.利用第三方变量一.什么是环…

如何校准Linux服务器时间

最近服务器上的时间与北京时间出现偏差&#xff0c;而Java代码里java.util.Date获取的是服务器时间&#xff0c;导致当前时间错误。 Linux查看服务器当前时间 查看当前时区&#xff1a;date -R 查看当前日期和时间&#xff1a;date 校准Linux服务器时间 Linux中有个ntp包可…

【Unity】URP渲染管线下代码获取相机的Volume Mask属性

步骤1. 引用URP的命名空间2. 获取摄像机3.通过URP扩展获取Volume Mask属性附 层级的相关代码Reference1. 引用URP的命名空间 using UnityEngine.Rendering.Universal;2. 获取摄像机 这里可以使用公有拖拽或者私有赋值的方式。 如果使用拖拽&#xff0c;则&#xff1a; publi…

神经网络和深度学习-多分类问题Softmax Classifier

多分类问题Softmax Classifier 在之前做糖尿病数据集的时候做的二分类问题&#xff0c;因为只有两类&#xff0c;所以只需要输出一个概率值&#xff0c;另一个概率值用1去减去就可以得到 实际上在大多数数据集中是在处理一个多分类问题&#xff0c;例如MNIST中有10类标签 神经…