fix: 修改短按录音崩溃的问题

This commit is contained in:
xiaoyan 2023-01-09 13:53:30 +08:00
commit cdc5e8a95f
46 changed files with 750 additions and 368 deletions

View File

@ -2,6 +2,7 @@ plugins {
id 'com.android.application' id 'com.android.application'
id 'org.jetbrains.kotlin.android' id 'org.jetbrains.kotlin.android'
id 'kotlin-android' id 'kotlin-android'
id 'kotlin-parcelize'
id 'kotlin-kapt' id 'kotlin-kapt'
id 'dagger.hilt.android.plugin' id 'dagger.hilt.android.plugin'
// id 'com.google.dagger.hilt.android' // id 'com.google.dagger.hilt.android'
@ -61,14 +62,17 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.5.1' implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0' implementation 'com.google.android.material:material:1.7.0'
implementation "androidx.compose.material3:material3:1.0.0-alpha04" implementation "androidx.compose.material3:material3:1.0.0-alpha04"
//
implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
//
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1' 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-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.lifecycle:lifecycle-common-java8:2.4.1"
//
implementation 'androidx.navigation:navigation-fragment-ktx:2.4.1' implementation 'androidx.navigation:navigation-fragment-ktx:2.4.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.4.1' implementation 'androidx.navigation:navigation-ui-ktx:2.4.1'
@ -76,7 +80,7 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.4' androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
//room //room
implementation 'com.tencent.wcdb:room:1.1-19' // room-runtime wcdb-android implementation 'com.tencent.wcdb:room:1.1-19' // room-runtime wcdb-android
api 'androidx.sqlite:sqlite:2.2.0' api 'androidx.sqlite:sqlite:2.2.0'
implementation 'androidx.room:room-runtime:2.4.3' implementation 'androidx.room:room-runtime:2.4.3'
@ -86,6 +90,10 @@ dependencies {
kapt 'android.arch.persistence.room:compiler:1.1.1'// compiler room kapt 'android.arch.persistence.room:compiler:1.1.1'// compiler room
kapt 'androidx.room:room-compiler:2.4.3' kapt 'androidx.room:room-compiler:2.4.3'
kapt 'androidx.room:room-ktx:2.4.3' kapt 'androidx.room:room-ktx:2.4.3'
//
implementation "androidx.room:room-paging:2.4.3"
implementation "androidx.paging:paging-runtime-ktx:3.1.1"
androidTestImplementation "android.arch.persistence.room:testing:1.1.1" androidTestImplementation "android.arch.persistence.room:testing:1.1.1"
// implementation "android.arch.lifecycle:extensions:1.1.1" // implementation "android.arch.lifecycle:extensions:1.1.1"
// annotationProcessor "android.arch.lifecycle:compiler:1.1.1" // annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
@ -96,6 +104,8 @@ dependencies {
implementation 'me.rosuh:AndroidFilePicker:0.8.2' implementation 'me.rosuh:AndroidFilePicker:0.8.2'
// https://github.com/Gredicer/datetimepicker // https://github.com/Gredicer/datetimepicker
implementation 'com.github.Gredicer:datetimepicker:V1.0.0' implementation 'com.github.Gredicer:datetimepicker:V1.0.0'
//
implementation 'com.yanzhenjie.recyclerview:x:1.3.2' implementation 'com.yanzhenjie.recyclerview:x:1.3.2'
// implementation 'androidx.appcompat:appcompat:1.5.1' // implementation 'androidx.appcompat:appcompat:1.5.1'

BIN
app/release/app-release.apk Normal file

Binary file not shown.

View File

@ -0,0 +1,20 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.navinfo.volvo",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 1,
"versionName": "1.0",
"outputFile": "app-release.apk"
}
],
"elementType": "File"
}

View File

@ -23,7 +23,7 @@
android:configChanges="locale" android:configChanges="locale"
android:dataExtractionRules="@xml/data_extraction_rules" android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules" android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/volvo_logo_small"
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
@ -34,6 +34,7 @@
android:name=".ui.message.MessageActivity" android:name=".ui.message.MessageActivity"
android:exported="false" android:exported="false"
android:label="@string/title_activity_second" android:label="@string/title_activity_second"
android:screenOrientation="portrait"
android:theme="@style/Theme.NavinfoVolvo.NoActionBar"> android:theme="@style/Theme.NavinfoVolvo.NoActionBar">
<meta-data <meta-data
android:name="android.app.lib_name" android:name="android.app.lib_name"

View File

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

View File

@ -10,7 +10,7 @@ import java.util.*
class RecorderLifecycleObserver: DefaultLifecycleObserver { class RecorderLifecycleObserver: DefaultLifecycleObserver {
private var mediaRecorder: MediaRecorder? = null private var mediaRecorder: MediaRecorder? = null
private lateinit var recorderAudioPath: String private var recorderAudioPath: String = "${SystemConstant.SoundFolder}/${DateUtils.date2Str(Date(), DateUtils.FORMAT_YMDHMS)}.m4a"
fun initAndStartRecorder() { fun initAndStartRecorder() {
recorderAudioPath = "${SystemConstant.SoundFolder}/${DateUtils.date2Str(Date(), DateUtils.FORMAT_YMDHMS)}.m4a" recorderAudioPath = "${SystemConstant.SoundFolder}/${DateUtils.date2Str(Date(), DateUtils.FORMAT_YMDHMS)}.m4a"
@ -22,17 +22,22 @@ class RecorderLifecycleObserver: DefaultLifecycleObserver {
setOutputFile(recorderAudioPath) setOutputFile(recorderAudioPath)
try { try {
prepare() prepare()
start()
} catch (e: Exception) { } catch (e: Exception) {
XLog.e("prepare() failed") XLog.e("prepare() failed")
} }
start()
} }
} }
fun stopAndReleaseRecorder(): String { fun stopAndReleaseRecorder(): String {
try {
mediaRecorder?.stop() mediaRecorder?.stop()
} catch (exception: Exception) {
XLog.e(exception.message)
} finally {
mediaRecorder?.release() mediaRecorder?.release()
mediaRecorder = null mediaRecorder = null
}
return recorderAudioPath return recorderAudioPath
} }

View File

@ -1,19 +1,44 @@
package com.navinfo.volvo.database.dao package com.navinfo.volvo.database.dao
import androidx.room.Dao import androidx.paging.PagingSource
import androidx.room.Insert import androidx.room.*
import androidx.room.OnConflictStrategy
import androidx.room.Query
import com.navinfo.volvo.database.entity.GreetingMessage import com.navinfo.volvo.database.entity.GreetingMessage
import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface GreetingMessageDao { interface GreetingMessageDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg check: GreetingMessage)
@Query("SELECT * FROM GreetingMessage where id =:id") @Insert
fun findCheckManagerById(id: Long): GreetingMessage? fun insert(message: GreetingMessage): Long
@Query("SELECT * FROM GreetingMessage") @Update(onConflict = OnConflictStrategy.REPLACE)
fun findList(): List<GreetingMessage> fun update(message: GreetingMessage)
@Query("SELECT count(id) FROM GreetingMessage WHERE read = 0")
fun countUnreadByFlow(): Flow<Long>
/**
* 分页查询
*/
@Query("SELECT * FROM GreetingMessage order by sendDate DESC")
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)
}else{
update(message)
}
}
}
} }

