Commit 42ec19d1 by 严久程

声网流程优化

parent 1ed4124c
......@@ -20,8 +20,8 @@ import java.util.List;
public final class DemoGlobalConfig implements IConfigModule {
String APP_DOMAIN = "https://api.github.com/";
// public static String appEnv = YDLConstants.ENV_AUTO_TEST;
// public static String appEnv = YDLConstants.ENV_TEST;
public static String appEnv = YDLConstants.ENV_PROD;
public static String appEnv = YDLConstants.ENV_TEST;
// public static String appEnv = YDLConstants.ENV_PROD;
@Override
public void injectAppLifecycle(@NotNull Context context, @NotNull List<IAppLifecycles> lifecycles) {
......
ext {
kotlin_version = "1.3.21"
dev_mode = false
dev_mode = true
ydl_app = [
appName : "心理咨询壹点灵",
......@@ -42,8 +42,8 @@ ext {
ydlPublishVersion = [
// -------------- 业务模块 --------------
//第三步 若干
"m-confide" : "0.0.48.22",
"m-consultant" : "0.0.59.8",
"m-confide" : "0.0.48.26",
"m-consultant" : "0.0.59.14",
"m-fm" : "0.0.29.3",
"m-user" : "0.0.60.3",
"m-home" : "0.0.22.2",
......@@ -75,7 +75,7 @@ ext {
"ydl-webview" : "0.0.38.29",
"ydl-media" : "0.0.20",
"ydl-pay" : "0.0.17",
"m-audioim" : "0.0.49.0",
"m-audioim" : "0.0.49.5",
"ydl-flutter-base": "0.0.14.12",
//以下 几乎不会动
......@@ -121,7 +121,7 @@ ext {
"ydl-webview" : "0.0.38.29",
"ydl-media" : "0.0.20",
"ydl-pay" : "0.0.17",
"m-audioim" : "0.0.49.0",
"m-audioim" : "0.0.49.5",
"ydl-flutter-base": "0.0.10.9",
//以下 几乎不会动
......
......@@ -85,11 +85,13 @@ dependencies {
api project(':ydl-webview')
implementation modularPublication('com.ydl:m-user-api')
implementation modularPublication('com.ydl:m-audioim-api')
implementation modularPublication('com.ydl:m-im-api')
}else {
//发布时使用
api rootProject.ext.dependencies["ydl-webview"]
compileOnly rootProject.ext.dependencies["ydl-m-user-api"]
compileOnly rootProject.ext.dependencies["ydl-m-audioim-api"]
compileOnly rootProject.ext.dependencies["ydl-m-im-api"]
api(rootProject.ext.dependencies["ydl-platform"]) {
transitive = true
}
......
......@@ -190,7 +190,7 @@ class AudioHomeActivity :
LogUtil.e("[agora]发生警告回调$warn")
runOnUiThread {
when (warn) {
103, 104, 105, 106, 107 -> {
103, 105, 107 -> {
writeAgoraLog("通话挂断:网络异常(${warn})")
showToast("当前网络较差,请更换网络!")
//通话结束或挂断时,上传日志文件
......@@ -334,8 +334,47 @@ class AudioHomeActivity :
updateExpertStatus(false, 1)
}, 500)
}
override fun onNetworkQuality(uid: Int, txQuality: Int, rxQuality: Int) {
super.onNetworkQuality(uid, txQuality, rxQuality)
var status = -1
var netStatus = when (uid) {
listenerUid!!.toInt() -> {
if (txQuality in 1..2 && rxQuality in 1..2) {
""
} else if (txQuality >= 5 || rxQuality >= 5) {
"对方的网络已断开"
} else {
status = if (txQuality >= 4 || rxQuality >= 4) {
0
} else {
1
}
"对方的网络状况不佳"
}
}
0-> {
if (txQuality in 1..2 && rxQuality in 1..2) {
""
} else if (txQuality >= 5 || rxQuality >= 5) {
"您的网络已断开"
} else {
status = if (txQuality >= 4 || rxQuality >= 4) {
0
} else {
1
}
"您的网络状况不佳"
}
}
else -> {
""
}
}
showNetStatus(netStatus, status)
}
}
//
override fun createPresenter(): IAudioHomeActivityContract.Presenter {
return AudioHomePresenterImpl()
......@@ -524,7 +563,7 @@ class AudioHomeActivity :
}
}
@SuppressLint("CheckResult")
@SuppressLint("CheckResult", "SetTextI18n")
private fun init() {
wave_view.start()
//初始化声网
......@@ -551,9 +590,10 @@ class AudioHomeActivity :
//开始60s等待倒计时
waitDisposable = Observable.interval(0, 100, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.computation())
.take(603)
.take(600)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
tv_change_time_counter.text = "${60 - it / 10}s"
var result = it.toFloat() / 2.5f
progress_view.setProgress(result)
if (result >= 100f && !iv_hang_up.isEnabled) {
......@@ -594,7 +634,7 @@ class AudioHomeActivity :
}
fun rtcCall() {
YDLRTMClient.instances.call(listenerUid!!, channelId, sendDoctocrMsg)
YDLavManager.instances.rtcCall(listenerUid, channelId, sendDoctocrMsg)
}
......@@ -766,6 +806,7 @@ class AudioHomeActivity :
* 60s等待完成,专家未接听
*/
private fun waittingStatus() {
tv_change_time_counter.visibility = View.GONE
//挂断按钮可点击
iv_hang_up.isEnabled = true
iv_hang_up.setImageResource(R.drawable.audioim_img_hang_up)
......@@ -777,54 +818,9 @@ class AudioHomeActivity :
}
//切换线路按钮可见
tv_change_route.isEnabled = true
tv_change_route.text = "切换至传统电话"
tv_change_route.setTextColor(ContextCompat.getColor(this, R.color.platform_white))
tv_change_route.setCompoundDrawablesWithIntrinsicBounds(
null,
null,
ContextCompat.getDrawable(this, R.drawable.audioim_img_choose_arrow),
null
)
}
/**
* 加入语音聊天频道成功
*/
private fun onJoinChannelSuccess() {
dismissProgressView()
playWaitingMusic()
//45s倒计时逻辑
// disposable = Observable.interval(0, 1, TimeUnit.SECONDS)
// .subscribeOn(Schedulers.computation())
// .take(45)
// .observeOn(AndroidSchedulers.mainThread())
// .subscribe({
// }, {
// LogUtil.d(it.message)
// }, {
// if (!isConnectSuccess) {
// tv_change_doctor.visibility = View.VISIBLE
// }
// })
//60超时倒计时逻辑
// waitDisposable = Observable.interval(0, 1, TimeUnit.SECONDS)
// .subscribeOn(Schedulers.computation())
// .take(60)
// .observeOn(AndroidSchedulers.mainThread())
// .subscribe({
// }, {
// LogUtil.d(it.message)
// }, {
// if (!isConnectSuccess) {
// ActivityManager.getInstance().finishActivity(NewH5Activity::class.java!!)
// showToast("专家未接听")
// userCloseCalling()
// }
// })
}
/**
......@@ -1065,15 +1061,34 @@ class AudioHomeActivity :
*/
private fun showToast(msg: String?) {
runOnUiThread {
// tv_toast.visibility = View.VISIBLE
//// tv_toast.text = msg
//// tv_toast.postDelayed({
//// tv_toast.visibility = View.GONE
//// }, 1000)
ToastHelper.show(msg ?: "")
}
}
/**
* 网络状态
*/
private fun showNetStatus(msg: String, status: Int = 0) {
runOnUiThread {
if (TextUtils.isEmpty(msg)) {
tv_nte_status.visibility = View.GONE
} else {
tv_nte_status.text = msg
if (status == 0) {
tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(this, R.drawable.av_audio_wifi_normal), null, null, null)
}
if (status == 1) {
tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(this, R.drawable.av_audio_wifi_better), null, null, null)
}
if (status == -1) {
tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
}
tv_nte_status.visibility = View.VISIBLE
}
}
}
override fun showProgressView() {
try {
showProgressDialog()
......
......@@ -7,6 +7,7 @@ import android.text.TextUtils
import com.alibaba.android.arouter.launcher.ARouter
import com.ydl.audioim.http.AudioApiRequestUtil
import com.ydl.audioim.http.command.ConnectExceptionCommand
import com.ydl.audioim.router.AudioImIn
import com.ydl.audioim.utils.AudioLogUtils
import com.ydl.consultantim.ConsultantAudioHomeActivity
import com.ydl.ydl_av.messge_service.YDLRTMClient
......@@ -22,6 +23,7 @@ import com.ydl.ydlcommon.utils.ActivityManager
import com.ydl.ydlcommon.utils.LogUtil
import com.ydl.ydlcommon.utils.log.LogHelper
import com.yidianling.common.tools.ToastUtil
import com.yidianling.im.api.bean.IMRegisterObserverCustomNotificationCallBack
import com.yidianling.user.api.service.IUserService
import io.agora.rtm.RtmStatusCode
import io.reactivex.Observable
......@@ -38,7 +40,7 @@ class YDLavManager {
companion object {
val FILE_NAME = "consult"
const val FILE_NAME = "consult"
//当前sdk的登录状态
var sdkStatus = -1
......@@ -128,21 +130,20 @@ class YDLavManager {
//专家离线或者30 秒后仍未收到专家响应,重新再邀请一次
when (errorCode) {
//被叫不在线 呼叫邀请发出 30 秒后被叫仍未 ACK 响应呼叫邀请
RtmStatusCode.LocalInvitationError.LOCAL_INVITATION_ERR_PEER_OFFLINE,
RtmStatusCode.LocalInvitationError.LOCAL_INVITATION_ERR_PEER_NO_RESPONSE -> {
RtmStatusCode.LocalInvitationError.LOCAL_INVITATION_ERR_PEER_OFFLINE, RtmStatusCode.LocalInvitationError.LOCAL_INVITATION_ERR_PEER_NO_RESPONSE -> {
if (act is AudioHomeActivity) {
act.runOnUiThread {
act.rtcCall()
}
}
}
RtmStatusCode.LocalInvitationError.LOCAL_INVITATION_ERR_INVITATION_EXPIRE -> {//呼叫邀请过期。被叫 ACK 响应呼叫邀请后 60 秒呼叫邀请未被取消、接受、拒绝,则呼叫邀请过期。
RtmStatusCode.LocalInvitationError.LOCAL_INVITATION_ERR_INVITATION_EXPIRE -> { //呼叫邀请过期。被叫 ACK 响应呼叫邀请后 60 秒呼叫邀请未被取消、接受、拒绝,则呼叫邀请过期。
if (act is AudioHomeActivity) {
act.runOnUiThread {
act.writeAgoraLog("呼叫失败:${errorCode}")
// //通话结束或挂断时,上传日志文件
// act.uploadLog()
// act.leaveChannel()
// //通话结束或挂断时,上传日志文件
// act.uploadLog()
// act.leaveChannel()
}
}
}
......@@ -175,7 +176,7 @@ class YDLavManager {
override fun onRemoteInvitationFailure(response: CallRemoteResponse?, errorCode: Int) {
//返回给被叫
LogUtil.e("[agora]来自主叫${response?.callerId}的呼叫邀请进程失败:${response?.response}")
if (errorCode == RtmStatusCode.RemoteInvitationError.REMOTE_INVITATION_ERR_INVITATION_EXPIRE) {//呼叫邀请过期
if (errorCode == RtmStatusCode.RemoteInvitationError.REMOTE_INVITATION_ERR_INVITATION_EXPIRE) { //呼叫邀请过期
AudioLogUtils.writeAgoraLog("呼叫邀请被取消:呼叫邀请过期", FILE_NAME)
} else {
AudioLogUtils.writeAgoraLog("呼叫邀请被取消:错误原因(${errorCode})", FILE_NAME)
......@@ -188,8 +189,20 @@ class YDLavManager {
LogUtil.e("[agora]其它消息:${error}")
}
})
AudioImIn.registerObserveCustomNotification(object : IMRegisterObserverCustomNotificationCallBack {
override fun onObserverCustomNotification(content: String) {
}
})
}
fun rtcCall(listenerUid: String?, channelId: String?, sendDoctocrMsg: String?) {
YDLRTMClient.instances.call(listenerUid, channelId, sendDoctocrMsg)
}
fun cancelCall()
fun login(userId: String?) {
login(userId) { _, _ ->
......@@ -206,14 +219,10 @@ class YDLavManager {
}
//登录实时消息
//获取token
AudioApiRequestUtil.getAgoraToken()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
if ("200".equals(it.code)) {
LogUtil.e("[agora]登录av的login-uid:$userId")
YDLRTMClient.instances.login(LoginParam(userId, it.data.token),
object : LoginCallback {
AudioApiRequestUtil.getAgoraToken().subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe({
if ("200".equals(it.code)) {
LogUtil.e("[agora]登录av的login-uid:$userId")
YDLRTMClient.instances.login(LoginParam(userId, it.data.token), object : LoginCallback {
override fun onSuccess() {
//登陆成功,发起呼叫
LogUtil.e("[agora]实时消息登录成功")
......@@ -226,14 +235,13 @@ class YDLavManager {
}
})
} else {
LogUtil.e("声网token获取失败uid:" + userId + " error:" + it.msg)
LogHelper.getInstance()
.writeLogSync("声网token获取失败uid:" + userId + " error:" + it.msg)
}
}, {
LogUtil.e("声网token获取异常uid:" + userId + " error:" + it.message)
})
} else {
LogUtil.e("声网token获取失败uid:" + userId + " error:" + it.msg)
LogHelper.getInstance().writeLogSync("声网token获取失败uid:" + userId + " error:" + it.msg)
}
}, {
LogUtil.e("声网token获取异常uid:" + userId + " error:" + it.message)
})
}
......@@ -244,22 +252,15 @@ class YDLavManager {
fun receivedCall(content: String?, from: String = "") {
if (!TextUtils.isEmpty(content)) {
//如果已经接听了用户电话 再有电话进来 是不能接听的
if (!activityIsExists(ConsultantAudioHomeActivity::class.java) && !activityIsExists(
AudioHomeActivity::class.java
)
) {
if (!activityIsExists(ConsultantAudioHomeActivity::class.java) && !activityIsExists(AudioHomeActivity::class.java)) {
//延时启动通话界面,防止刚打开就被main遮挡
Observable.timer(1000, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
LogUtil.e("[agora]启动通话界面")
//邀请加入频道消息,跳转通话界面
ARouter.getInstance().build("/av/ConsultantAudioHomeActivity")
.withString("param", content)
.navigation()
AudioLogUtils.writeAgoraLog("收到主叫方通话邀请($from)", FILE_NAME, false)
}
Observable.timer(1000, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe {
LogUtil.e("[agora]启动通话界面")
//邀请加入频道消息,跳转通话界面
ARouter.getInstance().build("/av/ConsultantAudioHomeActivity").withString("param", content).navigation()
AudioLogUtils.writeAgoraLog("收到主叫方通话邀请($from)", FILE_NAME, false)
}
} else {
LogUtil.d("[agora]收到声网邀请,但界面实例已存在")
}
......@@ -316,15 +317,13 @@ class YDLavManager {
*/
@SuppressLint("CheckResult")
fun uploadException(connectException: ConnectExceptionCommand, callback: UploadExceptionCallback?) {
AudioApiRequestUtil.connectException(connectException)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
callback?.onSuccess()
}, {
LogUtil.e("agora", "声网上传异常与错误日志接口调用失败:" + it.message)
})
AudioApiRequestUtil.connectException(connectException).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe({
callback?.onSuccess()
}, {
LogUtil.e("agora", "声网上传异常与错误日志接口调用失败:" + it.message)
})
}
/**
......
package com.ydl.audioim.router
import com.ydl.ydlcommon.modular.ModularServiceManager
import com.yidianling.im.api.bean.IMRegisterObserverCustomNotificationCallBack
import com.yidianling.im.api.bean.IMSendCustomNotificationResultCallBack
import com.yidianling.im.api.service.IImService
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2020/4/21
*/
object AudioImIn {
private fun getImService(): IImService {
return ModularServiceManager.provide(IImService::class.java)
}
/**
* 发送自定义通知
*/
fun sendCustomNotification(toUid: String, content: String, callback: IMSendCustomNotificationResultCallBack) {
getImService().sendCustomNotification(toUid, content, callback)
}
/**
* 注册自定通知接收器
*/
fun registerObserveCustomNotification(callback: IMRegisterObserverCustomNotificationCallBack) {
getImService().registerObserveCustomNotification(callback)
}
}
\ No newline at end of file
......@@ -13,6 +13,7 @@ import android.hardware.SensorManager
import android.net.Uri
import android.os.PowerManager
import android.provider.Settings
import android.support.v4.content.ContextCompat
import android.text.TextUtils
import android.view.View
import android.view.animation.AccelerateInterpolator
......@@ -104,6 +105,7 @@ class ConsultantAudioHomeActivity :
private var channelToken: String? = null
private var hasUpLoadLog = false
private var callStatus: Int = -1
private var userId = -1
/**
* 是否连接成功
......@@ -241,14 +243,6 @@ class ConsultantAudioHomeActivity :
}
}
/**
* 网络质量报告回调
* 报告本地用户的网络质量。当你调用 enableLastmileTest 之后,该回调函数每 2 秒触发一次
*/
override fun onLastmileQuality(quality: Int) {
super.onLastmileQuality(quality)
}
override fun onWarning(warn: Int) {
super.onWarning(warn)
// 过滤1031 录制声音模糊
......@@ -263,7 +257,7 @@ class ConsultantAudioHomeActivity :
//107:打开频道请求被服务器拒绝。服务器可能没有办法处理该请求或该请求是非法的
runOnUiThread {
when (warn) {
103, 104, 105, 106, 107 -> {
103, 105, 107 -> {
writeAgoraLog("通话挂断:网络异常($warn)")
showToast("当前网络较差,请更换网络!")
//通话结束或挂断时,上传日志文件
......@@ -316,6 +310,46 @@ class ConsultantAudioHomeActivity :
}
}
}
override fun onNetworkQuality(uid: Int, txQuality: Int, rxQuality: Int) {
super.onNetworkQuality(uid, txQuality, rxQuality)
var status = -1
var netStatus = when (uid) {
userId!!.toInt() -> {
if (txQuality in 1..2 && rxQuality in 1..2) {
""
} else if (txQuality >= 5 || rxQuality >= 5) {
"对方的网络已断开"
} else {
status = if (txQuality >= 4 ||rxQuality >= 4) {
0
} else {
1
}
"对方的网络状况不佳"
}
}
0 -> {
if (txQuality in 1..2 && rxQuality in 1..2) {
""
} else if (txQuality >= 5 || rxQuality >= 5) {
"您的网络已断开"
} else {
status = if (txQuality >= 4 ||rxQuality >= 4) {
0
} else {
1
}
"您的网络状况不佳"
}
}
else -> {
""
}
}
showNetStatus(netStatus, status)
}
}
......@@ -419,6 +453,7 @@ class ConsultantAudioHomeActivity :
} else {
iv_head.setBackgroundResource(R.drawable.audioim_head_place_hold_pic)
}
userId = mAudioMessageBean!!.userId?.toInt() ?: -1
} else {
iv_head.setBackgroundResource(R.drawable.audioim_head_place_hold_pic)
}
......@@ -733,6 +768,31 @@ class ConsultantAudioHomeActivity :
}
}
/**
* 网络状态
*/
private fun showNetStatus(msg: String, status: Int = 0) {
runOnUiThread {
if (TextUtils.isEmpty(msg)) {
tv_nte_status.visibility = View.GONE
} else {
tv_nte_status.text = msg
if (status == 0) {
tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(this, R.drawable.av_audio_wifi_normal), null, null, null)
}
if (status == 1) {
tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(ContextCompat.getDrawable(this, R.drawable.av_audio_wifi_better), null, null, null)
}
if (status == -1) {
tv_nte_status.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null)
}
tv_nte_status.visibility = View.VISIBLE
}
}
}
//关闭本页面
fun close(code: Int, msg: String) {
runOnUiThread {
......@@ -802,7 +862,7 @@ class ConsultantAudioHomeActivity :
.subscribe({}, {}, {
if (!isConnectSuccess) {
writeAgoraLog("通话未接通挂断:连接中的状态超过5s自动挂断")
showToast( "用户已挂断")
showToast("用户已挂断")
close(RESULT_NOT_ANSWERED_CODE, "")
}
})
......
......@@ -6,6 +6,7 @@
android:layout_height="match_parent"
android:background="@color/platform_color_80353535">
<TextView
android:id="@+id/tv_change_route"
android:layout_width="wrap_content"
......@@ -14,21 +15,30 @@
android:layout_marginTop="25dp"
android:layout_marginRight="10dp"
android:background="?android:attr/selectableItemBackground"
android:drawableRight="@drawable/audioim_img_choose_arrow_unuse"
android:drawablePadding="6dp"
android:padding="5dp"
android:text="切换至传统电话"
android:text="后可切换至传统电话"
android:textColor="@color/platform_color_50FFFFFF"
android:textSize="13sp"
android:visibility="visible" />
<TextView
android:id="@+id/tv_change_time_counter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/tv_change_route"
android:layout_toLeftOf="@+id/tv_change_route"
android:textColor="@color/white"
android:textSize="15dp"
tools:text="60s" />
<RelativeLayout
android:id="@+id/rl_head"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_centerHorizontal="true"
android:layout_marginTop="74dp">
android:layout_marginTop="60dp">
<com.ydl.ydlcommon.view.WaveView
android:id="@+id/wave_view"
......@@ -80,33 +90,53 @@
tools:text="你存在的本身就是值得被爱的你存在的本身就是值得被爱的" />
<!-- 倾诉剩余时间-->
<RelativeLayout
<android.support.constraint.ConstraintLayout
android:id="@+id/rl_remain_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/rl_hang_up"
android:layout_marginBottom="20dp"
android:visibility="gone">
android:visibility="gone"
tools:visibility="visible">
<TextView
android:id="@+id/tv_notes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:text="您的倾诉时间还有"
android:textColor="@color/platform_color_30FFFFFF"
android:textSize="12sp" />
android:text="剩余时长"
android:textColor="@color/white"
android:textSize="15dp"
app:layout_constraintEnd_toStartOf="@+id/tv_remain_time"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_remain_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_notes"
android:layout_centerHorizontal="true"
android:layout_marginStart="11dp"
android:layout_toRightOf="@+id/tv_notes"
android:text="23:23"
android:textColor="@color/white"
android:textSize="20sp" />
</RelativeLayout>
android:textSize="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/tv_notes"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_notes"
android:layout_marginTop="2dp"
android:text="(限24小时内拨打)"
android:textColor="#80FFFFFF"
android:textSize="15dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_remain_time" />
</android.support.constraint.ConstraintLayout>
<TextView
android:id="@+id/tv_change_doctor"
......@@ -130,7 +160,8 @@
android:text="正在等待聆听者接受邀请…"
android:textColor="@color/platform_color_70FFFFFF"
android:textSize="12sp"
android:visibility="visible" />
android:visibility="visible"
tools:visibility="gone" />
<!--挂断按钮-->
<RelativeLayout
......@@ -212,8 +243,27 @@
android:paddingBottom="4dp"
android:textColor="@color/white"
android:visibility="gone"
tools:visibility="visible"
tools:text="已接通"
/>
tools:visibility="visible" />
<TextView
android:id="@+id/tv_nte_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_tips"
android:layout_centerHorizontal="true"
android:layout_marginTop="70dp"
android:background="@drawable/audioim_toast_view_background"
android:drawableLeft="@drawable/av_audio_wifi_better"
android:elevation="6dp"
android:paddingLeft="11dp"
android:paddingTop="4dp"
android:paddingRight="11dp"
android:paddingBottom="4dp"
android:textColor="@color/white"
android:visibility="gone"
tools:text="对方的网络状况不佳"
tools:visibility="visible" />
</RelativeLayout>
......@@ -47,6 +47,7 @@
android:textColor="@color/white"
android:textSize="26sp"
tools:text="用户" />
<TextView
android:id="@+id/tv_tips"
android:layout_width="wrap_content"
......@@ -59,9 +60,9 @@
android:ellipsize="end"
android:gravity="center"
android:maxLines="2"
android:text="向您发起语音通话请求"
android:textColor="@color/white"
android:textSize="15sp"
android:text="向您发起语音通话请求" />
android:textSize="15sp" />
<!--自定义弹窗-->
......@@ -83,6 +84,26 @@
tools:text="连接中..."
tools:visibility="visible" />
<TextView
android:id="@+id/tv_nte_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/tv_tips"
android:layout_centerHorizontal="true"
android:layout_marginTop="70dp"
android:background="@drawable/audioim_toast_view_background"
android:drawableLeft="@drawable/av_audio_wifi_better"
android:elevation="6dp"
android:paddingLeft="11dp"
android:paddingTop="4dp"
android:paddingRight="11dp"
android:paddingBottom="4dp"
android:textColor="@color/white"
android:visibility="gone"
tools:text="对方的网络状况不佳"
tools:visibility="visible" />
<!-- 倾诉剩余时间-->
<RelativeLayout
android:id="@+id/rl_remain_time"
......
......@@ -361,9 +361,7 @@ class ExpertSearchFragment : BaseMvpFragment<IExpertSearchView, ExpertSearchPres
v_loading.visibility = View.VISIBLE
v_loading.setViewType(LogoLoadingView.TYPE_LOADING, null)
if (fromPageType != -1) {
doctorAdapter.setEntrance(fromPages[fromPageType], 0)
}
doctorAdapter.setEntrance(0)
}
/**
......
......@@ -59,11 +59,9 @@ class ExpertSearchAdapter(
var hasMore = true
var entranceName: String? = null
var pageIndex: Int = 0
fun setEntrance(entranceName: String, pageIndex: Int) {
this.entranceName = entranceName
fun setEntrance( pageIndex: Int) {
this.pageIndex = pageIndex
}
......@@ -465,14 +463,6 @@ class ExpertSearchAdapter(
} else {
ToastHelper.show("请联系客服,专家参数错误!")
}
if (!TextUtils.isEmpty(entranceName)) {
LogUtil.d("entrance name: $entranceName")
BuryPointUtils.getInstance().createMap()
.put("expert_entrance", entranceName ?: "")
.put("expert_ID", doctor.doctorId ?: 0)
.put("expert_name", doctor.name ?: "")
.burryPoint("Chat_click")
}
}
}
}
......
......@@ -12,10 +12,13 @@ import com.netease.nimlib.sdk.msg.MsgServiceObserve
import com.netease.nimlib.sdk.msg.constant.AttachStatusEnum
import com.netease.nimlib.sdk.msg.constant.MsgDirectionEnum
import com.netease.nimlib.sdk.msg.constant.MsgTypeEnum
import com.netease.nimlib.sdk.msg.model.CustomNotification
import com.netease.nimlib.sdk.msg.model.IMMessage
import com.netease.nimlib.sdk.msg.model.RevokeMsgNotification
import com.netease.nimlib.sdk.team.TeamServiceObserver
import com.netease.nimlib.sdk.team.model.Team
import com.ydl.ydlcommon.utils.LogUtil
import com.yidianling.im.api.bean.IMRegisterObserverCustomNotificationCallBack
import com.yidianling.im.api.event.AccountChangeEvent
import com.yidianling.im.event.MsgPushEvent
import com.yidianling.im.event.TeamRemoveEvent
......@@ -38,6 +41,10 @@ import java.util.concurrent.Executors
* Des:
*/
class ImObserversHelper {
var imCustomNotificationCallBack: IMRegisterObserverCustomNotificationCallBack? = null
set(value) {
field = value
}
companion object {
fun getInstance(): ImObserversHelper {
......@@ -45,23 +52,22 @@ class ImObserversHelper {
}
}
private object Holder {
val INSTANCE = ImObserversHelper()
}
fun registerObserver(register: Boolean) {
//注册`在线状态变化`观察者
NIMClient.getService(AuthServiceObserver::class.java)
.observeOnlineStatus(userStatusObserver, register)
NIMClient.getService(AuthServiceObserver::class.java).observeOnlineStatus(userStatusObserver, register)
//注册`消息撤回`观察者
NIMClient.getService(MsgServiceObserve::class.java)
.observeRevokeMessage(messageRevokeObserver, register)
NIMClient.getService(MsgServiceObserve::class.java).observeRevokeMessage(messageRevokeObserver, register)
//注册`消息接收`观察者
NIMClient.getService(MsgServiceObserve::class.java)
.observeReceiveMessage(incomingMessageObserver, register)
NIMClient.getService(MsgServiceObserve::class.java).observeReceiveMessage(incomingMessageObserver, register)
//注册`移出群`观察者通知
NIMClient.getService(TeamServiceObserver::class.java)
.observeTeamRemove(teamObserver, register)
NIMClient.getService(TeamServiceObserver::class.java).observeTeamRemove(teamObserver, register)
NIMClient.getService(MsgServiceObserve::class.java).observeCustomNotification(receiveSystemMessageObserver, register)
//注册`未读消息改变数量`观察者
registerMsgUnreadInfoObserver(register)
if (register) {
......@@ -76,15 +82,13 @@ class ImObserversHelper {
if (register) {
ReminderManager.getInstance().registerUnreadNumChangedCallback(unreadNumChangedCallback)
} else {
ReminderManager.getInstance()
.unregisterUnreadNumChangedCallback(unreadNumChangedCallback)
ReminderManager.getInstance().unregisterUnreadNumChangedCallback(unreadNumChangedCallback)
}
}
private var unreadNumChangedCallback: ReminderManager.UnreadNumChangedCallback =
ReminderManager.UnreadNumChangedCallback() {
MsgReceiveHelper.onMessageReceived()
}
private var unreadNumChangedCallback: ReminderManager.UnreadNumChangedCallback = ReminderManager.UnreadNumChangedCallback() {
MsgReceiveHelper.onMessageReceived()
}
private var userStatusObserver: Observer<StatusCode> = Observer { code ->
if (code.wontAutoLoginForever()) {
......@@ -95,9 +99,7 @@ class ImObserversHelper {
private var messageRevokeObserver: Observer<RevokeMsgNotification> = NimMessageRevokeObserver()
private var teamObserver: Observer<Team> = Observer<Team> { t ->
EventBus.getDefault().post(
TeamRemoveEvent(1, t.id)
)
EventBus.getDefault().post(TeamRemoveEvent(1, t.id))
}
private var incomingMessageObserver = Observer<List<IMMessage>> { messages ->
......@@ -150,7 +152,7 @@ class ImObserversHelper {
event.headUrl = userInfo.avatar
}
// LogUtil.e("发送事件:$event")
// LogUtil.e("发送事件:$event")
EventBus.getDefault().post(event)
}
}
......@@ -170,12 +172,13 @@ class ImObserversHelper {
false
}
private var receiveSystemMessageObserver: Observer<CustomNotification> = Observer<CustomNotification> {
LogUtil.e(it.content)
imCustomNotificationCallBack?.onObserverCustomNotification(it.content)
}
private var msgRevokeFilter = MsgRevokeFilter { message ->
if (message.attachment != null
&& message.attachment is AVChatAttachment
&& message.attachment is CustomAttachRedPacket
) {
if (message.attachment != null && message.attachment is AVChatAttachment && message.attachment is CustomAttachRedPacket) {
// 视频通话消息和白板消息 不允许撤回
return@MsgRevokeFilter true
} else if (IMCache.getAccount() != null && IMCache.getAccount() == message.sessionId) {
......@@ -188,39 +191,36 @@ class ImObserversHelper {
//如果是收款提醒消息 则更新历史收款消息的状态
fun flushReceivedMoney(m: IMMessage) {
//跟新收款消息
NIMClient.getService(MsgService::class.java)
.queryMessageListByType(MsgTypeEnum.custom, m, 100)
.setCallback(object : RequestCallback<List<IMMessage>> {
override fun onSuccess(imMessages: List<IMMessage>) {
for (im in imMessages) {
if (im.attachment is CustomAttachReceivedMoney) {
val money = im.attachment as CustomAttachReceivedMoney
if (money.orPay == 1) return
val status = m.attachment as CustomAttachmentReceivedSuccess
if (money.orderId == null || status.orderid == null) return
if (money.orderId == status.orderid) {
money.orPay = 1//设置为已支付
im.attachment = money
//更新此消息到sdk
NIMClient.getService(MsgService::class.java)
.updateIMMessageStatus(im)
//更新私聊界面聊天信息
MessageListPanelHelper.getInstance().notifyModifyMessage(im)
return
}
NIMClient.getService(MsgService::class.java).queryMessageListByType(MsgTypeEnum.custom, m, 100).setCallback(object : RequestCallback<List<IMMessage>> {
override fun onSuccess(imMessages: List<IMMessage>) {
for (im in imMessages) {
if (im.attachment is CustomAttachReceivedMoney) {
val money = im.attachment as CustomAttachReceivedMoney
if (money.orPay == 1) return
val status = m.attachment as CustomAttachmentReceivedSuccess
if (money.orderId == null || status.orderid == null) return
if (money.orderId == status.orderid) {
money.orPay = 1 //设置为已支付
im.attachment = money
//更新此消息到sdk
NIMClient.getService(MsgService::class.java).updateIMMessageStatus(im)
//更新私聊界面聊天信息
MessageListPanelHelper.getInstance().notifyModifyMessage(im)
return
}
}
}
}
override fun onFailed(i: Int) {
// Log.e("hzs","跟新收款消息失败");
}
override fun onFailed(i: Int) {
// Log.e("hzs","跟新收款消息失败");
}
override fun onException(throwable: Throwable) {
// Log.e("hzs","跟新收款消息异常:"+throwable);
}
})
override fun onException(throwable: Throwable) {
// Log.e("hzs","跟新收款消息异常:"+throwable);
}
})
}
}
......@@ -11,14 +11,19 @@ import com.netease.nimlib.sdk.auth.LoginInfo
import com.netease.nimlib.sdk.msg.MessageBuilder
import com.netease.nimlib.sdk.msg.MsgService
import com.netease.nimlib.sdk.msg.constant.SessionTypeEnum
import com.netease.nimlib.sdk.msg.model.CustomNotification
import com.netease.nimlib.sdk.msg.model.CustomNotificationConfig
import com.ydl.ydlcommon.router.YdlCommonOut
import com.ydl.ydlcommon.utils.StringUtils
import com.yidianling.im.R
import com.yidianling.im.api.bean.IMLoginInfo
import com.yidianling.im.api.bean.IMRegisterObserverCustomNotificationCallBack
import com.yidianling.im.api.bean.IMRequestCallback
import com.yidianling.im.api.bean.IMSendCustomNotificationResultCallBack
import com.yidianling.im.api.service.IImService
import com.yidianling.im.bridge.P2PCustomActionHandlerImpl
import com.yidianling.im.helper.IMUtil
import com.yidianling.im.helper.ImObserversHelper
import com.yidianling.im.helper.MsgReceiveHelper
import com.yidianling.im.preference.IMCache
import com.yidianling.im.router.ImIn
......@@ -53,9 +58,7 @@ class IMServiceImpl : IImService {
context.startActivity(ImIn.loginWayIntent(context))
return
}
SessionHelper.startP2PSession(context, -1, "14", null,
P2PCustomActionHandlerImpl("14",
"客服小壹", "https://static.ydlcdn.com/mobile/images/avatar_girl_app.png"))
SessionHelper.startP2PSession(context, -1, "14", null, P2PCustomActionHandlerImpl("14", "客服小壹", "https://static.ydlcdn.com/mobile/images/avatar_girl_app.png"))
}
override fun imLogin(info: IMLoginInfo) {
......@@ -109,43 +112,39 @@ class IMServiceImpl : IImService {
override fun createTextMessage(sessionId: String?, content: String, callback: IMRequestCallback<Void>) {
val message = MessageBuilder.createTextMessage(sessionId, SessionTypeEnum.P2P, content)
NIMClient.getService(MsgService::class.java)
.sendMessage(message, false)
.setCallback(object : RequestCallback<Void> {
override fun onSuccess(param: Void?) {
callback.onSuccess(param)
MessageListPanelHelper.getInstance().notifyAddMessage(message)
}
NIMClient.getService(MsgService::class.java).sendMessage(message, false).setCallback(object : RequestCallback<Void> {
override fun onSuccess(param: Void?) {
callback.onSuccess(param)
MessageListPanelHelper.getInstance().notifyAddMessage(message)
}
override fun onException(exception: Throwable?) {
callback.onException(exception)
}
override fun onException(exception: Throwable?) {
callback.onException(exception)
}
override fun onFailed(code: Int) {
callback.onFailed(code)
}
})
override fun onFailed(code: Int) {
callback.onFailed(code)
}
})
}
override fun sendSubscriptionTimeMessage(sessionId: String?, content: String, callback: IMRequestCallback<Void>) {
val customTime = CustomAttachSubScriptTime(content)
val message = MessageBuilder.createCustomMessage(sessionId, SessionTypeEnum.P2P, content, customTime)
NIMClient.getService(MsgService::class.java)
.sendMessage(message, false)
.setCallback(object : RequestCallback<Void> {
override fun onSuccess(param: Void?) {
callback.onSuccess(param)
MessageListPanelHelper.getInstance().notifyAddMessage(message)
}
NIMClient.getService(MsgService::class.java).sendMessage(message, false).setCallback(object : RequestCallback<Void> {
override fun onSuccess(param: Void?) {
callback.onSuccess(param)
MessageListPanelHelper.getInstance().notifyAddMessage(message)
}
override fun onException(exception: Throwable?) {
callback.onException(exception)
}
override fun onException(exception: Throwable?) {
callback.onException(exception)
}
override fun onFailed(code: Int) {
callback.onFailed(code)
}
})
override fun onFailed(code: Int) {
callback.onFailed(code)
}
})
}
......@@ -157,20 +156,13 @@ class IMServiceImpl : IImService {
option.crop = false
option.cropOutputImageWidth = 720
option.cropOutputImageHeight = 720
// option.outputPath = StorageUtil.getWritePath(StringUtils.get32UUID() + ".jpg", StorageType.TYPE_TEMP)
// option.outputPath = StorageUtil.getWritePath(StringUtils.get32UUID() + ".jpg", StorageType.TYPE_TEMP)
option.outputPath = YdlCommonOut.getApp().externalCacheDir.absolutePath + "/" + StringUtils.get32UUID() + ".jpg"
PickImageHelper.pickImage(activity, requestCode, option)
}
override fun sendTestResultMessage(uid: String, content: String, title: String?, head: String?, url: String?, id: Int, share_url: String?, callback: IMRequestCallback<Void>) {
val customAttachmentTest = CustomAttachmentTest(
CustomAttachmentTest.FLAG_RESULT,
title,
head,
url,
id,
share_url
)
val customAttachmentTest = CustomAttachmentTest(CustomAttachmentTest.FLAG_RESULT, title, head, url, id, share_url)
val message = MessageBuilder.createCustomMessage(uid, SessionTypeEnum.P2P, "测试结果", customAttachmentTest)
NIMClient.getService(MsgService::class.java).sendMessage(message, false).setCallback(object : RequestCallback<Void> {
......@@ -205,4 +197,36 @@ class IMServiceImpl : IImService {
override fun getAllUnReadNum(): Int {
return MsgReceiveHelper.getAllUnNum()
}
/**
* 发送自定义通知: 不推送、不计入未读消息
*/
override fun sendCustomNotification(toUid: String, content: String, callback: IMSendCustomNotificationResultCallBack) {
val config = CustomNotificationConfig()
config.enablePush = false
config.enablePushNick = false
config.enableUnreadCount = false
val customNotification = CustomNotification()
customNotification.sessionType = SessionTypeEnum.P2P
customNotification.sessionId = toUid
customNotification.config = config
customNotification.content = content
NIMClient.getService(MsgService::class.java).sendCustomNotification(customNotification).setCallback(object : RequestCallback<Void?> {
override fun onSuccess(param: Void?) {
callback.onSuccess()
}
override fun onFailed(code: Int) {
callback.onFailed(code)
}
override fun onException(exception: Throwable) {
callback.onException(exception)
}
})
}
override fun registerObserveCustomNotification(callback: IMRegisterObserverCustomNotificationCallBack) {
ImObserversHelper.getInstance().imCustomNotificationCallBack=callback
}
}
\ No newline at end of file
package com.yidianling.im.api.bean
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2020/4/21
*/
interface IMRegisterObserverCustomNotificationCallBack {
fun onObserverCustomNotification(content: String)
}
\ No newline at end of file
package com.yidianling.im.api.bean
/**
* @author jiucheng
* @描述:
* @Copyright Copyright (c) 2018
* @Company 壹点灵
* @date 2020/4/21
*/
interface IMSendCustomNotificationResultCallBack {
fun onSuccess()
fun onFailed(code: Int)
fun onException(throwable: Throwable)
}
\ No newline at end of file
......@@ -4,7 +4,9 @@ import android.app.Activity
import android.content.Context
import com.alibaba.android.arouter.facade.template.IProvider
import com.yidianling.im.api.bean.IMLoginInfo
import com.yidianling.im.api.bean.IMRegisterObserverCustomNotificationCallBack
import com.yidianling.im.api.bean.IMRequestCallback
import com.yidianling.im.api.bean.IMSendCustomNotificationResultCallBack
/**
* author : Zhangwenchao
......@@ -25,7 +27,7 @@ interface IImService : IProvider {
fun setChattingAccountNone()
fun isHasUnread():Boolean
fun isHasUnread(): Boolean
fun login(info: IMLoginInfo, callback: IMRequestCallback<IMLoginInfo>?)
......@@ -50,7 +52,7 @@ interface IImService : IProvider {
fun sendTestResultMessage(uid: String, content: String, title: String?, head: String?, url: String?, id: Int, share_url: String?, callback: IMRequestCallback<Void>)
fun startChat(context : Activity ,toUid : String ,flag : Int , canTalk : Int)
fun startChat(context: Activity, toUid: String, flag: Int, canTalk: Int)
/**
* 根据对方uid获取未读数
......@@ -62,4 +64,15 @@ interface IImService : IProvider {
* 获取自己的所有未读数
*/
fun getAllUnReadNum(): Int
/**
* 发送自定义通知
*/
fun sendCustomNotification(toUid: String, content: String, callback: IMSendCustomNotificationResultCallBack)
/**
* 注册自定通知接收器
*/
fun registerObserveCustomNotification(callback: IMRegisterObserverCustomNotificationCallBack)
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment