diff --git a/app/build.gradle b/app/build.gradle index 93a2907..4c41460 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -136,9 +136,13 @@ dependencies { // 日志工具 https://github.com/elvishew/xLog/blob/master/README_ZH.md implementation 'com.elvishew:xlog:1.10.1' //加载图片的依赖包 - implementation ("com.github.bumptech.glide:glide:4.11.0") { + implementation("com.github.bumptech.glide:glide:4.11.0") { exclude group: "com.android.support" } + // 多媒体播放库 https://github.com/JagarYousef/ChatVoicePlayer + implementation 'com.github.JagarYousef:ChatVoicePlayer:1.1.0' + // 图片查看器 https://github.com/XiaoGe-1996/ImageViewer + implementation 'com.github.XiaoGe-1996:ImageViewer:v1.0.0' } kapt { diff --git a/app/src/main/java/com/navinfo/volvo/database/AppDatabase.kt b/app/src/main/java/com/navinfo/volvo/database/AppDatabase.kt index 0f288af..4b5f880 100644 --- a/app/src/main/java/com/navinfo/volvo/database/AppDatabase.kt +++ b/app/src/main/java/com/navinfo/volvo/database/AppDatabase.kt @@ -2,19 +2,19 @@ package com.navinfo.volvo.database import androidx.room.Database import androidx.room.RoomDatabase -import com.navinfo.volvo.database.dao.MessageDao +import com.navinfo.volvo.database.dao.GreetingMessageDao import com.navinfo.volvo.database.dao.UserDao -import com.navinfo.volvo.model.Attachment -import com.navinfo.volvo.model.Message -import com.navinfo.volvo.model.User +import com.navinfo.volvo.database.entity.Attachment +import com.navinfo.volvo.database.entity.GreetingMessage +import com.navinfo.volvo.database.entity.User @Database( - entities = [Message::class, Attachment::class, User::class], + entities = [GreetingMessage::class, Attachment::class, User::class], version = 1, exportSchema = false ) abstract class AppDatabase : RoomDatabase() { - abstract fun getMessageDao(): MessageDao + abstract fun getMessageDao(): GreetingMessageDao abstract fun getUserDao(): UserDao } \ 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 index 857125f..f1ebae1 100644 --- a/app/src/main/java/com/navinfo/volvo/database/MapLifeDataBase.java +++ b/app/src/main/java/com/navinfo/volvo/database/MapLifeDataBase.java @@ -1,191 +1,191 @@ -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.model.Message; -import com.navinfo.volvo.model.Attachment; -import com.navinfo.volvo.model.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; - } -} +//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 new file mode 100644 index 0000000..479d490 --- /dev/null +++ b/app/src/main/java/com/navinfo/volvo/database/dao/GreetingMessageDao.kt @@ -0,0 +1,19 @@ +package com.navinfo.volvo.database.dao + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.navinfo.volvo.database.entity.GreetingMessage + +@Dao +interface GreetingMessageDao { + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun insert(vararg check: GreetingMessage) + + @Query("SELECT * FROM GreetingMessage where id =:id") + fun findCheckManagerById(id: Long): GreetingMessage? + + @Query("SELECT * FROM GreetingMessage") + fun findList(): List +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/volvo/database/dao/MessageDao.kt b/app/src/main/java/com/navinfo/volvo/database/dao/MessageDao.kt deleted file mode 100644 index fa60d36..0000000 --- a/app/src/main/java/com/navinfo/volvo/database/dao/MessageDao.kt +++ /dev/null @@ -1,19 +0,0 @@ -package com.navinfo.volvo.database.dao - -import androidx.room.Dao -import androidx.room.Insert -import androidx.room.OnConflictStrategy -import androidx.room.Query -import com.navinfo.volvo.model.Message - -@Dao -interface MessageDao { - @Insert(onConflict = OnConflictStrategy.REPLACE) - fun insert(vararg check: Message) - - @Query("SELECT * FROM Message where id =:id") - fun findCheckManagerById(id: Long): Message? - - @Query("SELECT * FROM Message") - fun findList(): List -} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/volvo/database/dao/UserDao.kt b/app/src/main/java/com/navinfo/volvo/database/dao/UserDao.kt index fdbd156..4057662 100644 --- a/app/src/main/java/com/navinfo/volvo/database/dao/UserDao.kt +++ b/app/src/main/java/com/navinfo/volvo/database/dao/UserDao.kt @@ -3,7 +3,7 @@ package com.navinfo.volvo.database.dao import androidx.room.Dao import androidx.room.Insert import androidx.room.OnConflictStrategy -import com.navinfo.volvo.model.User +import com.navinfo.volvo.database.entity.User @Dao interface UserDao { diff --git a/app/src/main/java/com/navinfo/volvo/model/Attachment.kt b/app/src/main/java/com/navinfo/volvo/database/entity/Attachment.kt similarity index 95% rename from app/src/main/java/com/navinfo/volvo/model/Attachment.kt rename to app/src/main/java/com/navinfo/volvo/database/entity/Attachment.kt index fefa2b3..4e226d4 100644 --- a/app/src/main/java/com/navinfo/volvo/model/Attachment.kt +++ b/app/src/main/java/com/navinfo/volvo/database/entity/Attachment.kt @@ -1,4 +1,4 @@ -package com.navinfo.volvo.model +package com.navinfo.volvo.database.entity import androidx.room.Entity import androidx.room.PrimaryKey @@ -8,7 +8,7 @@ import com.navinfo.volvo.tools.GsonUtil @Entity(tableName = "Attachment") data class Attachment( - @PrimaryKey() + @PrimaryKey var id: String, var pathUrl: String, var attachmentType: AttachmentType diff --git a/app/src/main/java/com/navinfo/volvo/database/entity/GreetingMessage.kt b/app/src/main/java/com/navinfo/volvo/database/entity/GreetingMessage.kt new file mode 100644 index 0000000..325af6b --- /dev/null +++ b/app/src/main/java/com/navinfo/volvo/database/entity/GreetingMessage.kt @@ -0,0 +1,44 @@ +package com.navinfo.volvo.database.entity + +import androidx.room.Entity +import androidx.room.PrimaryKey +import androidx.room.TypeConverters +import org.jetbrains.annotations.NotNull + +@Entity(tableName = "GreetingMessage") +@TypeConverters(AttachmentConverters::class) +data class GreetingMessage @JvmOverloads constructor( + @PrimaryKey(autoGenerate = true) + var uuid:Long = 0, + var id: Long = 0, + var searchValue: String? = "", + var createBy: String? = "", + var createTime: String? = "", + var updateBy: String? = "", + var updateTime: String? = "", + var remark: String? = "", + var name: String? = "", + var imageUrl: String? = "", + var mediaUrl: String? = "", + var who: String? = "", + var toWho: String? = "", + var sendDate: String? = "", + var status: String? = "", + var isSkip: String? = "", + var skipUrl: String? = "", + var startTime: String? = "", + var endTime: String? = "", + var sendVehicle: String? = "", + var sendSex: String? = "", + var sendAge: String? = "", + var sendNum: String? = "", + var sendVins: String? = "", + var sendType: String? = "", + var del: String? = "", + var version: String? = "", +// /** +// * 附件列表 +// */ +// var attachment: MutableList = mutableListOf() +) { +} diff --git a/app/src/main/java/com/navinfo/volvo/model/User.kt b/app/src/main/java/com/navinfo/volvo/database/entity/User.kt similarity index 93% rename from app/src/main/java/com/navinfo/volvo/model/User.kt rename to app/src/main/java/com/navinfo/volvo/database/entity/User.kt index 80a6c7a..1816bd4 100644 --- a/app/src/main/java/com/navinfo/volvo/model/User.kt +++ b/app/src/main/java/com/navinfo/volvo/database/entity/User.kt @@ -1,4 +1,4 @@ -package com.navinfo.volvo.model +package com.navinfo.volvo.database.entity import androidx.room.Entity import androidx.room.PrimaryKey @@ -7,8 +7,6 @@ import androidx.room.TypeConverters import com.google.gson.reflect.TypeToken import com.navinfo.volvo.tools.GsonUtil import org.jetbrains.annotations.NotNull -import java.time.LocalDateTime -import java.time.LocalTime import javax.inject.Inject @Entity(tableName = "User") diff --git a/app/src/main/java/com/navinfo/volvo/di/module/DatabaseModule.kt b/app/src/main/java/com/navinfo/volvo/di/module/DatabaseModule.kt index bd2582e..2a302b3 100644 --- a/app/src/main/java/com/navinfo/volvo/di/module/DatabaseModule.kt +++ b/app/src/main/java/com/navinfo/volvo/di/module/DatabaseModule.kt @@ -3,7 +3,7 @@ package com.navinfo.volvo.di.module import android.content.Context import androidx.room.Room import com.navinfo.volvo.database.AppDatabase -import com.navinfo.volvo.database.dao.MessageDao +import com.navinfo.volvo.database.dao.GreetingMessageDao import com.navinfo.volvo.database.dao.UserDao import com.tencent.wcdb.database.SQLiteCipherSpec import com.tencent.wcdb.room.db.WCDBOpenHelperFactory @@ -45,7 +45,7 @@ class DatabaseModule { @Singleton @Provides - fun provideMessageDao(database: AppDatabase): MessageDao { + fun provideMessageDao(database: AppDatabase): GreetingMessageDao { return database.getMessageDao() } diff --git a/app/src/main/java/com/navinfo/volvo/http/DownloadManager.kt b/app/src/main/java/com/navinfo/volvo/http/DownloadManager.kt new file mode 100644 index 0000000..666b263 --- /dev/null +++ b/app/src/main/java/com/navinfo/volvo/http/DownloadManager.kt @@ -0,0 +1,86 @@ +package com.navinfo.volvo.http + +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.catch +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import okhttp3.ResponseBody +import retrofit2.Retrofit +import java.io.File +import java.io.IOException + +object DownloadManager { + suspend fun download(url: String, file: File): Flow { + return flow { + val retrofit = Retrofit.Builder() + .baseUrl(UrlUtils.getBaseUrl(url)) + .build() + val response = retrofit.create(NavinfoVolvoService::class.java).downloadFile(url).execute() + if (response.isSuccessful) { + saveToFile(response.body()!!, file) { + emit(DownloadState.InProgress(it)) + } + emit(DownloadState.Success(file)) + } else { + emit(DownloadState.Error(IOException(response.toString()))) + } + }.catch { + emit(DownloadState.Error(it)) + }.flowOn(Dispatchers.IO) + } + + private inline fun saveToFile(responseBody: ResponseBody, file: File, progressListener: (Int) -> Unit) { + val total = responseBody.contentLength() + var bytesCopied = 0 + var emittedProgress = 0 + file.outputStream().use { output -> + val input = responseBody.byteStream() + val buffer = ByteArray(DEFAULT_BUFFER_SIZE) + var bytes = input.read(buffer) + while (bytes >= 0) { + output.write(buffer, 0, bytes) + bytesCopied += bytes + bytes = input.read(buffer) + val progress = (bytesCopied * 100 / total).toInt() + if (progress - emittedProgress > 0) { + progressListener(progress) + emittedProgress = progress + } + } + } + } +} + +sealed class DownloadState { + data class InProgress(val progress: Int) : DownloadState() + data class Success(val file: File) : DownloadState() + data class Error(val throwable: Throwable) : DownloadState() +} + +interface DownloadCallback { + fun progress(progress: Int) + fun error(throwable: Throwable) + fun success(file: File) +} + +object UrlUtils { + + /** + * 从url分割出BaseUrl + */ + fun getBaseUrl(url: String): String { + var mutableUrl = url + var head = "" + var index = mutableUrl.indexOf("://") + if (index != -1) { + head = mutableUrl.substring(0, index + 3) + mutableUrl = mutableUrl.substring(index + 3) + } + index = mutableUrl.indexOf("/") + if (index != -1) { + mutableUrl = mutableUrl.substring(0, index + 1) + } + return head + mutableUrl + } +} \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/volvo/http/NavinfoVolvoService.kt b/app/src/main/java/com/navinfo/volvo/http/NavinfoVolvoService.kt index 019e473..206d55a 100644 --- a/app/src/main/java/com/navinfo/volvo/http/NavinfoVolvoService.kt +++ b/app/src/main/java/com/navinfo/volvo/http/NavinfoVolvoService.kt @@ -2,11 +2,9 @@ package com.navinfo.volvo.http import okhttp3.MultipartBody import okhttp3.RequestBody +import okhttp3.ResponseBody import retrofit2.Call -import retrofit2.http.Body -import retrofit2.http.Multipart -import retrofit2.http.POST -import retrofit2.http.Part +import retrofit2.http.* import java.io.File interface NavinfoVolvoService { @@ -23,4 +21,7 @@ interface NavinfoVolvoService { suspend fun uploadAttachment(@Part attachmentFile: MultipartBody.Part):DefaultResponse> @POST("/img/download") suspend fun downLoadAttachment(@Body downloadData: Map):DefaultResponse + @Streaming + @GET + fun downloadFile(@Url url: String): Call } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/volvo/model/Message.kt b/app/src/main/java/com/navinfo/volvo/model/Message.kt deleted file mode 100644 index 82c591d..0000000 --- a/app/src/main/java/com/navinfo/volvo/model/Message.kt +++ /dev/null @@ -1,46 +0,0 @@ -package com.navinfo.volvo.model - -import androidx.room.Entity -import androidx.room.PrimaryKey -import androidx.room.TypeConverters - -@Entity(tableName = "message") -@TypeConverters(AttachmentConverters::class) -data class Message @JvmOverloads constructor( - @PrimaryKey(autoGenerate = true) - var id: Long = 0, - - var netId: String = "", - /** - *标题 - */ - var title: String = "", - /** - * 信息内容 - */ - var message: String = "", - /** - * 操作时间 - */ - var optionDate: String = "", - /** - * 发送时间 - */ - var sendDate: String = "", - /** - * 信息状态 - */ - var status: Int = 1, - /** - * 发送者ID - */ - var fromId: String = "", - /** - * 接收者ID - */ - var toId: String = "", - /** - * 附件列表 - */ - var attachment: MutableList = mutableListOf() -) diff --git a/app/src/main/java/com/navinfo/volvo/model/network/NetworkPostMessage.kt b/app/src/main/java/com/navinfo/volvo/model/messagelist/NetworkMessageListPost.kt similarity index 87% rename from app/src/main/java/com/navinfo/volvo/model/network/NetworkPostMessage.kt rename to app/src/main/java/com/navinfo/volvo/model/messagelist/NetworkMessageListPost.kt index 8e452f6..91d0dd5 100644 --- a/app/src/main/java/com/navinfo/volvo/model/network/NetworkPostMessage.kt +++ b/app/src/main/java/com/navinfo/volvo/model/messagelist/NetworkMessageListPost.kt @@ -1,6 +1,6 @@ -package com.navinfo.volvo.model.network +package com.navinfo.volvo.model.messagelist -data class NetworkPostMessage( +data class NetworkMessageListPost( val name: String,//问候名称,非必填项 val who: String, //我是谁 val toWho: String, //发送给谁 diff --git a/app/src/main/java/com/navinfo/volvo/model/messagelist/NetworkMessageListResponse.kt b/app/src/main/java/com/navinfo/volvo/model/messagelist/NetworkMessageListResponse.kt new file mode 100644 index 0000000..94b7a40 --- /dev/null +++ b/app/src/main/java/com/navinfo/volvo/model/messagelist/NetworkMessageListResponse.kt @@ -0,0 +1,8 @@ +package com.navinfo.volvo.model.messagelist + +import com.navinfo.volvo.database.entity.GreetingMessage + +data class NetworkMessageListResponse( + val total: Int, + val rows: List +) \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/volvo/repository/NetworkDataSource.kt b/app/src/main/java/com/navinfo/volvo/repository/NetworkDataSource.kt index 0791642..dddf32f 100644 --- a/app/src/main/java/com/navinfo/volvo/repository/NetworkDataSource.kt +++ b/app/src/main/java/com/navinfo/volvo/repository/NetworkDataSource.kt @@ -1,9 +1,10 @@ package com.navinfo.volvo.repository -import com.navinfo.volvo.model.Message -import com.navinfo.volvo.model.network.NetworkPostMessage +import com.navinfo.volvo.http.DefaultResponse +import com.navinfo.volvo.model.messagelist.NetworkMessageListPost +import com.navinfo.volvo.model.messagelist.NetworkMessageListResponse import com.navinfo.volvo.util.NetResult interface NetworkDataSource { - suspend fun getCardList(message: NetworkPostMessage): NetResult> + suspend fun getCardList(message: NetworkMessageListPost): NetResult> } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/volvo/repository/NetworkDataSourceImp.kt b/app/src/main/java/com/navinfo/volvo/repository/NetworkDataSourceImp.kt index 9bf7e4b..2d662bb 100644 --- a/app/src/main/java/com/navinfo/volvo/repository/NetworkDataSourceImp.kt +++ b/app/src/main/java/com/navinfo/volvo/repository/NetworkDataSourceImp.kt @@ -1,15 +1,17 @@ package com.navinfo.volvo.repository +import com.navinfo.volvo.database.AppDatabase +import com.navinfo.volvo.database.dao.GreetingMessageDao import com.navinfo.volvo.di.scope.IoDispatcher -import com.navinfo.volvo.model.Message -import com.navinfo.volvo.model.network.NetworkPostMessage +import com.navinfo.volvo.database.entity.GreetingMessage +import com.navinfo.volvo.http.DefaultResponse +import com.navinfo.volvo.model.messagelist.NetworkMessageListPost +import com.navinfo.volvo.model.messagelist.NetworkMessageListResponse import com.navinfo.volvo.repository.service.NetworkService import com.navinfo.volvo.tools.GsonUtil import com.navinfo.volvo.util.NetResult import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext -import okhttp3.FormBody -import okhttp3.MediaType import okhttp3.MediaType.Companion.toMediaType import okhttp3.RequestBody.Companion.toRequestBody import javax.inject.Inject @@ -17,17 +19,22 @@ import javax.inject.Inject class NetworkDataSourceImp @Inject constructor( private val netWorkService: NetworkService, + private val messageDao: GreetingMessageDao, @IoDispatcher private val ioDispatcher: CoroutineDispatcher ) : NetworkDataSource { - override suspend fun getCardList(message: NetworkPostMessage): NetResult> = + override suspend fun getCardList(message: NetworkMessageListPost): NetResult> = withContext(ioDispatcher) { return@withContext try { - val stringBody = GsonUtil.getInstance().toJson(message).toRequestBody("application/json;charset=utf-8".toMediaType()) + val stringBody = GsonUtil.getInstance().toJson(message) + .toRequestBody("application/json;charset=utf-8".toMediaType()) val result = netWorkService.queryCardListByApp(stringBody) if (result.isSuccessful) { - val list = result.body() - NetResult.Success(list) + val body = result.body() + val list: MutableList = + listOf(body!!.data!!.rows) as MutableList + messageDao.insert(*list.map { it }.toTypedArray()) + NetResult.Success(body) } else { NetResult.Success(null) } diff --git a/app/src/main/java/com/navinfo/volvo/repository/service/NetworkService.kt b/app/src/main/java/com/navinfo/volvo/repository/service/NetworkService.kt index df62a9c..208ce28 100644 --- a/app/src/main/java/com/navinfo/volvo/repository/service/NetworkService.kt +++ b/app/src/main/java/com/navinfo/volvo/repository/service/NetworkService.kt @@ -1,6 +1,7 @@ package com.navinfo.volvo.repository.service -import com.navinfo.volvo.model.Message +import com.navinfo.volvo.http.DefaultResponse +import com.navinfo.volvo.model.messagelist.NetworkMessageListResponse import okhttp3.RequestBody import retrofit2.Response import retrofit2.http.Body @@ -8,5 +9,5 @@ import retrofit2.http.POST interface NetworkService { @POST("/navi/cardDelivery/queryCardListByApp") - suspend fun queryCardListByApp(@Body body: RequestBody): Response> + suspend fun queryCardListByApp(@Body body: RequestBody): Response> } \ 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 5775985..86b1b8a 100644 --- a/app/src/main/java/com/navinfo/volvo/ui/MainActivity.kt +++ b/app/src/main/java/com/navinfo/volvo/ui/MainActivity.kt @@ -10,6 +10,7 @@ import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupWithNavController import com.easytools.tools.FileUtils +import com.elvishew.xlog.BuildConfig import com.elvishew.xlog.LogConfiguration import com.elvishew.xlog.LogLevel import com.elvishew.xlog.XLog @@ -25,7 +26,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.hjq.permissions.OnPermissionCallback import com.hjq.permissions.Permission import com.hjq.permissions.XXPermissions -import com.navinfo.volvo.BuildConfig import com.navinfo.volvo.R import com.navinfo.volvo.databinding.ActivityMainBinding import com.navinfo.volvo.utils.SystemConstant @@ -55,7 +55,8 @@ class MainActivity : AppCompatActivity() { override fun onGranted(permissions: MutableList, all: Boolean) { if (!all) { - Toast.makeText(this@MainActivity, "获取部分权限成功,但部分权限未正常授予", Toast.LENGTH_SHORT).show() + Toast.makeText(this@MainActivity, "获取部分权限成功,但部分权限未正常授予", Toast.LENGTH_SHORT) + .show() return } // 在SD卡创建项目目录 @@ -64,7 +65,8 @@ class MainActivity : AppCompatActivity() { override fun onDenied(permissions: MutableList, never: Boolean) { if (never) { - Toast.makeText(this@MainActivity, "永久拒绝授权,请手动授权文件读写权限", Toast.LENGTH_SHORT).show() + Toast.makeText(this@MainActivity, "永久拒绝授权,请手动授权文件读写权限", Toast.LENGTH_SHORT) + .show() // 如果是被永久拒绝就跳转到应用权限系统设置页面 XXPermissions.startPermissionActivity(this@MainActivity, permissions) } else { @@ -146,10 +148,11 @@ class MainActivity : AppCompatActivity() { val consolePrinter: Printer = ConsolePrinter() // 通过 System.out 打印日志到控制台的打印器 - val filePrinter: Printer = FilePrinter.Builder("${SystemConstant.ROOT_PATH}/Logs") // 指定保存日志文件的路径 - .fileNameGenerator(DateFileNameGenerator()) // 指定日志文件名生成器,默认为 ChangelessFileNameGenerator("log") - .backupStrategy(NeverBackupStrategy()) // 指定日志文件备份策略,默认为 FileSizeBackupStrategy(1024 * 1024) - .build() + val filePrinter: Printer = + FilePrinter.Builder("${SystemConstant.ROOT_PATH}/Logs") // 指定保存日志文件的路径 + .fileNameGenerator(DateFileNameGenerator()) // 指定日志文件名生成器,默认为 ChangelessFileNameGenerator("log") + .backupStrategy(NeverBackupStrategy()) // 指定日志文件备份策略,默认为 FileSizeBackupStrategy(1024 * 1024) + .build() XLog.init( // 初始化 XLog config, // 指定日志配置,如果不指定,会默认使用 new LogConfiguration.Builder().build() diff --git a/app/src/main/java/com/navinfo/volvo/ui/adapter/MessageAdapter.kt b/app/src/main/java/com/navinfo/volvo/ui/adapter/MessageAdapter.kt index 22875d9..cb7525c 100644 --- a/app/src/main/java/com/navinfo/volvo/ui/adapter/MessageAdapter.kt +++ b/app/src/main/java/com/navinfo/volvo/ui/adapter/MessageAdapter.kt @@ -7,18 +7,18 @@ import android.widget.ImageView import android.widget.TextView import androidx.recyclerview.widget.RecyclerView import com.navinfo.volvo.R -import com.navinfo.volvo.model.Message +import com.navinfo.volvo.database.entity.GreetingMessage class MessageAdapter : RecyclerView.Adapter() { - var itemList: MutableList = mutableListOf() + var itemList: MutableList = mutableListOf() - fun addItem(message: Message) { + fun addItem(message: GreetingMessage) { itemList.add(message) notifyItemInserted(itemList.size - 1) } - fun setItem(messageList: MutableList){ + fun setItem(messageList: MutableList){ itemList = messageList notifyDataSetChanged() } @@ -35,8 +35,8 @@ class MessageAdapter : RecyclerView.Adapter() { override fun onBindViewHolder(holder: MyViewHolder, position: Int) { val message = itemList[position] - holder.toName.text = message.fromId - holder.messageText.text = message.message + holder.toName.text = message.toWho + holder.messageText.text = message.name holder.sendTime.text = message.sendDate } diff --git a/app/src/main/java/com/navinfo/volvo/ui/fragments/home/MessageViewModel.kt b/app/src/main/java/com/navinfo/volvo/ui/fragments/home/MessageViewModel.kt index 4bbe309..c65fd8f 100644 --- a/app/src/main/java/com/navinfo/volvo/ui/fragments/home/MessageViewModel.kt +++ b/app/src/main/java/com/navinfo/volvo/ui/fragments/home/MessageViewModel.kt @@ -3,8 +3,9 @@ package com.navinfo.volvo.ui.fragments.home import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import com.navinfo.volvo.model.Message -import com.navinfo.volvo.model.network.NetworkPostMessage +import com.navinfo.volvo.database.entity.GreetingMessage +import com.navinfo.volvo.model.messagelist.NetworkMessageListPost +import com.navinfo.volvo.model.messagelist.NetworkMessageListResponse import com.navinfo.volvo.repository.NetworkDataSource import com.navinfo.volvo.util.NetResult import com.navinfo.volvo.util.asLiveData @@ -18,18 +19,18 @@ class MessageViewModel @Inject constructor( private val _isLoading = MutableLiveData() val isLoading = _isLoading.asLiveData() - private val _messageList = MutableLiveData>() + private val _messageList = MutableLiveData>() val messageList = _messageList.asLiveData() fun getMessageList() { _isLoading.postValue(true) viewModelScope.launch { - val messagePost = NetworkPostMessage(who = "北京测试", toWho = "volvo测试") + val messagePost = NetworkMessageListPost(who = "北京测试", toWho = "volvo测试") when (val result = repository.getCardList(messagePost)) { is NetResult.Success -> { _isLoading.value = false if (result.data != null) { - val list = result.data + val list = (result.data.data as NetworkMessageListResponse).rows _messageList.value = list } } 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 5c02c3e..ef6d19a 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 @@ -5,7 +5,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import com.navinfo.volvo.database.AppDatabase -import com.navinfo.volvo.model.User +import com.navinfo.volvo.database.entity.User import javax.inject.Inject class LoginViewModel @Inject constructor(private val dataBase: AppDatabase) : ViewModel() { 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 43a4a65..ff01973 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 @@ -1,9 +1,11 @@ package com.navinfo.volvo.ui.fragments.message import android.content.DialogInterface +import android.graphics.Paint import android.os.Bundle import android.text.TextUtils import android.view.LayoutInflater +import android.view.MotionEvent import android.view.View import android.view.View.* import android.view.ViewGroup @@ -13,12 +15,17 @@ import android.widget.ArrayAdapter import android.widget.Toast 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 com.bumptech.glide.Glide import com.bumptech.glide.load.engine.DiskCacheStrategy import com.easytools.tools.DateUtils +import com.easytools.tools.DeviceUtils +import com.easytools.tools.DisplayUtils +import com.easytools.tools.FileUtils +import com.easytools.tools.ResourceUtils import com.easytools.tools.ToastUtils import com.elvishew.xlog.XLog import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -28,15 +35,18 @@ import com.hjq.permissions.Permission import com.hjq.permissions.XXPermissions import com.navinfo.volvo.R import com.navinfo.volvo.RecorderLifecycleObserver +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.databinding.FragmentObtainMessageBinding -import com.navinfo.volvo.http.NavinfoVolvoCall -import com.navinfo.volvo.model.Attachment -import com.navinfo.volvo.model.AttachmentType -import com.navinfo.volvo.model.Message +import com.navinfo.volvo.http.DownloadCallback import com.navinfo.volvo.ui.markRequiredInRed +import com.navinfo.volvo.util.PhotoLoader import com.navinfo.volvo.utils.EasyMediaFile import com.navinfo.volvo.utils.SystemConstant import com.nhaarman.supertooltips.ToolTip +import indi.liyi.viewer.Utils +import indi.liyi.viewer.ViewData import top.zibin.luban.Luban import top.zibin.luban.OnCompressListener import java.io.File @@ -56,6 +66,9 @@ class ObtainMessageFragment: Fragment() { RecorderLifecycleObserver() } + private val dateSendFormat = "yyyy-MM-dd HH:mm:ss" + private val dateShowFormat = "yyyy-MM-dd HH:mm" + // This property is only valid between onCreateView and // onDestroyView. private val binding get() = _binding!! @@ -68,67 +81,71 @@ class ObtainMessageFragment: Fragment() { _binding = FragmentObtainMessageBinding.inflate(inflater, container, false) val root: View = binding.root - obtainMessageViewModel.setCurrentMessage(Message()) + obtainMessageViewModel.setCurrentMessage(GreetingMessage()) obtainMessageViewModel?.getMessageLiveData()?.observe( viewLifecycleOwner, Observer { // 初始化界面显示内容 - if(it.title?.isNotEmpty() == true) - binding.tvMessageTitle?.setText(it.title) + if(it.name?.isNotEmpty() == true) + binding.tvMessageTitle?.setText(it.name) if (it.sendDate?.isNotEmpty() == true) { // 获取当前发送时间,如果早于当前时间,则显示现在 - val sendDate = DateUtils.str2Date(it.sendDate, "yyyy-MM-dd HH:mm:ss") + val sendDate = DateUtils.str2Date(it.sendDate, dateSendFormat) if (sendDate<=Date()) { binding.btnSendTime.text = "现在" } else { binding.btnSendTime.text = it.sendDate } + } else { // 如果发送时间此时为空,自动设置发送时间为当前时间 + it.sendDate = DateUtils.date2Str(Date(), dateSendFormat) } var hasPhoto = false var hasAudio = false - if (it.attachment.isNotEmpty()) { - // 展示照片文件或录音文件 - for (attachment in it.attachment) { - if (attachment.attachmentType == AttachmentType.PIC) { - Glide.with(context!!) - .asBitmap().fitCenter() - .load(attachment.pathUrl) - .diskCacheStrategy(DiskCacheStrategy.ALL) - .into(binding.imgMessageAttachment) - // 显示名称 - hasPhoto = true - - // 如果当前attachment文件是本地文件,开始尝试网络上传 - val str = attachment.pathUrl.replace("\\", "/") - if (!str.startsWith("http")) { - obtainMessageViewModel.uploadAttachment(File(attachment.pathUrl), attachment.attachmentType) - binding.tvPhotoName.text = str.substringAfterLast("/", "picture.jpg") - } else { - binding.tvPhotoName.text = str.substring(str.lastIndexOf("/"), str.indexOf("?")) - } - } - if (attachment.attachmentType == AttachmentType.AUDIO) { - hasAudio = true - - // 如果当前attachment文件是本地文件,开始尝试网络上传 - val str = attachment.pathUrl.replace("\\", "/") - if (!str.startsWith("http")) { - obtainMessageViewModel.uploadAttachment(File(attachment.pathUrl), attachment.attachmentType) - binding.tvAudioName.text = str.substringAfterLast("/", "audio.m4a") - } else { - val str = attachment.pathUrl.replace("\\", "/") - binding.tvAudioName.text = str.substring(str.lastIndexOf("/"), str.indexOf("?")) - } + 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) + // 如果当前attachment文件是本地文件,开始尝试网络上传 + val str = it.imageUrl?.replace("\\", "/") + binding.tvPhotoName.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG ) + if (!str!!.startsWith("http")) { + 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("?")) + } else { + binding.tvPhotoName.text = str.substringAfterLast("/") } } + } - // 如果当前attachment不为空,可以显示预览按钮 + if (it.mediaUrl!=null&&it.mediaUrl?.isNotEmpty() == true) { + hasAudio = true + 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) + binding.tvAudioName.text = str.substringAfterLast("/", "audio.m4a") + } else { + if (str.contains("?")) { + binding.tvAudioName.text = str.substring(str.lastIndexOf("/")+1, str.indexOf("?")) + } else { + binding.tvAudioName.text = str.substringAfterLast("/") + } + } } 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 + binding.llAudioPlay.visibility = if (hasAudio) VISIBLE else GONE } ) lifecycle.addObserver(recorderLifecycleObserver) @@ -138,27 +155,21 @@ class ObtainMessageFragment: Fragment() { fun initView() { // 设置问候信息提示的红色星号 -// binding.tiLayoutTitle.markRequiredInRed() -// binding.tvMessageTitle.addTextChangedListener(afterTextChanged = { -// obtainMessageViewModel.updateMessageTitle(it.toString()) -// }) - - binding.tvMessageTitle.setOnFocusChangeListener { view, b -> - if (!b) { - obtainMessageViewModel.updateMessageTitle(binding.tvMessageTitle.text.toString()) - } - } + binding.tiLayoutTitle.markRequiredInRed() + binding.tvMessageTitle.addTextChangedListener(afterTextChanged = { + obtainMessageViewModel.getMessageLiveData().value?.name = it.toString() + }) binding.edtSendFrom.addTextChangedListener (afterTextChanged = { - obtainMessageViewModel.updateMessageSendFrom(it.toString()) + obtainMessageViewModel.getMessageLiveData().value?.who = it.toString() }) binding.imgPhotoDelete.setOnClickListener { - obtainMessageViewModel.updateMessagePic(null) + obtainMessageViewModel.updateMessagePic("") } binding.imgAudioDelete.setOnClickListener { - obtainMessageViewModel.updateMessageAudio(null) + obtainMessageViewModel.updateMessageAudio("") } val sendToArray = mutableListOf("绑定车辆1(LYVXFEFEXNL754427)") @@ -166,7 +177,7 @@ class ObtainMessageFragment: Fragment() { android.R.layout.simple_dropdown_item_1line, android.R.id.text1, sendToArray) binding.edtSendTo.onItemSelectedListener = object: OnItemSelectedListener { override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) { - obtainMessageViewModel.getMessageLiveData().value?.toId = sendToArray[p2] + obtainMessageViewModel.getMessageLiveData().value?.toWho = sendToArray[p2] } override fun onNothingSelected(p0: AdapterView<*>?) { @@ -179,11 +190,11 @@ class ObtainMessageFragment: Fragment() { val dialog = DateTimePickerFragment.newInstance().mode(0) dialog.listener = object : DateTimePickerFragment.OnClickListener { override fun onClickListener(selectTime: String) { - val sendDate = DateUtils.str2Date(selectTime, "yyyy-MM-dd HH:mm") + val sendDate = DateUtils.str2Date(selectTime, dateShowFormat) if (sendDate <= Date()) { - obtainMessageViewModel.updateMessageSendTime(DateUtils.date2Str(Date(), "yyyy-MM-dd HH:mm:ss")) + obtainMessageViewModel.updateMessageSendTime(DateUtils.date2Str(Date(), dateSendFormat)) } else { - obtainMessageViewModel.updateMessageSendTime(DateUtils.date2Str(sendDate, "yyyy-MM-dd HH:mm:ss")) + obtainMessageViewModel.updateMessageSendTime(DateUtils.date2Str(sendDate, dateSendFormat)) } } @@ -231,10 +242,9 @@ class ObtainMessageFragment: Fragment() { photoHelper.setCrop(false).selectAudio(activity!!) } - // 开始录音 - binding.btnStartRecord.setOnClickListener { + binding.btnStartRecord.setOnTouchListener { view, motionEvent -> // 申请权限 - XXPermissions.with(this) + XXPermissions.with(this@ObtainMessageFragment) // 申请单个权限 .permission(Permission.RECORD_AUDIO) .request(object : OnPermissionCallback { @@ -243,17 +253,23 @@ class ObtainMessageFragment: Fragment() { Toast.makeText(activity, "获取部分权限成功,但部分权限未正常授予", Toast.LENGTH_SHORT).show() return } - - if (it.isSelected) { - it.isSelected = false - val recorderAudioPath = recorderLifecycleObserver.stopAndReleaseRecorder() - if (File(recorderAudioPath).exists()) { - obtainMessageViewModel.updateMessageAudio(recorderAudioPath) + when(motionEvent.action) { + MotionEvent.ACTION_DOWN-> { + // 申请权限 + recorderLifecycleObserver.initAndStartRecorder() + ToastUtils.showToast("开始录音!") + false + } + MotionEvent.ACTION_UP -> { + val recorderAudioPath = recorderLifecycleObserver.stopAndReleaseRecorder() + if (File(recorderAudioPath).exists()) { + obtainMessageViewModel.updateMessageAudio(recorderAudioPath) + } + false + } + else -> { + false } - } else{ - it.isSelected = true - - recorderLifecycleObserver.initAndStartRecorder() } } @@ -268,6 +284,7 @@ class ObtainMessageFragment: Fragment() { } } }) + false } // 获取照片文件和音频文件 @@ -296,8 +313,15 @@ class ObtainMessageFragment: Fragment() { if (!it.absolutePath.equals(file?.absolutePath)) { it?.delete() } - // 跳转回原Fragment,展示拍摄的照片 - ViewModelProvider(requireActivity()).get(ObtainMessageViewModel::class.java).updateMessagePic(file!!.absolutePath) + // 如果当前文件不在camera缓存文件夹下,则移动该文件 + if (!file!!.parentFile.absolutePath.equals(SystemConstant.CameraFolder)) { + FileUtils.renameFile(file.absolutePath, File(SystemConstant.CameraFolder, fileName).absolutePath) + // 跳转回原Fragment,展示拍摄的照片 + ViewModelProvider(requireActivity()).get(ObtainMessageViewModel::class.java).updateMessagePic(File(SystemConstant.CameraFolder, fileName).absolutePath) + } else { + // 跳转回原Fragment,展示拍摄的照片 + ViewModelProvider(requireActivity()).get(ObtainMessageViewModel::class.java).updateMessagePic(file!!.absolutePath) + } } override fun onError(e: Throwable) { @@ -306,7 +330,12 @@ class ObtainMessageFragment: Fragment() { }).launch() } else if (fileName.endsWith(".mp3")||fileName.endsWith(".wav")||fileName.endsWith(".amr")||fileName.endsWith(".m4a")) { ToastUtils.showToast(it.absolutePath) - obtainMessageViewModel.updateMessageAudio(it.absolutePath) + if (!it.parentFile.parentFile.absolutePath.equals(SystemConstant.SoundFolder)) { + FileUtils.renameFile(it.absolutePath, File(SystemConstant.SoundFolder, fileName).absolutePath) + obtainMessageViewModel.updateMessageAudio(File(SystemConstant.SoundFolder, fileName).absolutePath) + } else { + obtainMessageViewModel.updateMessageAudio(it.absolutePath) + } } } @@ -315,76 +344,108 @@ class ObtainMessageFragment: Fragment() { ToastUtils.showToast(it.message) } + binding.voicePlayerView.setOnClickListener { + // 判断当前播放的文件是否在缓存文件夹内,如果不在首先下载该文件 + val fileUrl = obtainMessageViewModel.getMessageLiveData().value!!.mediaUrl!! + val localFile = obtainMessageViewModel.getLocalFileFromNetUrl(fileUrl, AttachmentType.AUDIO) + if (!localFile.exists()) { + obtainMessageViewModel.downLoadFile(fileUrl, localFile, object: DownloadCallback { + override fun progress(progress: Int) { + } + + override fun error(throwable: Throwable) { + } + + override fun success(file: File) { + binding.voicePlayerView.setAudio(localFile.absolutePath) + } + + }) + } else { + binding.voicePlayerView.setAudio(localFile.absolutePath) + } + } + binding.btnObtainMessageBack.setOnClickListener { Navigation.findNavController(it).popBackStack() } binding.btnObtainMessageConfirm.setOnClickListener { var checkResult = true + val toolTipBackColor = ResourceUtils.getColor(R.color.teal_200) + val toolTipTextColor = ResourceUtils.getColor(R.color.black) // 检查当前输入数据 val messageData = obtainMessageViewModel.getMessageLiveData().value - if (messageData?.title?.isEmpty() == true) { + if (messageData?.name?.isEmpty() == true) { val toolTipRelativeLayout = binding.ttTitle val toolTip = ToolTip() .withText("请输入问候信息") - .withColor(R.color.white) - .withTextColor(R.color.black) + .withColor(toolTipBackColor) + .withTextColor(toolTipTextColor) + .withoutShadow() .withAnimationType(ToolTip.AnimationType.FROM_MASTER_VIEW) toolTipRelativeLayout.showToolTipForView(toolTip, binding.tiLayoutTitle) checkResult = false - } - var hasPic = false - var hasAudio = false - for (attachment in messageData?.attachment!!) { - if (attachment.attachmentType == AttachmentType.PIC) { - hasPic = true - } - if (attachment.attachmentType == AttachmentType.AUDIO) { - hasAudio = true + } else { + if (messageData?.name!!.length>10) { + val toolTipRelativeLayout = + binding.ttTitle + val toolTip = ToolTip() + .withText("问候信息长度不能超过10") + .withColor(toolTipBackColor) + .withTextColor(toolTipTextColor) + .withoutShadow() + .withAnimationType(ToolTip.AnimationType.FROM_MASTER_VIEW) + toolTipRelativeLayout.showToolTipForView(toolTip, binding.tiLayoutTitle) + checkResult = false } } - if (!hasPic) { + if (messageData?.imageUrl?.isEmpty() == true) { val toolTipRelativeLayout = binding.ttPic val toolTip = ToolTip() .withText("需要提供照片文件") - .withColor(R.color.white) - .withTextColor(R.color.black) + .withColor(toolTipBackColor) + .withTextColor(toolTipTextColor) + .withoutShadow() .withAnimationType(ToolTip.AnimationType.FROM_MASTER_VIEW) toolTipRelativeLayout.showToolTipForView(toolTip, binding.tvUploadPic) checkResult = false } - if (!hasAudio) { + if (messageData?.mediaUrl?.isEmpty() == true) { val toolTipRelativeLayout = binding.ttAudio val toolTip = ToolTip() .withText("需要提供音频文件") - .withColor(R.color.white) - .withTextColor(R.color.black) + .withColor(toolTipBackColor) + .withTextColor(toolTipTextColor) + .withoutShadow() .withAnimationType(ToolTip.AnimationType.FROM_MASTER_VIEW) toolTipRelativeLayout.showToolTipForView(toolTip, binding.tvUploadPic) checkResult = false } - if (messageData?.fromId?.isEmpty()==true) { + if (messageData?.who?.isEmpty()==true) { val toolTipRelativeLayout = binding.ttSendFrom val toolTip = ToolTip() .withText("请输入您的名称") - .withColor(R.color.white) - .withTextColor(R.color.black) + .withColor(toolTipBackColor) + .withTextColor(toolTipTextColor) + .withoutShadow() .withAnimationType(ToolTip.AnimationType.FROM_MASTER_VIEW) toolTipRelativeLayout.showToolTipForView(toolTip, binding.edtSendFrom) checkResult = false } - if (messageData?.toId?.isEmpty()==true) { + if (messageData?.toWho?.isEmpty()==true) { val toolTipRelativeLayout = binding.ttSendTo val toolTip = ToolTip() .withText("请选择要发送的车辆") - .withColor(R.color.white) - .withTextColor(R.color.black) + .withColor(toolTipBackColor) + .withTextColor(toolTipTextColor) + .withoutShadow() .withAnimationType(ToolTip.AnimationType.FROM_MASTER_VIEW) toolTipRelativeLayout.showToolTipForView(toolTip, binding.edtSendTo) checkResult = false @@ -393,10 +454,13 @@ class ObtainMessageFragment: Fragment() { if (checkResult) { // 检查通过 // 检查attachment是否为本地数据,如果是本地则弹出对话框尝试上传 val localAttachmentList = mutableListOf() - for (attachment in messageData?.attachment!!) { - if (!attachment.pathUrl.startsWith("http")) { - localAttachmentList.add(attachment) - } + if (messageData?.imageUrl?.startsWith("http") == false) { + val imageAttachment = Attachment("", messageData.imageUrl!!, AttachmentType.PIC) + localAttachmentList.add(imageAttachment) + } + if (messageData?.mediaUrl?.startsWith("http") == false) { + val audioAttachment = Attachment("", messageData.mediaUrl!!, AttachmentType.AUDIO) + localAttachmentList.add(audioAttachment) } if (localAttachmentList.isNotEmpty()) { MaterialAlertDialogBuilder(context!!) @@ -408,21 +472,50 @@ class ObtainMessageFragment: Fragment() { obtainMessageViewModel.uploadAttachment(File(attachment.pathUrl), attachment.attachmentType) } }) + .setNegativeButton("取消", DialogInterface.OnClickListener { + dialogInterface, i -> dialogInterface.dismiss() + }) .show() return@setOnClickListener } // 检查发送时间 - + val sendDate = DateUtils.str2Date(messageData?.sendDate, dateSendFormat) + val cal = Calendar.getInstance() + cal.time = Date() + cal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE)+1) + if (cal.time.time < sendDate.time) { // 发送时间设置小于当前时间1分钟前,Toast提示用户并自动设置发送时间 + messageData?.sendDate = DateUtils.date2Str(cal.time, dateSendFormat) + ToastUtils.showToast("自动调整发送时间为1分钟后发送") + } // 开始网络提交数据 - if (obtainMessageViewModel.getMessageLiveData().value?.netId!!.isEmpty()) { // 如果网络id为空,则调用更新操作 + if (obtainMessageViewModel.getMessageLiveData().value?.id==0L) { // 如果网络id为空,则调用更新操作 obtainMessageViewModel.insertCardByApp() } else { obtainMessageViewModel.updateCardByApp() } } } + // 点击照片名称 + binding.tvPhotoName.setOnClickListener { + 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.targetHeight = Utils.dp2px(context, 200F) + val viewDataList = listOf(viewData) + binding.imageViewer.overlayStatusBar(true) // ImageViewer 是否会占据 StatusBar 的空间 + .viewData(viewDataList) // 图片数据 + .imageLoader(PhotoLoader()) // 设置图片加载方式 + .showIndex(true) // 是否显示图片索引,默认为true + .watch(0) // 开启浏览 + + } + // 点击音频名称 + binding.tvAudioName.setOnClickListener { + + } } override fun onDestroyView() { 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 3a026b1..8d101db 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,12 +1,18 @@ package com.navinfo.volvo.ui.fragments.message import androidx.lifecycle.* +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.model.Attachment -import com.navinfo.volvo.model.AttachmentType -import com.navinfo.volvo.model.Message +import com.navinfo.volvo.utils.SystemConstant +import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.launch import okhttp3.MediaType import okhttp3.MediaType.Companion.toMediaTypeOrNull @@ -17,72 +23,74 @@ import java.util.* class ObtainMessageViewModel: ViewModel() { - private val msgLiveData: MutableLiveData by lazy { - MutableLiveData() + private val msgLiveData: MutableLiveData by lazy { + MutableLiveData() } - fun setCurrentMessage(msg: Message) { + fun setCurrentMessage(msg: GreetingMessage) { msgLiveData.postValue(msg) } - fun getMessageLiveData(): MutableLiveData { + fun getMessageLiveData(): MutableLiveData { return msgLiveData } // 更新消息标题 fun updateMessageTitle(title: String) { - this.msgLiveData.value?.title = title + this.msgLiveData.value?.name = title this.msgLiveData.postValue(this.msgLiveData.value) } // 更新消息附件中的照片文件 fun updateMessagePic(picUrl: String?) { - var hasPic = false +// var hasPic = false - for (attachment in this.msgLiveData.value!!.attachment) { - if (attachment.attachmentType == AttachmentType.PIC) { - if (picUrl==null||picUrl.isEmpty()) { - this.msgLiveData.value!!.attachment.remove(attachment) - } else { - attachment.pathUrl = picUrl - } - hasPic = true - } - } - if (!hasPic&&picUrl!=null) { - this.msgLiveData.value!!.attachment.add(Attachment(UUID.randomUUID().toString(), picUrl, AttachmentType.PIC)) - } + this.msgLiveData.value?.imageUrl = picUrl +// for (attachment in this.msgLiveData.value!!.attachment) { +// if (attachment.attachmentType == AttachmentType.PIC) { +// if (picUrl==null||picUrl.isEmpty()) { +// this.msgLiveData.value!!.attachment.remove(attachment) +// } else { +// attachment.pathUrl = picUrl +// } +// hasPic = true +// } +// } +// if (!hasPic&&picUrl!=null) { +// this.msgLiveData.value!!.attachment.add(Attachment(UUID.randomUUID().toString(), picUrl, AttachmentType.PIC)) +// } this.msgLiveData.postValue(this.msgLiveData.value) } // 更新消息附件中的录音文件 fun updateMessageAudio(audioUrl: String?) { - var hasAudio = false - for (attachment in this.msgLiveData.value!!.attachment) { - if (attachment.attachmentType == AttachmentType.AUDIO) { - if (audioUrl==null||audioUrl.isEmpty()) { - this.msgLiveData.value!!.attachment.remove(attachment) - } else { - attachment.pathUrl = audioUrl - } - hasAudio = true - } - } - if (!hasAudio&&audioUrl!=null) { - this.msgLiveData.value!!.attachment.add(Attachment(UUID.randomUUID().toString(), audioUrl, AttachmentType.AUDIO)) - } +// var hasAudio = false +// for (attachment in this.msgLiveData.value!!.attachment) { +// if (attachment.attachmentType == AttachmentType.AUDIO) { +// if (audioUrl==null||audioUrl.isEmpty()) { +// this.msgLiveData.value!!.attachment.remove(attachment) +// } else { +// attachment.pathUrl = audioUrl +// } +// hasAudio = true +// } +// } +// if (!hasAudio&&audioUrl!=null) { +// this.msgLiveData.value!!.attachment.add(Attachment(UUID.randomUUID().toString(), audioUrl, AttachmentType.AUDIO)) +// } + this.msgLiveData.value?.mediaUrl = audioUrl this.msgLiveData.postValue(this.msgLiveData.value) } // 更新发送人 fun updateMessageSendFrom(sendFrom: String) { - this.msgLiveData.value?.fromId = sendFrom + this.msgLiveData.value?.who = sendFrom this.msgLiveData.postValue(this.msgLiveData.value) } // 更新接收人 fun updateMessageSendTo(sendTo: String) { - this.msgLiveData.value?.toId = sendTo + this.msgLiveData.value?.toWho = sendTo this.msgLiveData.postValue(this.msgLiveData.value) } @@ -92,30 +100,25 @@ class ObtainMessageViewModel: ViewModel() { this.msgLiveData.postValue(this.msgLiveData.value) } - // 获取照片url - fun getImageAttachment(attachementList: List): Attachment? { - for (attachment in attachementList) { - if (attachment.attachmentType == AttachmentType.PIC) { - return attachment - } - } - return null - } - - // 获取音频url - fun getAudioAttachment(attachementList: List): Attachment? { - for (attachment in attachementList) { - if (attachment.attachmentType == AttachmentType.AUDIO) { - return attachment - } - } - return null - } - - // 获取发送时间 - fun getSendDate(){ - - } +// // 获取照片url +// fun getImageAttachment(attachementList: List): Attachment? { +// for (attachment in attachementList) { +// if (attachment.attachmentType == AttachmentType.PIC) { +// return attachment +// } +// } +// return null +// } +// +// // 获取音频url +// fun getAudioAttachment(attachementList: List): Attachment? { +// for (attachment in attachementList) { +// if (attachment.attachmentType == AttachmentType.AUDIO) { +// return attachment +// } +// } +// return null +// } // 上传附件文件 fun uploadAttachment(attachmentFile: File, attachmentType: AttachmentType) { @@ -130,6 +133,21 @@ class ObtainMessageViewModel: ViewModel() { if (result.code == 200) { // 请求成功 // 获取上传后的结果 val fileKey = result.data?.get("fileKey") + val newFileName = fileKey!!.substringAfterLast("/") + // 修改缓存文件名 + if (attachmentType == AttachmentType.PIC) { // 修改当前文件在缓存文件夹的名称 + val destFile = File(SystemConstant.CameraFolder, newFileName) + if (destFile.exists()) { + FileUtils.deleteFile(destFile) + } + FileUtils.renameFile(attachmentFile.absolutePath, destFile.absolutePath) + } else { + val destFile = File(SystemConstant.SoundFolder, newFileName) + if (destFile.exists()) { + FileUtils.deleteFile(destFile) + } + FileUtils.renameFile(attachmentFile.absolutePath, destFile.absolutePath) + } if (fileKey!=null) { downloadAttachment(fileKey, attachmentType) } @@ -173,16 +191,41 @@ class ObtainMessageViewModel: ViewModel() { } } + fun downLoadFile(url: String, destFile: File, downloadCallback: DownloadCallback){ + viewModelScope.launch { + DownloadManager.download( + url, + destFile + ).collect { + when (it) { + is DownloadState.InProgress -> { + XLog.d("~~~", "download in progress: ${it.progress}.") + downloadCallback.progress(it.progress) + } + is DownloadState.Success -> { + XLog.d("~~~", "download finished.") + downloadCallback.success(it.file) + } + is DownloadState.Error -> { + XLog.d("~~~", "download error: ${it.throwable}.") + downloadCallback.error(it.throwable) + } + } + } + } + } + fun insertCardByApp() { viewModelScope.launch { try { + // TODO 首先保存数据到本地 val message = msgLiveData.value val insertData = mapOf( - "name" to message?.title, - "imageUrl" to getImageAttachment(message?.attachment!!)?.pathUrl, - "mediaUrl" to getAudioAttachment(message?.attachment!!)?.pathUrl, - "who" to message?.fromId, - "toWho" to message?.toId, + "name" to message?.name, + "imageUrl" to message?.imageUrl, + "mediaUrl" to message?.mediaUrl, + "who" to message?.who, + "toWho" to message?.toWho, "sendDate" to message?.sendDate ) val result = NavinfoVolvoCall.getApi().insertCardByApp(insertData as Map) @@ -190,8 +233,9 @@ class ObtainMessageViewModel: ViewModel() { if (result.code == 200) { // 请求成功 // 获取上传后的结果 val netId = result.data - message.netId = netId!! - // 尝试保存数据到本地 + message?.id = netId!!.toLong() + // TODO 尝试更新本地数据 + } else { ToastUtils.showToast(result.msg) } @@ -206,21 +250,21 @@ class ObtainMessageViewModel: ViewModel() { viewModelScope.launch { try { val message = msgLiveData.value - val insertData = mapOf( - "id" to message?.netId, - "name" to message?.title, - "imageUrl" to getImageAttachment(message?.attachment!!)?.pathUrl, - "mediaUrl" to getAudioAttachment(message?.attachment!!)?.pathUrl, - "who" to message?.fromId, - "toWho" to message?.toId, + val updateData = mapOf( + "id" to message?.id, + "name" to message?.name, + "imageUrl" to message?.imageUrl, + "mediaUrl" to message?.mediaUrl, + "who" to message?.who, + "toWho" to message?.toWho, "sendDate" to message?.sendDate ) - val result = NavinfoVolvoCall.getApi().updateCardByApp(insertData as Map) + val result = NavinfoVolvoCall.getApi().updateCardByApp(updateData as Map) XLog.d("updateCardByApp:${result.code}") if (result.code == 200) { // 请求成功 // 获取上传后的结果 val netId = result.data - message.netId = netId!! + message?.id = netId!!.toLong() // 尝试保存数据到本地 } else { ToastUtils.showToast(result.msg) @@ -231,4 +275,20 @@ class ObtainMessageViewModel: ViewModel() { } } } + + /** + * 根据网络地址获取本地的缓存文件路径 + * */ + fun getLocalFileFromNetUrl(url: String, attachmentType: AttachmentType):File { + val folder = when(attachmentType) { + AttachmentType.PIC-> SystemConstant.CameraFolder + else -> SystemConstant.SoundFolder + } + var name = if (url.contains("?")) { + url.substring(url.lastIndexOf("/")+1, url.indexOf("?")) + } else { + url.substringAfterLast("/") + } + return File(folder, name) + } } \ No newline at end of file diff --git a/app/src/main/java/com/navinfo/volvo/util/PhotoLoader.java b/app/src/main/java/com/navinfo/volvo/util/PhotoLoader.java new file mode 100644 index 0000000..6c69e64 --- /dev/null +++ b/app/src/main/java/com/navinfo/volvo/util/PhotoLoader.java @@ -0,0 +1,50 @@ +package com.navinfo.volvo.util; + +import android.graphics.drawable.Drawable; +import android.widget.ImageView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.target.CustomViewTarget; +import com.bumptech.glide.request.transition.Transition; + +import indi.liyi.viewer.ImageLoader; + +public class PhotoLoader extends ImageLoader { + @Override + public void displayImage(final Object src, ImageView imageView, final LoadCallback callback) { + Glide.with(imageView.getContext()) + .load(src) + .into(new CustomViewTarget(imageView) { + + @Override + protected void onResourceLoading(@Nullable Drawable placeholder) { + super.onResourceLoading(placeholder); + if(callback!=null){ + callback.onLoadStarted(placeholder); + } + } + + @Override + public void onResourceReady(@NonNull Drawable resource, @Nullable Transition transition) { + if(callback!=null) { + callback.onLoadSucceed(resource); + } + } + + @Override + public void onLoadFailed(@Nullable Drawable errorDrawable) { + if(callback!=null) { + callback.onLoadFailed(errorDrawable); + } + } + + @Override + protected void onResourceCleared(@Nullable Drawable placeholder) { + + } + }); + } +} diff --git a/app/src/main/java/com/navinfo/volvo/utils/EasyMediaFile.kt b/app/src/main/java/com/navinfo/volvo/utils/EasyMediaFile.kt index e04f57d..eebd1cf 100644 --- a/app/src/main/java/com/navinfo/volvo/utils/EasyMediaFile.kt +++ b/app/src/main/java/com/navinfo/volvo/utils/EasyMediaFile.kt @@ -131,7 +131,7 @@ class EasyMediaFile { * 选择文件 */ private fun selectFileInternal(intent: Intent, activity: Activity, type: Int) { - val resolveInfoList = activity.packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY) + var resolveInfoList = activity.packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY) if (resolveInfoList.isEmpty()) { error?.invoke(IllegalStateException("No Activity found to handle Intent ")) } else { diff --git a/app/src/main/res/layout/fragment_obtain_message.xml b/app/src/main/res/layout/fragment_obtain_message.xml index b40c6bb..77f28cc 100644 --- a/app/src/main/res/layout/fragment_obtain_message.xml +++ b/app/src/main/res/layout/fragment_obtain_message.xml @@ -121,9 +121,10 @@ android:orientation="horizontal"> + android:layout_weight="1"> @@ -147,7 +148,6 @@ @@ -156,6 +156,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" + android:layout_marginVertical="@dimen/default_widget_padding" android:orientation="horizontal"> - + + android:orientation="horizontal"> + + + @@ -283,7 +306,6 @@ @@ -379,4 +401,11 @@ android:layout_weight="1" android:text="确认提交"> + + \ No newline at end of file