View File

@ -1,15 +1,15 @@
package com.navinfo.volvo.database.entity package com.navinfo.volvo.database.entity
import android.os.Parcelable
import androidx.room.Entity import androidx.room.Entity
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import androidx.room.TypeConverters import androidx.room.TypeConverters
import org.jetbrains.annotations.NotNull
@Entity(tableName = "GreetingMessage") @Entity(tableName = "GreetingMessage")
@TypeConverters(AttachmentConverters::class) @TypeConverters(AttachmentConverters::class)
data class GreetingMessage @JvmOverloads constructor( data class GreetingMessage @JvmOverloads constructor(
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
var uuid:Long = 0, var uuid: Long = 0,
var id: Long = 0, var id: Long = 0,
var searchValue: String? = "", var searchValue: String? = "",
var createBy: String? = "", var createBy: String? = "",
@ -35,10 +35,10 @@ data class GreetingMessage @JvmOverloads constructor(
var sendVins: String? = "", var sendVins: String? = "",
var sendType: String? = "", var sendType: String? = "",
var del: String? = "", var del: String? = "",
var version: String? = "", var version: String? = "1",
// /** // /**
// * 附件列表 // * 附件列表
// */ // */
// var attachment: MutableList<Attachment> = mutableListOf() // var attachment: MutableList<Attachment> = mutableListOf(),
) { var read: Boolean = false,
} )

View File

@ -5,6 +5,7 @@ import androidx.room.Room
import com.navinfo.volvo.database.AppDatabase import com.navinfo.volvo.database.AppDatabase
import com.navinfo.volvo.database.dao.GreetingMessageDao import com.navinfo.volvo.database.dao.GreetingMessageDao
import com.navinfo.volvo.database.dao.UserDao import com.navinfo.volvo.database.dao.UserDao
import com.navinfo.volvo.utils.SystemConstant
import com.tencent.wcdb.database.SQLiteCipherSpec import com.tencent.wcdb.database.SQLiteCipherSpec
import com.tencent.wcdb.room.db.WCDBOpenHelperFactory import com.tencent.wcdb.room.db.WCDBOpenHelperFactory
import dagger.Module import dagger.Module
@ -31,7 +32,7 @@ class DatabaseModule {
.writeAheadLoggingEnabled(true) // enable WAL mode, remove if not needed .writeAheadLoggingEnabled(true) // enable WAL mode, remove if not needed
.asyncCheckpointEnabled(true); // enable asynchronous checkpoint, remove if not needed .asyncCheckpointEnabled(true); // enable asynchronous checkpoint, remove if not needed
return Room.databaseBuilder(context, AppDatabase::class.java, "NavinfoVolvoDb") return Room.databaseBuilder(context, AppDatabase::class.java, "${SystemConstant.ROOT_PATH}/NavinfoVolvoDb.db")
// [WCDB] Specify open helper to use WCDB database implementation instead // [WCDB] Specify open helper to use WCDB database implementation instead
// of the Android framework. // of the Android framework.

View File

@ -0,0 +1,15 @@
package com.navinfo.volvo.di.module
import com.navinfo.volvo.repository.database.DatabaseRepository
import com.navinfo.volvo.repository.database.DatabaseRepositoryImp
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@InstallIn(SingletonComponent::class)
@Module
abstract class DatabaseRepositoryModule {
@Binds
abstract fun bingDatabaseRepository(databaseRepositoryImp: DatabaseRepositoryImp): DatabaseRepository
}

View File

@ -1,15 +0,0 @@
package com.navinfo.volvo.di.module
import com.navinfo.volvo.repository.NetworkDataSource
import com.navinfo.volvo.repository.NetworkDataSourceImp
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@InstallIn(SingletonComponent::class)
@Module
abstract class NetworkDataModule {
@Binds
abstract fun bindNetworkData(networkDataSourceImp: NetworkDataSourceImp): NetworkDataSource
}

View File

@ -0,0 +1,15 @@
package com.navinfo.volvo.di.module
import com.navinfo.volvo.repository.network.NetworkRepository
import com.navinfo.volvo.repository.network.NetworkRepositoryImp
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@InstallIn(SingletonComponent::class)
@Module
abstract class NetworkRepositoryModule {
@Binds
abstract fun bindNetworkRepository(networkRepositoryImp: NetworkRepositoryImp): NetworkRepository
}

View File

@ -4,7 +4,7 @@ import android.app.Application
import android.content.Context import android.content.Context
import com.google.gson.Gson import com.google.gson.Gson
import com.navinfo.volvo.Constant import com.navinfo.volvo.Constant
import com.navinfo.volvo.repository.service.NetworkService import com.navinfo.volvo.repository.network.NetworkService
import com.navinfo.volvo.tools.GsonUtil import com.navinfo.volvo.tools.GsonUtil
import dagger.Lazy import dagger.Lazy
import dagger.Module import dagger.Module
@ -15,7 +15,6 @@ import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
import javax.inject.Singleton import javax.inject.Singleton
@ -101,4 +100,5 @@ class NetworkUtilModule {
fun provideNetworkService(retrofit: Retrofit): NetworkService { fun provideNetworkService(retrofit: Retrofit): NetworkService {
return retrofit.create(NetworkService::class.java) return retrofit.create(NetworkService::class.java)
} }
} }

View File

@ -3,8 +3,10 @@ package com.navinfo.volvo.di.module
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import com.navinfo.volvo.di.key.ViewModelKey import com.navinfo.volvo.di.key.ViewModelKey
import com.navinfo.volvo.ui.fragments.home.MessageViewModel 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.login.LoginViewModel
import com.navinfo.volvo.ui.fragments.message.ObtainMessageViewModel
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
@ -18,6 +20,11 @@ abstract class ViewModelModule {
@Binds @Binds
abstract fun bindViewModelFactory(viewModelFactory: ViewModelFactory): ViewModelProvider.Factory abstract fun bindViewModelFactory(viewModelFactory: ViewModelFactory): ViewModelProvider.Factory
@IntoMap
@Binds
@ViewModelKey(MainActivityViewModel::class)
abstract fun bindMainViewModel(viewModel: MainActivityViewModel): ViewModel
@IntoMap @IntoMap
@Binds @Binds
@ViewModelKey(LoginViewModel::class) @ViewModelKey(LoginViewModel::class)
@ -25,6 +32,13 @@ abstract class ViewModelModule {
@IntoMap @IntoMap
@Binds @Binds
@ViewModelKey(MessageViewModel::class) @ViewModelKey(HomeViewModel::class)
abstract fun bindMessageFragmentViewModel(viewModel: MessageViewModel): ViewModel abstract fun bindMessageFragmentViewModel(viewModel: HomeViewModel): ViewModel
@IntoMap
@Binds
@ViewModelKey(ObtainMessageViewModel::class)
abstract fun bindObtainMessageFragmentViewModel(viewModel: ObtainMessageViewModel): ViewModel
} }

View File

@ -0,0 +1,9 @@
package com.navinfo.volvo.model
/**
* 登录用户信息
*/
data class LoginUser(
var name: String,
var password: String
)

View File

@ -0,0 +1,3 @@
package com.navinfo.volvo.model
data class VolvoModel(val version: String, val model: String, val num:String)

View File

@ -0,0 +1,12 @@
package com.navinfo.volvo.repository.database
import androidx.paging.PagingData
import com.navinfo.volvo.database.entity.GreetingMessage
import kotlinx.coroutines.flow.Flow
/**
* 数据库操作接口
*/
interface DatabaseRepository {
fun getMessageByPaging(): Flow<PagingData<GreetingMessage>>
}

View File

@ -0,0 +1,26 @@
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 database: AppDatabase
) : DatabaseRepository {
companion object {
const val PAGE_SIZE = 20
}
override fun getMessageByPaging(): Flow<PagingData<GreetingMessage>> {
return Pager(PagingConfig(PAGE_SIZE)) {
messageDao.findAllByDataSource()
}.flow
}
}

