增加消息未读提示气泡

This commit is contained in:
squallzhjch 2023-01-06 13:46:55 +08:00
parent de0a2fe5fc
commit e569ab4a82
18 changed files with 210 additions and 66 deletions

View File

@ -5,7 +5,4 @@ import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
open class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
}
}

View File

@ -1,27 +1,42 @@
package com.navinfo.volvo.database.dao
import androidx.paging.PagingSource
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.*
import com.navinfo.volvo.database.entity.GreetingMessage
import kotlinx.coroutines.flow.Flow
@Dao
interface GreetingMessageDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg check: GreetingMessage)
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(list: List<GreetingMessage>)
@Insert
fun insert(message: GreetingMessage): Long
@Query("SELECT * FROM GreetingMessage where id =:id")
fun findCheckManagerById(id: Long): GreetingMessage?
@Update(onConflict = OnConflictStrategy.REPLACE)
fun update(message: GreetingMessage)
@Query("SELECT * FROM GreetingMessage")
fun findAllByFlow(): Flow<List<GreetingMessage>>
@Query("SELECT count(id) FROM GreetingMessage WHERE read = 0")
fun countUnreadByFlow(): Flow<Long>
/**
* 分页查询
*/
@Query("SELECT * FROM GreetingMessage")
fun findAllByDataSource(): PagingSource<Int, GreetingMessage>
/**
* 检查某条数据是否存在
*/
@Query("SELECT id From GreetingMessage WHERE id = :id LIMIT 1")
fun getMessageId(id: Long): Long
@Transaction
suspend fun insertOrUpdate(list: List<GreetingMessage>) {
for (message in list) {
val id = getMessageId(message.id)
if (id == 0L) {
insert(message)
}
}
}
}

View File

