Kotlin高仿微信-第13篇-单聊-小视频

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

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

效果图:

详细的聊天功能请查看Kotlin高仿微信-第8篇-单聊,这里是提取小视频功能的部分实现。

实现代码:

<com.wn.wechatclientdemo.view.SVideoView
    android:id="@+id/chat_item_me_video"
    app:layout_constraintEnd_toStartOf="@+id/chat_item_me_avatar"
    app:layout_constraintTop_toTopOf="@+id/chat_item_me_avatar"
    android:layout_width="160dp"
    android:layout_height="240dp"
    android:layout_marginEnd="10dp"
    android:visibility="gone"/>

/**
 * Author : wangning
 * Email : maoning20080809@163.com
 * Date : 2022/5/24 15:57
 * Description : 小视频播放
 */
class SVideoView : LinearLayout, SurfaceHolder.Callback,
    OnPreparedListener,
    OnCompletionListener,
    OnErrorListener,
    OnInfoListener, View.OnClickListener,
    OnSeekCompleteListener,
    OnVideoSizeChangedListener,
    OnSeekBarChangeListener{

    private var playOrPauseIv: ImageView? = null
    private var videoSuf: SurfaceView? = null
    private var mPlayer: MediaPlayer? = null
    private var mSeekBar: SeekBar? = null
    private var path: String? = null
    private var rootViewRl: RelativeLayout? = null
    private var controlLl: LinearLayout? = null
    private var startTime: TextView? = null
    private var endTime:TextView? = null
    private var secondTime:TextView? = null
    private var forwardButton: ImageView? = null
    private var backwardButton: ImageView? = null
    private var svideoThumbnail: ImageView? = null
    private var isShow = false
    private var chatCircleProgress: ChatCircleProgress? = null

    val UPDATE_TIME = 0X0001
    val HIDE_CONTROL = 0X0002
    private var view : View? = null

    private var isAutoPlay: Boolean = false

    private val mHandler: Handler = object : Handler() {
        override fun handleMessage(msg: Message) {
            super.handleMessage(msg)
            when (msg.what) {
                UPDATE_TIME -> {
                    updateTime()
                    sendEmptyMessageDelayed(UPDATE_TIME, 500)
                }
                HIDE_CONTROL -> hideControl()
            }
        }
    }

    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 {
        view = LayoutInflater.from(WcApp.getContext()).inflate(R.layout.wc_svideo_view, this)
        initViews()
    }

    fun processVideo(){
        initSurfaceView()
        initPlayer()
        initEvent()
        getVideoRoration(path)
    }

    fun onDestroy() {
        videoSuf = null
        mHandler.removeMessages(HIDE_CONTROL);
        mHandler.removeMessages(UPDATE_TIME);
        if(mPlayer != null){
            mPlayer?.stop()
            mPlayer?.release()
        }
        mPlayer = null;
    }

    fun onStop(){
        mPlayer?.let {
            it.stop()

        }
    }

    fun onStart(){
        mPlayer?.let {
            TagUtils.d("是否播放:${it.isPlaying}")
            if(!it.isPlaying){
                it.prepareAsync()
                it.start()
            }
        }
    }

    override fun onClick(v: View) {
        when (v.id) {
            R.id.tv_backward -> backWard()
            R.id.tv_forward -> forWard()
            R.id.playOrPause -> play()
            //R.id.root_rl -> showControl()
        }
    }

    private fun updateTime() {
        startTime?.setText(formatLongToTimeStr(mPlayer!!.currentPosition))
        mSeekBar!!.progress = mPlayer!!.currentPosition
    }

    private fun hideControl() {
        isShow = false
        mHandler.removeMessages(UPDATE_TIME)
        controlLl!!.animate().setDuration(300).translationY(controlLl!!.height.toFloat())
    }

    private fun showControl() {
        if (isShow) {
            play()
        }
        isShow = true
        mHandler.removeMessages(HIDE_CONTROL)
        mHandler.sendEmptyMessage(UPDATE_TIME)
        mHandler.sendEmptyMessageDelayed(
            HIDE_CONTROL,
            5000
        )
        controlLl!!.animate().setDuration(300).translationY(0f)
    }

    private fun forWard() {
        if (mPlayer != null) {
            val position = mPlayer!!.getCurrentPosition()
            mPlayer?.seekTo(position + 10000)
        }
    }

    fun backWard() {
        if (mPlayer != null) {
            var position = mPlayer!!.getCurrentPosition()
            if (position > 10000) {
                position -= 10000
            } else {
                position = 0
            }
            mPlayer?.seekTo(position)
        }
    }

    fun initData(filePath : String, isAutoPlay: Boolean) {
        path = filePath
        this.isAutoPlay = isAutoPlay
        processVideo()
    }

    //聊天页面下载小视频完成,自动播放
    fun processChatDownload(){
        videoSuf?.let {
            surfaceCreated(it.holder)
        }
    }

    private fun initEvent() {
        playOrPauseIv!!.setOnClickListener(this)
        //rootViewRl!!.setOnClickListener(this)
        forwardButton!!.setOnClickListener(this)
        backwardButton!!.setOnClickListener(this)
        mSeekBar!!.setOnSeekBarChangeListener(this)
    }

    private fun initSurfaceView() {
        TagUtils.d("initSurfaceView")
        videoSuf = findViewById<View>(R.id.surfaceView) as SurfaceView
        videoSuf?.let {
            it.setZOrderOnTop(false)
            it.getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)
            it.getHolder().addCallback(this)
            TagUtils.d("initSurfaceView addCallback ")
        }
    }

    private fun initPlayer() {
        mPlayer = MediaPlayer()
        mPlayer?.let {
            it.setOnCompletionListener(this)
            it.setOnErrorListener(this)
            it.setOnInfoListener(this)
            it.setOnPreparedListener(this)
            it.setOnSeekCompleteListener(this)
            it.setOnVideoSizeChangedListener(this)
            try {
                TagUtils.d("文件是否存在:" + File(path).exists() + " , path = " + path)
                it.setDataSource(path)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    //获取视频角度等信息
    fun getVideoRoration(mUri: String?): Int {
        val roration = 0
        val mmr = MediaMetadataRetriever()
        try {
            if (mUri != null) {
                var headers: HashMap<String, String> = HashMap<String, String>()

                headers["User-Agent"] = "Mozilla/5.0 (Linux; U; Android 4.4.2; zh-CN; MW-KW-001 Build/JRO03C) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 UCBrowser/1.0.0.001 U4/0.8.0 Mobile Safari/533.1"

                if (mUri.startsWith("http")) {
                    mmr.setDataSource(mUri, headers)
                } else {
                    mmr.setDataSource(mUri)
                }
            }
            val duration = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION) //时长(毫秒)
            val width = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH) //宽
            val height = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT) //高
            val rotationStr = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION) // 视频旋转方向
            TagUtils.d("视频信息:duration = $duration , width = $width , height = $height , rotationStr = $rotationStr")
            if (!TextUtils.isEmpty(rotationStr)) {
                return rotationStr!!.toInt()
            }
            TagUtils.d("rotation$rotationStr")
        } catch (ex: Exception) {
            TagUtils.d("MediaMetadataRetriever exception $ex")
            ex.printStackTrace()
        } finally {
            mmr.release()
        }
        return roration
    }


    private fun initViews() {
        view?.let {
            playOrPauseIv = it.findViewById(R.id.playOrPause)
            startTime = it.findViewById(R.id.tv_start_time)
            endTime = it.findViewById(R.id.tv_end_time)
            secondTime = it.findViewById(R.id.svideo_second)
            mSeekBar = it.findViewById(R.id.tv_progess)
            rootViewRl = it.findViewById(R.id.root_rl)
            controlLl = it.findViewById(R.id.control_ll)
            forwardButton = it.findViewById(R.id.tv_forward)
            backwardButton = it.findViewById(R.id.tv_backward)
            svideoThumbnail = it.findViewById(R.id.svideo_thumbnail)
            chatCircleProgress = it.findViewById(R.id.svideo_circle_progress)
        }
    }

    //设置圆形进度条
    fun setCircleProgress(current:Int){
        chatCircleProgress?.setCurrent(current)
    }

    fun showCircleProgress(){
        chatCircleProgress?.visibility = View.VISIBLE
    }

    fun hideCircleProgress(){
        chatCircleProgress?.visibility = View.GONE
    }

    /**
     * 显示缩略图
     */
    fun setThumbnail(thumbnailPath : String){
        svideoThumbnail?.setImageBitmap(BitmapFactory.decodeFile(thumbnailPath))
    }

    //本地小视频缩略图
    fun setThumbnail(bitmap: Bitmap?){
        svideoThumbnail?.setImageBitmap(bitmap)
    }

    //服务器小视频缩略图
    fun setThumbnailServer(videoUrl : String){
        svideoThumbnail?.let {
            GlideUtils.load(it, videoUrl)
        }
    }

    override fun surfaceCreated(holder: SurfaceHolder) {
        TagUtils.d("初始化surfaceCreated ")
        mPlayer!!.setDisplay(holder)
        mPlayer!!.prepareAsync()
    }

    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {}

    override fun surfaceDestroyed(holder: SurfaceHolder) {}

    override fun onPrepared(mp: MediaPlayer) {
        startTime?.setText(formatLongToTimeStr(mp.currentPosition))
        endTime?.setText(formatLongToTimeStr(mp.duration))
        mSeekBar?.max = mp.duration
        mSeekBar?.progress = mp.currentPosition
        //TagUtils.d("初始化完成。。")
        if(isAutoPlay){
            play()
        }
    }

    //显示多少秒
    fun setSecond(second:Int){
        secondTime?.visibility = View.VISIBLE
        secondTime?.setText("${second}秒")
    }

    override fun onCompletion(mp: MediaPlayer?) {
        //TagUtils.d("播放完成。。")
        playOrPauseIv?.visibility = View.VISIBLE
        playOrPauseIv!!.setImageResource(android.R.drawable.ic_media_play)
    }

    override fun onError(mp: MediaPlayer?, what: Int, extra: Int): Boolean {
        return false
    }

    override fun onInfo(mp: MediaPlayer?, what: Int, extra: Int): Boolean {
        return false
    }

    fun play() {
        //TagUtils.d("开始播放:${mPlayer}, ${path}")
        if (mPlayer == null) {
            return
        }
        svideoThumbnail?.visibility = View.GONE
        videoSuf?.visibility = View.VISIBLE
        hideCircleProgress()

        if (mPlayer?.isPlaying()!!) {
            mPlayer?.pause()
            mHandler.removeMessages(UPDATE_TIME)
            mHandler.removeMessages(HIDE_CONTROL)
            playOrPauseIv!!.visibility = VISIBLE
            playOrPauseIv!!.setImageResource(android.R.drawable.ic_media_play)
        } else {
            mPlayer?.start()
            mHandler.sendEmptyMessageDelayed(
                UPDATE_TIME,
                500
            )
            mHandler.sendEmptyMessageDelayed(
                HIDE_CONTROL,
                5000
            )
            playOrPauseIv!!.visibility = INVISIBLE
            playOrPauseIv!!.setImageResource(android.R.drawable.ic_media_pause)
        }
    }

    override fun onSeekComplete(mp: MediaPlayer?) {}

    override fun onVideoSizeChanged(mp: MediaPlayer?, width: Int, height: Int) {}

    override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
        if (mPlayer != null && fromUser) {
            mPlayer?.seekTo(progress)
        }
    }

    override fun onStartTrackingTouch(seekBar: SeekBar?) {}

    override fun onStopTrackingTouch(seekBar: SeekBar?) {}


    fun formatLongToTimeStr(millis: Int): String {
        return String.format(
            "%02d:%02d:%02d",
            millis / (1000 * 60 * 60), millis / (1000 * 60) % 60, millis / 1000 % 60
        )
    }
}

