Kotlin高仿微信-第12篇-单聊-图片

news2024/11/27 13:49:02

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

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

效果图:

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

实现代码:

显示图片:

<androidx.appcompat.widget.AppCompatImageView
    android:id="@+id/chat_item_me_img"
    app:layout_constraintEnd_toStartOf="@+id/chat_item_me_avatar"
    app:layout_constraintTop_toTopOf="parent"
    android:layout_width="100dp"
    android:layout_height="200dp"
    android:scaleType="centerCrop"
    android:layout_marginEnd="10dp"
    android:src="@drawable/wc_loading_default"
    android:visibility="gone"/>

打开相册:

//单选  // 打开相册
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) {
            }
        })
    }

 

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

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

相关文章

STC 51单片机45——51单片机对脉冲计数 汇编 16位除法

部分代码&#xff1a; ORG 0000H LJMP INIT ORG 0003H //外部中断0 LJMP INT0SUB ORG 0013H //外部中断1 LJMP INT1SUB ORG 0100H INIT: CLR P1.0 //控制端复位 …

D-019 EEROM硬件电路设计

EEROM硬件电路设计1 简介1.1 存储器的分类1.2EEPROM的特性2 接口介绍2.1 IIC接口2.2 SPI接口2.3 MicroWire 接口3 EEPROM 和 FLASH4 电路设计实战5 电路设计要点1 简介 1.1 存储器的分类 按照掉电数据是否丢失的特性&#xff0c;存储器可划分为&#xff1a; 易失性存储器&…

快排图文详解:快速排序算法的实现 - 【双边循环法与单边循环法 递归与非递归(栈的方式)的实现】

1.基本介绍 同冒泡排序一样&#xff0c;快速排序&#xff08;Quicksort&#xff09;也属于交换排序&#xff0c;通过元素之间的比较和交换位置来达到排序的目的。但快速排序是对冒泡排序的一种改进。 2.基本思想 关于基本思想&#xff0c;我们在这里先不考虑是如何具体实现的…

nuxtjs生命周期、项目创建、声明式导航与编程式导航、动态路由、嵌套路由、配置式路由、定制默认应用模板、扩展默认布局

文章目录1. 介绍2. 生命周期3. 项目创建4. 声明式导航和编程式导航5. 动态路由参数和验证6. 嵌套路由7. 404页面8. 配置式路由9. 定制默认应用模板10. 扩展默认布局10.1 默认布局10.2 自定义布局10.3 显示错误的布局1. 介绍 Nuxt.js 是一个基于 Vue.js 的通用应用框架。通过对…

离线解锁 CodeCombat 全关卡教程 使用docker安装实现

背景 暂时还没收入&#xff0c;想玩顺便&#xff0c;但官方的有点贵&#xff08;是真的贵&#xff0c;扛不住&#xff09; 前期准备 下载安装docker desktop https://www.123pan.com/s/fmvUVv-HqApH&#xff0c; 这个安装不会的随便搜一个教程&#xff0c;挺多的。我随便找了一…

创建实例化新表格及新行

这期讲一下如何创建创建实例化新表格及行进行添加数据&#xff0c; 在上图可以看到先实例化DataTable表格&#xff0c;用于接收数据&#xff0c; Columns 获取此表的列的集合&#xff0c; Add 创建并添加DataColumn对象&#xff0c; Typeof 数据类型 创建并添加表头。 接下来…

Java定时器选择

java计时器和死循环哪个好&#xff1f;哪个建议使用&#xff1f; 计时器性能更好&#xff0c;但是写起来稍微复杂一点。如果是非常短暂的延迟&#xff0c;用死循环也未尝不可。一般来说能不用死循环的尽量不用死循环&#xff01;如果你使用的是JDK1.5以上的&#xff0c;可以使…

PyQt5可视化编程-控件

控件就像是应用这座房子的一块块砖。PyQt5有很多的控件&#xff0c;比如按钮&#xff0c;单选框&#xff0c;滑动条&#xff0c;复选框等等。我们将介绍一些很有用的控件&#xff1a; QCheckBox,ToggleButton,QSlider,QProgressBar, QCalendarWidget,QPixmap,QLineEdit,QSplitt…

实验四+ R型指令设计实验【计算机组成原理】

实验四+ R型指令设计实验【计算机组成原理】 前言推荐实验四+ R型指令设计实验结果附录defineInstMemIDEX最后前言 编写于 2022/11/22 VIP发布于 2022/11/22 实验于 2022/11/24 发布于 2022/11/24 以下内容源自计算机组成原理实验 仅供学习交流使用 推荐 实验四+ R型指令…

论文指标评价体系及权重计算