@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull
@TypeConverters(AttachmentConverters::class)
data class GreetingMessage @JvmOverloads constructor(
@PrimaryKey(autoGenerate = true)
var uuid:Long = 0,
var uuid: Long = 0,
var id: Long = 0,
var searchValue: String? = "",
var createBy: String? = "",
@ -41,5 +41,6 @@ data class GreetingMessage @JvmOverloads constructor(
/**
* 附件列表
*/
var attachment: MutableList<Attachment> = mutableListOf()
var attachment: MutableList<Attachment> = mutableListOf(),
var read: Boolean = false,
)

View File

@ -3,6 +3,7 @@ package com.navinfo.volvo.di.module
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.navinfo.volvo.di.key.ViewModelKey
import com.navinfo.volvo.ui.MainActivityViewModel
import com.navinfo.volvo.ui.fragments.home.HomeViewModel
import com.navinfo.volvo.ui.fragments.login.LoginViewModel
import com.navinfo.volvo.ui.fragments.message.ObtainMessageViewModel
@ -19,6 +20,11 @@ abstract class ViewModelModule {
@Binds
abstract fun bindViewModelFactory(viewModelFactory: ViewModelFactory): ViewModelProvider.Factory
@IntoMap
@Binds
@ViewModelKey(MainActivityViewModel::class)
abstract fun bindMainViewModel(viewModel: MainActivityViewModel): ViewModel
@IntoMap
@Binds
@ViewModelKey(LoginViewModel::class)
@ -33,4 +39,6 @@ abstract class ViewModelModule {
@Binds
@ViewModelKey(ObtainMessageViewModel::class)
abstract fun bindObtainMessageFragmentViewModel(viewModel: ObtainMessageViewModel): ViewModel
}

View File

@ -3,13 +3,15 @@ package com.navinfo.volvo.repository.database
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.navinfo.volvo.database.AppDatabase
import com.navinfo.volvo.database.dao.GreetingMessageDao
import com.navinfo.volvo.database.entity.GreetingMessage
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
class DatabaseRepositoryImp @Inject constructor(
private val messageDao: GreetingMessageDao
private val messageDao: GreetingMessageDao,
private val database: AppDatabase
) : DatabaseRepository {
companion object {
const val PAGE_SIZE = 20
@ -20,4 +22,5 @@ class DatabaseRepositoryImp @Inject constructor(
messageDao.findAllByDataSource()
}.flow
}
}

View File

@ -28,7 +28,9 @@ class NetworkRepositoryImp @Inject constructor(
val result = netWorkService.queryCardListByApp(stringBody)
if (result.isSuccessful) {
val body = result.body()
messageDao.insert(body!!.data!!.rows)
if(body!!.data != null && body.data!!.rows != null){
messageDao.insertOrUpdate(body.data!!.rows)
}
NetResult.Success(body)
} else {
NetResult.Success(null)

View File

@ -0,0 +1,11 @@
package com.navinfo.volvo.ui
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider
import javax.inject.Inject
abstract class BaseActivity : AppCompatActivity() {
@Inject
lateinit var viewModelFactoryProvider: ViewModelProvider.Factory
}

View File

@ -4,7 +4,11 @@ import android.content.DialogInterface
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.viewModelScope
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
@ -30,18 +34,23 @@ import com.navinfo.volvo.R
import com.navinfo.volvo.databinding.ActivityMainBinding
import com.navinfo.volvo.utils.SystemConstant
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
class MainActivity : BaseActivity() {
private lateinit var binding: ActivityMainBinding
private val viewModel by viewModels<MainActivityViewModel> { viewModelFactoryProvider }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setupNavigation()
XXPermissions.with(this)
// 申请单个权限
@ -61,6 +70,7 @@ class MainActivity : AppCompatActivity() {
}
// 在SD卡创建项目目录
createRootFolder()
setupNavigation()
}
override fun onDenied(permissions: MutableList<String>, never: Boolean) {
@ -89,6 +99,20 @@ class MainActivity : AppCompatActivity() {
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
lifecycleScope.launch{
viewModel.getUnreadCount().collect {
runOnUiThread{
if(it == 0L){
navView.removeBadge(R.id.navigation_home)
}else{
var badge = navView.getOrCreateBadge(R.id.navigation_home);
badge.number = it.toInt()
}
}
}
}
navController.addOnDestinationChangedListener { controller, destination, arguments ->
if (destination.id == R.id.navigation_home
|| destination.id == R.id.navigation_dashboard

View File

@ -0,0 +1,17 @@
package com.navinfo.volvo.ui
import androidx.lifecycle.ViewModel
import androidx.paging.PagingData
import com.navinfo.volvo.database.dao.GreetingMessageDao
import com.navinfo.volvo.database.entity.GreetingMessage
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
class MainActivityViewModel @Inject constructor(
private val messageDao: GreetingMessageDao,
) : ViewModel() {
fun getUnreadCount(): Flow<Long> = messageDao.countUnreadByFlow()
}

View File

@ -1,4 +1,4 @@
package com.navinfo.volvo.ui
package com.navinfo.volvo.ui.fragments
import androidx.fragment.app.Fragment
import androidx.lifecycle.ViewModelProvider

View File

@ -12,7 +12,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.navinfo.volvo.R
import com.navinfo.volvo.databinding.FragmentHomeBinding
import com.navinfo.volvo.tools.DisplayUtil
import com.navinfo.volvo.ui.BaseFragment
import com.navinfo.volvo.ui.fragments.BaseFragment
import com.yanzhenjie.recyclerview.*
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
@ -21,27 +21,30 @@ import kotlinx.coroutines.launch
@AndroidEntryPoint
class HomeFragment : BaseFragment(), OnItemClickListener, OnItemMenuClickListener {
private var _binding: FragmentHomeBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
private val viewModel by viewModels<HomeViewModel> { viewModelFactoryProvider }
private lateinit var messageAdapter: HomeAdapter
private lateinit var mDataBinding: FragmentHomeBinding
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
mDataBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
mDataBinding.lifecycleOwner = this
_binding = FragmentHomeBinding.inflate(inflater, container, false)
val root: View = binding.root
initView()
return mDataBinding.root
return root
}
private fun initView() {
mDataBinding.homeViewModel = viewModel
// mDataBinding.homeViewModel = viewModel
messageAdapter = HomeAdapter(this)
val recyclerview: SwipeRecyclerView = mDataBinding.homeRecyclerview
val recyclerview: SwipeRecyclerView = binding.homeRecyclerview
recyclerview.adapter = null //先设置null否则会报错
//创建菜单选项
//注意:使用滑动菜单不能开启滑动删除,否则只有滑动删除没有滑动菜单
@ -96,6 +99,7 @@ class HomeFragment : BaseFragment(), OnItemClickListener, OnItemMenuClickListene
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
override fun onItemClick(view: View?, adapterPosition: Int) {

View File

@ -4,14 +4,11 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.Navigation
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import com.navinfo.volvo.R
import com.navinfo.volvo.databinding.FragmentLoginBinding
import com.navinfo.volvo.ui.BaseFragment
import com.navinfo.volvo.ui.fragments.BaseFragment
import dagger.hilt.android.AndroidEntryPoint

View File

@ -13,9 +13,10 @@ import okhttp3.MultipartBody
import okhttp3.RequestBody
import java.io.File
import java.util.*
import javax.inject.Inject
class ObtainMessageViewModel: ViewModel() {
class ObtainMessageViewModel @Inject constructor() : ViewModel() {
private val msgLiveData: MutableLiveData<GreetingMessage> by lazy {
MutableLiveData<GreetingMessage>()
}
@ -40,7 +41,7 @@ class ObtainMessageViewModel: ViewModel() {
for (attachment in this.msgLiveData.value!!.attachment) {
if (attachment.attachmentType == AttachmentType.PIC) {
if (picUrl==null||picUrl.isEmpty()) {
if (picUrl == null || picUrl.isEmpty()) {
this.msgLiveData.value!!.attachment.remove(attachment)
} else {
attachment.pathUrl = picUrl
@ -48,8 +49,14 @@ class ObtainMessageViewModel: ViewModel() {
hasPic = true
}
}
if (!hasPic&&picUrl!=null) {
this.msgLiveData.value!!.attachment.add(Attachment(UUID.randomUUID().toString(), picUrl, AttachmentType.PIC))
if (!hasPic && picUrl != null) {
this.msgLiveData.value!!.attachment.add(
Attachment(
UUID.randomUUID().toString(),
picUrl,
AttachmentType.PIC
)
)
}
this.msgLiveData.postValue(this.msgLiveData.value)
}
@ -59,7 +66,7 @@ class ObtainMessageViewModel: ViewModel() {
var hasAudio = false
for (attachment in this.msgLiveData.value!!.attachment) {
if (attachment.attachmentType == AttachmentType.AUDIO) {
if (audioUrl==null||audioUrl.isEmpty()) {
if (audioUrl == null || audioUrl.isEmpty()) {
this.msgLiveData.value!!.attachment.remove(attachment)
} else {
attachment.pathUrl = audioUrl
@ -67,8 +74,14 @@ class ObtainMessageViewModel: ViewModel() {
hasAudio = true
}
}
if (!hasAudio&&audioUrl!=null) {
this.msgLiveData.value!!.attachment.add(Attachment(UUID.randomUUID().toString(), audioUrl, AttachmentType.AUDIO))
if (!hasAudio && audioUrl != null) {
this.msgLiveData.value!!.attachment.add(
Attachment(
UUID.randomUUID().toString(),
audioUrl,
AttachmentType.AUDIO
)
)
}
this.msgLiveData.postValue(this.msgLiveData.value)
}
@ -97,7 +110,11 @@ class ObtainMessageViewModel: ViewModel() {
try {
val requestFile: RequestBody =
RequestBody.create("multipart/form-data".toMediaTypeOrNull(), attachmentFile)
val body = MultipartBody.Part.createFormData("picture", attachmentFile.getName(), requestFile)
val body = MultipartBody.Part.createFormData(
"picture",
attachmentFile.getName(),
requestFile
)
val result = NavinfoVolvoCall.getApi().uploadAttachment(body)
XLog.d(result.code)
if (result.code == 200) { // 请求成功

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
android:useLevel="false">
<solid android:color="#FF0000"/>
<size android:width="12dp"
android:height="12dp"/>
</shape>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<layout xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
@ -15,6 +16,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/message_head_icon"
android:layout_width="60dp"
@ -25,33 +27,50 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/message_badge"
android:layout_width="12dp"
android:layout_height="12dp"
android:background="@drawable/shape_circular"
android:gravity="center"
android:textColor="#000000"
app:layout_constraintCircle="@id/message_head_icon"
app:layout_constraintCircleAngle="45"
app:layout_constraintCircleRadius="40dp"
tools:ignore="MissingConstraints" />
<TextView
android:id="@+id/message_to_who"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:ellipsize="end"
android:maxLines="1"
android:text="@{greetingMessage.toWho,default=发送对象的名字很长还很长的}"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintLeft_toRightOf="@id/message_head_icon"
app:layout_constraintTop_toTopOf="@id/message_head_icon"
android:text="@{greetingMessage.toWho,default=发送对象}" />
app:layout_constraintRight_toLeftOf="@id/message_send_time"
app:layout_constraintTop_toTopOf="@id/message_head_icon" />
<TextView
android:id="@+id/message_text"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@{greetingMessage.name,default=消息内容}"
android:ellipsize="end"
android:maxLines="1"
android:text="@{greetingMessage.name,default=消息内容我的消息也很长0121231313123131313}"
app:layout_constraintBottom_toBottomOf="@id/message_head_icon"
app:layout_constraintLeft_toRightOf="@id/message_head_icon" />
app:layout_constraintLeft_toRightOf="@id/message_head_icon"
app:layout_constraintRight_toLeftOf="@id/message_status" />
<TextView
android:id="@+id/message_send_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:text="@{greetingMessage.sendDate,default=发送时间}"
android:text="@{greetingMessage.sendDate,default=l023x01x03x14x34x34}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/message_head_icon" />
@ -60,7 +79,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@{greetingMessage.status,default=消息状态}"
android:text="@{greetingMessage.status,default=消息状态很长的文字}"
app:layout_constraintBottom_toBottomOf="@id/message_head_icon"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,20 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.fragments.home.HomeFragment">
<data>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/home_search"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="5dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<import type="android.view.View" />
<variable
name="HomeViewModel"
type="com.navinfo.volvo.ui.fragments.home.HomeViewModel" />
</data>
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入查询内容" />
</com.google.android.material.textfield.TextInputLayout>
<com.yanzhenjie.recyclerview.SwipeRecyclerView
android:background="@color/gray1"
android:id="@+id/home_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.fragments.home.HomeFragment" />
</layout>
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="10dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/home_search" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,6 +1,6 @@
<resources>
<string name="app_name">NavinfoVolvo</string>
<string name="title_home">Home</string>
<string name="title_home">问候</string>
<string name="title_dashboard">Dashboard</string>
<string name="title_notifications">Notifications</string>
<string name="delete">删除</string>

View File

@ -1,6 +1,6 @@
<resources>
<string name="app_name">NavinfoVolvo</string>
<string name="title_home">Home</string>
<string name="title_home">Message</string>
<string name="title_dashboard">Dashboard</string>
<string name="title_notifications">Notifications</string>
<string name="delete">Del</string>