//打开相册选择小视频
ImageSelector.builder()
    .useCamera(false) // 设置是否使用拍照
    .setSingle(true) //设置是否单选
    .canPreview(true) //是否点击放大图片查看,,默认为true
    .start(this,REQUEST_PICTURE_CODE)

 

//选择小视频后返回的文件地址
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)
        }
    }
}

/**
 * 发送图片、小视频、语音
 * @param fileType Int
 * @param picPath String
 * @param toUserID String
 */
fun sendFile(fileType: Int, filePath : String, toUserId : String, time: Int) {
    CoroutineScope(Dispatchers.IO).launch {
        //语音、小视频多少秒
        val toId: String = BaseUtils.getChatId(toUserId) + "/Smack"
        var resultFilePath = ""

        if(TextUtils.isEmpty(filePath)){
            return@launch
        }

        if(!File(filePath).exists()){
            return@launch
        }

        var second = time

        if(fileType == ChatBean.CONTENT_TYPE_VOICE){
            second = time
        } else if(fileType == ChatBean.CONTENT_TYPE_VIDEO){
            second = CommonUtils.Media.getMediaTime(filePath, fileType)
        }

        //先刷新页面,再慢慢上传文件
        var chatBean = processSendChatBean(toUserId, fileType, filePath, second)

        if(fileType == ChatBean.CONTENT_TYPE_IMG){
            //图片
            //压缩图片后路径
            var resultPicPath = UploadFileUtils.getCompressFile(filePath)
            resultFilePath = resultPicPath

        } else if(fileType == ChatBean.CONTENT_TYPE_VOICE){
            //语音
            resultFilePath = filePath

            TagUtils.d("语音时间:${second}")
        } else if(fileType == ChatBean.CONTENT_TYPE_VIDEO){
            //小视频
            var videoFilePath = UploadFileUtils.getVideoCompressFile()
            //TagUtils.d("开始发送小视频压缩前文件2:${videoFilePath}")
            var compressResult = VideoController.getInstance().convertVideo(filePath, videoFilePath, VideoController.COMPRESS_QUALITY_LOW, object : VideoController.CompressProgressListener {
                override fun onProgress(percent: Float) {
                    //TagUtils.d("压缩小视频进度:${percent}")
                }
            })

            TagUtils.d("小视频时间:${second}")
            resultFilePath = videoFilePath
        }

        TagUtils.d("上传文件:${resultFilePath}")
        val filetosend = File(resultFilePath)
        if (!filetosend.exists()) {
            return@launch
        }


        try {
            var account : String = DataStoreUtils.getAccount()

            if(fileType == ChatBean.CONTENT_TYPE_IMG){
                //图片
                TagUtils.d("图片发送成功。")
                var chatBeanServer = UploadFileUtils.uploadChatImages(account, toUserId, resultFilePath,0)
                if(chatBeanServer != null){
                    chatBeanServer.imgPath = chatBeanServer.imgPath
                    chatBean = chatBeanServer
                }
            } else if(fileType == ChatBean.CONTENT_TYPE_VOICE){
                //录音完成,要转码,等待0.2秒再发送
                delay(100)
                //语音
                var chatBeanServer = UploadFileUtils.uploadChatVoice(account, toUserId, resultFilePath, second)
                if(chatBeanServer != null){
                    chatBeanServer.voiceLocal = resultFilePath
                    chatBean = chatBeanServer
                }
            } else if(fileType == ChatBean.CONTENT_TYPE_VIDEO){
                //小视频
                var chatBeanServer = UploadFileUtils.uploadChatVideo(account, toUserId, resultFilePath, second)
                if(chatBeanServer != null){
                    chatBeanServer.videoLocal = resultFilePath
                    chatBean = chatBeanServer
                }
            }
            chatBean?.let {
                ChatRepository.updateChat(it)
            }

            var baseSystemBoolean = BaseSystemRepository.getBaseSystemSync(WcApp.getContext().packageName)
            if(baseSystemBoolean != null && baseSystemBoolean.sync == CommonUtils.Sync.SERVER_SYNC){
                //同步不需要使用transfer上传文件,因为transfer上传太慢了, 直接上传到服务器,然后发送普通的消息
                if(fileType == ChatBean.CONTENT_TYPE_VOICE){
                    var content = CommonUtils.Chat.VOICE_MARK + chatBean.voice
                    ChatManagerUtils.getInstance().sendMessage(toUserId, content)
                } else if(fileType == ChatBean.CONTENT_TYPE_VIDEO){
                    var content = CommonUtils.Chat.VIDEO_MARK + chatBean.video
                    ChatManagerUtils.getInstance().sendMessage(toUserId, content)
                } else if(fileType == ChatBean.CONTENT_TYPE_IMG){
                    var content = CommonUtils.Chat.IMAGE_MARK + chatBean.imgPath
                    ChatManagerUtils.getInstance().sendMessage(toUserId, content)
                }
                return@launch
            }

            val fileTransferManager = getFileTransferManager()
            val transfer = fileTransferManager.createOutgoingFileTransfer(toId) // 创建一个输出文件传输对象

            //对方用户在线才需要上传文件
            if(XmppConnectionManager.getInstance().isOnLine(toUserId)){
                TagUtils.d("${toUserId} 在线 开始上传。")
                transfer.sendFile(filetosend,"recv img")
                while (!transfer.isDone) {
                    if (transfer.status == FileTransfer.Status.error) {
                        TagUtils.d("聊天文件上传错误 , ERROR!!! " + transfer.error)
                    } else {
                        TagUtils.d("聊天文件上传 " + transfer.status +" , " + transfer.progress)
                    }

                    Thread.sleep(20)

                }
            } else {
                TagUtils.d("toUserId 不在线")
            }
            if (transfer.isDone) {
                //上传完成
            }
        } catch (e1: XMPPException) {
            e1.printStackTrace()
        }
    }
}
/**
 * Author : wangning
 * Email : maoning20080809@163.com
 * Date : 2022/5/31 16:31
 * Description : 处理聊天信息发来的信息
 */