View File

@ -1,10 +1,13 @@
package com.navinfo.volvo.repository package com.navinfo.volvo.repository.network
import com.navinfo.volvo.http.DefaultResponse import com.navinfo.volvo.http.DefaultResponse
import com.navinfo.volvo.model.messagelist.NetworkMessageListPost import com.navinfo.volvo.model.messagelist.NetworkMessageListPost
import com.navinfo.volvo.model.messagelist.NetworkMessageListResponse import com.navinfo.volvo.model.messagelist.NetworkMessageListResponse
import com.navinfo.volvo.util.NetResult import com.navinfo.volvo.util.NetResult
interface NetworkDataSource { /**
* 网络访问接口
*/
interface NetworkRepository {
suspend fun getCardList(message: NetworkMessageListPost): NetResult<DefaultResponse<NetworkMessageListResponse>> suspend fun getCardList(message: NetworkMessageListPost): NetResult<DefaultResponse<NetworkMessageListResponse>>
} }

View File

@ -1,13 +1,10 @@
package com.navinfo.volvo.repository package com.navinfo.volvo.repository.network
import com.navinfo.volvo.database.AppDatabase
import com.navinfo.volvo.database.dao.GreetingMessageDao import com.navinfo.volvo.database.dao.GreetingMessageDao
import com.navinfo.volvo.di.scope.IoDispatcher import com.navinfo.volvo.di.scope.IoDispatcher
import com.navinfo.volvo.database.entity.GreetingMessage
import com.navinfo.volvo.http.DefaultResponse import com.navinfo.volvo.http.DefaultResponse
import com.navinfo.volvo.model.messagelist.NetworkMessageListPost import com.navinfo.volvo.model.messagelist.NetworkMessageListPost
import com.navinfo.volvo.model.messagelist.NetworkMessageListResponse import com.navinfo.volvo.model.messagelist.NetworkMessageListResponse
import com.navinfo.volvo.repository.service.NetworkService
import com.navinfo.volvo.tools.GsonUtil import com.navinfo.volvo.tools.GsonUtil
import com.navinfo.volvo.util.NetResult import com.navinfo.volvo.util.NetResult
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
@ -17,11 +14,11 @@ import okhttp3.RequestBody.Companion.toRequestBody
import javax.inject.Inject import javax.inject.Inject
class NetworkDataSourceImp @Inject constructor( class NetworkRepositoryImp @Inject constructor(
private val netWorkService: NetworkService, private val netWorkService: NetworkService,
private val messageDao: GreetingMessageDao, private val messageDao: GreetingMessageDao,
@IoDispatcher private val ioDispatcher: CoroutineDispatcher @IoDispatcher private val ioDispatcher: CoroutineDispatcher
) : NetworkDataSource { ) : NetworkRepository {
override suspend fun getCardList(message: NetworkMessageListPost): NetResult<DefaultResponse<NetworkMessageListResponse>> = override suspend fun getCardList(message: NetworkMessageListPost): NetResult<DefaultResponse<NetworkMessageListResponse>> =
withContext(ioDispatcher) { withContext(ioDispatcher) {
@ -31,9 +28,9 @@ class NetworkDataSourceImp @Inject constructor(
val result = netWorkService.queryCardListByApp(stringBody) val result = netWorkService.queryCardListByApp(stringBody)
if (result.isSuccessful) { if (result.isSuccessful) {
val body = result.body() val body = result.body()
val list: MutableList<GreetingMessage> = if(body!!.data != null && body.data!!.rows != null){
listOf(body!!.data!!.rows) as MutableList<GreetingMessage> messageDao.insertOrUpdate(body.data!!.rows)
messageDao.insert(*list.map { it }.toTypedArray()) }
NetResult.Success(body) NetResult.Success(body)
} else { } else {
NetResult.Success(null) NetResult.Success(null)

View File

@ -1,4 +1,4 @@
package com.navinfo.volvo.repository.service package com.navinfo.volvo.repository.network
import com.navinfo.volvo.http.DefaultResponse import com.navinfo.volvo.http.DefaultResponse
import com.navinfo.volvo.model.messagelist.NetworkMessageListResponse import com.navinfo.volvo.model.messagelist.NetworkMessageListResponse

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

@ -1,10 +1,12 @@
package com.navinfo.volvo.ui package com.navinfo.volvo.ui
import android.content.DialogInterface import android.content.DialogInterface
import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.activity.viewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupActionBarWithNavController
@ -28,20 +30,23 @@ import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions import com.hjq.permissions.XXPermissions
import com.navinfo.volvo.R import com.navinfo.volvo.R
import com.navinfo.volvo.databinding.ActivityMainBinding import com.navinfo.volvo.databinding.ActivityMainBinding
import com.navinfo.volvo.ui.message.MessageActivity
import com.navinfo.volvo.utils.SystemConstant import com.navinfo.volvo.utils.SystemConstant
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : AppCompatActivity() { class MainActivity : BaseActivity() {
private lateinit var binding: ActivityMainBinding private lateinit var binding: ActivityMainBinding
private val viewModel by viewModels<MainActivityViewModel> { viewModelFactoryProvider }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater) binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
setupNavigation()
XXPermissions.with(this) XXPermissions.with(this)
// 申请单个权限 // 申请单个权限
@ -61,6 +66,7 @@ class MainActivity : AppCompatActivity() {
} }
// 在SD卡创建项目目录 // 在SD卡创建项目目录
createRootFolder() createRootFolder()
setupNavigation()
} }
override fun onDenied(permissions: MutableList<String>, never: Boolean) { override fun onDenied(permissions: MutableList<String>, never: Boolean) {
@ -84,16 +90,29 @@ class MainActivity : AppCompatActivity() {
val navController = findNavController(R.id.nav_host_fragment_activity_main) val navController = findNavController(R.id.nav_host_fragment_activity_main)
val appBarConfiguration = AppBarConfiguration( val appBarConfiguration = AppBarConfiguration(
setOf( setOf(
R.id.navigation_message, R.id.navigation_dashboard, R.id.navigation_notifications, R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications,
) )
) )
setupActionBarWithNavController(navController, appBarConfiguration) setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController) 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 -> navController.addOnDestinationChangedListener { controller, destination, arguments ->
if (destination.id == R.id.navigation_message if (destination.id == R.id.navigation_home
|| destination.id == R.id.navigation_dashboard || destination.id == R.id.navigation_dashboard
|| destination.id == R.id.navigation_notifications || destination.id == R.id.navigation_notifications
|| destination.id == R.id.navigation_obtain_message
) { ) {
runOnUiThread { runOnUiThread {
navView.visibility = View.VISIBLE navView.visibility = View.VISIBLE
@ -106,6 +125,11 @@ class MainActivity : AppCompatActivity() {
} }
} }
} }
binding.newMessageFab.setOnClickListener {
// val intent: Intent = Intent(this@MainActivity, MessageActivity::class.java)
// startActivity(intent)
navController.navigate(R.id.navigation_obtain_message)
}
} }
override fun onSupportNavigateUp() = override fun onSupportNavigateUp() =

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,54 +0,0 @@
package com.navinfo.volvo.ui.adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.navinfo.volvo.R
import com.navinfo.volvo.database.entity.GreetingMessage
class MessageAdapter : RecyclerView.Adapter<MessageAdapter.MyViewHolder>() {
var itemList: MutableList<GreetingMessage> = mutableListOf()
fun addItem(message: GreetingMessage) {
itemList.add(message)
notifyItemInserted(itemList.size - 1)
}
fun setItem(messageList: MutableList<GreetingMessage>){
itemList = messageList
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val view =
LayoutInflater.from(parent.context).inflate(R.layout.adapter_message, parent, false)
var viewHolder = MyViewHolder(view)
viewHolder.itemView.setOnClickListener {
}
return viewHolder
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
val message = itemList[position]
holder.toName.text = message.toWho
holder.messageText.text = message.name
holder.sendTime.text = message.sendDate
}
override fun getItemCount(): Int {
return itemList.size
}
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
var image: ImageView = itemView.findViewById(R.id.message_head_icon)
var toName: TextView = itemView.findViewById(R.id.message_to_username)
var sendTime: TextView = itemView.findViewById(R.id.message_send_time)
var status: TextView = itemView.findViewById(R.id.message_status)
var messageText: TextView = itemView.findViewById(R.id.message_text)
}
}

View File

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

View File

@ -0,0 +1,81 @@
package com.navinfo.volvo.ui.fragments.home
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.Fragment
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.navinfo.volvo.R
import com.navinfo.volvo.database.entity.GreetingMessage
import com.navinfo.volvo.databinding.AdapterHomeBinding
class HomeAdapter(fragment: Fragment) :
PagingDataAdapter<GreetingMessage, HomeAdapter.MyViewHolder>(DiffCallback()) {
val fragment = fragment
// var itemList = ArrayList<GreetingMessage>()
//
// fun addItem(message: GreetingMessage) {
// itemList.add(message)
// notifyItemInserted(itemList.size - 1)
// }
//
// fun setItems(messageList: List<GreetingMessage>) {
// itemList.clear()
// itemList.addAll(messageList)
// notifyDataSetChanged()
// }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val mDataBinding: AdapterHomeBinding =
DataBindingUtil.inflate(
LayoutInflater.from(fragment.context),
R.layout.adapter_home,
parent,
false
)
return MyViewHolder(mDataBinding)
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.onBind(position)
}
// override fun getItemCount(): Int {
// return itemList.size
// }
inner class MyViewHolder(private val mDataBinding: AdapterHomeBinding) :
RecyclerView.ViewHolder(mDataBinding.root) {
fun onBind(position: Int) {
var row = getItem(position)
mDataBinding.greetingMessage = row
Glide.with(fragment)
.asBitmap().fitCenter()
.load(row!!.imageUrl)
.placeholder(R.mipmap.volvo_logo_small)
.error(R.mipmap.volvo_logo_small)
.into(mDataBinding.messageHeadIcon)
}
}
class DiffCallback : DiffUtil.ItemCallback<GreetingMessage>() {
override fun areItemsTheSame(oldItem: GreetingMessage, newItem: GreetingMessage): Boolean {
return oldItem.uuid == newItem.uuid
}
override fun areContentsTheSame(
oldItem: GreetingMessage,
newItem: GreetingMessage
): Boolean {
return oldItem == newItem
}
}
}

View File

@ -4,50 +4,47 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import com.navinfo.volvo.R import com.navinfo.volvo.R
import com.navinfo.volvo.databinding.FragmentHomeBinding import com.navinfo.volvo.databinding.FragmentHomeBinding
import com.navinfo.volvo.tools.DisplayUtil import com.navinfo.volvo.tools.DisplayUtil
import com.navinfo.volvo.ui.BaseFragment import com.navinfo.volvo.ui.fragments.BaseFragment
import com.navinfo.volvo.ui.adapter.MessageAdapter
import com.navinfo.volvo.ui.fragments.message.ObtainMessageViewModel
import com.yanzhenjie.recyclerview.* import com.yanzhenjie.recyclerview.*
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
@AndroidEntryPoint @AndroidEntryPoint
class MessageFragment : BaseFragment(), OnItemClickListener, OnItemMenuClickListener { class HomeFragment : BaseFragment(), OnItemClickListener, OnItemMenuClickListener {
private var _binding: FragmentHomeBinding? = null private var _binding: FragmentHomeBinding? = null
// This property is only valid between onCreateView and // This property is only valid between onCreateView and
// onDestroyView. // onDestroyView.
private val binding get() = _binding!! private val binding get() = _binding!!
private val viewModel by viewModels<MessageViewModel> { viewModelFactoryProvider } private val viewModel by viewModels<HomeViewModel> { viewModelFactoryProvider }
private lateinit var messageAdapter: HomeAdapter
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, inflater: LayoutInflater,
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View { ): View {
// val homeViewModel =
// ViewModelProvider(this)[MessageViewModel::class.java]
// val obtainMessageViewModel =
// ViewModelProvider(requireActivity()).get(ObtainMessageViewModel::class.java)
_binding = FragmentHomeBinding.inflate(inflater, container, false) _binding = FragmentHomeBinding.inflate(inflater, container, false)
val root: View = binding.root val root: View = binding.root
initView() initView()
return root return root
} }
private fun initView() { private fun initView() {
val recyclerview: SwipeRecyclerView = binding.homeMessageRecyclerview // mDataBinding.homeViewModel = viewModel
messageAdapter = HomeAdapter(this)
val recyclerview: SwipeRecyclerView = binding.homeRecyclerview
recyclerview.adapter = null //先设置null否则会报错 recyclerview.adapter = null //先设置null否则会报错
//创建菜单选项 //创建菜单选项
//注意:使用滑动菜单不能开启滑动删除,否则只有滑动删除没有滑动菜单 //注意:使用滑动菜单不能开启滑动删除,否则只有滑动删除没有滑动菜单
@ -71,28 +68,32 @@ class MessageFragment : BaseFragment(), OnItemClickListener, OnItemMenuClickList
rightMenu.addMenuItem(shareItem) rightMenu.addMenuItem(shareItem)
} }
val layoutManager = LinearLayoutManager(context) val layoutManager = LinearLayoutManager(context)
val adapter = MessageAdapter()
recyclerview.layoutManager = layoutManager recyclerview.layoutManager = layoutManager
recyclerview.addItemDecoration(DividerItemDecoration(context, layoutManager.orientation)) recyclerview.addItemDecoration(DividerItemDecoration(context, layoutManager.orientation))
recyclerview.setSwipeMenuCreator(mSwipeMenuCreator) recyclerview.setSwipeMenuCreator(mSwipeMenuCreator)
recyclerview.setOnItemClickListener(this) recyclerview.setOnItemClickListener(this)
recyclerview.useDefaultLoadMore() // recyclerview.useDefaultLoadMore()
recyclerview.setLoadMoreListener { // recyclerview.setLoadMoreListener {
//
// }
lifecycleScope.launch {
viewModel.messageList.collectLatest {
messageAdapter.submitData(it)
} }
recyclerview.adapter = adapter }
// homeViewModel.getMessageList().observe(viewLifecycleOwner, Observer { contacts -> // messageAdapter.withLoadStateFooter(
// adapter.setItem(contacts) // footer = RecLoadStateAdapter { messageAdapter.retry() }
// }) // )
// messageAdapter.withLoadStateHeader()
recyclerview.adapter = messageAdapter
} }
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
getMessageList() viewModel.getNetMessageList()
}
private fun getMessageList() {
viewModel.getMessageList()
} }

