diff --git a/app/build.gradle b/app/build.gradle
index 0210770..a020d87 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -2,9 +2,10 @@ plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-android'
- id 'kotlin-parcelize'
+ id 'kotlin-parcelize' // 序列化
id 'kotlin-kapt'
- id 'dagger.hilt.android.plugin'
+ id 'dagger.hilt.android.plugin' //hilt 依赖注入
+ id "com.google.protobuf" version "0.8.17" //Proto DataStore 插件
// id 'com.google.dagger.hilt.android'
}
@@ -82,7 +83,7 @@ dependencies {
//room 数据库相关
implementation 'com.tencent.wcdb:room:1.1-19' // 代替 room-runtime,同时也不需要再引用 wcdb-android
- api 'androidx.sqlite:sqlite:2.2.0'
+ implementation 'androidx.sqlite:sqlite-ktx:2.2.0'
implementation 'androidx.room:room-runtime:2.4.3'
implementation 'androidx.room:room-ktx:2.4.3'
annotationProcessor 'androidx.room:room-compiler:2.4.3'
@@ -90,13 +91,12 @@ dependencies {
kapt 'android.arch.persistence.room:compiler:1.1.1'// compiler 需要用 room 的
kapt 'androidx.room:room-compiler: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"
-// implementation "android.arch.lifecycle:extensions:1.1.1"
-// annotationProcessor "android.arch.lifecycle:compiler:1.1.1"
implementation 'com.tencent.wcdb:wcdb-android:1.1-19'
@@ -108,29 +108,20 @@ dependencies {
//带侧滑的自定义列表
implementation 'com.yanzhenjie.recyclerview:x:1.3.2'
-// implementation 'androidx.appcompat:appcompat:1.5.1'
-
-// // Koin
-// implementation("io.insert-koin:koin-android:3.3.2")
-// implementation("io.insert-koin:koin-core:3.3.2")
+ //下拉刷新,上拉加载
+ implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
// 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")
-// const val chuck = "com.readystatesoftware.chuck:library:${Versions.chuck}"
-// const val chuckNoOp = "com.readystatesoftware.chuck:library-no-op:${Versions.chuck}"
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")
-
//hilt
implementation "com.google.dagger:hilt-android:2.41"
kapt "com.google.dagger:hilt-compiler:2.41"
-// implementation "androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03"
-// androidTestImplementation "com.google.dagger:hilt-android-testing:2.41"
-// kaptAndroidTest "com.google.dagger:hilt-android-compiler:2.41"
// 显示错误提示 https://github.com/nhaarman/supertooltips
implementation 'com.nhaarman.supertooltips:library:3.0.0'
@@ -155,6 +146,30 @@ dependencies {
// 图片查看器 https://github.com/XiaoGe-1996/ImageViewer
implementation 'com.github.XiaoGe-1996:ImageViewer:v1.0.0'
implementation 'com.github.majidarabi:AndroidFilePicker:0.2.1'
+ // 数据存储 Preferences DataStore 键值对
+ implementation "androidx.datastore:datastore-preferences:1.0.0"
+ // 数据存储 Proto DataStore 对象
+ implementation "androidx.datastore:datastore-core:1.0.0"
+ implementation "com.google.protobuf:protobuf-javalite:3.18.0"
+}
+
+//Proto DataStore 数据存储插件
+protobuf {
+ protoc {
+ artifact = "com.google.protobuf:protoc:3.14.0"
+ }
+ // Generates the java Protobuf-lite code for the Protobufs in this project. See
+ // https://github.com/google/protobuf-gradle-plugin#customizing-protobuf-compilation
+ // for more information.
+ generateProtoTasks {
+ all().each { task ->
+ task.builtins {
+ java {
+ option 'lite'
+ }
+ }
+ }
+ }
}
kapt {
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d539e1e..8bfd0a9 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -24,14 +24,15 @@
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/volvo_logo_small"
- android:requestLegacyExternalStorage="true"
android:label="@string/app_name"
+ android:requestLegacyExternalStorage="true"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.NavinfoVolvo"
android:usesCleartextTraffic="true">
-
+
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/Constant.kt b/app/src/main/java/com/navinfo/volvo/Constant.kt
index 60c9260..0af2369 100644
--- a/app/src/main/java/com/navinfo/volvo/Constant.kt
+++ b/app/src/main/java/com/navinfo/volvo/Constant.kt
@@ -9,6 +9,8 @@ class Constant {
*/
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 message_status_late = "预约,待发送"
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/MyApplication.kt b/app/src/main/java/com/navinfo/volvo/MyApplication.kt
index d076fd5..d8aa2ba 100644
--- a/app/src/main/java/com/navinfo/volvo/MyApplication.kt
+++ b/app/src/main/java/com/navinfo/volvo/MyApplication.kt
@@ -1,8 +1,39 @@
package com.navinfo.volvo
+import android.app.Activity
import android.app.Application
+import android.content.pm.ActivityInfo
+import android.os.Bundle
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
open class MyApplication : Application() {
+ override fun onCreate() {
+ super.onCreate()
+
+ registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks {
+
+ override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
+ activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
+ }
+
+ override fun onActivityStarted(activity: Activity) {
+ }
+
+ override fun onActivityResumed(activity: Activity) {
+ }
+
+ override fun onActivityPaused(activity: Activity) {
+ }
+
+ override fun onActivityStopped(activity: Activity) {
+ }
+
+ override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
+ }
+
+ override fun onActivityDestroyed(activity: Activity) {
+ }
+ })
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/database/MapLifeDataBase.java b/app/src/main/java/com/navinfo/volvo/database/MapLifeDataBase.java
deleted file mode 100644
index f1ebae1..0000000
--- a/app/src/main/java/com/navinfo/volvo/database/MapLifeDataBase.java
+++ /dev/null
@@ -1,191 +0,0 @@
-//package com.navinfo.volvo.database;
-//
-//
-//import android.content.Context;
-//
-//import androidx.annotation.NonNull;
-//import androidx.room.Database;
-//import androidx.room.Room;
-//import androidx.room.RoomDatabase;
-//import androidx.sqlite.db.SupportSQLiteDatabase;
-//import androidx.sqlite.db.SupportSQLiteOpenHelper;
-//
-//import com.navinfo.volvo.database.dao.MessageDao;
-//import com.navinfo.volvo.database.dao.UserDao;
-//import com.navinfo.volvo.database.entity.Message;
-//import com.navinfo.volvo.database.entity.Attachment;
-//import com.navinfo.volvo.database.entity.User;
-//import com.tencent.wcdb.database.SQLiteCipherSpec;
-//import com.tencent.wcdb.database.SQLiteDatabase;
-//
-//import com.tencent.wcdb.room.db.WCDBOpenHelperFactory;
-//
-//import android.os.AsyncTask;
-//import android.util.Log;
-//
-//import com.tencent.wcdb.repair.BackupKit;
-//import com.tencent.wcdb.repair.RecoverKit;
-//import com.tencent.wcdb.room.db.WCDBDatabase;
-//
-//@Database(entities = {Message.class, Attachment.class, User.class}, version = 1, exportSchema = false)
-//public abstract class MapLifeDataBase extends RoomDatabase {
-// // marking the instance as volatile to ensure atomic access to the variable
-// /**
-// * 数据库单例对象
-// */
-// private static volatile MapLifeDataBase INSTANCE;
-//
-// /**
-// * 要素数据库类
-// */
-// public abstract MessageDao getMessageDao();
-//
-// public abstract UserDao getUserDao();
-//
-// /**
-// * 数据库秘钥
-// */
-// private final static String DB_PASSWORD = "123456";
-//
-// public static MapLifeDataBase getDatabase(final Context context, final String name) {
-// if (INSTANCE == null) {
-// synchronized (MapLifeDataBase.class) {
-// if (INSTANCE == null) {
-// // [WCDB] To use Room library with WCDB, pass a WCDBOpenHelper factory object
-// // to the database builder with .openHelperFactory(...). In the factory object,
-// // you can specify passphrase and cipher options to open or create encrypted
-// // database, as well as optimization options like asynchronous checkpoint.
-// SQLiteCipherSpec cipherSpec = new SQLiteCipherSpec()
-// .setPageSize(1024)
-// .setSQLCipherVersion(3);
-// WCDBOpenHelperFactory factory = new WCDBOpenHelperFactory()
-// .passphrase(DB_PASSWORD.getBytes()) // passphrase to the database, remove this line for plain-text
-// .cipherSpec(cipherSpec) // cipher to use, remove for default settings
-// .writeAheadLoggingEnabled(true) // enable WAL mode, remove if not needed
-// .asyncCheckpointEnabled(true); // enable asynchronous checkpoint, remove if not needed
-//
-// INSTANCE = Room.databaseBuilder(context.getApplicationContext(), MapLifeDataBase.class, name)
-//
-// // [WCDB] Specify open helper to use WCDB database implementation instead
-// // of the Android framework.
-// .openHelperFactory((SupportSQLiteOpenHelper.Factory) factory)
-//
-// // Wipes and rebuilds instead of migrating if no Migration object.
-// // Migration is not part of this codelab.
-// .fallbackToDestructiveMigration().addCallback(sRoomDatabaseCallback).build();
-// }
-// }
-// }
-// return INSTANCE;
-// }
-//
-// /**
-// * Override the onOpen method to populate the database.
-// * For this sample, we clear the database every time it is created or opened.
-// *
-// * If you want to populate the database only when the database is created for the 1st time,
-// * override RoomDatabase.Callback()#onCreate
-// */
-// private static Callback sRoomDatabaseCallback = new Callback() {
-//
-// @Override
-// public void onOpen(@NonNull SupportSQLiteDatabase db) {
-// super.onOpen(db);
-// // If you want to keep the data through app restarts,
-// // comment out the following line.
-// new PopulateDbAsync(INSTANCE).execute();
-// }
-// };
-//
-// /**
-// * Populate the database in the background.
-// * If you want to start with more words, just add them.
-// */
-// private static class PopulateDbAsync extends AsyncTask {
-//
-// private final MessageDao messageDao;
-//
-// PopulateDbAsync(MapLifeDataBase db) {
-// messageDao = db.getMessageDao();
-// }
-//
-// @Override
-// protected Void doInBackground(final Void... params) {
-// // Start the app with a clean database every time.
-// // Not needed if you only populate on creation.
-// //mDao.deleteAll();
-// Log.e("qj", "doInBackground");
-// return null;
-// }
-// }
-//
-// /**
-// * 数据恢复
-// */
-// protected boolean recoverData() {
-// if (INSTANCE != null) {
-// SQLiteDatabase sqlite = ((WCDBDatabase) INSTANCE.getOpenHelper().getWritableDatabase()).getInnerDatabase();
-// RecoverKit recover = new RecoverKit(sqlite, // 要恢复到的目标 DB
-// sqlite.getPath() + "-backup", // 备份文件
-// DB_PASSWORD.getBytes() // 加密备份文件的密钥,非 DB 密钥
-// );
-// int result = recover.run(false); // fatal 参数传 false 表示遇到错误忽略并继续,
-// // 若传 true 遇到错误则中止并返回 FAILED
-// switch (result) {
-// case RecoverKit.RESULT_OK:
-// /* 成功 */
-// Log.e("qj", "sRoomDatabaseCallback==RecoverKit成功");
-// return true;
-// case RecoverKit.RESULT_CANCELED: /* 取消操作 */
-// Log.e("qj", "sRoomDatabaseCallback==RecoverKit取消操作");
-// break;
-// case RecoverKit.RESULT_FAILED: /* 失败 */
-// Log.e("qj", "sRoomDatabaseCallback==RecoverKit失败");
-// break;
-//
-// }
-//
-// recover.release();
-// }
-//
-// return false;
-// }
-//
-// /**
-// * 备份数据
-// */
-// protected boolean backup() {
-// Log.e("qj", "sRoomDatabaseCallback===backup==start");
-// if (INSTANCE != null) {
-// //备份文件
-// SQLiteDatabase sqlite = ((WCDBDatabase) INSTANCE.getOpenHelper().getWritableDatabase()).getInnerDatabase();
-// BackupKit backup = new BackupKit(sqlite, // 要备份的 DB
-// sqlite.getPath() + "-backup", // 备份文件
-// "123456".getBytes(), // 加密备份文件的密钥,非 DB 密钥
-// 0, null);
-// int result = backup.run();
-// switch (result) {
-// case BackupKit.RESULT_OK:
-// /* 成功 */
-// Log.e("qj", "sRoomDatabaseCallback==成功");
-// return true;
-// case BackupKit.RESULT_CANCELED:
-// /* 取消操作 */
-// Log.e("qj", "sRoomDatabaseCallback==取消操作");
-// break;
-// case BackupKit.RESULT_FAILED:
-// /* 失败 */
-// Log.e("qj", "sRoomDatabaseCallback==失败");
-// break;
-// }
-//
-// backup.release();
-// }
-// Log.e("qj", "sRoomDatabaseCallback===backup==end");
-// return false;
-// }
-//
-// protected void release() {
-// INSTANCE = null;
-// }
-//}
diff --git a/app/src/main/java/com/navinfo/volvo/database/dao/GreetingMessageDao.kt b/app/src/main/java/com/navinfo/volvo/database/dao/GreetingMessageDao.kt
index 3da19ab..26b4c98 100644
--- a/app/src/main/java/com/navinfo/volvo/database/dao/GreetingMessageDao.kt
+++ b/app/src/main/java/com/navinfo/volvo/database/dao/GreetingMessageDao.kt
@@ -1,21 +1,28 @@
package com.navinfo.volvo.database.dao
+import android.util.Log
import androidx.paging.PagingSource
import androidx.room.*
+import com.navinfo.volvo.Constant
import com.navinfo.volvo.database.entity.GreetingMessage
import kotlinx.coroutines.flow.Flow
@Dao
interface GreetingMessageDao {
+ @Query("DELETE from GreetingMessage WHERE id=:id")
+ suspend fun deleteById(id: Long)
+
@Insert
- fun insert(message: GreetingMessage): Long
+ suspend fun insert(message: GreetingMessage): Long
@Update(onConflict = OnConflictStrategy.REPLACE)
- fun update(message: GreetingMessage)
+ suspend fun update(message: GreetingMessage)
-
- @Query("SELECT count(id) FROM GreetingMessage WHERE read = 0")
+ /**
+ * 未读消息统计
+ */
+ @Query("SELECT count(id) FROM GreetingMessage WHERE status = '${Constant.message_status_late}'")
fun countUnreadByFlow(): Flow
/**
@@ -27,18 +34,29 @@ interface GreetingMessageDao {
/**
* 检查某条数据是否存在
*/
- @Query("SELECT id From GreetingMessage WHERE id = :id LIMIT 1")
- fun getMessageId(id: Long): Long
+ @Query("SELECT uuid From GreetingMessage WHERE id = :id LIMIT 1")
+ suspend fun getMessageId(id: Long): Long?
+ /**
+ *
+ */
@Transaction
suspend fun insertOrUpdate(list: List) {
for (message in list) {
- val id = getMessageId(message.id)
- if (id == 0L) {
- insert(message)
- }else{
+ 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 ")
+ } else {
+ message.uuid = uuid
update(message)
}
+ Log.e("jingo", "insertOrUpdate end")
}
}
+
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/di/module/NetworkUtilModule.kt b/app/src/main/java/com/navinfo/volvo/di/module/NetworkUtilModule.kt
index 6e0212e..406016f 100644
--- a/app/src/main/java/com/navinfo/volvo/di/module/NetworkUtilModule.kt
+++ b/app/src/main/java/com/navinfo/volvo/di/module/NetworkUtilModule.kt
@@ -22,6 +22,7 @@ import javax.inject.Singleton
@Module
class NetworkUtilModule {
+
@Provides
@Singleton
fun provideContext(application: Application): Context {
diff --git a/app/src/main/java/com/navinfo/volvo/di/module/UtilModule.kt b/app/src/main/java/com/navinfo/volvo/di/module/UtilModule.kt
index 316e5c5..32af514 100644
--- a/app/src/main/java/com/navinfo/volvo/di/module/UtilModule.kt
+++ b/app/src/main/java/com/navinfo/volvo/di/module/UtilModule.kt
@@ -1,7 +1,13 @@
package com.navinfo.volvo.di.module
import android.content.Context
-import com.navinfo.volvo.util.SharedPreferenceHelper
+import androidx.datastore.core.DataStore
+import androidx.datastore.core.DataStoreFactory
+import androidx.datastore.core.Serializer
+import androidx.datastore.dataStoreFile
+import androidx.datastore.preferences.core.Preferences
+import androidx.datastore.preferences.preferencesDataStore
+import com.navinfo.volvo.model.proto.LoginUser
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@@ -14,7 +20,12 @@ class UtilModule {
@Provides
@Singleton
- fun provideSharedPreferencesHelper(context: Context): SharedPreferenceHelper {
- return SharedPreferenceHelper.getInstance(context)
- }
+ fun provideLoginUserDataStore(
+ context: Context,
+ serializer: Serializer
+ ): DataStore = DataStoreFactory.create(
+ serializer = serializer,
+ produceFile = { context.dataStoreFile("login_user") }
+ )
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/di/module/UtilRepositoryModule.kt b/app/src/main/java/com/navinfo/volvo/di/module/UtilRepositoryModule.kt
new file mode 100644
index 0000000..ec5dd0e
--- /dev/null
+++ b/app/src/main/java/com/navinfo/volvo/di/module/UtilRepositoryModule.kt
@@ -0,0 +1,22 @@
+package com.navinfo.volvo.di.module
+
+import androidx.datastore.core.Serializer
+import com.navinfo.volvo.model.proto.LoginUser
+import com.navinfo.volvo.model.proto.LoginUserSerializer
+import com.navinfo.volvo.repository.preferences.PreferencesRepository
+import com.navinfo.volvo.repository.preferences.PreferencesRepositoryImp
+import dagger.Binds
+import dagger.Module
+import dagger.hilt.InstallIn
+import dagger.hilt.components.SingletonComponent
+import javax.inject.Singleton
+
+@InstallIn(SingletonComponent::class)
+@Module
+abstract class UtilRepositoryModule {
+ @Binds
+ abstract fun providePreferencesRepository(preferencesRepositoryImp: PreferencesRepositoryImp): PreferencesRepository
+
+ @Binds
+ abstract fun userLocalSerializer(impl: LoginUserSerializer): Serializer
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/di/module/ViewModelFactory.kt b/app/src/main/java/com/navinfo/volvo/di/module/ViewModelFactory.kt
index 079be5e..93bd5ce 100644
--- a/app/src/main/java/com/navinfo/volvo/di/module/ViewModelFactory.kt
+++ b/app/src/main/java/com/navinfo/volvo/di/module/ViewModelFactory.kt
@@ -1,35 +1,35 @@
-package com.navinfo.volvo.di.module
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import javax.inject.Inject
-import javax.inject.Provider
-import javax.inject.Singleton
-
-
-/**
- * Factory for all ViewModels.
- * reference : https://github.com/googlesamples/android-architecture-components
- */
-@Singleton
-class ViewModelFactory @Inject constructor(
- private val viewModelMap: Map, @JvmSuppressWildcards Provider>
-) : ViewModelProvider.Factory {
-
- @Suppress("UNCHECKED_CAST")
- override fun create(modelClass: Class): T {
- var viewModel = viewModelMap[modelClass]
-
- if (viewModel == null) {
- for (entry in viewModelMap) {
- if (modelClass.isAssignableFrom(entry.key)) {
- viewModel = entry.value
- break
- }
- }
- }
-
- if (viewModel == null) throw IllegalArgumentException("Unknown model class $modelClass")
- return viewModel.get() as T
- }
-}
+//package com.navinfo.volvo.di.module
+//
+//import androidx.lifecycle.ViewModel
+//import androidx.lifecycle.ViewModelProvider
+//import javax.inject.Inject
+//import javax.inject.Provider
+//import javax.inject.Singleton
+//
+//
+///**
+// * Factory for all ViewModels.
+// * reference : https://github.com/googlesamples/android-architecture-components
+// */
+//@Singleton
+//class ViewModelFactory @Inject constructor(
+// private val viewModelMap: Map, @JvmSuppressWildcards Provider>
+//) : ViewModelProvider.Factory {
+//
+// @Suppress("UNCHECKED_CAST")
+// override fun create(modelClass: Class): T {
+// var viewModel = viewModelMap[modelClass]
+//
+// if (viewModel == null) {
+// for (entry in viewModelMap) {
+// if (modelClass.isAssignableFrom(entry.key)) {
+// viewModel = entry.value
+// break
+// }
+// }
+// }
+//
+// if (viewModel == null) throw IllegalArgumentException("Unknown model class $modelClass")
+// return viewModel.get() as T
+// }
+//}
diff --git a/app/src/main/java/com/navinfo/volvo/di/module/ViewModelModule.kt b/app/src/main/java/com/navinfo/volvo/di/module/ViewModelModule.kt
index ec45c18..611e8fa 100644
--- a/app/src/main/java/com/navinfo/volvo/di/module/ViewModelModule.kt
+++ b/app/src/main/java/com/navinfo/volvo/di/module/ViewModelModule.kt
@@ -1,44 +1,44 @@
-package com.navinfo.volvo.di.module
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.ViewModelProvider
-import com.navinfo.volvo.di.key.ViewModelKey
-import com.navinfo.volvo.ui.MainActivityViewModel
-import com.navinfo.volvo.ui.fragments.home.HomeViewModel
-import com.navinfo.volvo.ui.fragments.login.LoginViewModel
-import com.navinfo.volvo.ui.fragments.message.ObtainMessageViewModel
-import dagger.Binds
-import dagger.Module
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-import dagger.multibindings.IntoMap
-
-@InstallIn(SingletonComponent::class)
-@Module
-abstract class ViewModelModule {
-
- @Binds
- abstract fun bindViewModelFactory(viewModelFactory: ViewModelFactory): ViewModelProvider.Factory
-
- @IntoMap
- @Binds
- @ViewModelKey(MainActivityViewModel::class)
- abstract fun bindMainViewModel(viewModel: MainActivityViewModel): ViewModel
-
- @IntoMap
- @Binds
- @ViewModelKey(LoginViewModel::class)
- abstract fun bindLoginFragmentViewModel(viewModel: LoginViewModel): ViewModel
-
- @IntoMap
- @Binds
- @ViewModelKey(HomeViewModel::class)
- abstract fun bindMessageFragmentViewModel(viewModel: HomeViewModel): ViewModel
-
- @IntoMap
- @Binds
- @ViewModelKey(ObtainMessageViewModel::class)
- abstract fun bindObtainMessageFragmentViewModel(viewModel: ObtainMessageViewModel): ViewModel
-
-
-}
\ No newline at end of file
+//package com.navinfo.volvo.di.module
+//
+//import androidx.lifecycle.ViewModel
+//import androidx.lifecycle.ViewModelProvider
+//import com.navinfo.volvo.di.key.ViewModelKey
+//import com.navinfo.volvo.ui.MainActivityViewModel
+//import com.navinfo.volvo.ui.fragments.home.HomeViewModel
+//import com.navinfo.volvo.ui.fragments.login.LoginViewModel
+//import com.navinfo.volvo.ui.fragments.message.ObtainMessageViewModel
+//import dagger.Binds
+//import dagger.Module
+//import dagger.hilt.InstallIn
+//import dagger.hilt.components.SingletonComponent
+//import dagger.multibindings.IntoMap
+//
+//@InstallIn(SingletonComponent::class)
+//@Module
+//abstract class ViewModelModule {
+//
+// @Binds
+// abstract fun bindViewModelFactory(viewModelFactory: ViewModelFactory): ViewModelProvider.Factory
+//
+// @IntoMap
+// @Binds
+// @ViewModelKey(MainActivityViewModel::class)
+// abstract fun bindMainViewModel(viewModel: MainActivityViewModel): ViewModel
+//
+// @IntoMap
+// @Binds
+// @ViewModelKey(LoginViewModel::class)
+// abstract fun bindLoginFragmentViewModel(viewModel: LoginViewModel): ViewModel
+//
+// @IntoMap
+// @Binds
+// @ViewModelKey(HomeViewModel::class)
+// abstract fun bindMessageFragmentViewModel(viewModel: HomeViewModel): ViewModel
+//
+// @IntoMap
+// @Binds
+// @ViewModelKey(ObtainMessageViewModel::class)
+// abstract fun bindObtainMessageFragmentViewModel(viewModel: ObtainMessageViewModel): ViewModel
+//
+//
+//}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/model/LoginUser.kt b/app/src/main/java/com/navinfo/volvo/model/LoginUser.kt
deleted file mode 100644
index 1c55d05..0000000
--- a/app/src/main/java/com/navinfo/volvo/model/LoginUser.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package com.navinfo.volvo.model
-
-/**
- * 登录用户信息
- */
-data class LoginUser(
- var name: String,
- var password: String
-)
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/model/messagelist/NetworkMessageListResponse.kt b/app/src/main/java/com/navinfo/volvo/model/network/NetworkMessageListResponse.kt
similarity index 59%
rename from app/src/main/java/com/navinfo/volvo/model/messagelist/NetworkMessageListResponse.kt
rename to app/src/main/java/com/navinfo/volvo/model/network/NetworkMessageListResponse.kt
index 94b7a40..2061065 100644
--- a/app/src/main/java/com/navinfo/volvo/model/messagelist/NetworkMessageListResponse.kt
+++ b/app/src/main/java/com/navinfo/volvo/model/network/NetworkMessageListResponse.kt
@@ -1,8 +1,8 @@
-package com.navinfo.volvo.model.messagelist
+package com.navinfo.volvo.model.network
import com.navinfo.volvo.database.entity.GreetingMessage
data class NetworkMessageListResponse(
val total: Int,
- val rows: List
+ val rows: List?
)
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/model/messagelist/NetworkMessageListPost.kt b/app/src/main/java/com/navinfo/volvo/model/network/NetworkPosts.kt
similarity index 85%
rename from app/src/main/java/com/navinfo/volvo/model/messagelist/NetworkMessageListPost.kt
rename to app/src/main/java/com/navinfo/volvo/model/network/NetworkPosts.kt
index 91d0dd5..2d65102 100644
--- a/app/src/main/java/com/navinfo/volvo/model/messagelist/NetworkMessageListPost.kt
+++ b/app/src/main/java/com/navinfo/volvo/model/network/NetworkPosts.kt
@@ -1,4 +1,4 @@
-package com.navinfo.volvo.model.messagelist
+package com.navinfo.volvo.model.network
data class NetworkMessageListPost(
val name: String,//问候名称,非必填项
@@ -12,4 +12,8 @@ data class NetworkMessageListPost(
constructor(who: String, toWho: String) : this("", who, toWho, "", "", "10", "1") {
}
-}
\ No newline at end of file
+}
+
+data class NetworkDeleteMessagePost(
+ val id: Long
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/model/proto/LoginUserSerializer.kt b/app/src/main/java/com/navinfo/volvo/model/proto/LoginUserSerializer.kt
new file mode 100644
index 0000000..5784ffc
--- /dev/null
+++ b/app/src/main/java/com/navinfo/volvo/model/proto/LoginUserSerializer.kt
@@ -0,0 +1,22 @@
+package com.navinfo.volvo.model.proto
+
+import androidx.datastore.core.CorruptionException
+import androidx.datastore.core.Serializer
+import androidx.datastore.preferences.protobuf.InvalidProtocolBufferException
+import java.io.InputStream
+import java.io.OutputStream
+import javax.inject.Inject
+
+class LoginUserSerializer @Inject constructor(): Serializer {
+ override val defaultValue: LoginUser = LoginUser.getDefaultInstance()
+
+ override suspend fun readFrom(input: InputStream): LoginUser {
+ try {
+ return LoginUser.parseFrom(input)
+ } catch (exception: InvalidProtocolBufferException) {
+ throw CorruptionException("Cannot read proto.", exception)
+ }
+ }
+
+ override suspend fun writeTo(t: LoginUser, output: OutputStream) = t.writeTo(output)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/repository/database/DatabaseRepositoryImp.kt b/app/src/main/java/com/navinfo/volvo/repository/database/DatabaseRepositoryImp.kt
index fcbba0d..7c0b535 100644
--- a/app/src/main/java/com/navinfo/volvo/repository/database/DatabaseRepositoryImp.kt
+++ b/app/src/main/java/com/navinfo/volvo/repository/database/DatabaseRepositoryImp.kt
@@ -11,12 +11,14 @@ 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> {
return Pager(PagingConfig(PAGE_SIZE)) {
messageDao.findAllByDataSource()
diff --git a/app/src/main/java/com/navinfo/volvo/repository/network/NetworkRepository.kt b/app/src/main/java/com/navinfo/volvo/repository/network/NetworkRepository.kt
index b03fde5..461f0b0 100644
--- a/app/src/main/java/com/navinfo/volvo/repository/network/NetworkRepository.kt
+++ b/app/src/main/java/com/navinfo/volvo/repository/network/NetworkRepository.kt
@@ -1,13 +1,22 @@
package com.navinfo.volvo.repository.network
import com.navinfo.volvo.http.DefaultResponse
-import com.navinfo.volvo.model.messagelist.NetworkMessageListPost
-import com.navinfo.volvo.model.messagelist.NetworkMessageListResponse
+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
/**
* 网络访问接口
*/
-interface NetworkRepository {
- suspend fun getCardList(message: NetworkMessageListPost): NetResult>
+interface NetworkRepository {
+ /**
+ * 获取问候列表
+ */
+ suspend fun getMessageList(message: NetworkMessageListPost): NetResult>
+
+ /**
+ *删除问候
+ */
+ suspend fun deleteMessage(message: NetworkDeleteMessagePost): NetResult>
}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/repository/network/NetworkRepositoryImp.kt b/app/src/main/java/com/navinfo/volvo/repository/network/NetworkRepositoryImp.kt
index 5fd1e2f..d367065 100644
--- a/app/src/main/java/com/navinfo/volvo/repository/network/NetworkRepositoryImp.kt
+++ b/app/src/main/java/com/navinfo/volvo/repository/network/NetworkRepositoryImp.kt
@@ -1,11 +1,12 @@
package com.navinfo.volvo.repository.network
+import com.google.gson.Gson
import com.navinfo.volvo.database.dao.GreetingMessageDao
import com.navinfo.volvo.di.scope.IoDispatcher
import com.navinfo.volvo.http.DefaultResponse
-import com.navinfo.volvo.model.messagelist.NetworkMessageListPost
-import com.navinfo.volvo.model.messagelist.NetworkMessageListResponse
-import com.navinfo.volvo.tools.GsonUtil
+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.CoroutineDispatcher
import kotlinx.coroutines.withContext
@@ -16,22 +17,47 @@ import javax.inject.Inject
class NetworkRepositoryImp @Inject constructor(
private val netWorkService: NetworkService,
- private val messageDao: GreetingMessageDao,
+ private val gson: Gson,
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
) : NetworkRepository {
-
- override suspend fun getCardList(message: NetworkMessageListPost): NetResult> =
+ /**
+ * 获取问候列表
+ */
+ override suspend fun getMessageList(message: NetworkMessageListPost): NetResult> =
withContext(ioDispatcher) {
return@withContext try {
- val stringBody = GsonUtil.getInstance().toJson(message)
+ val stringBody = gson.toJson(message)
.toRequestBody("application/json;charset=utf-8".toMediaType())
- val result = netWorkService.queryCardListByApp(stringBody)
+ val result = netWorkService.queryMessageListByApp(stringBody)
if (result.isSuccessful) {
- val body = result.body()
- if(body!!.data != null && body.data!!.rows != null){
- messageDao.insertOrUpdate(body.data!!.rows)
+ if (result.body()!!.code == 200) {
+ NetResult.Success(result.body())
+ } else {
+ NetResult.Failure(result.body()!!.code, result.body()!!.msg)
+ }
+ } else {
+ NetResult.Success(null)
+ }
+ } catch (e: Exception) {
+ NetResult.Error(e)
+ }
+ }
+
+ /**
+ * 删除问候
+ */
+ override suspend fun deleteMessage(message: NetworkDeleteMessagePost): NetResult> =
+ withContext(ioDispatcher) {
+ return@withContext try {
+ val stringBody = gson.toJson(message)
+ .toRequestBody("application/json;charset=utf-8".toMediaType())
+ val result = netWorkService.deleteMessage(stringBody)
+ if (result.isSuccessful) {
+ if (result.body()!!.code == 200) {
+ NetResult.Success(result.body())
+ } else {
+ NetResult.Failure(result.body()!!.code, result.body()!!.msg)
}
- NetResult.Success(body)
} else {
NetResult.Success(null)
}
diff --git a/app/src/main/java/com/navinfo/volvo/repository/network/NetworkService.kt b/app/src/main/java/com/navinfo/volvo/repository/network/NetworkService.kt
index b211c41..f39d4b9 100644
--- a/app/src/main/java/com/navinfo/volvo/repository/network/NetworkService.kt
+++ b/app/src/main/java/com/navinfo/volvo/repository/network/NetworkService.kt
@@ -1,13 +1,23 @@
package com.navinfo.volvo.repository.network
import com.navinfo.volvo.http.DefaultResponse
-import com.navinfo.volvo.model.messagelist.NetworkMessageListResponse
+import com.navinfo.volvo.model.network.NetworkMessageListResponse
import okhttp3.RequestBody
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.POST
interface NetworkService {
+ /**
+ * 获取问候列表
+ */
@POST("/navi/cardDelivery/queryCardListByApp")
- suspend fun queryCardListByApp(@Body body: RequestBody): Response>
+ suspend fun queryMessageListByApp(@Body body: RequestBody): Response>
+
+ /**
+ * 删除问候
+ */
+ @POST("/navi/cardDelivery/deleteCardByApp")
+ suspend fun deleteMessage(@Body body: RequestBody): Response>
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/repository/preferences/PreferencesRepository.kt b/app/src/main/java/com/navinfo/volvo/repository/preferences/PreferencesRepository.kt
new file mode 100644
index 0000000..d35e07e
--- /dev/null
+++ b/app/src/main/java/com/navinfo/volvo/repository/preferences/PreferencesRepository.kt
@@ -0,0 +1,17 @@
+package com.navinfo.volvo.repository.preferences
+
+import com.navinfo.volvo.model.proto.LoginUser
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * 数据库操作接口
+ */
+interface PreferencesRepository {
+ suspend fun saveLoginUser(id: String, name: String, password: String)
+ fun loginUser(): Flow
+ suspend fun saveString(key: String, content: String)
+ suspend fun getString(key: String): Flow
+ suspend fun saveInt(key: String, content: Int)
+ suspend fun getInt(key: String): Flow
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/repository/preferences/PreferencesRepositoryImp.kt b/app/src/main/java/com/navinfo/volvo/repository/preferences/PreferencesRepositoryImp.kt
new file mode 100644
index 0000000..1bdd0d9
--- /dev/null
+++ b/app/src/main/java/com/navinfo/volvo/repository/preferences/PreferencesRepositoryImp.kt
@@ -0,0 +1,61 @@
+package com.navinfo.volvo.repository.preferences
+
+import android.content.Context
+import androidx.datastore.core.DataStore
+import androidx.datastore.preferences.core.Preferences
+import androidx.datastore.preferences.core.edit
+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.model.proto.LoginUser
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+
+const val DataStore_NAME = "ShardPreferences"
+val Context.datastore: DataStore by preferencesDataStore(name = DataStore_NAME)
+
+class PreferencesRepositoryImp @Inject constructor(
+ private val context: Context,
+ private val loginUser: DataStore
+) : 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()
+ }
+ }
+
+ override suspend fun saveString(key: String, content: String) {
+ context.datastore.edit {
+ it[stringPreferencesKey(key)] = content
+ }
+ }
+
+ override suspend fun getString(key: String): Flow = context.datastore.data.map {
+ it[stringPreferencesKey(key)]
+ }
+
+ override suspend fun saveInt(key: String, content: Int) {
+ context.datastore.edit {
+ it[intPreferencesKey(key)] = content
+ }
+ }
+
+ override suspend fun getInt(key: String): Flow = context.datastore.data.map {
+ it[intPreferencesKey(key)]
+ }
+
+ override fun loginUser(): Flow = loginUser.data
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/ui/BaseActivity.kt b/app/src/main/java/com/navinfo/volvo/ui/BaseActivity.kt
index 77c1577..8748a0c 100644
--- a/app/src/main/java/com/navinfo/volvo/ui/BaseActivity.kt
+++ b/app/src/main/java/com/navinfo/volvo/ui/BaseActivity.kt
@@ -6,6 +6,6 @@ import androidx.lifecycle.ViewModelProvider
import javax.inject.Inject
abstract class BaseActivity : AppCompatActivity() {
- @Inject
- lateinit var viewModelFactoryProvider: ViewModelProvider.Factory
+// @Inject
+// lateinit var viewModelFactoryProvider: ViewModelProvider.Factory
}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/ui/MainActivity.kt b/app/src/main/java/com/navinfo/volvo/ui/MainActivity.kt
index e4fce06..191b16a 100644
--- a/app/src/main/java/com/navinfo/volvo/ui/MainActivity.kt
+++ b/app/src/main/java/com/navinfo/volvo/ui/MainActivity.kt
@@ -1,8 +1,8 @@
package com.navinfo.volvo.ui
import android.content.DialogInterface
-import android.content.Intent
import android.os.Bundle
+import android.view.Gravity
import android.view.View
import android.widget.Toast
import androidx.activity.viewModels
@@ -11,6 +11,9 @@ import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
+import androidx.transition.Slide
+import androidx.transition.Transition
+import androidx.transition.TransitionManager
import com.easytools.tools.FileUtils
import com.elvishew.xlog.BuildConfig
import com.elvishew.xlog.LogConfiguration
@@ -30,16 +33,17 @@ import com.hjq.permissions.Permission
import com.hjq.permissions.XXPermissions
import com.navinfo.volvo.R
import com.navinfo.volvo.databinding.ActivityMainBinding
-import com.navinfo.volvo.ui.message.MessageActivity
import com.navinfo.volvo.utils.SystemConstant
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
+
@AndroidEntryPoint
class MainActivity : BaseActivity() {
private lateinit var binding: ActivityMainBinding
- private val viewModel by viewModels { viewModelFactoryProvider }
+ private val viewModel by viewModels()
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -47,7 +51,6 @@ class MainActivity : BaseActivity() {
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
-
XXPermissions.with(this)
// 申请单个权限
.permission(Permission.WRITE_EXTERNAL_STORAGE)
@@ -98,28 +101,29 @@ class MainActivity : BaseActivity() {
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()
- }
+ if (it == 0L) {
+ navView.removeBadge(R.id.navigation_home)
+ } else {
+ var badge = navView.getOrCreateBadge(R.id.navigation_home);
+ badge.number = it.toInt()
}
}
}
navController.addOnDestinationChangedListener { controller, destination, arguments ->
- if (destination.id == R.id.navigation_home
- || destination.id == R.id.navigation_dashboard
- || destination.id == R.id.navigation_notifications
- ) {
+ 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)
+ transition.duration = 300;
+ TransitionManager.beginDelayedTransition(binding.root, transition);
navView.visibility = View.VISIBLE
newMessageView.visibility = View.VISIBLE
}
} else {
runOnUiThread {
+ val transition: Transition = Slide(Gravity.BOTTOM)
+ transition.duration = 300;
+ TransitionManager.beginDelayedTransition(binding.root, transition);
navView.visibility = View.GONE
newMessageView.visibility = View.GONE
}
@@ -132,6 +136,7 @@ class MainActivity : BaseActivity() {
}
}
+
override fun onSupportNavigateUp() =
findNavController(R.id.nav_host_fragment_activity_main).navigateUp()
@@ -151,13 +156,10 @@ class MainActivity : BaseActivity() {
}
fun xLogInit(logFolder: String) {
- val config = LogConfiguration.Builder()
- .logLevel(
- if (BuildConfig.DEBUG)
- LogLevel.ALL // 指定日志级别,低于该级别的日志将不会被打印,默认为 LogLevel.ALL
- else LogLevel.NONE
- )
- .tag("Volvo") // 指定 TAG,默认为 "X-LOG"
+ val config = LogConfiguration.Builder().logLevel(
+ if (BuildConfig.DEBUG) LogLevel.ALL // 指定日志级别,低于该级别的日志将不会被打印,默认为 LogLevel.ALL
+ else LogLevel.NONE
+ ).tag("Volvo") // 指定 TAG,默认为 "X-LOG"
.enableThreadInfo() // 允许打印线程信息,默认禁止
.enableStackTrace(2) // 允许打印深度为 2 的调用栈信息,默认禁止
.enableBorder() // 允许打印日志边框,默认禁止
@@ -165,8 +167,7 @@ class MainActivity : BaseActivity() {
BlacklistTagsFilterInterceptor( // 添加黑名单 TAG 过滤器
"blacklist1", "blacklist2", "blacklist3"
)
- )
- .build()
+ ).build()
val androidPrinter: Printer = AndroidPrinter(true) // 通过 android.util.Log 打印日志的打印器
@@ -181,8 +182,7 @@ class MainActivity : BaseActivity() {
XLog.init( // 初始化 XLog
config, // 指定日志配置,如果不指定,会默认使用 new LogConfiguration.Builder().build()
androidPrinter, // 添加任意多的打印器。如果没有添加任何打印器,会默认使用 AndroidPrinter(Android)/ConsolePrinter(java)
- consolePrinter,
- filePrinter
+ consolePrinter, filePrinter
)
}
@@ -190,14 +190,11 @@ class MainActivity : BaseActivity() {
fun showRationaleForSDCard(permissions: MutableList) {
// showRationaleDialog(R.string.permission_camera_rationale, request)
// Toast.makeText(context, "当前操作需要您授权相机权限!", Toast.LENGTH_SHORT).show()
- MaterialAlertDialogBuilder(this)
- .setTitle("提示")
- .setMessage("当前操作需要您授权读写SD卡权限!")
+ MaterialAlertDialogBuilder(this).setTitle("提示").setMessage("当前操作需要您授权读写SD卡权限!")
.setPositiveButton("确定", DialogInterface.OnClickListener { dialogInterface, i ->
dialogInterface.dismiss()
XXPermissions.startPermissionActivity(this@MainActivity, permissions)
- })
- .show()
+ }).show()
}
// @OnPermissionDenied(Manifest.permission.MANAGE_EXTERNAL_STORAGE)
diff --git a/app/src/main/java/com/navinfo/volvo/ui/MainActivityViewModel.kt b/app/src/main/java/com/navinfo/volvo/ui/MainActivityViewModel.kt
index b0ffafe..cec763a 100644
--- a/app/src/main/java/com/navinfo/volvo/ui/MainActivityViewModel.kt
+++ b/app/src/main/java/com/navinfo/volvo/ui/MainActivityViewModel.kt
@@ -4,9 +4,12 @@ import androidx.lifecycle.ViewModel
import androidx.paging.PagingData
import com.navinfo.volvo.database.dao.GreetingMessageDao
import com.navinfo.volvo.database.entity.GreetingMessage
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
+import javax.inject.Singleton
+@HiltViewModel
class MainActivityViewModel @Inject constructor(
private val messageDao: GreetingMessageDao,
) : ViewModel() {
diff --git a/app/src/main/java/com/navinfo/volvo/ui/fragments/BaseFragment.kt b/app/src/main/java/com/navinfo/volvo/ui/fragments/BaseFragment.kt
index b112973..93cd6e2 100644
--- a/app/src/main/java/com/navinfo/volvo/ui/fragments/BaseFragment.kt
+++ b/app/src/main/java/com/navinfo/volvo/ui/fragments/BaseFragment.kt
@@ -5,6 +5,6 @@ import androidx.lifecycle.ViewModelProvider
import javax.inject.Inject
abstract class BaseFragment : Fragment() {
- @Inject
- lateinit var viewModelFactoryProvider: ViewModelProvider.Factory
+// @Inject
+// lateinit var viewModelFactoryProvider: ViewModelProvider.Factory
}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/ui/fragments/home/HomeAdapter.kt b/app/src/main/java/com/navinfo/volvo/ui/fragments/home/HomeAdapter.kt
index 398faf6..06c4d19 100644
--- a/app/src/main/java/com/navinfo/volvo/ui/fragments/home/HomeAdapter.kt
+++ b/app/src/main/java/com/navinfo/volvo/ui/fragments/home/HomeAdapter.kt
@@ -19,23 +19,11 @@ class HomeAdapter(fragment: Fragment) :
PagingDataAdapter(DiffCallback()) {
val fragment = fragment
-// var itemList = ArrayList()
-//
-// fun addItem(message: GreetingMessage) {
-// itemList.add(message)
-// notifyItemInserted(itemList.size - 1)
-// }
-//
-// fun setItems(messageList: List) {
-// itemList.clear()
-// itemList.addAll(messageList)
-// notifyDataSetChanged()
-// }
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
val mDataBinding: AdapterHomeBinding =
DataBindingUtil.inflate(
- LayoutInflater.from(fragment.context),
+ LayoutInflater.from(parent.context),
R.layout.adapter_home,
parent,
false
@@ -47,9 +35,11 @@ class HomeAdapter(fragment: Fragment) :
holder.onBind(position)
}
-// override fun getItemCount(): Int {
-// return itemList.size
-// }
+
+ fun getItemData(position: Int): GreetingMessage {
+ return getItem(position)!!
+ }
+
inner class MyViewHolder(private val mDataBinding: AdapterHomeBinding) :
RecyclerView.ViewHolder(mDataBinding.root) {
@@ -63,12 +53,11 @@ class HomeAdapter(fragment: Fragment) :
.error(R.mipmap.volvo_logo_small)
.into(mDataBinding.messageHeadIcon)
}
-
}
class DiffCallback : DiffUtil.ItemCallback() {
override fun areItemsTheSame(oldItem: GreetingMessage, newItem: GreetingMessage): Boolean {
- return oldItem.uuid == newItem.uuid
+ return oldItem.uuid == newItem.uuid && oldItem.status == newItem.status
}
override fun areContentsTheSame(
diff --git a/app/src/main/java/com/navinfo/volvo/ui/fragments/home/HomeFragment.kt b/app/src/main/java/com/navinfo/volvo/ui/fragments/home/HomeFragment.kt
index d78a6e7..a23ee65 100644
--- a/app/src/main/java/com/navinfo/volvo/ui/fragments/home/HomeFragment.kt
+++ b/app/src/main/java/com/navinfo/volvo/ui/fragments/home/HomeFragment.kt
@@ -1,96 +1,172 @@
package com.navinfo.volvo.ui.fragments.home
import android.os.Bundle
+import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import androidx.databinding.DataBindingUtil
+import android.widget.Toast
import androidx.fragment.app.viewModels
+import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
+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.collectLatest
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
+import java.io.IOException
@AndroidEntryPoint
class HomeFragment : BaseFragment(), OnItemClickListener, OnItemMenuClickListener {
private var _binding: FragmentHomeBinding? = null
+
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
- private val viewModel by viewModels { viewModelFactoryProvider }
-
- private lateinit var messageAdapter: HomeAdapter
+ private val viewModel by viewModels()
+ private val messageAdapter by lazy { HomeAdapter(this) }
+ private var headBinding: HomeAdapterNotingBinding? = null
override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
_binding = FragmentHomeBinding.inflate(inflater, container, false)
val root: View = binding.root
+
+ headBinding = HomeAdapterNotingBinding.inflate(inflater, container, false)
initView()
return root
}
private fun initView() {
-// mDataBinding.homeViewModel = viewModel
- messageAdapter = HomeAdapter(this)
- val recyclerview: SwipeRecyclerView = binding.homeRecyclerview
- recyclerview.adapter = null //先设置null,否则会报错
+
+
//创建菜单选项
//注意:使用滑动菜单不能开启滑动删除,否则只有滑动删除没有滑动菜单
- var mSwipeMenuCreator =
- SwipeMenuCreator { _, rightMenu, position ->
- //添加菜单自动添加至尾部
- var deleteItem = SwipeMenuItem(context)
- deleteItem.height = DisplayUtil.dip2px(context!!, 60f)
- deleteItem.width = DisplayUtil.dip2px(context!!, 80f)
- deleteItem.background = context!!.getDrawable(R.color.red)
- deleteItem.text = context!!.getString(R.string.delete)
- rightMenu.addMenuItem(deleteItem)
+ 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 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.setTextColor(requireContext().getColor(R.color.white))
+ 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 shareItem = SwipeMenuItem(context)
- shareItem.height = DisplayUtil.dip2px(context!!, 60f)
- shareItem.width = DisplayUtil.dip2px(context!!, 80f)
- shareItem.background = context!!.getDrawable(R.color.gray)
- shareItem.text = context!!.getString(R.string.share)
- shareItem.setTextColor(R.color.white)
- rightMenu.addMenuItem(shareItem)
}
- val layoutManager = LinearLayoutManager(context)
+ }
- recyclerview.layoutManager = layoutManager
- recyclerview.addItemDecoration(DividerItemDecoration(context, layoutManager.orientation))
- recyclerview.setSwipeMenuCreator(mSwipeMenuCreator)
- recyclerview.setOnItemClickListener(this)
-// recyclerview.useDefaultLoadMore()
-// recyclerview.setLoadMoreListener {
-//
-// }
+ val layoutManager = LinearLayoutManager(context)
+ 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.setLoadMoreListener {
+ Log.e("jingo", "下拉加载开始")
+
+ } // 加载更多的监听。
+
+ //开始下拉刷新
+ binding.homeSwipeRefreshLayout.setOnRefreshListener {
+ Log.e("jingo", "开始刷新")
+ viewModel.getNetMessageList()
+ }
+
+ //列表自动分页
lifecycleScope.launch {
- viewModel.messageList.collectLatest {
+ viewModel.messageList.collect {
messageAdapter.submitData(it)
}
}
-// messageAdapter.withLoadStateFooter(
-// footer = RecLoadStateAdapter { messageAdapter.retry() }
-// )
+ 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)
+ }
+ Log.d("jingo", "is NotLoading")
+ }
+ is LoadState.Loading -> {
+ Log.d("jingo", "is Loading")
+ }
+ is LoadState.Error -> {
+ 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()
+ //监听数据请求是否结束
+ viewModel.isLoading.observe(viewLifecycleOwner, Observer {
+ if (!it) loadMoreFinish()
+ })
-// messageAdapter.withLoadStateHeader()
- recyclerview.adapter = messageAdapter
}
+ private fun loadMoreFinish() {
+ binding.homeSwipeRefreshLayout.isRefreshing = false
+
+ // 第一次加载数据:一定要掉用这个方法。
+ // 第一个参数:表示此次数据是否为空,假如你请求到的list为空(== null || list.size == 0),那么这里就要true。
+ // 第二个参数:表示是否还有更多数据,根据服务器返回给你的page等信息判断是否还有更多,这样可以提供性能,如果不能判断则传true。
+ binding.homeRecyclerview.loadMoreFinish(false, false)
+ }
+
+
override fun onStart() {
super.onStart()
viewModel.getNetMessageList()
@@ -100,6 +176,7 @@ class HomeFragment : BaseFragment(), OnItemClickListener, OnItemMenuClickListene
override fun onDestroyView() {
super.onDestroyView()
_binding = null
+ headBinding = null
}
override fun onItemClick(view: View?, adapterPosition: Int) {
diff --git a/app/src/main/java/com/navinfo/volvo/ui/fragments/home/HomeViewModel.kt b/app/src/main/java/com/navinfo/volvo/ui/fragments/home/HomeViewModel.kt
index ac68d39..8b4a0fe 100644
--- a/app/src/main/java/com/navinfo/volvo/ui/fragments/home/HomeViewModel.kt
+++ b/app/src/main/java/com/navinfo/volvo/ui/fragments/home/HomeViewModel.kt
@@ -1,49 +1,100 @@
package com.navinfo.volvo.ui.fragments.home
+import android.app.Application
+import android.widget.Toast
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.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.preferences.PreferencesRepository
import com.navinfo.volvo.util.NetResult
import com.navinfo.volvo.util.asLiveData
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch
import javax.inject.Inject
+@HiltViewModel
class HomeViewModel @Inject constructor(
+ private val application: Application,
private val netRepository: NetworkRepository,
- private val dataRepository: DatabaseRepository
+ private val dataRepository: DatabaseRepository,
+ private val messageDao: GreetingMessageDao,
+ private val shard: PreferencesRepository
) : ViewModel() {
private val _isLoading = MutableLiveData()
val isLoading = _isLoading.asLiveData()
+
// private val _messageList = MutableLiveData>()
// val messageList = _messageList.asLiveData()
-
val messageList: Flow>
get() = dataRepository.getMessageByPaging()
+ lateinit var userName: String
+
+ init {
+ viewModelScope.launch {
+ shard.loginUser().collect {
+ userName = it!!.username
+ }
+ }
+ }
fun getNetMessageList() {
+ if (_isLoading.value == true)
+ return
_isLoading.postValue(true)
viewModelScope.launch {
- val messagePost = NetworkMessageListPost(who = "", toWho = "")
- when (val result = netRepository.getCardList(messagePost)) {
+ val messagePost = NetworkMessageListPost(who = userName, toWho = "")
+ when (val result = netRepository.getMessageList(messagePost)) {
is NetResult.Success -> {
_isLoading.value = false
-// if (result.data != null) {
-// val list = (result.data.data as NetworkMessageListResponse).rows
-// _messageList.value = list
-// }
+ 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 -> {
+ _isLoading.value = false
+ }
+ is NetResult.Failure -> {
+ _isLoading.value = false
+ Toast.makeText(
+ application,
+ "服务返回信息:${result.code}:${result.msg}",
+ Toast.LENGTH_SHORT
+ )
+ .show()
+ }
is NetResult.Error -> {
_isLoading.value = false
}
diff --git a/app/src/main/java/com/navinfo/volvo/ui/fragments/home/LoadStateAdapter.kt b/app/src/main/java/com/navinfo/volvo/ui/fragments/home/LoadStateAdapter.kt
new file mode 100644
index 0000000..d3aa8e3
--- /dev/null
+++ b/app/src/main/java/com/navinfo/volvo/ui/fragments/home/LoadStateAdapter.kt
@@ -0,0 +1,18 @@
+package com.navinfo.volvo.ui.fragments.home
+
+import android.view.ViewGroup
+import androidx.paging.LoadState
+import androidx.paging.LoadStateAdapter
+
+class LoadStateAdapter(private val retry: () -> Unit) :
+ LoadStateAdapter() {
+
+ override fun onBindViewHolder(holder: LoadStateViewHolder, loadState: LoadState) {
+ holder.bindState(loadState)
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, loadState: LoadState): LoadStateViewHolder {
+ return LoadStateViewHolder(parent, retry)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/ui/fragments/home/LoadStateViewHolder.kt b/app/src/main/java/com/navinfo/volvo/ui/fragments/home/LoadStateViewHolder.kt
new file mode 100644
index 0000000..4a2c190
--- /dev/null
+++ b/app/src/main/java/com/navinfo/volvo/ui/fragments/home/LoadStateViewHolder.kt
@@ -0,0 +1,39 @@
+package com.navinfo.volvo.ui.fragments.home
+
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.paging.LoadState
+import androidx.recyclerview.widget.RecyclerView
+import com.navinfo.volvo.R
+import com.navinfo.volvo.databinding.LoadStateViewBinding
+
+class LoadStateViewHolder(parent: ViewGroup, var retry: () -> Unit) : RecyclerView.ViewHolder(
+ LayoutInflater.from(parent.context)
+ .inflate(R.layout.load_state_view, parent, false)
+) {
+
+ var itemLoadStateBindingUtil: LoadStateViewBinding = LoadStateViewBinding.bind(itemView)
+
+ fun bindState(loadState: LoadState) {
+ when (loadState) {
+ is LoadState.Error -> {
+ itemLoadStateBindingUtil.loadStateLayout.visibility = View.VISIBLE
+// itemLoadStateBindingUtil.btnRetry.setOnClickListener {
+// retry()
+// }
+ Log.d("jingo", "error了吧")
+ }
+ is LoadState.Loading -> {
+ itemLoadStateBindingUtil.loadStateLayout.visibility = View.VISIBLE
+ Log.d("jingo", "该显示了")
+ }
+ else -> {
+ Log.d("jingo", "--其他的错误")
+ }
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/ui/fragments/home/RecLoadStateAdapter.kt b/app/src/main/java/com/navinfo/volvo/ui/fragments/home/RecLoadStateAdapter.kt
deleted file mode 100644
index 034840f..0000000
--- a/app/src/main/java/com/navinfo/volvo/ui/fragments/home/RecLoadStateAdapter.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-//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() {
-//
-// 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()
-// }
-// }
-// }
-//}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/ui/fragments/login/LoginFragment.kt b/app/src/main/java/com/navinfo/volvo/ui/fragments/login/LoginFragment.kt
index e921ce5..4844f7a 100644
--- a/app/src/main/java/com/navinfo/volvo/ui/fragments/login/LoginFragment.kt
+++ b/app/src/main/java/com/navinfo/volvo/ui/fragments/login/LoginFragment.kt
@@ -4,13 +4,18 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
+import android.widget.Toast
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.viewModels
+import androidx.lifecycle.Observer
+import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.navinfo.volvo.R
import com.navinfo.volvo.databinding.FragmentLoginBinding
import com.navinfo.volvo.ui.fragments.BaseFragment
import dagger.hilt.android.AndroidEntryPoint
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.launch
@AndroidEntryPoint
@@ -20,7 +25,7 @@ class LoginFragment : BaseFragment() {
private lateinit var viewBinding: FragmentLoginBinding
- private val viewModel by viewModels { viewModelFactoryProvider }
+ private val viewModel by viewModels()
override fun onCreateView(
inflater: LayoutInflater,
@@ -34,11 +39,30 @@ class LoginFragment : BaseFragment() {
}
private fun initView() {
+
+ lifecycleScope.launch {
+ viewModel.user.collect {
+ if (it != null){
+ viewBinding.loginUser = it
+ }
+ }
+ }
viewBinding.loginFragmentRegisterButton.setOnClickListener {
}
viewBinding.loginFragmentLoginButton.setOnClickListener {
-// viewModel.login(viewBinding.loginFragmentUserLayout)
+ if (viewBinding.loginUsername.text!!.isEmpty()) {
+ Toast.makeText(context, "请输入用户名", Toast.LENGTH_SHORT).show()
+ return@setOnClickListener
+ }
+ if (viewBinding.loginPassword.text!!.isEmpty()) {
+ Toast.makeText(context, "请输入密码", Toast.LENGTH_SHORT).show()
+ return@setOnClickListener
+ }
+ viewModel.onClickLogin(
+ viewBinding.loginUsername.text.toString(),
+ viewBinding.loginPassword.text.toString()
+ )
findNavController().navigate(R.id.action_login_to_home)
}
}
diff --git a/app/src/main/java/com/navinfo/volvo/ui/fragments/login/LoginViewModel.kt b/app/src/main/java/com/navinfo/volvo/ui/fragments/login/LoginViewModel.kt
index 8f47282..a868bb6 100644
--- a/app/src/main/java/com/navinfo/volvo/ui/fragments/login/LoginViewModel.kt
+++ b/app/src/main/java/com/navinfo/volvo/ui/fragments/login/LoginViewModel.kt
@@ -1,23 +1,29 @@
package com.navinfo.volvo.ui.fragments.login
-import android.view.View
-import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
-import com.navinfo.volvo.database.AppDatabase
-import com.navinfo.volvo.database.entity.User
-import com.navinfo.volvo.util.SharedPreferenceHelper
+import androidx.lifecycle.viewModelScope
+import com.navinfo.volvo.repository.preferences.PreferencesRepository
+import com.navinfo.volvo.util.asLiveData
+//import com.navinfo.volvo.repository.preferences.PreferencesRepository
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.launch
import javax.inject.Inject
-class LoginViewModel @Inject constructor(private val sharedPreferenceHelper: SharedPreferenceHelper) : ViewModel() {
+@HiltViewModel
+class LoginViewModel @Inject constructor(private val repository: PreferencesRepository) :
+ ViewModel() {
-// val user: LiveData = _user
-
- fun liveDataOnclick(view: View) {
+ val user = repository.loginUser()
+ fun onClickLogin(name: String, password: String) {
+ viewModelScope.launch {
+ repository.saveLoginUser(id = "", name = name, password = password)
+ }
}
- fun userRegister(username: String, password: String) {
+ fun onClickLoginRegister(username: String, password: String) {
}
}
\ No newline at end of file
diff --git a/app/src/main/java/com/navinfo/volvo/ui/fragments/message/ObtainMessageFragment.kt b/app/src/main/java/com/navinfo/volvo/ui/fragments/message/ObtainMessageFragment.kt
index 1fe7bf3..ab43736 100644
--- a/app/src/main/java/com/navinfo/volvo/ui/fragments/message/ObtainMessageFragment.kt
+++ b/app/src/main/java/com/navinfo/volvo/ui/fragments/message/ObtainMessageFragment.kt
@@ -7,7 +7,8 @@ import android.text.TextUtils
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
-import android.view.View.*
+import android.view.View.GONE
+import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.AdapterView.OnItemSelectedListener
@@ -17,15 +18,11 @@ import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.Fragment
+import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
-import androidx.lifecycle.ViewModelProvider
import androidx.navigation.Navigation
import androidx.navigation.fragment.findNavController
-import com.easytools.tools.DateUtils
-import com.easytools.tools.DisplayUtils
-import com.easytools.tools.FileIOUtils
-import com.easytools.tools.ResourceUtils
-import com.easytools.tools.ToastUtils
+import com.easytools.tools.*
import com.elvishew.xlog.XLog
import com.github.file_picker.FileType
import com.github.file_picker.ListDirection
@@ -52,6 +49,7 @@ import com.navinfo.volvo.util.PhotoLoader
import com.navinfo.volvo.utils.EasyMediaFile
import com.navinfo.volvo.utils.SystemConstant
import com.nhaarman.supertooltips.ToolTip
+import dagger.hilt.android.AndroidEntryPoint
import indi.liyi.viewer.Utils
import indi.liyi.viewer.ViewData
import top.zibin.luban.Luban
@@ -62,12 +60,10 @@ import java.util.*
import kotlin.streams.toList
-//@RuntimePermissions
-class ObtainMessageFragment: Fragment() {
+@AndroidEntryPoint
+class ObtainMessageFragment : Fragment() {
private var _binding: FragmentObtainMessageBinding? = null
- private val obtainMessageViewModel by lazy {
- ViewModelProvider(requireActivity()).get(ObtainMessageViewModel::class.java)
- }
+ private val obtainMessageViewModel by viewModels()
private val photoHelper by lazy {
EasyMediaFile().setCrop(true)
}
@@ -91,18 +87,17 @@ class ObtainMessageFragment: Fragment() {
_binding = FragmentObtainMessageBinding.inflate(inflater, container, false)
val root: View = binding.root
- val greetingMessage = GreetingMessage()
- obtainMessageViewModel.setCurrentMessage(greetingMessage)
+ obtainMessageViewModel.setCurrentMessage(GreetingMessage(who = obtainMessageViewModel.username))
- obtainMessageViewModel?.getMessageLiveData()?.observe(
+ obtainMessageViewModel.getMessageLiveData().observe(
viewLifecycleOwner, Observer {
// 初始化界面显示内容
- if(it.name?.isNotEmpty() == true)
+ if (it.name?.isNotEmpty() == true)
binding.tvMessageTitle?.setText(it.name)
if (it.sendDate?.isNotEmpty() == true) {
// 获取当前发送时间,如果早于当前时间,则显示现在
val sendDate = DateUtils.str2Date(it.sendDate, dateSendFormat)
- if (sendDate<=Date()) {
+ if (sendDate <= Date()) {
binding.btnSendTime.text = "现在"
} else {
binding.btnSendTime.text = it.sendDate
@@ -112,39 +107,47 @@ class ObtainMessageFragment: Fragment() {
}
var hasPhoto = false
var hasAudio = false
- if (it.imageUrl!=null&&it.imageUrl?.isNotEmpty() == true) {
+ if (it.imageUrl != null && it.imageUrl?.isNotEmpty() == true) {
hasPhoto = true
-// Glide.with(this@ObtainMessageFragment)
-// .asBitmap().fitCenter()
-// .load(it.imageUrl)
-// .diskCacheStrategy(DiskCacheStrategy.ALL)
-// .into(binding.imgMessageAttachment)
+ // Glide.with(this@ObtainMessageFragment)
+ // .asBitmap().fitCenter()
+ // .load(it.imageUrl)
+ // .diskCacheStrategy(DiskCacheStrategy.ALL)
+ // .into(binding.imgMessageAttachment)
// 如果当前attachment文件是本地文件,开始尝试网络上传
val str = it.imageUrl?.replace("\\", "/")
- binding.tvPhotoName.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG )
+ binding.tvPhotoName.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG)
if (!str!!.startsWith("http")) {
- obtainMessageViewModel.uploadAttachment(File(it.imageUrl), AttachmentType.PIC)
+ obtainMessageViewModel.uploadAttachment(
+ File(it.imageUrl),
+ AttachmentType.PIC
+ )
binding.tvPhotoName.text = str.substringAfterLast("/", "picture.jpg")
} else {
if (str.contains("?")) {
- binding.tvPhotoName.text = str.substring(str.lastIndexOf("/")+1, str.indexOf("?"))
+ binding.tvPhotoName.text =
+ str.substring(str.lastIndexOf("/") + 1, str.indexOf("?"))
} else {
binding.tvPhotoName.text = str.substringAfterLast("/")
}
}
}
- if (it.mediaUrl!=null&&it.mediaUrl?.isNotEmpty() == true) {
+ if (it.mediaUrl != null && it.mediaUrl?.isNotEmpty() == true) {
hasAudio = true
- binding.tvAudioName.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG )
+ binding.tvAudioName.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG)
// 如果当前attachment文件是本地文件,开始尝试网络上传
val str = it.mediaUrl?.replace("\\", "/")
if (!str!!.startsWith("http")) {
- obtainMessageViewModel.uploadAttachment(File(it.mediaUrl),AttachmentType.AUDIO)
+ obtainMessageViewModel.uploadAttachment(
+ File(it.mediaUrl),
+ AttachmentType.AUDIO
+ )
binding.tvAudioName.text = str.substringAfterLast("/", "audio.m4a")
} else {
if (str.contains("?")) {
- binding.tvAudioName.text = str.substring(str.lastIndexOf("/")+1, str.indexOf("?"))
+ binding.tvAudioName.text =
+ str.substring(str.lastIndexOf("/") + 1, str.indexOf("?"))
} else {
binding.tvAudioName.text = str.substringAfterLast("/")
}
@@ -152,7 +155,7 @@ class ObtainMessageFragment: Fragment() {
}
binding.layerPhotoResult.visibility = if (hasPhoto) VISIBLE else GONE
binding.layerGetPhoto.visibility = if (hasPhoto) GONE else VISIBLE
-// binding.imgMessageAttachment.visibility = if (hasPhoto) VISIBLE else GONE
+ // binding.imgMessageAttachment.visibility = if (hasPhoto) VISIBLE else GONE
binding.layerAudioResult.visibility = if (hasAudio) VISIBLE else GONE
binding.layerGetAudio.visibility = if (hasAudio) GONE else VISIBLE
@@ -188,7 +191,7 @@ class ObtainMessageFragment: Fragment() {
obtainMessageViewModel.getMessageLiveData().value?.name = it.toString()
})
- binding.edtSendFrom.addTextChangedListener (afterTextChanged = {
+ binding.edtSendFrom.addTextChangedListener(afterTextChanged = {
obtainMessageViewModel.getMessageLiveData().value?.who = it.toString()
})
@@ -201,8 +204,11 @@ class ObtainMessageFragment: Fragment() {
}
val sendToArray = mutableListOf(VolvoModel("XC60", "智雅", "LYVXFEFEXNL754427"))
binding.edtSendTo.adapter = ArrayAdapter(requireContext(),
- 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 {
+ 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 {
override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
obtainMessageViewModel.getMessageLiveData().value?.toWho = sendToArray[p2].num
}
@@ -219,9 +225,19 @@ class ObtainMessageFragment: Fragment() {
override fun onClickListener(selectTime: String) {
val sendDate = DateUtils.str2Date(selectTime, dateShowFormat)
if (sendDate <= Date()) {
- obtainMessageViewModel.updateMessageSendTime(DateUtils.date2Str(Date(), dateSendFormat))
+ obtainMessageViewModel.updateMessageSendTime(
+ DateUtils.date2Str(
+ Date(),
+ dateSendFormat
+ )
+ )
} else {
- obtainMessageViewModel.updateMessageSendTime(DateUtils.date2Str(sendDate, dateSendFormat))
+ obtainMessageViewModel.updateMessageSendTime(
+ DateUtils.date2Str(
+ sendDate,
+ dateSendFormat
+ )
+ )
}
}
}
@@ -238,7 +254,8 @@ class ObtainMessageFragment: Fragment() {
override fun onGranted(permissions: MutableList, all: Boolean) {
if (!all) {
- Toast.makeText(activity, "获取部分权限成功,但部分权限未正常授予", Toast.LENGTH_SHORT).show()
+ Toast.makeText(activity, "获取部分权限成功,但部分权限未正常授予", Toast.LENGTH_SHORT)
+ .show()
return
}
// 开始启动拍照界面
@@ -280,13 +297,23 @@ class ObtainMessageFragment: Fragment() {
// Do something here with selected files
val audioFile = files.get(0).file
if (!audioFile.parentFile.parentFile.absolutePath.equals(SystemConstant.SoundFolder)) {
- val copyResult = FileIOUtils.writeFileFromIS(File(SystemConstant.SoundFolder, audioFile.name), FileInputStream(audioFile))
- XLog.e("拷贝结果:"+copyResult)
+ val copyResult = FileIOUtils.writeFileFromIS(
+ File(
+ SystemConstant.SoundFolder,
+ audioFile.name
+ ), FileInputStream(audioFile)
+ )
+ XLog.e("拷贝结果:" + copyResult)
if (!copyResult) {
ToastUtils.showToast("无法访问该文件,请重新选择其他文件")
return
}
- obtainMessageViewModel.updateMessageAudio(File(SystemConstant.SoundFolder, audioFile.name).absolutePath)
+ obtainMessageViewModel.updateMessageAudio(
+ File(
+ SystemConstant.SoundFolder,
+ audioFile.name
+ ).absolutePath
+ )
} else {
obtainMessageViewModel.updateMessageAudio(audioFile.absolutePath)
}
@@ -299,7 +326,7 @@ class ObtainMessageFragment: Fragment() {
ToastUtils.showToast("只能选择.m4a文件")
return
}
- if (media.file.length()>2*1000*1000) {
+ if (media.file.length() > 2 * 1000 * 1000) {
ToastUtils.showToast("文件不能超过2M!")
return
}
@@ -330,23 +357,25 @@ class ObtainMessageFragment: Fragment() {
.request(object : OnPermissionCallback {
override fun onGranted(permissions: MutableList, all: Boolean) {
if (!all) {
- Toast.makeText(activity, "获取部分权限成功,但部分权限未正常授予", Toast.LENGTH_SHORT).show()
+ Toast.makeText(activity, "获取部分权限成功,但部分权限未正常授予", Toast.LENGTH_SHORT)
+ .show()
return
}
- when(motionEvent.action) {
- MotionEvent.ACTION_DOWN-> {
+ when (motionEvent.action) {
+ MotionEvent.ACTION_DOWN -> {
// 申请权限
recorderLifecycleObserver.initAndStartRecorder()
startRecordTime = System.currentTimeMillis()
false
}
MotionEvent.ACTION_UP -> {
- if (System.currentTimeMillis() - startRecordTime<2000) {
+ if (System.currentTimeMillis() - startRecordTime < 2000) {
ToastUtils.showToast("录音时间太短!")
recorderLifecycleObserver.stopAndReleaseRecorder()
return
}
- val recorderAudioPath = recorderLifecycleObserver.stopAndReleaseRecorder()
+ val recorderAudioPath =
+ recorderLifecycleObserver.stopAndReleaseRecorder()
if (File(recorderAudioPath).exists()) {
obtainMessageViewModel.updateMessageAudio(recorderAudioPath)
}
@@ -376,7 +405,7 @@ class ObtainMessageFragment: Fragment() {
photoHelper.setCallback {
if (it.exists()) {
val fileName = it.name.lowercase()
- if (fileName.endsWith(".jpg")||fileName.endsWith(".jpeg")||fileName.endsWith(".png")) {
+ if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") || fileName.endsWith(".png")) {
// 获取选中的图片,自动压缩图片质量
// 压缩图片文件
Luban.with(context)
@@ -394,19 +423,35 @@ class ObtainMessageFragment: Fragment() {
override fun onSuccess(file: File?) {
XLog.d("压缩图片成功:${file?.absolutePath}")
- // 删除源文件
- if (!it.absolutePath.equals(file?.absolutePath)) {
- it?.delete()
- }
+ // 删除源文件
+ if (!it.absolutePath.equals(file?.absolutePath)) {
+ it?.delete()
+ }
// 如果当前文件不在camera缓存文件夹下,则移动该文件
if (!file!!.parentFile.absolutePath.equals(SystemConstant.CameraFolder)) {
- val copyResult = FileIOUtils.writeFileFromIS(File(SystemConstant.CameraFolder, fileName), FileInputStream(file))
- XLog.e("拷贝结果:"+copyResult)
- // 跳转回原Fragment,展示拍摄的照片
- ViewModelProvider(requireActivity()).get(ObtainMessageViewModel::class.java).updateMessagePic(File(SystemConstant.CameraFolder, fileName).absolutePath)
+ try {
+ val copyResult = FileIOUtils.writeFileFromIS(
+ File(
+ SystemConstant.CameraFolder,
+ fileName
+ ), FileInputStream(file)
+ )
+ XLog.e("拷贝结果:$copyResult")
+ // 跳转回原Fragment,展示拍摄的照片
+ obtainMessageViewModel
+ .updateMessagePic(
+ File(
+ SystemConstant.CameraFolder,
+ fileName
+ ).absolutePath
+ )
+ } catch (e: Exception) {
+ XLog.e("崩溃:${e.message}")
+ }
+
} else {
// 跳转回原Fragment,展示拍摄的照片
- ViewModelProvider(requireActivity()).get(ObtainMessageViewModel::class.java).updateMessagePic(file!!.absolutePath)
+ obtainMessageViewModel.updateMessagePic(file!!.absolutePath)
}
}
@@ -414,12 +459,23 @@ class ObtainMessageFragment: Fragment() {
XLog.d("压缩图片失败:${e.message}")
}
}).launch()
- } else if (fileName.endsWith(".mp3")||fileName.endsWith(".wav")||fileName.endsWith(".amr")||fileName.endsWith(".m4a")) {
+ } else if (fileName.endsWith(".mp3") || fileName.endsWith(".wav") || fileName.endsWith(
+ ".amr"
+ ) || fileName.endsWith(".m4a")
+ ) {
ToastUtils.showToast(it.absolutePath)
if (!it.parentFile.parentFile.absolutePath.equals(SystemConstant.SoundFolder)) {
- val copyResult = FileIOUtils.writeFileFromIS(File(SystemConstant.SoundFolder, fileName), FileInputStream(it))
- XLog.e("拷贝结果:"+copyResult)
- obtainMessageViewModel.updateMessageAudio(File(SystemConstant.SoundFolder, fileName).absolutePath)
+ val copyResult = FileIOUtils.writeFileFromIS(
+ File(SystemConstant.SoundFolder, fileName),
+ FileInputStream(it)
+ )
+ XLog.e("拷贝结果:" + copyResult)
+ obtainMessageViewModel.updateMessageAudio(
+ File(
+ SystemConstant.SoundFolder,
+ fileName
+ ).absolutePath
+ )
} else {
obtainMessageViewModel.updateMessageAudio(it.absolutePath)
}
@@ -432,12 +488,14 @@ class ObtainMessageFragment: Fragment() {
}
binding.tvAudioName.setOnClickListener {
- binding.llAudioPlay.visibility = if (binding.llAudioPlay.visibility == VISIBLE) GONE else VISIBLE
+ binding.llAudioPlay.visibility =
+ if (binding.llAudioPlay.visibility == VISIBLE) GONE else VISIBLE
// 判断当前播放的文件是否在缓存文件夹内,如果不在首先下载该文件
val fileUrl = obtainMessageViewModel.getMessageLiveData().value!!.mediaUrl!!
- val localFile = obtainMessageViewModel.getLocalFileFromNetUrl(fileUrl, AttachmentType.AUDIO)
+ val localFile =
+ obtainMessageViewModel.getLocalFileFromNetUrl(fileUrl, AttachmentType.AUDIO)
if (!localFile.exists()) {
- obtainMessageViewModel.downLoadFile(fileUrl, localFile, object: DownloadCallback {
+ obtainMessageViewModel.downLoadFile(fileUrl, localFile, object : DownloadCallback {
override fun progress(progress: Int) {
}
@@ -455,7 +513,7 @@ class ObtainMessageFragment: Fragment() {
}
binding.btnObtainMessageBack.setOnClickListener {
- Navigation.findNavController(it).popBackStack()
+ findNavController().popBackStack()
}
binding.btnObtainMessageConfirm.setOnClickListener {
@@ -476,7 +534,7 @@ class ObtainMessageFragment: Fragment() {
toolTipRelativeLayout.showToolTipForView(toolTip, binding.tiLayoutTitle)
checkResult = false
} else {
- if (messageData?.name!!.length>10) {
+ if (messageData?.name!!.length > 10) {
val toolTipRelativeLayout =
binding.ttTitle
val toolTip = ToolTip()
@@ -514,7 +572,7 @@ class ObtainMessageFragment: Fragment() {
checkResult = false
}
- if (messageData?.who?.isEmpty()==true) {
+ if (messageData?.who?.isEmpty() == true) {
val toolTipRelativeLayout =
binding.ttSendFrom
val toolTip = ToolTip()
@@ -526,7 +584,7 @@ class ObtainMessageFragment: Fragment() {
toolTipRelativeLayout.showToolTipForView(toolTip, binding.edtSendFrom)
checkResult = false
}
- if (messageData?.toWho?.isEmpty()==true) {
+ if (messageData?.toWho?.isEmpty() == true) {
val toolTipRelativeLayout =
binding.ttSendTo
val toolTip = ToolTip()
@@ -547,22 +605,30 @@ class ObtainMessageFragment: Fragment() {
localAttachmentList.add(imageAttachment)
}
if (messageData?.mediaUrl?.startsWith("http") == false) {
- val audioAttachment = Attachment("", messageData.mediaUrl!!, AttachmentType.AUDIO)
+ val audioAttachment =
+ Attachment("", messageData.mediaUrl!!, AttachmentType.AUDIO)
localAttachmentList.add(audioAttachment)
}
if (localAttachmentList.isNotEmpty()) {
MaterialAlertDialogBuilder(requireContext())
.setTitle("提示")
.setMessage("当前照片及音频内容需首先上传,是否尝试上传?")
- .setPositiveButton("确定", DialogInterface.OnClickListener { dialogInterface, i ->
- dialogInterface.dismiss()
- for (attachment in localAttachmentList) {
- obtainMessageViewModel.uploadAttachment(File(attachment.pathUrl), attachment.attachmentType)
- }
- })
- .setNegativeButton("取消", DialogInterface.OnClickListener {
- dialogInterface, i -> dialogInterface.dismiss()
- })
+ .setPositiveButton(
+ "确定",
+ DialogInterface.OnClickListener { dialogInterface, i ->
+ dialogInterface.dismiss()
+ for (attachment in localAttachmentList) {
+ obtainMessageViewModel.uploadAttachment(
+ File(attachment.pathUrl),
+ attachment.attachmentType
+ )
+ }
+ })
+ .setNegativeButton(
+ "取消",
+ DialogInterface.OnClickListener { dialogInterface, i ->
+ dialogInterface.dismiss()
+ })
.show()
return@setOnClickListener
}
@@ -571,7 +637,7 @@ class ObtainMessageFragment: Fragment() {
val sendDate = DateUtils.str2Date(messageData?.sendDate, dateSendFormat)
val cal = Calendar.getInstance()
cal.time = Date()
- cal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE)+1)
+ cal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE) + 1)
if (sendDate.time < cal.time.time) { // 发送时间设置小于当前时间1分钟后,Toast提示用户并自动设置发送时间
messageData?.sendDate = DateUtils.date2Str(cal.time, dateSendFormat)
ToastUtils.showToast("自动调整发送时间为1分钟后发送")
@@ -581,7 +647,7 @@ class ObtainMessageFragment: Fragment() {
}
// 开始网络提交数据
- if (obtainMessageViewModel.getMessageLiveData().value?.id==0L) { // 如果网络id为空,则调用更新操作
+ if (obtainMessageViewModel.getMessageLiveData().value?.id == 0L) { // 如果网络id为空,则调用更新操作
obtainMessageViewModel.insertCardByApp(confirmCallback)
} else {
obtainMessageViewModel.updateCardByApp(confirmCallback)
@@ -593,7 +659,8 @@ class ObtainMessageFragment: Fragment() {
val viewData = ViewData()
viewData.imageSrc = obtainMessageViewModel.getMessageLiveData().value!!.imageUrl
viewData.targetX = Utils.dp2px(context, 10F).toFloat()
- viewData.targetWidth = DisplayUtils.getScreenWidthPixels(activity) - Utils.dp2px(context, 20F)
+ viewData.targetWidth =
+ DisplayUtils.getScreenWidthPixels(activity) - Utils.dp2px(context, 20F)
viewData.targetHeight = Utils.dp2px(context, 200F)
val viewDataList = listOf(viewData)
binding.imageViewer.overlayStatusBar(true) // ImageViewer 是否会占据 StatusBar 的空间
@@ -603,11 +670,13 @@ class ObtainMessageFragment: Fragment() {
.watch(0) // 开启浏览
}
+ binding.edtSendFrom.setText(obtainMessageViewModel.username)
+
}
- val confirmCallback = object: ObtainMessageViewModel.MyConfirmCallback {
+ val confirmCallback = object : ObtainMessageViewModel.MyConfirmCallback {
override fun onSucess() {
- findNavController().navigate(R.id.navigation_home)
+ findNavController().popBackStack()
}
}
@@ -648,6 +717,7 @@ class ObtainMessageFragment: Fragment() {
})
.show()
}
+
fun onRecorderDenied() {
ToastUtils.showToast("当前操作需要您授权录音权限!")
}
diff --git a/app/src/main/java/com/navinfo/volvo/ui/fragments/message/ObtainMessageViewModel.kt b/app/src/main/java/com/navinfo/volvo/ui/fragments/message/ObtainMessageViewModel.kt
index 3ef2925..db7cde8 100644
--- a/app/src/main/java/com/navinfo/volvo/ui/fragments/message/ObtainMessageViewModel.kt
+++ b/app/src/main/java/com/navinfo/volvo/ui/fragments/message/ObtainMessageViewModel.kt
@@ -1,36 +1,47 @@
package com.navinfo.volvo.ui.fragments.message
-import android.security.ConfirmationCallback
-import androidx.lifecycle.*
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
import com.easytools.tools.FileIOUtils
import com.easytools.tools.FileUtils
import com.easytools.tools.ToastUtils
import com.elvishew.xlog.XLog
-import com.navinfo.volvo.database.entity.Attachment
import com.navinfo.volvo.database.entity.AttachmentType
import com.navinfo.volvo.database.entity.GreetingMessage
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.repository.preferences.PreferencesRepository
import com.navinfo.volvo.utils.SystemConstant
-import kotlinx.coroutines.flow.Flow
+import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
-import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import java.io.File
import java.io.FileInputStream
-import java.util.*
import javax.inject.Inject
-
-class ObtainMessageViewModel @Inject constructor(): ViewModel() {
+@HiltViewModel
+class ObtainMessageViewModel @Inject constructor(
+ private val pre: PreferencesRepository,
+) : ViewModel() {
private val msgLiveData: MutableLiveData by lazy {
MutableLiveData()
}
+ var username: String = ""
+
+ init {
+ viewModelScope.launch {
+ pre.loginUser().collect {
+ username = it!!.username
+ }
+ }
+ }
+
fun setCurrentMessage(msg: GreetingMessage) {
msgLiveData.postValue(msg)
}
@@ -131,7 +142,11 @@ class ObtainMessageViewModel @Inject constructor(): ViewModel() {
try {
val requestFile: RequestBody =
RequestBody.create("multipart/form-data".toMediaTypeOrNull(), attachmentFile)
- val body = MultipartBody.Part.createFormData("picture", attachmentFile.getName(), requestFile)
+ val body = MultipartBody.Part.createFormData(
+ "picture",
+ attachmentFile.getName(),
+ requestFile
+ )
val result = NavinfoVolvoCall.getApi().uploadAttachment(body)
XLog.d(result.code)
if (result.code == 200) { // 请求成功
@@ -144,17 +159,19 @@ class ObtainMessageViewModel @Inject constructor(): ViewModel() {
if (destFile.exists()) {
FileUtils.deleteFile(destFile)
}
- val copyResult = FileIOUtils.writeFileFromIS(destFile, FileInputStream(attachmentFile))
- XLog.e("拷贝结果:"+copyResult)
+ val copyResult =
+ FileIOUtils.writeFileFromIS(destFile, FileInputStream(attachmentFile))
+ XLog.e("拷贝结果:" + copyResult)
} else {
val destFile = File(SystemConstant.SoundFolder, newFileName)
if (destFile.exists()) {
FileUtils.deleteFile(destFile)
}
- val copyResult = FileIOUtils.writeFileFromIS(destFile, FileInputStream(attachmentFile))
- XLog.e("拷贝结果:"+copyResult)
+ val copyResult =
+ FileIOUtils.writeFileFromIS(destFile, FileInputStream(attachmentFile))
+ XLog.e("拷贝结果:" + copyResult)
}
- if (fileKey!=null) {
+ if (fileKey != null) {
downloadAttachment(fileKey, attachmentType)
}
} else {
@@ -179,7 +196,7 @@ class ObtainMessageViewModel @Inject constructor(): ViewModel() {
if (result.code == 200) { // 请求成功
// 获取上传后的结果
val imageUrl = result.data
- if (imageUrl!=null) {
+ if (imageUrl != null) {
XLog.d("downloadAttachment-imageUrl:${imageUrl}")
// 获取到图片的网络地址
if (attachmentType == AttachmentType.PIC) {
@@ -198,7 +215,7 @@ class ObtainMessageViewModel @Inject constructor(): ViewModel() {
}
}
- fun downLoadFile(url: String, destFile: File, downloadCallback: DownloadCallback){
+ fun downLoadFile(url: String, destFile: File, downloadCallback: DownloadCallback) {
viewModelScope.launch {
DownloadManager.download(
url,
@@ -236,7 +253,8 @@ class ObtainMessageViewModel @Inject constructor(): ViewModel() {
"sendDate" to message?.sendDate,
"version" to message?.version
)
- val result = NavinfoVolvoCall.getApi().insertCardByApp(insertData as Map)
+ val result =
+ NavinfoVolvoCall.getApi().insertCardByApp(insertData as Map)
XLog.d("insertCardByApp:${result.code}")
if (result.code == 200) { // 请求成功
// 获取上传后的结果
@@ -269,7 +287,8 @@ class ObtainMessageViewModel @Inject constructor(): ViewModel() {
"sendDate" to message?.sendDate,
"version" to message?.version
)
- val result = NavinfoVolvoCall.getApi().updateCardByApp(updateData as Map)
+ val result =
+ NavinfoVolvoCall.getApi().updateCardByApp(updateData as Map)
XLog.d("updateCardByApp:${result.code}")
if (result.code == 200) { // 请求成功
// 数据更新成功
@@ -289,14 +308,14 @@ class ObtainMessageViewModel @Inject constructor(): ViewModel() {
/**
* 根据网络地址获取本地的缓存文件路径
* */
- fun getLocalFileFromNetUrl(url: String, attachmentType: AttachmentType):File {
+ fun getLocalFileFromNetUrl(url: String, attachmentType: AttachmentType): File {
if (url.startsWith("http")) {
- val folder = when(attachmentType) {
- AttachmentType.PIC-> SystemConstant.CameraFolder
+ val folder = when (attachmentType) {
+ AttachmentType.PIC -> SystemConstant.CameraFolder
else -> SystemConstant.SoundFolder
}
var name = if (url.contains("?")) {
- url.substring(url.lastIndexOf("/")+1, url.indexOf("?"))
+ url.substring(url.lastIndexOf("/") + 1, url.indexOf("?"))
} else {
url.substringAfterLast("/")
}
diff --git a/app/src/main/java/com/navinfo/volvo/util/NetResult.kt b/app/src/main/java/com/navinfo/volvo/util/NetResult.kt
index 21c532c..8f5aca2 100644
--- a/app/src/main/java/com/navinfo/volvo/util/NetResult.kt
+++ b/app/src/main/java/com/navinfo/volvo/util/NetResult.kt
@@ -11,14 +11,16 @@ package com.navinfo.volvo.util
sealed class NetResult {
data class Success(val data: T?) : NetResult()
+ data class Failure(val code: Int, val msg: String) : NetResult()
data class Error(val exception: Exception) : NetResult()
object Loading : NetResult()
override fun toString(): String {
return when (this) {
- is Success<*> -> "Success[data=$data]"
- is Error -> "Error[exception=$exception]"
- is Loading -> "Loading"
+ is Success<*> -> "网络访问成功,返回正确结果Success[data=$data]"
+ is Failure -> "网络访问成功,返回错误结果Failure[$msg]"
+ is Error -> "网络访问出错 Error[exception=$exception]"
+ is Loading -> "网络访问中 Loading"
}
}
}
diff --git a/app/src/main/java/com/navinfo/volvo/util/SharedPreferenceHelper.kt b/app/src/main/java/com/navinfo/volvo/util/SharedPreferenceHelper.kt
deleted file mode 100644
index f4e5fdc..0000000
--- a/app/src/main/java/com/navinfo/volvo/util/SharedPreferenceHelper.kt
+++ /dev/null
@@ -1,131 +0,0 @@
-package com.navinfo.volvo.util
-
-import android.content.Context
-import android.content.SharedPreferences
-import android.preference.PreferenceManager
-import androidx.core.content.edit
-import com.google.gson.Gson
-
-
-class SharedPreferenceHelper {
-
- companion object {
-
- private const val WEATHER_PREF_TIME = "Weather pref time"
- private const val WEATHER_FORECAST_PREF_TIME = "Forecast pref time"
- private const val CITY_ID = "City ID"
- private var prefs: SharedPreferences? = null
- private const val LOCATION = "LOCATION"
-
- @Volatile
- private var instance: SharedPreferenceHelper? = null
-
- /**
- * This checks if there is an existing instance of the [SharedPreferences] in the
- * specified [context] and creates one if there isn't or else, it returns the
- * already existing instance. This function ensures that the [SharedPreferences] is
- * accessed at any instance by a single thread.
- */
- fun getInstance(context: Context): SharedPreferenceHelper {
- synchronized(this) {
- val _instance = instance
- if (_instance == null) {
- prefs = PreferenceManager.getDefaultSharedPreferences(context)
- instance = _instance
- }
- return SharedPreferenceHelper()
- }
- }
- }
-
- /**
- * This function saves the initial time [System.nanoTime] at which the weather information
- * at the user's location is accessed.
- * @param time the value of [System.nanoTime] when the weather information is received.
- */
- fun saveTimeOfInitialWeatherFetch(time: Long) {
- prefs?.edit(commit = true) {
- putLong(WEATHER_PREF_TIME, time)
- }
- }
-
- /**
- * This function returns the saved value of [System.nanoTime] when the weather information
- * at the user's location was accessed.
- * @see saveTimeOfInitialWeatherFetch
- */
- fun getTimeOfInitialWeatherFetch() = prefs?.getLong(WEATHER_PREF_TIME, 0L)
-
- /**
- * This function saves the initial time [System.nanoTime] at which the weather forecast
- * at the user's location is accessed.
- * @param time the value of [System.nanoTime] when the weather forecast is received.
- */
- fun saveTimeOfInitialWeatherForecastFetch(time: Long) {
- prefs?.edit(commit = true) {
- putLong(WEATHER_FORECAST_PREF_TIME, time)
- }
- }
-
- /**
- * This function returns the saved value of [System.nanoTime] when the weather forecast
- * at the user's location was accessed.
- * @see saveTimeOfInitialWeatherForecastFetch
- */
- fun getTimeOfInitialWeatherForecastFetch() = prefs?.getLong(WEATHER_FORECAST_PREF_TIME, 0L)
-
- /**
- * This function saves the [cityId] of the location whose weather information has been
- * received.
- * @param cityId the id of the location whose weather has been received
- */
- fun saveCityId(cityId: Int) {
- prefs?.edit(commit = true) {
- putInt(CITY_ID, cityId)
- }
- }
-
- /**
- * This function returns the id of the location whose weather information has been received.
- * @see saveCityId
- */
- fun getCityId() = prefs?.getInt(CITY_ID, 0)
-
- /**
- * This function gets the value of the cache duration the user set in the
- * Settings Fragment.
- */
- fun getUserSetCacheDuration() = prefs?.getString("cache_key", "0")
-
- /**
- * This function gets the value of the app theme the user set in the
- * Settings Fragment.
- */
- fun getSelectedThemePref() = prefs?.getString("theme_key", "")
-
- /**
- * This function gets the value of the temperature unit the user set in the
- * Settings Fragment.
- */
- fun getSelectedTemperatureUnit() = prefs?.getString("unit_key", "")
-
-// /**
-// * This function saves a [LocationModel]
-// */
-// fun saveLocation(location: LocationModel) {
-// prefs?.edit(commit = true) {
-// val gson = Gson()
-// val json = gson.toJson(location)
-// putString(LOCATION, json)
-// }
-// }
-
-// /**
-// * This function gets the value of the saved [LocationModel]
-// */
-// fun getLocation(): LocationModel {
-// val gson = Gson()
-// val json = prefs?.getString(LOCATION, null)
-// return gson.fromJson(json, LocationModel::class.java)
-// }
-}
diff --git a/app/src/main/proto/LoginUser.proto b/app/src/main/proto/LoginUser.proto
new file mode 100644
index 0000000..15d5d45
--- /dev/null
+++ b/app/src/main/proto/LoginUser.proto
@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+option java_package = "com.navinfo.volvo.model.proto";
+option java_multiple_files = true;
+
+message LoginUser {
+ string username = 1;
+ string password = 2;
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/adapter_home.xml b/app/src/main/res/layout/adapter_home.xml
index 7a24c31..98fc513 100644
--- a/app/src/main/res/layout/adapter_home.xml
+++ b/app/src/main/res/layout/adapter_home.xml
@@ -1,12 +1,14 @@
-
+
+
+
@@ -17,15 +19,17 @@
android:layout_height="wrap_content">
-
+ app:layout_constraintTop_toTopOf="parent"
+ app:roundPercent="0.4" />
@@ -23,8 +23,8 @@
android:hint="请输入查询内容" />
-
+ app:layout_constraintTop_toBottomOf="@id/home_search">
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_login.xml b/app/src/main/res/layout/fragment_login.xml
index 6829329..f468b7a 100644
--- a/app/src/main/res/layout/fragment_login.xml
+++ b/app/src/main/res/layout/fragment_login.xml
@@ -6,7 +6,7 @@
+ type="com.navinfo.volvo.model.proto.LoginUser" />
-
-
@@ -54,6 +55,7 @@
app:layout_constraintTop_toBottomOf="@id/login_fragment_user_layout">
+ tools:context="com.navinfo.volvo.ui.fragments.message.ObtainMessageFragment">
+
+
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/home_adapter_noting.xml b/app/src/main/res/layout/home_adapter_noting.xml
new file mode 100644
index 0000000..56ba3de
--- /dev/null
+++ b/app/src/main/res/layout/home_adapter_noting.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/load_state_view.xml b/app/src/main/res/layout/load_state_view.xml
new file mode 100644
index 0000000..7450e8b
--- /dev/null
+++ b/app/src/main/res/layout/load_state_view.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/mobile_navigation.xml b/app/src/main/res/navigation/mobile_navigation.xml
index 83fe244..c59218b 100644
--- a/app/src/main/res/navigation/mobile_navigation.xml
+++ b/app/src/main/res/navigation/mobile_navigation.xml
@@ -13,12 +13,9 @@
+