一 、评价指标体系 评价指标体系构建在实际研究中使用较为广泛&#xff0c;比如企业绩效评价指标体系构建、政府财政支出绩效评价、医院绩效评价研究等等。 ‍1、相关背景 在中国知网搜索 “ 评价指标 ”、“ 指标体系权重 ” 等相关关键词&#xff0c;可以发现&#xff0c;…

学习ASP.NET Core Blazor编程系列十三——路由(完)

九、NavigationManager 有的时候我们可能需要在代码里进行导航&#xff0c;如果是JavaScript我们会用window.location来切换页面&#xff0c;Blazor为我们提供了相应的封装&#xff1a;NavigationManager。使用NavigationManager可以通过代码直接进行页面间的跳转。我们在BookI…

算法训练Day34 贪心算法专题 | LeetCode1005.K次取反后最大化的数组和 ;134.加油站;135.分发糖果(不要两头兼顾,一边一边处理)

前言&#xff1a; 算法训练系列是做《代码随想录》一刷&#xff0c;个人的学习笔记和详细的解题思路&#xff0c;总共会有60篇博客来记录&#xff0c;计划用60天的时间刷完。 内容包括了面试常见的10类题目&#xff0c;分别是&#xff1a;数组&#xff0c;链表&#xff0c;哈…

基于人工势场法的移动机器人路径规划研究(Matlab代码实现)

目录 &#x1f4a5;1 概述 &#x1f4da;2 运行结果 &#x1f389;3 参考文献 &#x1f468;‍&#x1f4bb;4 Matlab代码 &#x1f4a5;1 概述 路径规划是移动机器人领域的热点研究方向&#xff0c;人工势场法已在工业机器人路径规划中得到广泛应用&#xff0c;近年来正逐…

RKMEDIA--VI的使用

在上一篇文章RKMEDIA使用简介中简单的介绍了rkmedia的组成部分&#xff0c;本章主要聊聊VI模块。 rkmedia中的VI模块主要可以从两个方式获取流&#xff1a;直接打开video节点的方式、使用rk平台的rkaiq。 1、直接打开video节点的方式 顾名思义只需要在vi初始化中配置VI_CHN_AT…

Redeis缓存查询基于元注解与AOP结合使用——不过时的优雅

Redeis缓存查询基于元注解与AOP结合使用 根据优化需要&#xff0c;数据查询的时候无法避免的使用Redis基于缓存查询&#xff0c;进而减少对于数据库的查询压力&#xff0c;对于过多的方法基于缓存存储&#xff0c;为提高代码的复用性&#xff0c;采用一种不过时的写法。 整体的…

spring JPA整合hibernate,IDEA社区版,Java

spring JPA整合hibernate&#xff0c;IDEA社区版&#xff0c;Java 本文基于IDEA社区版&#xff0c;不是IDEA企业版。 &#xff08;1&#xff09;首先用IDEA新建一个spring web项目。参考文章&#xff1a; IDEA社区版(Community Edition)创建Springboot-Web项目&#xff0c;J…

第十二章 使用 Monorepo 方式管理组件生态

组件库一般都会配有周边产品&#xff0c;比如 Admin 、Template、CLI 工具等等。周边产品相当于有关联的多个项目&#xff0c;更准确的说法是多个软件包。这个时候就应该使用 Monorepo 方式组织代码&#xff0c;方便频繁在多个项目间同时交替开发&#xff0c;同时发布&#xff…

图解LeetCode——895. 最大频率栈(难度:困难)

一、题目 设计一个类似堆栈的数据结构&#xff0c;将元素推入堆栈&#xff0c;并从堆栈中弹出 出现频率 最高的元素。 实现 FreqStack 类: FreqStack() 构造一个空的堆栈。void push(int val) 将一个整数 val 压入栈顶。int pop() 删除并返回堆栈中出现频率最高的元素。如果出…

圣杯与双飞翼布局,clip-path,列表与生成元素,计数器

❤️ Author&#xff1a; 老九 ☕️ 个人博客&#xff1a;老九的CSDN博客 &#x1f64f; 个人名言&#xff1a;不可控之事 乐观面对 &#x1f60d; 系列专栏&#xff1a; 文章目录圣杯与双飞翼布局clip属性clip-path属性例子&#xff08;不同区域使用不同颜色的导航&#xff09…

【MySQL 18】Docker 安装 MySQL8 .0.30

1、查看可用的 MySQL 版本 访问 MySQL 镜像库地址&#xff1a; https://hub.docker.com/_/mysql?tabtags 。2、拉取 MySQL 8.0.30 镜像 拉取官方的指定版本的镜像&#xff1a; docker pull mysql:8.0.30[rootlocalhost deploy]# docker pull mysql:8.0.30 8.0.30: Pulling…