View File

@ -0,0 +1,57 @@
package com.navinfo.volvo.ui.fragments.home
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.PagingData
import com.navinfo.volvo.database.dao.GreetingMessageDao
import com.navinfo.volvo.database.entity.GreetingMessage
import com.navinfo.volvo.model.messagelist.NetworkMessageListPost
import com.navinfo.volvo.repository.database.DatabaseRepository
import com.navinfo.volvo.repository.network.NetworkRepository
import com.navinfo.volvo.util.NetResult
import com.navinfo.volvo.util.asLiveData
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import javax.inject.Inject
class HomeViewModel @Inject constructor(
private val netRepository: NetworkRepository,
private val dataRepository: DatabaseRepository
) : ViewModel() {
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()
fun getNetMessageList() {
_isLoading.postValue(true)
viewModelScope.launch {
val messagePost = NetworkMessageListPost(who = "", toWho = "")
when (val result = netRepository.getCardList(messagePost)) {
is NetResult.Success -> {
_isLoading.value = false
// if (result.data != null) {
// val list = (result.data.data as NetworkMessageListResponse).rows
// _messageList.value = list
// }
}
is NetResult.Error -> {
_isLoading.value = false
}
is NetResult.Loading -> {
_isLoading.postValue(true)
}
}
}
}
}