class ChatManagerListener : ChatManagerListener {

    override fun chatCreated(chat: Chat, createdLocally: Boolean) {
        TagUtils.d("消息监听回调:chat = ${chat} , createdLocally = ${createdLocally}")
        if(!createdLocally){
            chat.addMessageListener { chat, message ->
                TagUtils.d("获取好友发来的信息 ${message.from} , ${message.to}, ${message.body}")
                var content = message.getBody()
                if(!TextUtils.isEmpty(content) && content.length > 0){
                    var fromUser = BaseUtils.getChatAccountFrom(message.from)
                    var toUser = BaseUtils.getChatAccount(message.to)
                    var userType = ChatBean.USER_TYPE_OTHER

                    if(content.startsWith(CommonUtils.Chat.LOCATION_MARK)){
                        //发送定位
                        //去掉location###标志
                        var remarkContent = CommonUtils.Chat.getLocation(content)
                        //使用逗号分隔符,分别读取经纬度
                        var contents = remarkContent.split(",")
                        var latitude = contents[0].toDouble()
                        var longitude = contents[1].toDouble()
                        var chatBean = CommonUtils.Chat.getChatBean(fromUser, toUser, userType, content, ChatBean.CONTENT_TYPE_LOCATION, "", latitude, longitude)
                        ChatRepository.insertChat(chatBean)
                        chatBean.isReceive = true
                        EventBus.getDefault().post(chatBean)
                    } else if(content.startsWith(CommonUtils.Chat.REDPACKET_MARK)){
                        //发送红包, 去掉redpacket###写入数据库
                        content = CommonUtils.Chat.getRedpacket(content).toString()
                        var chatBean = CommonUtils.Chat.getChatBean(fromUser, toUser, userType, content, ChatBean.CONTENT_TYPE_REDPACKET, "",0.0, 0.0)
                        ChatRepository.insertChat(chatBean)
                        chatBean.isReceive = true
                        EventBus.getDefault().post(chatBean)
                    } else if(content.startsWith(CommonUtils.Chat.VOICE_MARK)){
                        //发送语音, 去掉voice###写入数据库
                        content = CommonUtils.Chat.getMedia(content, CommonUtils.Chat.VOICE_MARK)
                        var chatBean = CommonUtils.Chat.getChatBeanVoiceServer(fromUser, toUser, userType,ChatBean.CONTENT_TYPE_VOICE, content,0)
                        chatBean.isReceive = true
                        processDownload(chatBean)
                    } else if(content.startsWith(CommonUtils.Chat.VIDEO_MARK)){
                        //发送小视频, 去掉video###写入数据库
                        content = CommonUtils.Chat.getMedia(content, CommonUtils.Chat.VIDEO_MARK)
                        var chatBean = CommonUtils.Chat.getChatBeanVideoServer(fromUser, toUser, userType,ChatBean.CONTENT_TYPE_VIDEO, content,0)
                        chatBean.isReceive = true
                        processDownload(chatBean)
                    } else if(content.startsWith(CommonUtils.Chat.IMAGE_MARK)){
                        //发送图片, 去掉image###写入数据库
                        content = CommonUtils.Chat.getMedia(content, CommonUtils.Chat.IMAGE_MARK)
                        var chatBean = CommonUtils.Chat.getChatBeanImageServer(fromUser, toUser, userType,ChatBean.CONTENT_TYPE_IMG, content,0)
                        chatBean.isReceive = true
                        processDownload(chatBean)
                    } else if(content.startsWith(CommonUtils.Chat.TRANSFER_MARK)){
                        //发送转账, 去掉transfer###写入数据库
                        content = CommonUtils.Chat.getTransfer(content).toString()
                        var chatBean = CommonUtils.Chat.getChatBean(fromUser, toUser, userType, content, ChatBean.CONTENT_TYPE_TRANSFER, "",0.0, 0.0)
                        ChatRepository.insertChat(chatBean)
                        chatBean.isReceive = true
                        EventBus.getDefault().post(chatBean)
                    } else if(content.startsWith(CommonUtils.QRCommon.QR_RECEIVE_CODE)){
                        //向个人发送收款
                        var balance = content.substring(CommonUtils.QRCommon.QR_RECEIVE_CODE.length, content.length)
                        TagUtils.d("MyChatManagerListener 向个人发送收款金额: ${fromUser} , ${toUser},  ${balance}")
                        updateBalanceServer(fromUser, toUser, CommonUtils.User.OPERATOR_PLUS, balance.toFloat())
                    } else if(content.startsWith(CommonUtils.QRCommon.QR_PAYMENT_CODE)){
                        //向商家付款
                        var balance = content.substring(CommonUtils.QRCommon.QR_RECEIVE_CODE.length, content.length)
                        TagUtils.d("MyChatManagerListener 向商家付款金额: ${fromUser} , ${toUser}, ${balance}")
                        updateBalanceServer(fromUser, toUser, CommonUtils.User.OPERATOR_MINUS, balance.toFloat())
                    } else {
                        var chatBean = CommonUtils.Chat.getChatBean(fromUser, toUser, userType, content, ChatBean.CONTENT_TYPE_TEXT, "",0.0, 0.0)
                        ChatRepository.insertChat(chatBean)
                        chatBean.isReceive = true
                        EventBus.getDefault().post(chatBean)
                    }
                    ChatNotificationUtils.sendNotification(fromUser)
                }
            }
        }
    }

