消息列表

This commit is contained in:
2026-05-27 17:44:37 +08:00
parent 97a0cdc14f
commit c5043e4b94
20 changed files with 783 additions and 82 deletions

View File

@@ -1,6 +1,6 @@
package com.example.defenseapplication.bean
data class MessageItem(
data class MessageBean(
val id: String,
val userId: String,
val deviceId: String,
@@ -10,9 +10,4 @@ data class MessageItem(
val imageUrl: String?,
val video: String?,
val createTime: String
)
data class MessageGroup(
val time: String,
val list: List<MessageItem>
)

View File

@@ -0,0 +1,6 @@
package com.example.defenseapplication.bean
data class MessageListResponse(
val total: Int,
val rows: List<MessageBean>
)

View File

@@ -267,17 +267,7 @@ class HomeMenuFragment : Fragment() {
try {
val response = RetrofitNetwork.getNetworkService().getMessage()
withContext(Dispatchers.Main) {
if (response.code == 200 && response.data != null) {
val messageGroups = response.data as List<*>
var unreadCount = 0
messageGroups.forEach { group ->
if (group is Map<*, *>) {
val list = group["list"] as? List<*>
list?.let { unreadCount += it.size }
}
}
MessageStatusManager.setUnreadCount(unreadCount)
}
}
} catch (e: Exception) {
e.printStackTrace()

View File

@@ -2,15 +2,11 @@ package com.example.defenseapplication.home
import android.os.Bundle
import android.view.View
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.defenseapplication.adapter.MessageListAdapter
import com.example.defenseapplication.adapter.MessageListItem
import com.example.defenseapplication.bean.MessageGroup
import com.example.defenseapplication.bean.MessageItem
import com.example.defenseapplication.databinding.MessageActivityBinding
import com.example.defenseapplication.utils.MessageStatusManager
import com.example.defenseapplication.utils.RetrofitNetwork
@@ -23,6 +19,13 @@ import kotlinx.coroutines.withContext
class MessageActivity : AppCompatActivity() {
private lateinit var binding: MessageActivityBinding
private val messageAdapter by lazy { MessageListAdapter() }
private var currentPage = 1
private val pageSize = 10
private var isLoading = false
private var hasMoreData = true
private val allMessages = mutableListOf<com.example.defenseapplication.bean.MessageBean>()
private var lastLoadedCount = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -41,53 +44,132 @@ class MessageActivity : AppCompatActivity() {
binding.ivBack.setOnClickListener { finish() }
binding.rvMessageList.layoutManager = LinearLayoutManager(this)
binding.rvMessageList.adapter = messageAdapter
binding.rvMessageList.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val layoutManager = recyclerView.layoutManager as LinearLayoutManager
val totalItemCount = layoutManager.itemCount
val lastVisibleItem = layoutManager.findLastVisibleItemPosition()
if (!isLoading && hasMoreData && lastVisibleItem >= totalItemCount - 3 && dy > 0) {
loadMoreData()
}
}
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
if (newState == RecyclerView.SCROLL_STATE_IDLE && !hasMoreData && !isLoading) {
showNoMoreDataHint()
}
}
})
}
private fun loadMessageList() {
if (isLoading) return
isLoading = true
CoroutineScope(Dispatchers.IO).launch {
try {
val response = RetrofitNetwork.getNetworkService().getMessage()
if (response.code == 0 && response.data != null) {
val messageGroups = response.data as List<MessageGroup>
val items = convertToMessageListItems(messageGroups)
withContext(Dispatchers.Main) {
if (items.isEmpty()) {
val messageResponse = RetrofitNetwork.getNetworkService().getMessage(
pageNum = currentPage,
pageSize = pageSize
)
println("total: ${messageResponse.total}")
println("rows size: ${messageResponse.rows.size}")
println("当前页:$currentPage, 加载条数:${messageResponse.rows.size}")
val newMessages = messageResponse.rows
val loadedCount = newMessages.size
if (loadedCount < pageSize) {
hasMoreData = false
}
if (newMessages.isEmpty()) {
if (currentPage == 1) {
withContext(Dispatchers.Main) {
showEmptyState()
} else {
hideEmptyState()
messageAdapter.submitList(items)
}
}
} else {
if (currentPage == 1) {
allMessages.clear()
}
allMessages.addAll(newMessages)
lastLoadedCount = loadedCount
val items = convertToMessageListItems(allMessages)
withContext(Dispatchers.Main) {
hideEmptyState()
messageAdapter.submitList(items)
if (!hasMoreData) {
showNoMoreDataHint()
} else {
hideNoMoreDataHint()
}
}
}
withContext(Dispatchers.Main) {
if (allMessages.isEmpty()) {
println("items is empty, showing empty state")
showEmptyState()
}
}
} catch (e: Exception) {
println("Exception: ${e.message}")
e.printStackTrace()
withContext(Dispatchers.Main) {
showEmptyState()
if (allMessages.isEmpty()) {
showEmptyState()
}
}
} finally {
isLoading = false
}
}
}
private fun loadMoreData() {
if (!hasMoreData || isLoading) return
currentPage++
loadMessageList()
}
private fun showEmptyState() {
binding.contentLayout.visibility = View.GONE
binding.rvMessageList.visibility = View.GONE
binding.emptyLayout.visibility = View.VISIBLE
binding.tvNoMoreData.visibility = View.GONE
}
private fun hideEmptyState() {
binding.contentLayout.visibility = View.VISIBLE
binding.rvMessageList.visibility = View.VISIBLE
binding.emptyLayout.visibility = View.GONE
}
private fun showNoMoreDataHint() {
binding.tvNoMoreData.visibility = View.VISIBLE
}
private fun hideNoMoreDataHint() {
binding.tvNoMoreData.visibility = View.GONE
}
private fun convertToMessageListItems(groups: List<MessageGroup>): List<MessageListItem> {
private fun convertToMessageListItems(messages: List<com.example.defenseapplication.bean.MessageBean>): List<MessageListItem> {
val items = mutableListOf<MessageListItem>()
groups.forEach { group ->
val headerTitle = formatDate(group.time)
val groupedMessages = messages.groupBy { extractDate(it.createTime) }
groupedMessages.forEach { (date, messageList) ->
val headerTitle = formatDate(date)
messageList.forEachIndexed { index, message ->
println(" 消息${index + 1}: id=${message.id}, categoryName=${message.categoryName}, createTime=${message.createTime}")
}
items.add(MessageListItem.Header(headerTitle))
group.list.forEach { message ->
messageList.forEach { message ->
items.add(
MessageListItem.Message(
time = extractTime(message.createTime),
@@ -101,9 +183,24 @@ class MessageActivity : AppCompatActivity() {
return items
}
private fun extractDate(dateTime: String): String {
return if (dateTime.contains(" ")) {
dateTime.split(" ")[0]
} else {
dateTime
}
}
private fun formatDate(dateStr: String): String {
return if (dateStr == "今天" || dateStr.contains("今天")) {
"今天"
} else if (dateStr.contains("-")) {
val parts = dateStr.split("-")
if (parts.size >= 3) {
"${parts[1]}-${parts[2]}"
} else {
dateStr
}
} else {
dateStr
}

View File

@@ -6,7 +6,6 @@ import android.content.pm.PackageManager
import android.media.MediaRecorder
import android.os.Bundle
import android.util.Log
import android.view.View
import android.view.animation.ScaleAnimation
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
@@ -23,6 +22,10 @@ import android.content.res.Configuration
import androidx.activity.OnBackPressedCallback
import chuangyuan.ycj.videolibrary.listener.VideoInfoListener
import chuangyuan.ycj.videolibrary.video.VideoPlayerManager
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
private const val TAG = "LiveVideoActivity"
//智能防御机A1
@@ -35,6 +38,8 @@ class LiveVideoActivity : BaseActivity() {
private var isRecording = false
private var mediaRecorder: MediaRecorder? = null
private var micPulseAnimation: ScaleAnimation? = null
private var isFullscreen = false
private var fullscreenBackButton: ImageView? = null
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
@@ -112,6 +117,78 @@ class LiveVideoActivity : BaseActivity() {
.create()
exoPlayerManager.startPlayer()
setupFullscreenListener()
}
private fun setupFullscreenListener() {
binding.exoPlayContextId.setOnClickListener {
if (!isFullscreen) {
enterFullscreen()
}
}
}
private fun enterFullscreen() {
isFullscreen = true
binding.topBar.visibility = View.GONE
binding.functionBar.visibility = View.GONE
val params = binding.exoPlayContextId.layoutParams
params.width = LinearLayout.LayoutParams.MATCH_PARENT
params.height = LinearLayout.LayoutParams.MATCH_PARENT
binding.exoPlayContextId.layoutParams = params
exoPlayerManager.onConfigurationChanged(Configuration().apply {
orientation = Configuration.ORIENTATION_LANDSCAPE
})
showFullscreenBackButton()
}
private fun exitFullscreen() {
isFullscreen = false
binding.topBar.visibility = View.VISIBLE
binding.functionBar.visibility = View.VISIBLE
val params = binding.exoPlayContextId.layoutParams
params.width = LinearLayout.LayoutParams.MATCH_PARENT
params.height = 250
binding.exoPlayContextId.layoutParams = params
exoPlayerManager.onConfigurationChanged(Configuration().apply {
orientation = Configuration.ORIENTATION_PORTRAIT
})
hideFullscreenBackButton()
}
private fun showFullscreenBackButton() {
fullscreenBackButton = ImageView(this).apply {
setImageResource(R.drawable.back_white)
scaleType = ImageView.ScaleType.CENTER_CROP
val params = LinearLayout.LayoutParams(60, 60)
params.topMargin = 60
params.leftMargin = 20
layoutParams = params
setOnClickListener {
exitFullscreen()
}
}
(binding.root as ViewGroup).addView(fullscreenBackButton)
fullscreenBackButton?.bringToFront()
}
private fun hideFullscreenBackButton() {
fullscreenBackButton?.let {
(binding.root as ViewGroup).removeView(it)
fullscreenBackButton = null
}
}
private fun initListener() {

View File

@@ -13,7 +13,8 @@ import com.example.defenseapplication.bean.AddDeviceUserRequest
import com.example.defenseapplication.bean.DeleteBean
import com.example.defenseapplication.bean.DeleteDeviceUserRequest
import com.example.defenseapplication.bean.FamilyMembersBean
import com.example.defenseapplication.bean.MessageGroup
import com.example.defenseapplication.bean.MessageBean
import com.example.defenseapplication.bean.MessageListResponse
import com.example.defenseapplication.bean.ObtainInviterInformationBean
import com.example.defenseapplication.bean.ObtainInviterInformationRequest
import com.example.defenseapplication.bean.SwitchFamilyRequest
@@ -75,7 +76,10 @@ interface ApiService {
* 查看消息列表
*/
@GET("/app/appMessage/list")
suspend fun getMessage(): GetCodeBean<List<MessageGroup>>
suspend fun getMessage(
@Query("pageNum") pageNum: Int = 1,
@Query("pageSize") pageSize: Int = 10
): MessageListResponse
/**
@@ -216,6 +220,13 @@ interface ApiService {
@POST("/app/upload")
suspend fun uploadFile(@retrofit2.http.Part file: MultipartBody.Part): UploadResponse
/**
* 查看告警消息
*/
//@GET("/app/appMessageInfo/{id}")
//suspend fun getMessageInfo(@retrofit2.http.Path("id") id: String): GetCodeBean<MessageBean>
/**
* 修改家庭用户状态
*/