View File

@ -1,48 +0,0 @@
package com.navinfo.volvo.ui.fragments.home
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.navinfo.volvo.database.entity.GreetingMessage
import com.navinfo.volvo.model.messagelist.NetworkMessageListPost
import com.navinfo.volvo.model.messagelist.NetworkMessageListResponse
import com.navinfo.volvo.repository.NetworkDataSource
import com.navinfo.volvo.util.NetResult
import com.navinfo.volvo.util.asLiveData
import kotlinx.coroutines.launch
import javax.inject.Inject
class MessageViewModel @Inject constructor(
private val repository: NetworkDataSource
) : ViewModel() {
private val _isLoading = MutableLiveData<Boolean>()
val isLoading = _isLoading.asLiveData()
private val _messageList = MutableLiveData<List<GreetingMessage>>()
val messageList = _messageList.asLiveData()
fun getMessageList() {
_isLoading.postValue(true)
viewModelScope.launch {
val messagePost = NetworkMessageListPost(who = "北京测试", toWho = "volvo测试")
when (val result = repository.getCardList(messagePost)) {
is NetResult.Success -> {
_isLoading.value = false
if (result.data != null) {
val list = (result.data.data as NetworkMessageListResponse).rows
_messageList.value = list
}
}
is NetResult.Error -> {
_isLoading.value = false
}
is NetResult.Loading -> {
_isLoading.postValue(true)
}
}
}
}
}

View File