    /**
     * 下载图片、语音、小视频
     */
    private fun processDownload(chatBean : ChatBean){
        var fileName = ""
        if(chatBean.contentType == ChatBean.CONTENT_TYPE_VOICE){
            fileName = chatBean.voice
        } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_VIDEO){
            fileName = chatBean.video
        } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_IMG){
            fileName = chatBean.imgPath
        } else {
            return
        }

        var videoUrl = CommonUtils.Moments.getReallyImageUrl(fileName)
        var videoFile = FileUtils.getBaseFile(fileName)

        TagUtils.d("下载多媒体Url :${videoUrl} ")
        TagUtils.d("下载多媒体File :${videoFile} ")

        VideoDownloadManager.downloadFast(videoUrl, videoFile, object : VideoDownloadInter {
            override fun onDone(filePath: String) {
                TagUtils.d("小视频多媒体完成:${filePath}")

                if(chatBean.contentType == ChatBean.CONTENT_TYPE_VOICE){
                    var second = CommonUtils.Media.getMediaTime(filePath, chatBean.contentType)
                    chatBean.second = second
                    chatBean.voiceLocal = filePath
                } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_VIDEO){
                    chatBean.videoLocal = filePath
                    var second = CommonUtils.Media.getMediaTime(filePath, chatBean.contentType)
                    chatBean.second = second
                } else if(chatBean.contentType == ChatBean.CONTENT_TYPE_IMG){
                    chatBean.imgPathLocal = filePath
                }

                ChatRepository.insertChat(chatBean)
                EventBus.getDefault().post(chatBean)
            }

            override fun onError() {
            }

            override fun onProgress(process: Int) {
            }
        })
    }

