修改datastore的数据获取,

修改上拉加载
This commit is contained in:
squallzhjch 2023-01-11 09:32:39 +08:00
parent 7b5b4b08e5
commit b5ad8b596e
33 changed files with 411 additions and 350 deletions

View File

@ -6,6 +6,7 @@ plugins {
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin' //hilt
id "com.google.protobuf" version "0.8.17" //Proto DataStore
id 'androidx.navigation.safeargs.kotlin'//Safe Args传递数据
// id 'com.google.dagger.hilt.android'
}
@ -59,6 +60,7 @@ android {
}
dependencies {
def nav_version = "2.5.3"
implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0'
@ -70,12 +72,12 @@ dependencies {
//
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
implementation "androidx.lifecycle:lifecycle-common-java8:2.4.1"
//
implementation 'androidx.navigation:navigation-fragment-ktx:2.4.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.4.1'
// // Kotlin
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
@ -113,7 +115,6 @@ dependencies {
// Retrofit
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
implementation("com.squareup.okhttp3:okhttp:4.9.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.9.0")
implementation("com.google.code.gson:gson:2.8.6")

View File

@ -1,16 +1,18 @@
package com.navinfo.volvo
import java.lang.Boolean
class Constant {
companion object{
companion object {
/**
* 服务器地址
*/
const val SERVER_ADDRESS = "http://ec2-52-81-73-5.cn-north-1.compute.amazonaws.com.cn:8088/"
val DEBUG = Boolean.parseBoolean("true")
const val DEBUG = true
const val message_status_late = "预约,待发送"
const val message_status_send_over = "已发送"
const val message_version_right_off = "1" //立即发送
const val MESSAGE_PAGE_SIZE = 30 //消息列表一页最多数量
}
}

View File

@ -14,7 +14,7 @@ open class MyApplication : Application() {
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
activity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
override fun onActivityStarted(activity: Activity) {

View File

@ -5,6 +5,7 @@ import androidx.paging.PagingSource
import androidx.room.*
import com.navinfo.volvo.Constant
import com.navinfo.volvo.database.entity.GreetingMessage
import com.navinfo.volvo.database.entity.GreetingMessageKtx
import kotlinx.coroutines.flow.Flow
@Dao
@ -34,8 +35,8 @@ interface GreetingMessageDao {
/**
* 检查某条数据是否存在
*/
@Query("SELECT uuid From GreetingMessage WHERE id = :id LIMIT 1")
suspend fun getMessageId(id: Long): Long?
@Query("SELECT uuid,id,status From GreetingMessage WHERE id = :id LIMIT 1")
suspend fun getMessageId(id: Long): GreetingMessageKtx?
/**
*
@ -43,16 +44,17 @@ interface GreetingMessageDao {
@Transaction
suspend fun insertOrUpdate(list: List<GreetingMessage>) {
for (message in list) {
Log.e("jingo", "insertOrUpdate ${message.id}")
val uuid = getMessageId(message.id)
Log.e("jingo", "insertOrUpdate $uuid")
if (uuid == null || uuid == 0L) {
Log.e("jingo", "insertOrUpdate start ")
val l = insert(message)
Log.e("jingo", "insertOrUpdate $l ")
val locMessage = getMessageId(message.id)
if (message.version == Constant.message_version_right_off && message.status == Constant.message_status_late)
message.status = Constant.message_status_send_over
if (locMessage == null) {
Log.e("jingo", "插入数据 id=${message.id} ")
insert(message)
} else {
message.uuid = uuid
update(message)
if (locMessage.status != message.status) {
message.uuid = locMessage.uuid
update(message)
}
}
Log.e("jingo", "insertOrUpdate end")
}

View File

@ -1,15 +1,21 @@
package com.navinfo.volvo.database.entity
import android.os.Parcelable
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.TypeConverters
import com.navinfo.volvo.Constant
import kotlinx.parcelize.Parcelize
@Entity(tableName = "GreetingMessage")
@TypeConverters(AttachmentConverters::class)
@Parcelize
data class GreetingMessage @JvmOverloads constructor(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "uuid")
var uuid: Long = 0,
@ColumnInfo(name = "id")
var id: Long = 0,
var searchValue: String? = "",
var createBy: String? = "",
@ -23,6 +29,7 @@ data class GreetingMessage @JvmOverloads constructor(
var who: String? = "",
var toWho: String? = "",
var sendDate: String? = "",
@ColumnInfo(name = "status")
var status: String? = "",
var isSkip: String? = "",
var skipUrl: String? = "",
@ -35,10 +42,11 @@ data class GreetingMessage @JvmOverloads constructor(
var sendVins: String? = "",
var sendType: String? = "",
var del: String? = "",
var version: String? = "1",
@ColumnInfo(name = "version")
var version: String? = Constant.message_version_right_off,
// /**
// * 附件列表
// */
// var attachment: MutableList<Attachment> = mutableListOf(),
var read: Boolean = false,
)
) : Parcelable

View File

@ -0,0 +1,15 @@
package com.navinfo.volvo.database.entity
import androidx.room.ColumnInfo
/**
* 用来用较少的字段查询数是否存在
*/
data class GreetingMessageKtx(
@ColumnInfo(name = "uuid")
var uuid: Long = 0,
@ColumnInfo(name = "id")
var id: Long = 0,
@ColumnInfo(name = "status")
var status: String? = "",
)

View File

@ -53,7 +53,7 @@ class NetworkUtilModule {
fun provideRetrofit(
client: Lazy<OkHttpClient>,
converterFactory: GsonConverterFactory,
context: Context
// context: Context
): Retrofit {
val retrofitBuilder = Retrofit.Builder()
.baseUrl(Constant.SERVER_ADDRESS)

View File

@ -14,8 +14,6 @@ interface NavinfoVolvoService {
suspend fun updateCardByApp(@Body updateData: Map<String, String>):DefaultResponse<String>
@POST("/navi/cardDelivery/queryCardListByApp")
fun queryCardListByApp(@Body queryData: MutableMap<String, String>)
@POST("/navi/cardDelivery/deleteCardByApp")
fun deleteCardByApp(@Body deleteData: MutableMap<String, String>)
@POST("/img/upload")
@Multipart
suspend fun uploadAttachment(@Part attachmentFile: MultipartBody.Part):DefaultResponse<MutableMap<String, String>>

View File

@ -1,18 +1,16 @@
package com.navinfo.volvo.model.network
data class NetworkMessageListPost(
val name: String,//问候名称,非必填项
val who: String, //我是谁
val toWho: String, //发送给谁
val startTime: String, //2023-01-02 15:49:50", //创建开始时间 非必填项 暂不支持按时间查询
val endTime: String,//" 2023-01-03 15:52:50", //创建结束时间 非必填项 暂不支持按时间查询
val pageSize: String, //查询数量
val pageNum: String, //分页查询
) {
constructor(who: String, toWho: String) : this("", who, toWho, "", "", "10", "1") {
import com.navinfo.volvo.Constant.Companion.MESSAGE_PAGE_SIZE
}
}
data class NetworkMessageListPost @JvmOverloads constructor(
var name: String = "",//问候名称,非必填项
var who: String, //我是谁
var toWho: String = "", //发送给谁
var startTime: String = "", //2023-01-02 15:49:50", //创建开始时间 非必填项 暂不支持按时间查询
var endTime: String = "",//" 2023-01-03 15:52:50", //创建结束时间 非必填项 暂不支持按时间查询
var pageSize: String = "$MESSAGE_PAGE_SIZE", //查询数量
var pageNum: String = "1", //分页查询
)
data class NetworkDeleteMessagePost(
val id: Long

View File

@ -12,15 +12,12 @@ import javax.inject.Inject
class DatabaseRepositoryImp @Inject constructor(
private val messageDao: GreetingMessageDao,
) : DatabaseRepository {
companion object {
const val PAGE_SIZE = 20
}
/**
* 分页加载消息
*/
override fun getMessageByPaging(): Flow<PagingData<GreetingMessage>> {
return Pager(PagingConfig(PAGE_SIZE)) {
return Pager(PagingConfig(10,2,false,10)) {
messageDao.findAllByDataSource()
}.flow
}

View File

@ -0,0 +1,66 @@
package com.navinfo.volvo.repository.network
import android.content.Context
import android.widget.Toast
import androidx.paging.PagingSource
import androidx.paging.PagingState
import com.google.gson.Gson
import com.navinfo.volvo.Constant
import com.navinfo.volvo.database.entity.GreetingMessage
import com.navinfo.volvo.model.network.NetworkMessageListPost
import com.navinfo.volvo.tools.GsonUtil
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
class MessagePagingSource(
private val networkService: NetworkService,
private val context: Context,
private val messagePost: NetworkMessageListPost,
) : PagingSource<Int, GreetingMessage>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, GreetingMessage> {
return try {
val page = params.key ?: 1
val pageSize = params.loadSize
messagePost.pageSize = "${Constant.MESSAGE_PAGE_SIZE}"
messagePost.pageNum = "$page";
val stringBody = GsonUtil.getInstance().toJson(messagePost)
.toRequestBody("application/json;charset=utf-8".toMediaType())
val result = networkService.queryMessageListByApp(stringBody)
var list: List<GreetingMessage> = emptyList()
if (result.isSuccessful) {
val body = result.body();
body?.let {
if (it.code == 200) {
val data = it.data
data?.let { d ->
if (d.rows != null) {
list = d.rows
for (item in list){
if(item.version == Constant.message_version_right_off && item.status == Constant.message_status_late){
item.status = Constant.message_status_send_over
}
}
}
}
} else {
Toast.makeText(context, "${it.msg}", Toast.LENGTH_SHORT).show()
}
}
} else {
Toast.makeText(context, "${result.message()}", Toast.LENGTH_SHORT).show()
}
val prevKey = if (page > 1) page - 1 else null
val nextKey = if (list.isNotEmpty()) page + 1 else null
LoadResult.Page(list, prevKey, nextKey)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
override fun getRefreshKey(state: PagingState<Int, GreetingMessage>): Int? {
return null
}
}

View File

@ -1,10 +1,14 @@
package com.navinfo.volvo.repository.network
import android.content.Context
import androidx.paging.PagingData
import com.navinfo.volvo.database.entity.GreetingMessage
import com.navinfo.volvo.http.DefaultResponse
import com.navinfo.volvo.model.network.NetworkDeleteMessagePost
import com.navinfo.volvo.model.network.NetworkMessageListPost
import com.navinfo.volvo.model.network.NetworkMessageListResponse
import com.navinfo.volvo.util.NetResult
import kotlinx.coroutines.flow.Flow
/**
* 网络访问接口
@ -19,4 +23,8 @@ interface NetworkRepository {
*删除问候
*/
suspend fun deleteMessage(message: NetworkDeleteMessagePost): NetResult<DefaultResponse<*>>
suspend fun getMessagePaging(
context: Context, messagePost: NetworkMessageListPost
): Flow<PagingData<GreetingMessage>>
}

View File

@ -1,7 +1,13 @@
package com.navinfo.volvo.repository.network
import android.content.Context
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingData
import com.google.gson.Gson
import com.navinfo.volvo.Constant
import com.navinfo.volvo.database.dao.GreetingMessageDao
import com.navinfo.volvo.database.entity.GreetingMessage
import com.navinfo.volvo.di.scope.IoDispatcher
import com.navinfo.volvo.http.DefaultResponse
import com.navinfo.volvo.model.network.NetworkDeleteMessagePost
@ -9,6 +15,7 @@ import com.navinfo.volvo.model.network.NetworkMessageListPost
import com.navinfo.volvo.model.network.NetworkMessageListResponse
import com.navinfo.volvo.util.NetResult
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.withContext
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody
@ -20,6 +27,8 @@ class NetworkRepositoryImp @Inject constructor(
private val gson: Gson,
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
) : NetworkRepository {
/**
* 获取问候列表
*/
@ -66,5 +75,17 @@ class NetworkRepositoryImp @Inject constructor(
}
}
override suspend fun getMessagePaging(
context: Context, messagePost: NetworkMessageListPost
): Flow<PagingData<GreetingMessage>> {
return Pager(config = PagingConfig(
pageSize = Constant.MESSAGE_PAGE_SIZE,
prefetchDistance = 1
), pagingSourceFactory = {
MessagePagingSource(
netWorkService, context, messagePost
)
}).flow
}
}

View File

@ -8,10 +8,12 @@ import kotlinx.coroutines.flow.Flow
* 数据库操作接口
*/
interface PreferencesRepository {
suspend fun saveLoginUser(id: String, name: String, password: String)
fun loginUser(): Flow<LoginUser?>
suspend fun saveString(key: String, content: String)
suspend fun getString(key: String): Flow<String?>
suspend fun saveInt(key: String, content: Int)
suspend fun getInt(key: String): Flow<Int?>
fun getUserName(): String
}

View File

@ -1,6 +1,7 @@
package com.navinfo.volvo.repository.preferences
import android.content.Context
import android.util.Log
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
@ -8,11 +9,11 @@ import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import androidx.lifecycle.viewModelScope
import com.navinfo.volvo.di.scope.IoDispatcher
import com.navinfo.volvo.di.scope.MainDispatcher
import com.navinfo.volvo.model.proto.LoginUser
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
import javax.inject.Inject
@ -21,15 +22,9 @@ val Context.datastore: DataStore<Preferences> by preferencesDataStore(name = Dat
class PreferencesRepositoryImp @Inject constructor(
private val context: Context,
private val loginUser: DataStore<LoginUser>
private val loginUser: DataStore<LoginUser>,
) : PreferencesRepository {
companion object {
val NAME = stringPreferencesKey("NAME")
val PHONE_NUMBER = stringPreferencesKey("PHONE")
val address = stringPreferencesKey("ADDRESS")
}
override suspend fun saveLoginUser(id: String, name: String, password: String) {
loginUser.updateData { preference ->
preference.toBuilder().setUsername(name).setPassword(password).build()
@ -58,4 +53,14 @@ class PreferencesRepositoryImp @Inject constructor(
override fun loginUser(): Flow<LoginUser?> = loginUser.data
override fun getUserName(): String {
Log.e("jingo", "获取用户名 开始")
var username = ""
loginUser.data.map {
username = it.username
}
Log.e("jingo", "获取用户名 结束后 $username")
return username
}
}

View File

@ -6,7 +6,9 @@ import android.view.Gravity
import android.view.View
import android.widget.Toast
import androidx.activity.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
@ -100,17 +102,19 @@ class MainActivity : BaseActivity() {
navView.setupWithNavController(navController)
lifecycleScope.launch {
viewModel.getUnreadCount().collect {
if (it == 0L) {
navView.removeBadge(R.id.navigation_home)
} else {
var badge = navView.getOrCreateBadge(R.id.navigation_home);
badge.number = it.toInt()
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.getUnreadCount().collect {
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 ->
navController.addOnDestinationChangedListener { _, destination, _ ->
if (destination.id == R.id.navigation_home || destination.id == R.id.navigation_dashboard || destination.id == R.id.navigation_notifications) {
runOnUiThread {
val transition: Transition = Slide(Gravity.BOTTOM)
@ -144,15 +148,18 @@ class MainActivity : BaseActivity() {
fun createRootFolder() {
// 在SD卡创建项目目录
val sdCardPath = getExternalFilesDir(null)
// SystemConstant.ROOT_PATH = "${sdCardPath}/${SystemConstant.FolderName}"
SystemConstant.ROOT_PATH = sdCardPath!!.absolutePath
SystemConstant.LogFolder = "${sdCardPath!!.absolutePath}/log"
FileUtils.createOrExistsDir(SystemConstant.LogFolder)
SystemConstant.CameraFolder = "${sdCardPath!!.absolutePath}/camera"
FileUtils.createOrExistsDir(SystemConstant.CameraFolder)
SystemConstant.SoundFolder = "${sdCardPath!!.absolutePath}/sound"
FileUtils.createOrExistsDir(SystemConstant.SoundFolder)
xLogInit(SystemConstant.LogFolder)
sdCardPath?.let {
// SystemConstant.ROOT_PATH = "${sdCardPath}/${SystemConstant.FolderName}"
SystemConstant.ROOT_PATH = sdCardPath.absolutePath
SystemConstant.LogFolder = "${sdCardPath.absolutePath}/log"
FileUtils.createOrExistsDir(SystemConstant.LogFolder)
SystemConstant.CameraFolder = "${sdCardPath.absolutePath}/camera"
FileUtils.createOrExistsDir(SystemConstant.CameraFolder)
SystemConstant.SoundFolder = "${sdCardPath.absolutePath}/sound"
FileUtils.createOrExistsDir(SystemConstant.SoundFolder)
xLogInit(SystemConstant.LogFolder)
}
}
fun xLogInit(logFolder: String) {

View File

@ -47,8 +47,8 @@ class CameraFragment : Fragment() {
): View {
// lifecycle.addObserver(cameraLifeCycleObserver)
val cameraViewModel =
ViewModelProvider(this).get(CameraViewModel::class.java)
// val cameraViewModel =
// ViewModelProvider(this).get(CameraViewModel::class.java)
_binding = FragmentCameraBinding.inflate(inflater, container, false)
val root: View = binding.root
@ -80,10 +80,11 @@ class CameraFragment : Fragment() {
XLog.d("压缩图片成功:${file?.absolutePath}")
// 删除源文件
if (!resultFile!!.absolutePath.equals(file!!.absolutePath)) {
resultFile!!.delete()
resultFile.delete()
}
// 跳转回原Fragment展示拍摄的照片
ViewModelProvider(requireActivity()).get(ObtainMessageViewModel::class.java).updateMessagePic(file!!.absolutePath)
ViewModelProvider(requireActivity())[ObtainMessageViewModel::class.java].updateMessagePic(
file.absolutePath)
// 跳转回原界面
Navigation.findNavController(root).popBackStack()
}

View File

@ -5,24 +5,24 @@ import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.findNavController
import androidx.paging.LoadState
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.easytools.tools.ThreadPoolUtils.runOnUiThread
import com.navinfo.volvo.R
import com.navinfo.volvo.databinding.FragmentHomeBinding
import com.navinfo.volvo.databinding.HomeAdapterNotingBinding
import com.navinfo.volvo.databinding.LoadStateViewBinding
import com.navinfo.volvo.tools.DisplayUtil
import com.navinfo.volvo.ui.fragments.BaseFragment
import com.yanzhenjie.recyclerview.*
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.IOException
@AndroidEntryPoint
@ -32,7 +32,6 @@ class HomeFragment : BaseFragment(), OnItemClickListener, OnItemMenuClickListene
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
private val viewModel by viewModels<HomeViewModel>()
@ -42,7 +41,7 @@ class HomeFragment : BaseFragment(), OnItemClickListener, OnItemMenuClickListene
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
val root: View = binding.root
val root: View = _binding!!.root
headBinding = HomeAdapterNotingBinding.inflate(inflater, container, false)
initView()
@ -50,126 +49,148 @@ class HomeFragment : BaseFragment(), OnItemClickListener, OnItemMenuClickListene
}
private fun initView() {
//创建菜单选项
//注意:使用滑动菜单不能开启滑动删除,否则只有滑动删除没有滑动菜单
var mSwipeMenuCreator = SwipeMenuCreator { _, rightMenu, _ ->
//添加菜单自动添加至尾部
var deleteItem = SwipeMenuItem(context)
deleteItem.height = DisplayUtil.dip2px(requireContext(), 60f)
deleteItem.width = DisplayUtil.dip2px(requireContext(), 80f)
deleteItem.background = requireContext().getDrawable(R.color.red)
deleteItem.text = requireContext().getString(R.string.delete)
rightMenu.addMenuItem(deleteItem)
//预览
var previewItem = SwipeMenuItem(context)
previewItem.height = DisplayUtil.dip2px(requireContext(), 60f)
previewItem.width = DisplayUtil.dip2px(requireContext(), 80f)
previewItem.background = requireContext().getDrawable(R.color.yellow)
previewItem.setTextColor(requireContext().getColor(R.color.white))
previewItem.text = requireContext().getString(R.string.preview)
rightMenu.addMenuItem(previewItem)
//分享
var shareItem = SwipeMenuItem(context)
shareItem.height = DisplayUtil.dip2px(requireContext(), 60f)
shareItem.width = DisplayUtil.dip2px(requireContext(), 80f)
shareItem.background = requireContext().getDrawable(R.color.gray)
shareItem.text = requireContext().getString(R.string.share)
shareItem.background = requireContext().getDrawable(R.color.blue)
shareItem.setTextColor(requireContext().getColor(R.color.white))
shareItem.text = requireContext().getString(R.string.share)
rightMenu.addMenuItem(shareItem)
}
//侧滑按钮
binding.homeRecyclerview.setOnItemMenuClickListener { menuBridge, position ->
menuBridge.closeMenu()
// val direction: Int = menuBridge.getDirection() // 左侧还是右侧菜单。
when (menuBridge.position) {// 菜单在RecyclerView的Item中的Position。
0 -> {//删除按钮
viewModel.deleteMessage(messageAdapter.getItemData(position).id)
}
1 -> {//分享按钮
}
//添加菜单自动添加至尾部
var deleteItem = SwipeMenuItem(context)
deleteItem.height = DisplayUtil.dip2px(requireContext(), 60f)
deleteItem.width = DisplayUtil.dip2px(requireContext(), 80f)
deleteItem.text = requireContext().getString(R.string.delete)
deleteItem.background = requireContext().getDrawable(R.color.red)
deleteItem.setTextColor(requireContext().getColor(R.color.white))
rightMenu.addMenuItem(deleteItem)
}
}
val layoutManager = LinearLayoutManager(context)
binding.homeRecyclerview.layoutManager = layoutManager
//自动增加分割线
binding.homeRecyclerview.addItemDecoration(
DividerItemDecoration(
context, layoutManager.orientation
_binding?.let {
_binding!!.homeRecyclerview.layoutManager = layoutManager
//自动增加分割线
_binding!!.homeRecyclerview.addItemDecoration(
DividerItemDecoration(
context, layoutManager.orientation
)
)
)
//增加侧滑按钮
binding.homeRecyclerview.setSwipeMenuCreator(mSwipeMenuCreator)
//单项点击
binding.homeRecyclerview.setOnItemClickListener(this)
//使用下拉加载
// binding.homeRecyclerview.useDefaultLoadMore() // 使用默认的加载更多的View。
//增加侧滑按钮
_binding!!.homeRecyclerview.setSwipeMenuCreator(mSwipeMenuCreator)
//单项点击
_binding!!.homeRecyclerview.setOnItemClickListener(this)
binding.homeRecyclerview.setLoadMoreListener {
Log.e("jingo", "下拉加载开始")
_binding!!.homeRecyclerview.setLoadMoreListener {
Log.e("jingo", "下拉加载开始")
} // 加载更多的监听。
} // 加载更多的监听。
//开始下拉刷新
binding.homeSwipeRefreshLayout.setOnRefreshListener {
Log.e("jingo", "开始刷新")
viewModel.getNetMessageList()
}
//列表自动分页
lifecycleScope.launch {
viewModel.messageList.collect {
messageAdapter.submitData(it)
//开始下拉刷新
_binding!!.homeSwipeRefreshLayout.setOnRefreshListener {
Log.e("jingo", "开始刷新")
// viewModel.getNetMessageList()
messageAdapter.refresh()
}
}
binding.homeRecyclerview.adapter = messageAdapter
//初始状态添加监听
messageAdapter.addLoadStateListener {
when (it.refresh) {
is LoadState.NotLoading -> {
if (messageAdapter.itemCount == 0)
binding.homeRecyclerview.addHeaderView(headBinding!!.root)
else{
binding.homeRecyclerview.removeHeaderView(headBinding!!.root)
//列表自动分页
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.getNetMessageList().collect {
messageAdapter.submitData(it)
}
Log.d("jingo", "is NotLoading")
}
is LoadState.Loading -> {
Log.d("jingo", "is Loading")
}
//侧滑菜单的监听必需在设置adapter之前
_binding!!.homeRecyclerview.setOnItemMenuClickListener { menuBridge, adapterPosition ->
menuBridge.closeMenu()
// val direction: Int = menuBridge.getDirection() // 左侧还是右侧菜单。
when (menuBridge.position) {// 菜单在RecyclerView的Item中的Position。
0 -> {//预览按钮
}
1 -> {//分享按钮
}
2 -> {//删除按钮
viewModel.deleteMessage(messageAdapter.getItemData(adapterPosition).id)
}
}
is LoadState.Error -> {
Log.d("jingo", "is Error:")
when ((it.refresh as LoadState.Error).error) {
is IOException -> {
Log.d("jingo", "IOException")
}
_binding!!.homeRecyclerview.adapter = messageAdapter
//初始状态添加监听
messageAdapter.addLoadStateListener {
when (it.refresh) {
is LoadState.NotLoading -> {
_binding!!.homeSwipeRefreshLayout.isRefreshing = false
if (messageAdapter.itemCount == 0)
_binding?.let {
_binding!!.homeRecyclerview.addHeaderView(headBinding?.root)
}
else {
_binding?.let {
_binding!!.homeRecyclerview.removeHeaderView(headBinding?.root)
}
}
else -> {
Log.d("jingo", "others exception")
Log.d("jingo", "is NotLoading")
}
is LoadState.Loading -> {
Log.d("jingo", "is Loading")
_binding!!.homeSwipeRefreshLayout.isRefreshing = true
}
is LoadState.Error -> {
_binding!!.homeSwipeRefreshLayout.isRefreshing = false
Log.d("jingo", "is Error:")
when ((it.refresh as LoadState.Error).error) {
is IOException -> {
Log.d("jingo", "IOException")
}
else -> {
Log.d("jingo", "others exception")
}
}
}
}
}
loadMoreFinish()
}
loadMoreFinish()
//监听数据请求是否结束
viewModel.isLoading.observe(viewLifecycleOwner, Observer {
if (!it) loadMoreFinish()
})
}
private fun loadMoreFinish() {
binding.homeSwipeRefreshLayout.isRefreshing = false
// 第一次加载数据:一定要掉用这个方法。
// 第一个参数表示此次数据是否为空假如你请求到的list为空(== null || list.size == 0)那么这里就要true。
// 第二个参数表示是否还有更多数据根据服务器返回给你的page等信息判断是否还有更多这样可以提供性能如果不能判断则传true。
binding.homeRecyclerview.loadMoreFinish(false, false)
_binding?.let {
_binding!!.homeSwipeRefreshLayout.isRefreshing = false
// 第一次加载数据:一定要掉用这个方法。
// 第一个参数表示此次数据是否为空假如你请求到的list为空(== null || list.size == 0)那么这里就要true。
// 第二个参数表示是否还有更多数据根据服务器返回给你的page等信息判断是否还有更多这样可以提供性能如果不能判断则传true。
_binding!!.homeRecyclerview.loadMoreFinish(false, true)
}
}
override fun onStart() {
super.onStart()
viewModel.getNetMessageList()
}
@ -179,10 +200,15 @@ class HomeFragment : BaseFragment(), OnItemClickListener, OnItemMenuClickListene
headBinding = null
}
//点击项
override fun onItemClick(view: View?, adapterPosition: Int) {
val directions = HomeFragmentDirections.actionHomeToObtainMessage()
directions.arguments.putParcelable("message", messageAdapter.getItemData(adapterPosition))
findNavController().navigate(directions)
}
override fun onItemClick(menuBridge: SwipeMenuBridge?, adapterPosition: Int) {
}
}

View File

@ -1,9 +1,11 @@
package com.navinfo.volvo.ui.fragments.home
import android.app.Application
import android.content.Context
import android.util.Log
import android.widget.Toast
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import com.navinfo.volvo.database.dao.GreetingMessageDao
@ -12,19 +14,21 @@ import com.navinfo.volvo.model.network.NetworkDeleteMessagePost
import com.navinfo.volvo.model.network.NetworkMessageListPost
import com.navinfo.volvo.repository.database.DatabaseRepository
import com.navinfo.volvo.repository.network.NetworkRepository
import com.navinfo.volvo.repository.network.NetworkService
import com.navinfo.volvo.repository.preferences.PreferencesRepository
import com.navinfo.volvo.util.NetResult
import com.navinfo.volvo.util.asLiveData
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.cancel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class HomeViewModel @Inject constructor(
private val application: Application,
private val application: Context,
private val netRepository: NetworkRepository,
private val dataRepository: DatabaseRepository,
private val messageDao: GreetingMessageDao,
private val shard: PreferencesRepository
) : ViewModel() {
@ -32,55 +36,51 @@ class HomeViewModel @Inject constructor(
private val _isLoading = MutableLiveData<Boolean>()
val isLoading = _isLoading.asLiveData()
// private val _messageList = MutableLiveData<List<GreetingMessage>>()
// val messageList = _messageList.asLiveData()
val messageList: Flow<PagingData<GreetingMessage>>
get() = dataRepository.getMessageByPaging()
lateinit var userName: String
var userName: String = ""
init {
Log.e("jingo","当前的homeviewmodel 是 ${hashCode()}")
viewModelScope.launch {
shard.loginUser().collect {
shard.loginUser().collectLatest {
userName = it!!.username
Log.e("jingo","用户赋值结束 是 ${userName.hashCode()}")
}
}
}
fun getNetMessageList() {
if (_isLoading.value == true)
return
_isLoading.postValue(true)
viewModelScope.launch {
val messagePost = NetworkMessageListPost(who = userName, toWho = "")
when (val result = netRepository.getMessageList(messagePost)) {
is NetResult.Success -> {
_isLoading.value = false
if ((result.data!!.data != null) && (result.data.data!!.rows != null)) {
messageDao.insertOrUpdate(result.data.data!!.rows!!)
}
}
is NetResult.Failure -> {
_isLoading.value = false
Toast.makeText(application, "${result.code}:${result.msg}", Toast.LENGTH_SHORT)
.show()
}
is NetResult.Error -> {
_isLoading.value = false
}
is NetResult.Loading -> {
_isLoading.postValue(true)
}
}
}
suspend fun getNetMessageList(): Flow<PagingData<GreetingMessage>> {
Log.e("jingo","用户赋值了吗? $userName ${userName.hashCode()}")
val messagePost = NetworkMessageListPost(who = userName)
return netRepository.getMessagePaging(context = application, messagePost)
// when (val result = netRepository.getMessageList(messagePost)) {
// is NetResult.Success -> {
// _isLoading.value = false
// if ((result.data!!.data != null) && (result.data.data!!.rows != null)) {
// messageDao.insertOrUpdate(result.data.data!!.rows!!)
// }
// }
// is NetResult.Failure -> {
// _isLoading.value = false
// Toast.makeText(application, "${result.code}:${result.msg}", Toast.LENGTH_SHORT)
// .show()
// }
// is NetResult.Error -> {
// _isLoading.value = false
// }
// is NetResult.Loading -> {
// _isLoading.postValue(true)
// }
// }
}
fun deleteMessage(id: Long) {
viewModelScope.launch {
val post = NetworkDeleteMessagePost(id)
netRepository.deleteMessage(post)
messageDao.deleteById(id)
when (val result = netRepository.deleteMessage(post)) {
is NetResult.Success -> {

View File

@ -7,8 +7,10 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.navigation.fragment.findNavController
import com.navinfo.volvo.R
import com.navinfo.volvo.databinding.FragmentLoginBinding
@ -41,9 +43,11 @@ class LoginFragment : BaseFragment() {
private fun initView() {
lifecycleScope.launch {
viewModel.user.collect {
if (it != null){
viewBinding.loginUser = it
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.user.collect {
if (it != null) {
viewBinding.loginUser = it
}
}
}
}

View File

@ -18,12 +18,18 @@ class LoginViewModel @Inject constructor(private val repository: PreferencesRepo
val user = repository.loginUser()
fun onClickLogin(name: String, password: String) {
viewModelScope.launch {
repository.saveLoginUser(id = "", name = name, password = password)
if (name != "") {
viewModelScope.launch {
repository.saveLoginUser(id = "", name = name, password = password)
}
}
}
fun onClickLoginRegister(username: String, password: String) {
}
// fun onClickLoginRegister(username: String, password: String) {
// if (username != "") {
// viewModelScope.launch {
// repository.saveLoginUser(id = "", name = username, password = password)
// }
// }
// }
}

View File

@ -86,13 +86,17 @@ class ObtainMessageFragment : Fragment() {
_binding = FragmentObtainMessageBinding.inflate(inflater, container, false)
val root: View = binding.root
obtainMessageViewModel.setCurrentMessage(GreetingMessage(who = obtainMessageViewModel.username))
var messege = arguments?.getParcelable<GreetingMessage>("message")
if (messege == null) {
messege = GreetingMessage(who = obtainMessageViewModel.username)
}
obtainMessageViewModel.setCurrentMessage(messege)
obtainMessageViewModel.getMessageLiveData().observe(
viewLifecycleOwner, Observer {
// 初始化界面显示内容
if (it.name?.isNotEmpty() == true)
binding.tvMessageTitle?.setText(it.name)
binding.tvMessageTitle.setText(it.name)
if (it.sendDate?.isNotEmpty() == true) {
// 获取当前发送时间,如果早于当前时间,则显示现在
val sendDate = DateUtils.str2Date(it.sendDate, dateSendFormat)
@ -187,7 +191,8 @@ class ObtainMessageFragment : Fragment() {
obtainMessageViewModel.updateMessageAudio("")
}
val sendToArray = mutableListOf<VolvoModel>(VolvoModel("XC60", "智雅", "LYVXFEFEXNL754427"))
binding.edtSendTo.adapter = ArrayAdapter<String>(requireContext(),
binding.edtSendTo.adapter = ArrayAdapter<String>(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
android.R.id.text1,
sendToArray.stream().map { it -> "${it.version} ${it.model} ${it.num}" }.toList()
@ -656,7 +661,6 @@ class ObtainMessageFragment : Fragment() {
}
binding.edtSendFrom.setText(obtainMessageViewModel.username)
}
val confirmCallback = object : ObtainMessageViewModel.MyConfirmCallback {
@ -671,7 +675,7 @@ class ObtainMessageFragment : Fragment() {
}
fun startCamera(it: View) {
Navigation.findNavController(binding.root).navigate(com.navinfo.volvo.R.id.nav_2_camera)
// Navigation.findNavController(binding.root).navigate(com.navinfo.volvo.R.id.nav_2_camera)
}
fun showRationaleForCamera(permissions: MutableList<String>) {

View File

@ -1,5 +1,7 @@
package com.navinfo.volvo.ui.fragments.message
import android.util.Log
import androidx.compose.runtime.collectAsState
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
@ -13,10 +15,10 @@ import com.navinfo.volvo.http.DownloadCallback
import com.navinfo.volvo.http.DownloadManager
import com.navinfo.volvo.http.DownloadState
import com.navinfo.volvo.http.NavinfoVolvoCall
import com.navinfo.volvo.model.proto.LoginUser
import com.navinfo.volvo.repository.preferences.PreferencesRepository
import com.navinfo.volvo.utils.SystemConstant
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
@ -29,19 +31,20 @@ import javax.inject.Inject
class ObtainMessageViewModel @Inject constructor(
private val pre: PreferencesRepository,
) : ViewModel() {
var username = ""
init {
viewModelScope.launch {
pre.loginUser().collectLatest {
username = it!!.username
Log.e("jingo", "用户赋值结束 是 ${username.hashCode()}")
}
}
}
private val msgLiveData: MutableLiveData<GreetingMessage> by lazy {
MutableLiveData<GreetingMessage>()
}
var username: String = ""
init {
viewModelScope.launch {
pre.loginUser().collect {
username = it!!.username
}
}
}
fun setCurrentMessage(msg: GreetingMessage) {
msgLiveData.postValue(msg)

View File

@ -1,39 +0,0 @@
package com.navinfo.volvo.ui.message
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.Navigation
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import com.navinfo.volvo.R
import com.navinfo.volvo.databinding.ActivityMessageBinding
class MessageActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityMessageBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMessageBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.toolbar)
binding.toolbar.setOnClickListener {
Navigation.findNavController(it).popBackStack()
}
val navController = findNavController(R.id.nav_host_fragment_message)
appBarConfiguration = AppBarConfiguration(navController.graph)
setupActionBarWithNavController(navController, appBarConfiguration)
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment_message)
return navController.navigateUp(appBarConfiguration)
|| super.onSupportNavigateUp()
}
}

View File

@ -1,35 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.message.MessageActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/Theme.NavinfoVolvo.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:navigationIcon="@drawable/ic_back_file_picker"
app:popupTheme="@style/Theme.NavinfoVolvo.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_message" />
<!-- <com.google.android.material.floatingactionbutton.FloatingActionButton-->
<!-- android:id="@+id/fab"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_gravity="bottom|end"-->
<!-- android:layout_marginEnd="@dimen/fab_margin"-->
<!-- android:layout_marginBottom="16dp"-->
<!-- app:srcCompat="@android:drawable/ic_dialog_email" />-->
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<fragment
android:id="@+id/nav_host_fragment_message"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -30,6 +30,7 @@
android:layout_marginTop="10dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"

View File

@ -21,7 +21,17 @@
android:id="@+id/navigation_home"
android:name="com.navinfo.volvo.ui.fragments.home.HomeFragment"
android:label="@string/title_home"
tools:layout="@layout/fragment_home"></fragment>
tools:layout="@layout/fragment_home">
<action
android:id="@+id/action_home_to_obtainMessage"
app:destination="@id/navigation_obtain_message"
/>
<argument
android:name="message"
app:nullable="true"
app:argType="com.navinfo.volvo.database.entity.GreetingMessage"
/>
</fragment>
<fragment
android:id="@+id/navigation_dashboard"
@ -29,12 +39,6 @@
android:label="@string/title_dashboard"
tools:layout="@layout/fragment_dashboard" />
<fragment
android:id="@+id/fab_new_message"
android:name="com.navinfo.volvo.ui.fragments.dashboard.DashboardFragment"
android:label="@string/title_dashboard"
tools:layout="@layout/fragment_dashboard" />
<fragment
android:id="@+id/navigation_notifications"
android:name="com.navinfo.volvo.ui.fragments.notifications.NotificationsFragment"
@ -46,15 +50,6 @@
android:name="com.navinfo.volvo.ui.fragments.message.ObtainMessageFragment"
android:label="问候编辑"
tools:layout="@layout/fragment_obtain_message" >
<action
android:id="@+id/action_login_to_home"
app:destination="@id/navigation_home"
app:enterAnim="@anim/from_left"
app:exitAnim="@anim/to_right"
app:popEnterAnim="@anim/from_right"
app:popExitAnim="@anim/to_left"
app:popUpTo="@id/navigation_obtain_message"
app:popUpToInclusive="true" />
</fragment>
</navigation>

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<navigation 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"
android:id="@+id/nav_graph"
app:startDestination="@id/navigation_obtain_message">
<fragment
android:id="@+id/navigation_obtain_message"
android:name="com.navinfo.volvo.ui.message.ObtainMessageFragment"
android:label="问候编辑"
tools:layout="@layout/fragment_obtain_message" >
<action
android:id="@+id/nav_2_camera"
app:destination="@id/navigation_camera"></action>
</fragment>
<fragment
android:id="@+id/navigation_camera"
android:name="com.navinfo.volvo.ui.camera.CameraFragment"
android:label="拍照"
tools:layout="@layout/fragment_camera" />
</navigation>

View File

@ -15,4 +15,5 @@
<string name="hello_first_fragment">Hello first fragment</string>
<string name="hello_second_fragment">Hello second fragment. Arg: %1$s</string>
<string name="preview">预览</string>
</resources>

View File

@ -7,7 +7,9 @@
<color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="red">#FFFF0000</color>
<color name="red">#FA5151</color>
<color name="gray">#5E5E5E</color>
<color name="gray1">#D2CACA</color>
<color name="blue">#1285EC</color>
<color name="yellow">#F99C3E</color>
</resources>

View File

@ -5,6 +5,7 @@
<string name="title_notifications">Notifications</string>
<string name="delete">Del</string>
<string name="share">Share</string>
<string name="preview">Preview</string>
<string name="my">My</string>
<string name="title_activity_second">SecondActivity</string>
<!-- Strings used for fragments for navigation -->

View File

@ -2,12 +2,14 @@
buildscript {
// ext.kotlin_version = '1.7.20'
dependencies {
def nav_version = "2.5.3"
// classpath 'com.android.tools.build:gradle:7.3.1'
classpath('androidx.multidex:multidex:2.0.1')
// classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
// classpath "io.realm:realm-gradle-plugin:10.10.1"
// classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.google.dagger:hilt-android-gradle-plugin:2.41"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
}
}
@ -15,6 +17,7 @@ plugins {
id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
// id 'com.google.dagger.hilt.android' version "2.44.2" apply false
// id 'io.realm.kotlin' version '0.10.0' apply false
}