@ -0,0 +1,51 @@
//package com.navinfo.volvo.ui.fragments.home
//
//import android.view.LayoutInflater
//import android.view.View
//import android.view.ViewGroup
//import androidx.core.view.isVisible
//import androidx.paging.LoadState
//import androidx.paging.LoadStateAdapter
//import androidx.recyclerview.widget.RecyclerView
//import com.example.picsapp.R
//import com.example.picsapp.databinding.LoadStateViewBinding
//
//class RecLoadStateAdapter(
// private val retry: () -> Unit
//) : LoadStateAdapter<RecLoadStateAdapter.LoadStateViewHolder>() {
//
// override fun onCreateViewHolder(parent: ViewGroup, loadState: LoadState): LoadStateViewHolder {
//
// val binding = LoadStateViewBinding
// .inflate(LayoutInflater.from(parent.context), parent, false)
//
// return LoadStateViewHolder(binding)
// }
//
// override fun onBindViewHolder(holder: LoadStateViewHolder, loadState: LoadState) {
// holder.onBind(loadState)
//
// }
//
//
//
// inner class LoadStateViewHolder(private val binding: LoadStateViewBinding) : RecyclerView.ViewHolder(binding.root){
// fun onBind(loadState: LoadState) {
// val progress = binding.loadStateProgress
// val btnRetry = binding.loadStateRetry
// val txtErrorMessage = binding.loadStateErrorMessage
//
// btnRetry.isVisible = loadState !is LoadState.Loading
// txtErrorMessage.isVisible = loadState !is LoadState.Loading
// progress.isVisible = loadState is LoadState.Loading
//
// if (loadState is LoadState.Error){
// txtErrorMessage.text = loadState.error.localizedMessage
// }
//
// btnRetry.setOnClickListener {
// retry.invoke()
// }
// }
// }
//}

View File

@ -4,14 +4,12 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment import androidx.databinding.DataBindingUtil
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.navigation.Navigation
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.navinfo.volvo.R import com.navinfo.volvo.R
import com.navinfo.volvo.databinding.FragmentLoginBinding import com.navinfo.volvo.databinding.FragmentLoginBinding
import com.navinfo.volvo.ui.BaseFragment import com.navinfo.volvo.ui.fragments.BaseFragment
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
@ -19,11 +17,8 @@ import dagger.hilt.android.AndroidEntryPoint
class LoginFragment : BaseFragment() { class LoginFragment : BaseFragment() {
// private var loginViewModel:LoginViewModel by viewModel(get()) // private var loginViewModel:LoginViewModel by viewModel(get())
private var viewBinding: FragmentLoginBinding? = null private lateinit var viewBinding: FragmentLoginBinding
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = viewBinding!!
private val viewModel by viewModels<LoginViewModel> { viewModelFactoryProvider } private val viewModel by viewModels<LoginViewModel> { viewModelFactoryProvider }
@ -32,20 +27,21 @@ class LoginFragment : BaseFragment() {
container: ViewGroup?, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?
): View { ): View {
viewBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_login, container, false)
viewBinding = FragmentLoginBinding.inflate(inflater, container, false) viewBinding.lifecycleOwner = this
val root: View = binding.root initView()
binding.loginFragmentRegisterButton.setOnClickListener { return viewBinding.root
} }
binding.loginFragmentLoginButton.setOnClickListener {
private fun initView() {
viewBinding.loginFragmentRegisterButton.setOnClickListener {
}
viewBinding.loginFragmentLoginButton.setOnClickListener {
// viewModel.login(viewBinding.loginFragmentUserLayout)
findNavController().navigate(R.id.action_login_to_home) findNavController().navigate(R.id.action_login_to_home)
} }
return root
} }
override fun onDestroyView() {
viewBinding = null
super.onDestroyView()
}
} }

View File