/**
 * 聊天小视频上传到服务器, 因为发送之前已经压缩,这里不需要再压缩了
 */
fun uploadChatVideo(fromAccount: String, toAccount: String, filePath : String, second: Int) : ChatBean? {
    if(TextUtils.isEmpty(fromAccount)){
        return null
    }
    if(TextUtils.isEmpty(toAccount)){
        return null
    }
    if(TextUtils.isEmpty(filePath)){
        return null
    }

    var client = OkHttpClient()
    var builder = MultipartBody.Builder()
    var mediaType : MediaType? = "application/json; charset=utf-8".toMediaTypeOrNull()
    var url = BaseUtils.BASE_URL +"chat?method=uploadChatVideo"
    TagUtils.d("uploadVideo url = ${url}")
    var file = File(filePath)
    builder.addFormDataPart("file", filePath, file.asRequestBody(mediaType))
    builder.addFormDataPart("from_account", fromAccount)
    builder.addFormDataPart("to_account", toAccount)
    builder.addFormDataPart("content_type", ChatBean.CONTENT_TYPE_VIDEO.toString())
    builder.addFormDataPart("user_type", ChatBean.USER_TYPE_ME.toString())
    builder.addFormDataPart("message_id", UUID.randomUUID().toString())
    builder.addFormDataPart("second", second.toString())

    var requestBody = builder.build()

    var reqBuilder = Request.Builder()
    var request = reqBuilder
        .url(url)
        .post(requestBody)
        .build()

    var call = client.newCall(request)
    var response = call.execute()
    var result = response.body?.string()
    var baseResult = Gson().fromJson(result , BaseResult::class.java)

    if(baseResult.isSuccess){
        var chatBeanGson = baseResult.data as String
        var chatBean = Gson().fromJson(chatBeanGson, ChatBean::class.java)
        return chatBean
    } else {
        return null
    }
}
根据提供的引用内容,出现了两个关于Kotlin的错误信息。第一个引用中显示了一个无法解析依赖的错误,指出无法下载kotlin-reflect.jar文件。第二个引用中显示了一个关于kotlin-gradle-1.8.10.jar (org.jetbrains.kotlin:kotlin-reflect)",这个错误通常是由于Gradle无法找到所需的kotlin-reflect库而引起的。解决这个问题的方法是确保你的项目的Gradle配置正确,并且指定了正确的Kotlin版本。 你可以尝试以下几个步骤来解决这个问题: 1. 确保你的项目的build.gradle文件中包含了正确的Kotlin版本和kotlin-gradle-plugin版本。你可以在build.gradle文件中找到类似于以下代码的部分: ```groovy ext { kotlin_version = '1.8.10' } dependencies { // ... implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" // ... } buildscript { // ... dependencies { // ... classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // ... } } ``` 请确保kotlin_version变量的值与你想要使用的Kotlin版本一致,并且在dependencies和buildscript的classpath中正确引用了kotlin-gradle-plugin。 2. 如果你已经确认了build.gradle文件中的配置正确无误,那么可能是因为Gradle无法从远程仓库下载kotlin-reflect.jar文件。你可以尝试清除Gradle的缓存并重新构建项目。在命令行中执行以下命令: ```shell ./gradlew clean ``` 然后重新构建项目: ```shell ./gradlew build ``` 这将清除Gradle的缓存并重新下载所需的依赖。 3. 如果上述步骤***切换到其他网络环境来解决这个问题。 希望以上步骤能够帮助你解决问题。如果你还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

六毛六66

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值