新增聊天消息提醒
This commit is contained in:
@@ -37,9 +37,9 @@
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/Theme.RiderPro">
|
||||
android:theme="@style/Theme.RiderPro"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
@@ -69,6 +69,9 @@
|
||||
<action android:name="cn.jiguang.user.service.action" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service
|
||||
android:name=".TrtcService"
|
||||
android:exported="false" />
|
||||
|
||||
<receiver
|
||||
android:name=".JpushReciver"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.aiosman.riderpro
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.icu.util.Calendar
|
||||
import android.icu.util.TimeZone
|
||||
import android.util.Log
|
||||
@@ -23,7 +24,6 @@ import com.tencent.imsdk.v2.V2TIMLogListener
|
||||
import com.tencent.imsdk.v2.V2TIMManager
|
||||
import com.tencent.imsdk.v2.V2TIMSDKConfig
|
||||
import com.tencent.imsdk.v2.V2TIMUserFullInfo
|
||||
import com.tencent.imsdk.v2.V2TIMValueCallback
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
|
||||
@@ -66,8 +66,12 @@ object AppState {
|
||||
val sign = accountService.getMyTrtcSign()
|
||||
loginToTrtc(sign.userId, sign.sig)
|
||||
updateTrtcUserProfile()
|
||||
// 登录成功后,启动TrtcService
|
||||
context.startService(
|
||||
Intent(context, TrtcService::class.java)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +109,7 @@ object AppState {
|
||||
}
|
||||
}
|
||||
|
||||
fun ReloadAppState() {
|
||||
fun ReloadAppState(context: Context) {
|
||||
// 重置动态列表页面
|
||||
MomentViewModel.ResetModel()
|
||||
// 重置我的页面
|
||||
@@ -129,5 +133,13 @@ object AppState {
|
||||
// 重置关注通知页面
|
||||
IndexViewModel.ResetModel()
|
||||
UserId = null
|
||||
|
||||
// 关闭 TrtcService
|
||||
val trtcService = Intent(
|
||||
context,
|
||||
TrtcService::class.java
|
||||
)
|
||||
context.stopService(trtcService)
|
||||
|
||||
}
|
||||
}
|
||||
40
app/src/main/java/com/aiosman/riderpro/ChatState.kt
Normal file
40
app/src/main/java/com/aiosman/riderpro/ChatState.kt
Normal file
@@ -0,0 +1,40 @@
|
||||
package com.aiosman.riderpro
|
||||
|
||||
import com.aiosman.riderpro.data.ChatService
|
||||
import com.aiosman.riderpro.data.ChatServiceImpl
|
||||
import com.aiosman.riderpro.entity.ChatNotification
|
||||
|
||||
/**
|
||||
* 保存一些关于聊天的状态
|
||||
*/
|
||||
object ChatState {
|
||||
val chatService: ChatService = ChatServiceImpl()
|
||||
var chatNotificationList = mutableListOf<ChatNotification>()
|
||||
suspend fun getStrategyByTargetTrtcId(targetTrtcId: String): ChatNotification? {
|
||||
// 先从缓存中查找
|
||||
if (chatNotificationList.isNotEmpty()) {
|
||||
chatNotificationList.forEach {
|
||||
if (it.targetTrtcId == targetTrtcId) {
|
||||
return it
|
||||
}
|
||||
}
|
||||
}
|
||||
// 缓存中没有再从网络获取
|
||||
chatService.getChatNotifications(targetTrtcId)?.let {
|
||||
chatNotificationList.add(it)
|
||||
return it
|
||||
}
|
||||
// 存在未设置策略的情况
|
||||
return null
|
||||
}
|
||||
|
||||
suspend fun updateChatNotification(targetUserId: Int, strategy: String): ChatNotification {
|
||||
val updatedData = chatService.updateChatNotification(targetUserId, strategy)
|
||||
chatNotificationList = chatNotificationList.filter {
|
||||
it.targetUserId != targetUserId
|
||||
}.toMutableList().apply {
|
||||
add(updatedData)
|
||||
}
|
||||
return updatedData
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,8 @@ import cn.jiguang.api.utils.JCollectionAuth
|
||||
import cn.jpush.android.api.JPushInterface
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.data.UserService
|
||||
import com.aiosman.riderpro.data.UserServiceImpl
|
||||
import com.aiosman.riderpro.ui.Navigation
|
||||
import com.aiosman.riderpro.ui.NavigationRoute
|
||||
import com.aiosman.riderpro.ui.navigateToPost
|
||||
@@ -109,7 +111,7 @@ class MainActivity : ComponentActivity() {
|
||||
// 处理带有 postId 的通知点击
|
||||
val postId = intent.getStringExtra("POST_ID")
|
||||
var commentId = intent.getStringExtra("COMMENT_ID")
|
||||
var action = intent.getStringExtra("ACTION")
|
||||
val action = intent.getStringExtra("ACTION")
|
||||
if (action == "newFollow") {
|
||||
navController.navigate(NavigationRoute.Followers.route)
|
||||
return@Navigation
|
||||
@@ -118,6 +120,25 @@ class MainActivity : ComponentActivity() {
|
||||
navController.navigate(NavigationRoute.Followers.route)
|
||||
return@Navigation
|
||||
}
|
||||
if (action == "TRTC_NEW_MESSAGE") {
|
||||
val userService:UserService = UserServiceImpl()
|
||||
val sender = intent.getStringExtra("SENDER")
|
||||
sender?.let {
|
||||
scope.launch {
|
||||
try {
|
||||
val profile = userService.getUserProfileByTrtcUserId(it)
|
||||
navController.navigate(NavigationRoute.Chat.route.replace(
|
||||
"{id}",
|
||||
profile.id.toString()
|
||||
))
|
||||
}catch (e:Exception){
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
return@Navigation
|
||||
}
|
||||
|
||||
if (commentId == null) {
|
||||
commentId = "0"
|
||||
}
|
||||
|
||||
129
app/src/main/java/com/aiosman/riderpro/TrtcService.kt
Normal file
129
app/src/main/java/com/aiosman/riderpro/TrtcService.kt
Normal file
@@ -0,0 +1,129 @@
|
||||
package com.aiosman.riderpro
|
||||
|
||||
import android.Manifest
|
||||
import android.app.NotificationChannel
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import com.aiosman.riderpro.entity.ChatItem
|
||||
import com.tencent.imsdk.v2.V2TIMAdvancedMsgListener
|
||||
import com.tencent.imsdk.v2.V2TIMManager
|
||||
import com.tencent.imsdk.v2.V2TIMMessage
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class TrtcService : Service() {
|
||||
private var trtcMessageListener: V2TIMAdvancedMsgListener? = null
|
||||
private val channelId = "chat_notification"
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
Log.d("TrtcService", "onStartCommand")
|
||||
createNotificationChannel()
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
registerMessageListener(applicationContext)
|
||||
}
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
Log.d("TrtcService", "onDestroy")
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
unRegisterMessageListener()
|
||||
}
|
||||
}
|
||||
|
||||
private fun registerMessageListener(context: Context) {
|
||||
val scope = CoroutineScope(Dispatchers.IO)
|
||||
trtcMessageListener = object : V2TIMAdvancedMsgListener() {
|
||||
override fun onRecvNewMessage(msg: V2TIMMessage?) {
|
||||
super.onRecvNewMessage(msg)
|
||||
msg?.let {
|
||||
if (MainActivityLifecycle.isForeground) {
|
||||
return
|
||||
}
|
||||
scope.launch {
|
||||
// 先获取通知策略
|
||||
val notiStrategy = ChatState.getStrategyByTargetTrtcId(it.sender)
|
||||
if (notiStrategy == null) {
|
||||
// 未设置策略, 默认通知
|
||||
sendNotification(context, it)
|
||||
return@launch
|
||||
}
|
||||
if (notiStrategy.strategy != "mute") {
|
||||
sendNotification(context, it)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
V2TIMManager.getMessageManager().addAdvancedMsgListener(trtcMessageListener)
|
||||
}
|
||||
|
||||
private fun unRegisterMessageListener() {
|
||||
V2TIMManager.getMessageManager().removeAdvancedMsgListener(trtcMessageListener)
|
||||
}
|
||||
|
||||
private fun createNotificationChannel() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val name = "Chat Notification"
|
||||
val descriptionText = "Notification for chat message"
|
||||
val importance = NotificationManager.IMPORTANCE_DEFAULT
|
||||
val channel = NotificationChannel(channelId, name, importance).apply {
|
||||
description = descriptionText
|
||||
}
|
||||
val notificationManager: NotificationManager =
|
||||
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
}
|
||||
|
||||
private fun sendNotification(context: Context, message: V2TIMMessage) {
|
||||
val intent = Intent(context, MainActivity::class.java).apply {
|
||||
putExtra("ACTION", "TRTC_NEW_MESSAGE")
|
||||
putExtra("SENDER", message.sender)
|
||||
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
|
||||
}
|
||||
|
||||
val pendingIntent: PendingIntent = PendingIntent.getActivity(
|
||||
context,
|
||||
0,
|
||||
intent,
|
||||
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
val chatItem = ChatItem.convertToChatItem(message, context) ?: return
|
||||
val builder = NotificationCompat.Builder(context, channelId)
|
||||
.setSmallIcon(R.mipmap.rider_pro_log_round)
|
||||
.setContentTitle(chatItem.nickname)
|
||||
.setContentText(chatItem.textDisplay)
|
||||
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(true)
|
||||
|
||||
with(NotificationManagerCompat.from(context)) {
|
||||
if (ActivityCompat.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.POST_NOTIFICATIONS
|
||||
) != PackageManager.PERMISSION_GRANTED
|
||||
) {
|
||||
return
|
||||
}
|
||||
notify(message.msgID.hashCode(), builder.build())
|
||||
}
|
||||
}
|
||||
}
|
||||
42
app/src/main/java/com/aiosman/riderpro/data/ChatService.kt
Normal file
42
app/src/main/java/com/aiosman/riderpro/data/ChatService.kt
Normal file
@@ -0,0 +1,42 @@
|
||||
package com.aiosman.riderpro.data
|
||||
|
||||
import com.aiosman.riderpro.data.api.ApiClient
|
||||
import com.aiosman.riderpro.data.api.UpdateChatNotificationRequestBody
|
||||
import com.aiosman.riderpro.entity.ChatNotification
|
||||
|
||||
interface ChatService {
|
||||
suspend fun getChatNotifications(
|
||||
targetTrtcId: String
|
||||
): ChatNotification?
|
||||
|
||||
suspend fun updateChatNotification(
|
||||
targetUserId: Int,
|
||||
strategy: String
|
||||
): ChatNotification
|
||||
}
|
||||
|
||||
class ChatServiceImpl : ChatService {
|
||||
override suspend fun getChatNotifications(
|
||||
targetTrtcId: String
|
||||
): ChatNotification? {
|
||||
val resp = ApiClient.api.getChatNotification(targetTrtcId)
|
||||
if (resp.isSuccessful) {
|
||||
return resp.body()?.data
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override suspend fun updateChatNotification(
|
||||
targetUserId: Int,
|
||||
strategy: String
|
||||
): ChatNotification {
|
||||
val resp = ApiClient.api.updateChatNotification(UpdateChatNotificationRequestBody(
|
||||
targetUserId = targetUserId,
|
||||
strategy = strategy
|
||||
))
|
||||
if (resp.isSuccessful) {
|
||||
return resp.body()?.data!!
|
||||
}
|
||||
throw Exception("update chat notification failed")
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import com.aiosman.riderpro.data.Comment
|
||||
import com.aiosman.riderpro.data.DataContainer
|
||||
import com.aiosman.riderpro.data.ListContainer
|
||||
import com.aiosman.riderpro.data.Moment
|
||||
import com.aiosman.riderpro.entity.ChatNotification
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.RequestBody
|
||||
@@ -154,31 +155,6 @@ data class GenerateLoginCaptchaRequestBody(
|
||||
@SerializedName("username")
|
||||
val username: String,
|
||||
)
|
||||
//{
|
||||
// "id":48,
|
||||
// "dot": [
|
||||
// {
|
||||
// "index": 0,
|
||||
// "x": 76,
|
||||
// "y": 165
|
||||
// },
|
||||
// {
|
||||
// "index": 1,
|
||||
// "x": 144,
|
||||
// "y": 21
|
||||
// },
|
||||
// {
|
||||
// "index": 2,
|
||||
// "x": 220,
|
||||
// "y": 42
|
||||
// },
|
||||
// {
|
||||
// "index": 3,
|
||||
// "x": 10,
|
||||
// "y": 10
|
||||
// }
|
||||
// ]
|
||||
//}
|
||||
data class DotPosition(
|
||||
@SerializedName("index")
|
||||
val index: Int,
|
||||
@@ -193,6 +169,15 @@ data class CaptchaInfo(
|
||||
@SerializedName("dot")
|
||||
val dot: List<DotPosition>
|
||||
)
|
||||
|
||||
|
||||
data class UpdateChatNotificationRequestBody(
|
||||
@SerializedName("targetUserId")
|
||||
val targetUserId: Int,
|
||||
@SerializedName("strategy")
|
||||
val strategy: String,
|
||||
)
|
||||
|
||||
interface RiderProAPI {
|
||||
@POST("register")
|
||||
suspend fun register(@Body body: RegisterRequestBody): Response<Unit>
|
||||
@@ -417,4 +402,14 @@ interface RiderProAPI {
|
||||
@Body body: GenerateLoginCaptchaRequestBody
|
||||
): Response<DataContainer<CaptchaResponseBody>>
|
||||
|
||||
}
|
||||
@GET("chat/notification")
|
||||
suspend fun getChatNotification(
|
||||
@Query("targetTrtcId") targetTrtcId: String
|
||||
): Response<DataContainer<ChatNotification>>
|
||||
|
||||
@POST("chat/notification")
|
||||
suspend fun updateChatNotification(
|
||||
@Body body: UpdateChatNotificationRequestBody
|
||||
): Response<DataContainer<ChatNotification>>
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.aiosman.riderpro.entity
|
||||
import android.content.Context
|
||||
import android.icu.util.Calendar
|
||||
import com.aiosman.riderpro.exp.formatChatTime
|
||||
import com.google.gson.annotations.SerializedName
|
||||
import com.tencent.imsdk.v2.V2TIMImageElem
|
||||
import com.tencent.imsdk.v2.V2TIMMessage
|
||||
|
||||
@@ -15,11 +16,11 @@ data class ChatItem(
|
||||
val timeCategory: String = "",
|
||||
val timestamp: Long = 0,
|
||||
val imageList: MutableList<V2TIMImageElem.V2TIMImage> = emptyList<V2TIMImageElem.V2TIMImage>().toMutableList(),
|
||||
val messageType : Int = 0,
|
||||
val textDisplay : String = "",
|
||||
val messageType: Int = 0,
|
||||
val textDisplay: String = "",
|
||||
val msgId: String, // Add this property
|
||||
var showTimestamp: Boolean = false,
|
||||
var showTimeDivider:Boolean = false
|
||||
var showTimeDivider: Boolean = false
|
||||
) {
|
||||
companion object {
|
||||
fun convertToChatItem(message: V2TIMMessage, context: Context): ChatItem? {
|
||||
@@ -36,7 +37,7 @@ data class ChatItem(
|
||||
val timestamp = message.timestamp
|
||||
val calendar = Calendar.getInstance()
|
||||
calendar.timeInMillis = timestamp * 1000
|
||||
val imageElm = message.imageElem?.imageList
|
||||
val imageElm = message.imageElem?.imageList
|
||||
when (message.elemType) {
|
||||
V2TIMMessage.V2TIM_ELEM_TYPE_IMAGE -> {
|
||||
val imageElm = message.imageElem?.imageList?.all {
|
||||
@@ -74,8 +75,8 @@ data class ChatItem(
|
||||
textDisplay = message.textElem?.text ?: "Unsupported message type",
|
||||
msgId = message.msgID // Add this line to include msgId
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
else -> {
|
||||
return null
|
||||
}
|
||||
@@ -85,3 +86,16 @@ data class ChatItem(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
data class ChatNotification(
|
||||
@SerializedName("userId")
|
||||
val userId: Int,
|
||||
@SerializedName("userTrtcId")
|
||||
val userTrtcId: String,
|
||||
@SerializedName("targetUserId")
|
||||
val targetUserId: Int,
|
||||
@SerializedName("targetTrtcId")
|
||||
val targetTrtcId: String,
|
||||
@SerializedName("strategy")
|
||||
val strategy: String
|
||||
)
|
||||
@@ -66,12 +66,15 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import com.aiosman.riderpro.LocalNavController
|
||||
import com.aiosman.riderpro.R
|
||||
import com.aiosman.riderpro.entity.ChatItem
|
||||
import com.aiosman.riderpro.exp.formatChatTime
|
||||
import com.aiosman.riderpro.ui.composables.CustomAsyncImage
|
||||
import com.aiosman.riderpro.ui.composables.DropdownMenu
|
||||
import com.aiosman.riderpro.ui.composables.MenuItem
|
||||
import com.aiosman.riderpro.ui.composables.StatusBarSpacer
|
||||
import com.aiosman.riderpro.ui.modifiers.noRippleClickable
|
||||
import com.tencent.imsdk.v2.V2TIMMessage
|
||||
@@ -80,6 +83,7 @@ import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun ChatScreen(userId: String) {
|
||||
var isMenuExpanded by remember { mutableStateOf(false) }
|
||||
val navController = LocalNavController.current
|
||||
val context = LocalNavController.current.context
|
||||
val viewModel = viewModel<ChatViewModel>(
|
||||
@@ -131,7 +135,7 @@ fun ChatScreen(userId: String) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp, horizontal = 16.dp),
|
||||
.padding(vertical = 16.dp, horizontal = 16.dp),
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
verticalAlignment = androidx.compose.ui.Alignment.CenterVertically
|
||||
) {
|
||||
@@ -154,6 +158,41 @@ fun ChatScreen(userId: String) {
|
||||
fontWeight = androidx.compose.ui.text.font.FontWeight.Bold
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Box {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.rider_pro_more_horizon),
|
||||
modifier = Modifier
|
||||
.size(28.dp)
|
||||
.noRippleClickable {
|
||||
isMenuExpanded = true
|
||||
},
|
||||
contentDescription = null
|
||||
)
|
||||
DropdownMenu(
|
||||
expanded = isMenuExpanded,
|
||||
onDismissRequest = {
|
||||
isMenuExpanded = false
|
||||
},
|
||||
menuItems = listOf(
|
||||
MenuItem(
|
||||
title = if (viewModel.notificationStrategy == "mute") "Unmute" else "Mute",
|
||||
icon = if (viewModel.notificationStrategy == "mute") R.drawable.rider_pro_notice_mute else R.drawable.rider_pro_notice_active,
|
||||
){
|
||||
|
||||
isMenuExpanded = false
|
||||
viewModel.viewModelScope.launch {
|
||||
if (viewModel.notificationStrategy == "mute") {
|
||||
viewModel.updateNotificationStrategy("active")
|
||||
} else {
|
||||
viewModel.updateNotificationStrategy("mute")
|
||||
}
|
||||
}
|
||||
}
|
||||
),
|
||||
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.aiosman.riderpro.ui.chat
|
||||
|
||||
import android.content.Context
|
||||
import android.icu.util.Calendar
|
||||
import android.net.Uri
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
@@ -11,16 +10,16 @@ import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.aiosman.riderpro.ChatState
|
||||
import com.aiosman.riderpro.data.AccountService
|
||||
import com.aiosman.riderpro.data.AccountServiceImpl
|
||||
import com.aiosman.riderpro.data.UserService
|
||||
import com.aiosman.riderpro.data.UserServiceImpl
|
||||
import com.aiosman.riderpro.entity.AccountProfileEntity
|
||||
import com.aiosman.riderpro.entity.ChatItem
|
||||
import com.aiosman.riderpro.exp.formatChatTime
|
||||
import com.aiosman.riderpro.entity.ChatNotification
|
||||
import com.tencent.imsdk.v2.V2TIMAdvancedMsgListener
|
||||
import com.tencent.imsdk.v2.V2TIMCallback
|
||||
import com.tencent.imsdk.v2.V2TIMImageElem
|
||||
import com.tencent.imsdk.v2.V2TIMManager
|
||||
import com.tencent.imsdk.v2.V2TIMMessage
|
||||
import com.tencent.imsdk.v2.V2TIMSendCallback
|
||||
@@ -44,6 +43,7 @@ class ChatViewModel(
|
||||
var isLoading by mutableStateOf(false)
|
||||
var lastMessage: V2TIMMessage? = null
|
||||
val showTimestampMap = mutableMapOf<String, Boolean>() // Add this map
|
||||
var chatNotification by mutableStateOf<ChatNotification?>(null)
|
||||
fun init(context: Context) {
|
||||
// 获取用户信息
|
||||
viewModelScope.launch {
|
||||
@@ -53,6 +53,9 @@ class ChatViewModel(
|
||||
|
||||
RegistListener(context)
|
||||
fetchHistoryMessage(context)
|
||||
// 获取通知信息
|
||||
val notiStrategy = ChatState.getStrategyByTargetTrtcId(resp.trtcUserId)
|
||||
chatNotification = notiStrategy
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,4 +246,13 @@ class ChatViewModel(
|
||||
}
|
||||
return list
|
||||
}
|
||||
|
||||
suspend fun updateNotificationStrategy(strategy: String) {
|
||||
userProfile?.let {
|
||||
val result = ChatState.updateChatNotification(it.id, strategy)
|
||||
chatNotification = result
|
||||
}
|
||||
}
|
||||
|
||||
val notificationStrategy get() = chatNotification?.strategy ?: "default"
|
||||
}
|
||||
@@ -73,13 +73,13 @@ object MyProfileViewModel : ViewModel() {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun logout() {
|
||||
suspend fun logout(context: Context) {
|
||||
AppStore.apply {
|
||||
token = null
|
||||
rememberMe = false
|
||||
saveData()
|
||||
}
|
||||
AppState.ReloadAppState()
|
||||
AppState.ReloadAppState(context)
|
||||
}
|
||||
|
||||
fun updateUserProfileBanner(bannerImageUrl: Uri?,file:File, context: Context) {
|
||||
|
||||
@@ -378,62 +378,65 @@ fun ProfileV3(
|
||||
color = Color.Black
|
||||
)
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
) {
|
||||
if (isSelf) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.rider_pro_more_horizon),
|
||||
contentDescription = "",
|
||||
modifier = Modifier.noRippleClickable {
|
||||
minibarExpanded = true
|
||||
},
|
||||
tint = Color.Black
|
||||
)
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = minibarExpanded,
|
||||
onDismissRequest = { minibarExpanded = false },
|
||||
width = 250,
|
||||
menuItems = listOf(
|
||||
MenuItem(
|
||||
stringResource(R.string.logout),
|
||||
R.mipmap.rider_pro_logout
|
||||
) {
|
||||
minibarExpanded = false
|
||||
scope.launch {
|
||||
onLogout()
|
||||
navController.navigate(NavigationRoute.Login.route) {
|
||||
popUpTo(NavigationRoute.Index.route) {
|
||||
inclusive = true
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.rider_pro_more_horizon),
|
||||
contentDescription = "",
|
||||
modifier = Modifier.noRippleClickable {
|
||||
minibarExpanded = true
|
||||
},
|
||||
tint = Color.Black
|
||||
)
|
||||
}
|
||||
DropdownMenu(
|
||||
expanded = minibarExpanded,
|
||||
onDismissRequest = { minibarExpanded = false },
|
||||
width = 250,
|
||||
menuItems = listOf(
|
||||
MenuItem(
|
||||
stringResource(R.string.logout),
|
||||
R.mipmap.rider_pro_logout
|
||||
) {
|
||||
minibarExpanded = false
|
||||
scope.launch {
|
||||
onLogout()
|
||||
navController.navigate(NavigationRoute.Login.route) {
|
||||
popUpTo(NavigationRoute.Index.route) {
|
||||
inclusive = true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
MenuItem(
|
||||
stringResource(R.string.change_password),
|
||||
R.mipmap.rider_pro_change_password
|
||||
) {
|
||||
minibarExpanded = false
|
||||
scope.launch {
|
||||
navController.navigate(NavigationRoute.ChangePasswordScreen.route)
|
||||
}
|
||||
},
|
||||
MenuItem(
|
||||
stringResource(R.string.favourites),
|
||||
R.drawable.rider_pro_favourite
|
||||
) {
|
||||
minibarExpanded = false
|
||||
scope.launch {
|
||||
navController.navigate(NavigationRoute.FavouriteList.route)
|
||||
}
|
||||
}
|
||||
},
|
||||
MenuItem(
|
||||
stringResource(R.string.change_password),
|
||||
R.mipmap.rider_pro_change_password
|
||||
) {
|
||||
minibarExpanded = false
|
||||
scope.launch {
|
||||
navController.navigate(NavigationRoute.ChangePasswordScreen.route)
|
||||
}
|
||||
},
|
||||
MenuItem(
|
||||
stringResource(R.string.favourites),
|
||||
R.drawable.rider_pro_favourite
|
||||
) {
|
||||
minibarExpanded = false
|
||||
scope.launch {
|
||||
navController.navigate(NavigationRoute.FavouriteList.route)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.aiosman.riderpro.ui.index.tabs.profile
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@@ -9,29 +10,17 @@ import kotlinx.coroutines.launch
|
||||
fun ProfileWrap(
|
||||
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
LaunchedEffect(Unit) {
|
||||
MyProfileViewModel.loadProfile()
|
||||
}
|
||||
// ProfileV2(
|
||||
// onUpdateBanner = { uri, context ->
|
||||
// MyProfileViewModel.updateUserProfileBanner(uri, context)
|
||||
// },
|
||||
// onLogout = {
|
||||
// MyProfileViewModel.viewModelScope.launch {
|
||||
// MyProfileViewModel.logout()
|
||||
// }
|
||||
//
|
||||
// },
|
||||
// profile = MyProfileViewModel.profile,
|
||||
// sharedFlow = MyProfileViewModel.sharedFlow
|
||||
// )
|
||||
ProfileV3(
|
||||
onUpdateBanner = { uri, file, context ->
|
||||
MyProfileViewModel.updateUserProfileBanner(uri, file, context)
|
||||
},
|
||||
onLogout = {
|
||||
MyProfileViewModel.viewModelScope.launch {
|
||||
MyProfileViewModel.logout()
|
||||
MyProfileViewModel.logout(context)
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
5
app/src/main/res/drawable/rider_pro_notice_active.xml
Normal file
5
app/src/main/res/drawable/rider_pro_notice_active.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:alpha="0.77" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zM18,16v-5c0,-3.07 -1.63,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.64,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2zM16,17L8,17v-6c0,-2.48 1.51,-4.5 4,-4.5s4,2.02 4,4.5v6z"/>
|
||||
|
||||
</vector>
|
||||
5
app/src/main/res/drawable/rider_pro_notice_mute.xml
Normal file
5
app/src/main/res/drawable/rider_pro_notice_mute.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:alpha="0.77" android:height="24dp" android:tint="#FFFFFF" android:viewportHeight="24" android:viewportWidth="24" android:width="24dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.9,2 2,2zM12,6.5c2.49,0 4,2.02 4,4.5v0.1l2,2L18,11c0,-3.07 -1.63,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68c-0.24,0.06 -0.47,0.15 -0.69,0.23l1.64,1.64c0.18,-0.02 0.36,-0.05 0.55,-0.05zM5.41,3.35L4,4.76l2.81,2.81C6.29,8.57 6,9.74 6,11v5l-2,2v1h14.24l1.74,1.74 1.41,-1.41L5.41,3.35zM16,17L8,17v-6c0,-0.68 0.12,-1.32 0.34,-1.9L16,16.76L16,17z"/>
|
||||
|
||||
</vector>
|
||||
Reference in New Issue
Block a user