@ -6,14 +6,12 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.navinfo.volvo.database.AppDatabase import com.navinfo.volvo.database.AppDatabase
import com.navinfo.volvo.database.entity.User import com.navinfo.volvo.database.entity.User
import com.navinfo.volvo.util.SharedPreferenceHelper
import javax.inject.Inject import javax.inject.Inject
class LoginViewModel @Inject constructor(private val dataBase: AppDatabase) : ViewModel() { class LoginViewModel @Inject constructor(private val sharedPreferenceHelper: SharedPreferenceHelper) : ViewModel() {
private val _user = MutableLiveData<User>().apply { // val user: LiveData<User> = _user
}
val user: LiveData<User> = _user
fun liveDataOnclick(view: View) { fun liveDataOnclick(view: View) {

View File

@ -2,7 +2,6 @@ package com.navinfo.volvo.ui.fragments.message
import android.content.DialogInterface import android.content.DialogInterface
import android.graphics.Paint import android.graphics.Paint
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.text.TextUtils import android.text.TextUtils
import android.view.LayoutInflater import android.view.LayoutInflater
@ -17,18 +16,13 @@ import android.widget.Toast
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.widget.addTextChangedListener import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import androidx.navigation.Navigation import androidx.navigation.Navigation
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.easytools.tools.DateUtils import com.easytools.tools.DateUtils
import com.easytools.tools.DeviceUtils
import com.easytools.tools.DisplayUtils import com.easytools.tools.DisplayUtils
import com.easytools.tools.FileIOUtils import com.easytools.tools.FileIOUtils
import com.easytools.tools.FileUtils
import com.easytools.tools.ResourceUtils import com.easytools.tools.ResourceUtils
import com.easytools.tools.ToastUtils import com.easytools.tools.ToastUtils
import com.elvishew.xlog.XLog import com.elvishew.xlog.XLog
@ -51,6 +45,7 @@ import com.navinfo.volvo.database.entity.AttachmentType
import com.navinfo.volvo.database.entity.GreetingMessage import com.navinfo.volvo.database.entity.GreetingMessage
import com.navinfo.volvo.databinding.FragmentObtainMessageBinding import com.navinfo.volvo.databinding.FragmentObtainMessageBinding
import com.navinfo.volvo.http.DownloadCallback import com.navinfo.volvo.http.DownloadCallback
import com.navinfo.volvo.model.VolvoModel
import com.navinfo.volvo.ui.markRequiredInRed import com.navinfo.volvo.ui.markRequiredInRed
import com.navinfo.volvo.util.PhotoLoader import com.navinfo.volvo.util.PhotoLoader
import com.navinfo.volvo.utils.EasyMediaFile import com.navinfo.volvo.utils.EasyMediaFile
@ -62,8 +57,8 @@ import top.zibin.luban.Luban
import top.zibin.luban.OnCompressListener import top.zibin.luban.OnCompressListener
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.io.FileOutputStream
import java.util.* import java.util.*
import kotlin.streams.toList
//@RuntimePermissions //@RuntimePermissions
@ -81,6 +76,7 @@ class ObtainMessageFragment: Fragment() {
private val dateSendFormat = "yyyy-MM-dd HH:mm:ss" private val dateSendFormat = "yyyy-MM-dd HH:mm:ss"
private val dateShowFormat = "yyyy-MM-dd HH:mm" private val dateShowFormat = "yyyy-MM-dd HH:mm"
private var startRecordTime = System.currentTimeMillis()
// This property is only valid between onCreateView and // This property is only valid between onCreateView and
// onDestroyView. // onDestroyView.
@ -186,13 +182,12 @@ class ObtainMessageFragment: Fragment() {
binding.imgAudioDelete.setOnClickListener { binding.imgAudioDelete.setOnClickListener {
obtainMessageViewModel.updateMessageAudio("") obtainMessageViewModel.updateMessageAudio("")
} }
val sendToArray = mutableListOf<VolvoModel>(VolvoModel("XC60", "智雅", "LYVXFEFEXNL754427"))
val sendToArray = mutableListOf<String>("绑定车辆1(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) android.R.layout.simple_dropdown_item_1line, android.R.id.text1, sendToArray.stream().map { it -> "${it.version} ${it.model} ${it.num}" }.toList())
binding.edtSendTo.onItemSelectedListener = object: OnItemSelectedListener { binding.edtSendTo.onItemSelectedListener = object: OnItemSelectedListener {
override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) { override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
obtainMessageViewModel.getMessageLiveData().value?.toWho = sendToArray[p2] obtainMessageViewModel.getMessageLiveData().value?.toWho = sendToArray[p2].num
} }
override fun onNothingSelected(p0: AdapterView<*>?) { override fun onNothingSelected(p0: AdapterView<*>?) {
@ -326,10 +321,15 @@ class ObtainMessageFragment: Fragment() {
MotionEvent.ACTION_DOWN-> { MotionEvent.ACTION_DOWN-> {
// 申请权限 // 申请权限
recorderLifecycleObserver.initAndStartRecorder() recorderLifecycleObserver.initAndStartRecorder()
ToastUtils.showToast("开始录音!") startRecordTime = System.currentTimeMillis()
false false
} }
MotionEvent.ACTION_UP -> { MotionEvent.ACTION_UP -> {
if (System.currentTimeMillis() - startRecordTime<2000) {
ToastUtils.showToast("录音时间太短!")
recorderLifecycleObserver.stopAndReleaseRecorder()
return
}
val recorderAudioPath = recorderLifecycleObserver.stopAndReleaseRecorder() val recorderAudioPath = recorderLifecycleObserver.stopAndReleaseRecorder()
if (File(recorderAudioPath).exists()) { if (File(recorderAudioPath).exists()) {
obtainMessageViewModel.updateMessageAudio(recorderAudioPath) obtainMessageViewModel.updateMessageAudio(recorderAudioPath)
@ -556,9 +556,12 @@ class ObtainMessageFragment: Fragment() {
val cal = Calendar.getInstance() val cal = Calendar.getInstance()
cal.time = Date() cal.time = Date()
cal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE)+1) cal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE)+1)
if (cal.time.time < sendDate.time) { // 发送时间设置小于当前时间1分钟前Toast提示用户并自动设置发送时间 if (sendDate.time < cal.time.time) { // 发送时间设置小于当前时间1分钟后Toast提示用户并自动设置发送时间
messageData?.sendDate = DateUtils.date2Str(cal.time, dateSendFormat) messageData?.sendDate = DateUtils.date2Str(cal.time, dateSendFormat)
ToastUtils.showToast("自动调整发送时间为1分钟后发送") ToastUtils.showToast("自动调整发送时间为1分钟后发送")
messageData.version = "1" // 立即发送
} else {
messageData.version = "0" // 预约发送
} }
// 开始网络提交数据 // 开始网络提交数据
@ -588,6 +591,7 @@ class ObtainMessageFragment: Fragment() {
val confirmCallback = object: ObtainMessageViewModel.MyConfirmCallback { val confirmCallback = object: ObtainMessageViewModel.MyConfirmCallback {
override fun onSucess() { override fun onSucess() {
findNavController().navigate(R.id.navigation_home)
} }
} }

View File

@ -23,9 +23,10 @@ import okhttp3.RequestBody
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.util.* import java.util.*
import javax.inject.Inject
class ObtainMessageViewModel: ViewModel() { class ObtainMessageViewModel @Inject constructor(): ViewModel() {
private val msgLiveData: MutableLiveData<GreetingMessage> by lazy { private val msgLiveData: MutableLiveData<GreetingMessage> by lazy {
MutableLiveData<GreetingMessage>() MutableLiveData<GreetingMessage>()
} }
@ -232,7 +233,8 @@ class ObtainMessageViewModel: ViewModel() {
"mediaUrl" to message?.mediaUrl, "mediaUrl" to message?.mediaUrl,
"who" to message?.who, "who" to message?.who,
"toWho" to message?.toWho, "toWho" to message?.toWho,
"sendDate" to message?.sendDate "sendDate" to message?.sendDate,
"version" to message?.version
) )
val result = NavinfoVolvoCall.getApi().insertCardByApp(insertData as Map<String, String>) val result = NavinfoVolvoCall.getApi().insertCardByApp(insertData as Map<String, String>)
XLog.d("insertCardByApp:${result.code}") XLog.d("insertCardByApp:${result.code}")
@ -264,7 +266,8 @@ class ObtainMessageViewModel: ViewModel() {
"mediaUrl" to message?.mediaUrl, "mediaUrl" to message?.mediaUrl,
"who" to message?.who, "who" to message?.who,
"toWho" to message?.toWho, "toWho" to message?.toWho,
"sendDate" to message?.sendDate "sendDate" to message?.sendDate,
"version" to message?.version
) )
val result = NavinfoVolvoCall.getApi().updateCardByApp(updateData as Map<String, String>) val result = NavinfoVolvoCall.getApi().updateCardByApp(updateData as Map<String, String>)
XLog.d("updateCardByApp:${result.code}") XLog.d("updateCardByApp:${result.code}")

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

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<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>
<import type="android.view.View" />
<variable
name="greetingMessage"
type="com.navinfo.volvo.database.entity.GreetingMessage" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/message_head_icon"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginLeft="8dp"
android:src="@mipmap/volvo_logo_small"
app:layout_constraintBottom_toBottomOf="parent"
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="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_constraintRight_toLeftOf="@id/message_send_time"
app:layout_constraintTop_toTopOf="@id/message_head_icon" />
<TextView
android:id="@+id/message_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
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_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=l023x01x03x14x34x34}"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/message_head_icon" />
<TextView
android:id="@+id/message_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="@{greetingMessage.status,default=消息状态很长的文字}"
app:layout_constraintBottom_toBottomOf="@id/message_head_icon"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -1,54 +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="wrap_content">
<ImageView
android:id="@+id/message_head_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:src="@mipmap/volvo_logo_small"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/message_to_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="问候对象"
android:ellipsize="end"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintLeft_toRightOf="@id/message_head_icon"
app:layout_constraintTop_toTopOf="@id/message_head_icon" />
<TextView
android:id="@+id/message_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="信息内容"
app:layout_constraintBottom_toBottomOf="@id/message_head_icon"
app:layout_constraintLeft_toRightOf="@id/message_head_icon" />
<TextView
android:id="@+id/message_send_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="8dp"
android:text="日期"
app:layout_constraintTop_toTopOf="@id/message_head_icon"
app:layout_constraintEnd_toEndOf="parent"
/>
<TextView
android:id="@+id/message_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:text="状态"
app:layout_constraintBottom_toBottomOf="@id/message_head_icon"
app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,10 +1,39 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<com.yanzhenjie.recyclerview.SwipeRecyclerView <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/home_message_recyclerview"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" 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_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context=".ui.fragments.home.MessageFragment"> tools:context=".ui.fragments.home.HomeFragment">
</com.yanzhenjie.recyclerview.SwipeRecyclerView>
<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">
<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:id="@+id/home_recyclerview"
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,7 +1,15 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" <layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="loginUser"
type="com.navinfo.volvo.model.LoginUser" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
tools:context="com.navinfo.volvo.ui.fragments.login.LoginFragment"> tools:context="com.navinfo.volvo.ui.fragments.login.LoginFragment">
@ -11,7 +19,7 @@
android:id="@+id/login_fragment_logo" android:id="@+id/login_fragment_logo"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher" android:src="@mipmap/volvo_logo_small"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
@ -34,7 +42,8 @@
<com.google.android.material.textfield.TextInputEditText <com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="用户名" /> android:text="@{loginUser.name}"
android:hint="请输入用户名" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout <com.google.android.material.textfield.TextInputLayout
@ -47,7 +56,9 @@
<com.google.android.material.textfield.TextInputEditText <com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="密码" /> android:inputType="textPassword"
android:text="@{loginUser.password}"
android:hint="请输入密码" />
</com.google.android.material.textfield.TextInputLayout> </com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
@ -75,4 +86,5 @@
app:layout_constraintLeft_toRightOf="@id/login_fragment_register_button" app:layout_constraintLeft_toRightOf="@id/login_fragment_register_button"
app:layout_constraintRight_toRightOf="parent" /> app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@ -365,7 +365,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
style="@style/Widget.Material3.Button.ElevatedButton" style="@style/Widget.Material3.Button.ElevatedButton"
app:icon="@drawable/ic_baseline_access_time_24" app:icon="@drawable/ic_baseline_access_time_24"
android:text="现在" android:text="选择时间"
android:padding="@dimen/default_widget_padding"></com.google.android.material.button.MaterialButton> android:padding="@dimen/default_widget_padding"></com.google.android.material.button.MaterialButton>
</LinearLayout> </LinearLayout>
<com.nhaarman.supertooltips.ToolTipRelativeLayout <com.nhaarman.supertooltips.ToolTipRelativeLayout

View File

@ -2,7 +2,7 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <menu xmlns:android="http://schemas.android.com/apk/res/android">
<item <item
android:id="@+id/navigation_message" android:id="@+id/navigation_home"
android:icon="@drawable/ic_home_black_24dp" android:icon="@drawable/ic_home_black_24dp"
android:title="@string/title_home" /> android:title="@string/title_home" />
<item <item
@ -25,6 +25,6 @@
<item <item
android:id="@+id/navigation_obtain_message" android:id="@+id/navigation_obtain_message"
android:icon="@drawable/ic_baseline_mail_24" android:icon="@drawable/ic_baseline_mail_24"
android:title="消息" /> android:title="我的" />
</menu> </menu>

View File

@ -12,7 +12,7 @@
tools:layout="@layout/fragment_login"> tools:layout="@layout/fragment_login">
<action <action
android:id="@+id/action_login_to_home" android:id="@+id/action_login_to_home"
app:destination="@id/navigation_message" app:destination="@id/navigation_home"
app:enterAnim="@anim/from_left" app:enterAnim="@anim/from_left"
app:exitAnim="@anim/to_right" app:exitAnim="@anim/to_right"
app:popEnterAnim="@anim/from_right" app:popEnterAnim="@anim/from_right"
@ -21,8 +21,8 @@
app:popUpToInclusive="true" /> app:popUpToInclusive="true" />
</fragment> </fragment>
<fragment <fragment
android:id="@+id/navigation_message" android:id="@+id/navigation_home"
android:name="com.navinfo.volvo.ui.fragments.home.MessageFragment" android:name="com.navinfo.volvo.ui.fragments.home.HomeFragment"
android:label="@string/title_home" android:label="@string/title_home"
tools:layout="@layout/fragment_home"></fragment> tools:layout="@layout/fragment_home"></fragment>
@ -48,5 +48,16 @@
android:id="@+id/navigation_obtain_message" android:id="@+id/navigation_obtain_message"
android:name="com.navinfo.volvo.ui.fragments.message.ObtainMessageFragment" android:name="com.navinfo.volvo.ui.fragments.message.ObtainMessageFragment"
android:label="问候编辑" android:label="问候编辑"
tools:layout="@layout/fragment_obtain_message" /> 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> </navigation>

View File

@ -1,9 +1,18 @@
<resources> <resources>
<string name="app_name">NavinfoVolvo</string> <string name="app_name">VolvoMessage</string>
<string name="title_home">Home</string> <string name="title_home">问候</string>
<string name="title_dashboard">Dashboard</string> <string name="title_dashboard">Dashboard</string>
<string name="title_notifications">Notifications</string> <string name="title_notifications">Notifications</string>
<string name="delete">删除</string> <string name="delete">删除</string>
<string name="share">分享</string> <string name="share">分享</string>
<string name="my">我的</string> <string name="my">我的</string>
<string name="title_activity_second">SecondActivity</string>
<!-- Strings used for fragments for navigation -->
<string name="first_fragment_label">First Fragment</string>
<string name="second_fragment_label">Second Fragment</string>
<string name="next">Next</string>
<string name="previous">Previous</string>
<string name="hello_first_fragment">Hello first fragment</string>
<string name="hello_second_fragment">Hello second fragment. Arg: %1$s</string>
</resources> </resources>

View File

@ -9,4 +9,5 @@
<color name="white">#FFFFFFFF</color> <color name="white">#FFFFFFFF</color>
<color name="red">#FFFF0000</color> <color name="red">#FFFF0000</color>
<color name="gray">#5E5E5E</color> <color name="gray">#5E5E5E</color>
<color name="gray1">#D2CACA</color>
</resources> </resources>

View File

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