使用Hilt框架

This commit is contained in:
squallzhjch 2023-01-04 15:08:35 +08:00
parent dc6d5424dc
commit 6852953866
63 changed files with 1183 additions and 193 deletions

2
.idea/gradle.xml generated
View File

@ -8,7 +8,7 @@
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleHome" value="$USER_HOME$/.gradle/wrapper/dists/gradle-7.2-all/260hg96vuh6ex27h9vo47iv4d/gradle-7.2" />
<option name="gradleJvm" value="corretto-11" />
<option name="gradleJvm" value="JDK" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />

View File

@ -1,9 +1,13 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
// id 'com.google.dagger.hilt.android'
}
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
//apply plugin: 'realm-android'
android {
namespace 'com.navinfo.volvo'
@ -21,7 +25,7 @@ android {
// room.schemaLocation生成的文件路径
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
arguments += ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
ndk {
@ -41,45 +45,84 @@ android {
}
kotlinOptions {
jvmTarget = '1.8'
freeCompilerArgs += [
"-Xjvm-default=all",
]
}
buildFeatures {
viewBinding true
dataBinding true
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.8.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0'
implementation "androidx.compose.material3:material3:1.0.0-alpha04"
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.4.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1"
implementation "androidx.lifecycle:lifecycle-common-java8:2.4.1"
implementation 'androidx.navigation:navigation-fragment-ktx:2.4.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.4.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
//room
implementation 'com.tencent.wcdb:room:1.1-19' // room-runtime wcdb-android
api 'androidx.sqlite:sqlite: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'
annotationProcessor 'android.arch.persistence.room:compiler:1.1.1'
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'
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'
// https://github.com/rosuH/AndroidFilePicker/blob/master/README_CN.md
implementation 'me.rosuh:AndroidFilePicker:0.8.2'
// https://github.com/Gredicer/datetimepicker
implementation 'com.github.Gredicer:datetimepicker:V1.0.0'
implementation 'com.google.code.gson:gson:2.10'
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")
// 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"
}
kapt {
correctErrorTypes true
}

View File

@ -3,6 +3,7 @@
xmlns:tools="http://schemas.android.com/tools">
<application
android:name=".MyApplication"
android:allowBackup="true"
android:configChanges="locale"
android:dataExtractionRules="@xml/data_extraction_rules"
@ -14,7 +15,7 @@
android:theme="@style/Theme.NavinfoVolvo"
tools:targetApi="31">
<activity
android:name="com.navinfo.volvo.MainActivity"
android:name="com.navinfo.volvo.ui.MainActivity"
android:exported="true"
android:label="@string/app_name">
<intent-filter>
@ -28,5 +29,5 @@
android:value="" />
</activity>
</application>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
</manifest>

View File

@ -0,0 +1,14 @@
package com.navinfo.volvo
import java.lang.Boolean
class Constant {
companion object{
/**
* 服务器地址
*/
const val SERVER_ADDRESS = "http://ec2-52-81-73-5.cn-north-1.compute.amazonaws.com.cn:8088/"
val DEBUG = Boolean.parseBoolean("true")
}
}

View File

@ -0,0 +1,11 @@
package com.navinfo.volvo
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
open class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
}
}

View File

@ -0,0 +1,20 @@
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.UserDao
import com.navinfo.volvo.model.Attachment
import com.navinfo.volvo.model.Message
import com.navinfo.volvo.model.User
@Database(
entities = [Message::class, Attachment::class, User::class],
version = 1,
exportSchema = false
)
abstract class AppDatabase : RoomDatabase() {
abstract fun getMessageDao(): MessageDao
abstract fun getUserDao(): UserDao
}

View File

@ -1,4 +1,4 @@
package com.navinfo.volvo.db.dao;
package com.navinfo.volvo.database;
import android.content.Context;
@ -10,10 +10,11 @@ import androidx.room.RoomDatabase;
import androidx.sqlite.db.SupportSQLiteDatabase;
import androidx.sqlite.db.SupportSQLiteOpenHelper;
import com.navinfo.volvo.db.dao.entity.Message;
import com.navinfo.volvo.db.dao.entity.Attachment;
import com.navinfo.volvo.db.dao.entity.Message;
import com.navinfo.volvo.db.dao.entity.User;
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;
@ -39,6 +40,8 @@ public abstract class MapLifeDataBase extends RoomDatabase {
*/
public abstract MessageDao getMessageDao();
public abstract UserDao getUserDao();
/**
* 数据库秘钥
*/

View File

@ -1,10 +1,10 @@
package com.navinfo.volvo.db.dao
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.db.dao.entity.Message
import com.navinfo.volvo.model.Message
@Dao
interface MessageDao {

View File

@ -0,0 +1,12 @@
package com.navinfo.volvo.database.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import com.navinfo.volvo.model.User
@Dao
interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertUser(vararg user: User)
}

View File

@ -1,13 +0,0 @@
package com.navinfo.volvo.db.dao.entity
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "User")
data class User(
@PrimaryKey()
val id:String,
var name:String,
var nickname:String,
)

View File

@ -0,0 +1,16 @@
package com.navinfo.volvo.di.key
import androidx.lifecycle.ViewModel
import dagger.MapKey
import kotlin.reflect.KClass
@MustBeDocumented
@MapKey
@Retention(AnnotationRetention.RUNTIME)
@Target(
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER
)
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)

View File

@ -0,0 +1,57 @@
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.UserDao
import com.tencent.wcdb.database.SQLiteCipherSpec
import com.tencent.wcdb.room.db.WCDBOpenHelperFactory
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
@Module
class DatabaseModule {
@Singleton
@Provides
fun provideDatabase(context: Context): AppDatabase {
val DB_PASSWORD = "123456";
val cipherSpec = SQLiteCipherSpec()
.setPageSize(1024)
.setSQLCipherVersion(3)
val factory = WCDBOpenHelperFactory()
.passphrase(DB_PASSWORD.toByteArray()) // 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
return Room.databaseBuilder(context, AppDatabase::class.java, "NavinfoVolvoDb")
// [WCDB] Specify open helper to use WCDB database implementation instead
// of the Android framework.
.openHelperFactory(factory)
// Wipes and rebuilds instead of migrating if no Migration object.
// Migration is not part of this codelab.
// .fallbackToDestructiveMigration().addCallback(sRoomDatabaseCallback)
.build();
}
@Singleton
@Provides
fun provideMessageDao(database: AppDatabase): MessageDao {
return database.getMessageDao()
}
@Singleton
@Provides
fun provideUserDao(database: AppDatabase): UserDao {
return database.getUserDao()
}
}

View File

@ -0,0 +1,29 @@
package com.navinfo.volvo.di.module
import com.navinfo.volvo.di.scope.DefaultDispatcher
import com.navinfo.volvo.di.scope.IoDispatcher
import com.navinfo.volvo.di.scope.MainDispatcher
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
@InstallIn(SingletonComponent::class)
@Module
object DispatcherModule {
@Provides
@DefaultDispatcher
fun provideDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Default
@Provides
@IoDispatcher
fun providesIODispatcher(): CoroutineDispatcher = Dispatchers.IO
@Provides
@MainDispatcher
fun providesMainDispatcher(): CoroutineDispatcher = Dispatchers.Main
}

View File

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

View File

@ -0,0 +1,104 @@
package com.navinfo.volvo.di.module
import android.app.Application
import android.content.Context
import com.google.gson.Gson
import com.navinfo.volvo.Constant
import com.navinfo.volvo.repository.service.NetworkService
import com.navinfo.volvo.tools.GsonUtil
import dagger.Lazy
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
@Module
class NetworkUtilModule {
@Provides
@Singleton
fun provideContext(application: Application): Context {
return application.applicationContext
}
@Provides
@Singleton
fun provideOkHttpClient(interceptor: HttpLoggingInterceptor): OkHttpClient {
return OkHttpClient.Builder().addInterceptor(interceptor).build()
}
@Provides
@Singleton
fun provideLoggingInterceptor(): HttpLoggingInterceptor {
return HttpLoggingInterceptor().apply {
level = if (Constant.DEBUG) {
HttpLoggingInterceptor.Level.BODY
} else {
HttpLoggingInterceptor.Level.NONE
}
}
}
@Provides
@Singleton
fun provideRetrofit(
client: Lazy<OkHttpClient>,
converterFactory: GsonConverterFactory,
context: Context
): Retrofit {
val retrofitBuilder = Retrofit.Builder()
.baseUrl(Constant.SERVER_ADDRESS)
.client(client.get())
.addConverterFactory(converterFactory)
// val okHttpClientBuilder = OkHttpClient.Builder()
// .addInterceptor { chain ->
//
// val original = chain.request()
// val originalHttpUrl = original.url
//
// val url = originalHttpUrl.newBuilder()
// .addQueryParameter("appid", BuildConfig.API_KEY)
// .build()
//
// Timber.d("Started making network call")
//
// val requestBuilder = original.newBuilder()
// .url(url)
//
// val request = requestBuilder.build()
// return@addInterceptor chain.proceed(request)
// }
// .readTimeout(60, TimeUnit.SECONDS)
// if (Constant.DEBUG) {
// okHttpClientBuilder.addInterceptor(ChuckInterceptor(context))
// }
// return retrofitBuilder.client(okHttpClientBuilder.build()).build()
return retrofitBuilder.build()
}
@Provides
@Singleton
fun provideGson(): Gson = GsonUtil.getInstance()
@Provides
@Singleton
fun provideGsonConverterFactory(gson: Gson): GsonConverterFactory {
return GsonConverterFactory.create(gson)
}
@Provides
@Singleton
fun provideNetworkService(retrofit: Retrofit): NetworkService {
return retrofit.create(NetworkService::class.java)
}
}

View File

@ -0,0 +1,20 @@
package com.navinfo.volvo.di.module
import android.content.Context
import com.navinfo.volvo.util.SharedPreferenceHelper
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@InstallIn(SingletonComponent::class)
@Module
class UtilModule {
@Provides
@Singleton
fun provideSharedPreferencesHelper(context: Context): SharedPreferenceHelper {
return SharedPreferenceHelper.getInstance(context)
}
}

View File

@ -0,0 +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<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): 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
}
}

View File

@ -0,0 +1,30 @@
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.fragments.home.MessageViewModel
import com.navinfo.volvo.ui.fragments.login.LoginViewModel
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(LoginViewModel::class)
abstract fun bindLoginFragmentViewModel(viewModel: LoginViewModel): ViewModel
@IntoMap
@Binds
@ViewModelKey(MessageViewModel::class)
abstract fun bindMessageFragmentViewModel(viewModel: MessageViewModel): ViewModel
}

View File

@ -0,0 +1,15 @@
package com.navinfo.volvo.di.scope
import javax.inject.Qualifier
@Retention(AnnotationRetention.BINARY)
@Qualifier
annotation class DefaultDispatcher
@Retention(AnnotationRetention.BINARY)
@Qualifier
annotation class IoDispatcher
@Retention(AnnotationRetention.BINARY)
@Qualifier
annotation class MainDispatcher

View File

@ -1,4 +1,4 @@
package com.navinfo.volvo.db.dao.entity
package com.navinfo.volvo.model
import androidx.room.Entity
import androidx.room.PrimaryKey

View File

@ -1,4 +1,4 @@
package com.navinfo.volvo.db.dao.entity
package com.navinfo.volvo.model
import androidx.room.Entity
import androidx.room.PrimaryKey

View File

@ -0,0 +1,52 @@
package com.navinfo.volvo.model
import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.TypeConverter
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")
@TypeConverters()
data class User(
@PrimaryKey()
@NotNull
val id: String,
var name: String,
var nickname: String,
){
@Inject constructor():this("${System.currentTimeMillis()}","df","sdfds")
}
class UserConverters() {
@TypeConverter
fun stringToUser(value: String): User {
val type = object : TypeToken<User>() {
}.type
return GsonUtil.getInstance().fromJson(value, type)
}
@TypeConverter
fun userToString(user: User): String {
return GsonUtil.getInstance().toJson(user)
}
@TypeConverter
fun userListToString(list: List<User>): String {
return GsonUtil.getInstance().toJson(list)
}
@TypeConverter
fun stringToUserList(value: String): List<User> {
val type = object : TypeToken<List<User>>() {
}.type
return GsonUtil.getInstance().fromJson(value, type)
}
}

View File

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

View File

@ -0,0 +1,9 @@
package com.navinfo.volvo.repository
import com.navinfo.volvo.model.Message
import com.navinfo.volvo.model.network.NetworkPostMessage
import com.navinfo.volvo.util.NetResult
interface NetworkDataSource {
suspend fun getCardList(message: NetworkPostMessage): NetResult<List<Message>>
}

View File

@ -0,0 +1,40 @@
package com.navinfo.volvo.repository
import com.navinfo.volvo.di.scope.IoDispatcher
import com.navinfo.volvo.model.Message
import com.navinfo.volvo.model.network.NetworkPostMessage
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
class NetworkDataSourceImp @Inject constructor(
private val netWorkService: NetworkService,
@IoDispatcher private val ioDispatcher: CoroutineDispatcher
) : NetworkDataSource {
override suspend fun getCardList(message: NetworkPostMessage): NetResult<List<Message>> =
withContext(ioDispatcher) {
return@withContext try {
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)
} else {
NetResult.Success(null)
}
} catch (e: Exception) {
NetResult.Error(e)
}
}
}

View File

@ -0,0 +1,12 @@
package com.navinfo.volvo.repository.service
import com.navinfo.volvo.model.Message
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<List<Message>>
}

View File

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

View File

@ -1,17 +1,18 @@
package com.navinfo.volvo
package com.navinfo.volvo.ui
import android.os.Bundle
import android.view.View
import com.google.android.material.bottomnavigation.BottomNavigationView
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.Navigation
import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.navinfo.volvo.R
import com.navinfo.volvo.databinding.ActivityMainBinding
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
@ -21,23 +22,39 @@ class MainActivity : AppCompatActivity() {
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setupNavigation()
}
private fun setupNavigation() {
val navView: BottomNavigationView = binding.navView
val newMessageView = binding.newMessageFab
val navController = findNavController(R.id.nav_host_fragment_activity_main)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
val appBarConfiguration = AppBarConfiguration(
setOf(
R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications, R.id.navigation_obtain_message
R.id.navigation_message, R.id.navigation_dashboard, R.id.navigation_notifications,
)
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
findViewById<View>(R.id.fab_new_message).apply {
this.setOnClickListener {
navController.navigate(R.id.fab_new_message)
navController.addOnDestinationChangedListener { controller, destination, arguments ->
if (destination.id == R.id.navigation_message
|| destination.id == R.id.navigation_dashboard
|| destination.id == R.id.navigation_notifications
|| destination.id == R.id.navigation_obtain_message
) {
runOnUiThread {
navView.visibility = View.VISIBLE
newMessageView.visibility = View.VISIBLE
}
} else {
runOnUiThread {
navView.visibility = View.GONE
newMessageView.visibility = View.GONE
}
}
}
}
override fun onSupportNavigateUp() =
findNavController(R.id.nav_host_fragment_activity_main).navigateUp()
}

View File

@ -7,7 +7,7 @@ import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.navinfo.volvo.R
import com.navinfo.volvo.db.dao.entity.Message
import com.navinfo.volvo.model.Message
class MessageAdapter : RecyclerView.Adapter<MessageAdapter.MyViewHolder>() {

View File

@ -1,4 +1,4 @@
package com.navinfo.volvo.ui.dashboard
package com.navinfo.volvo.ui.fragments.dashboard
import android.os.Bundle
import android.view.LayoutInflater
@ -23,7 +23,7 @@ class DashboardFragment : Fragment() {
savedInstanceState: Bundle?
): View {
val dashboardViewModel =
ViewModelProvider(this).get(DashboardViewModel::class.java)
ViewModelProvider(this)[DashboardViewModel::class.java]
_binding = FragmentDashboardBinding.inflate(inflater, container, false)
val root: View = binding.root

View File

@ -1,4 +1,4 @@
package com.navinfo.volvo.ui.dashboard
package com.navinfo.volvo.ui.fragments.dashboard
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData

View File

@ -1,11 +1,10 @@
package com.navinfo.volvo.ui.home
package com.navinfo.volvo.ui.fragments.home
import android.os.Bundle
import android.view.Display
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.DividerItemDecoration
@ -13,12 +12,14 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.navinfo.volvo.R
import com.navinfo.volvo.databinding.FragmentHomeBinding
import com.navinfo.volvo.tools.DisplayUtil
import com.navinfo.volvo.ui.BaseFragment
import com.navinfo.volvo.ui.adapter.MessageAdapter
import com.navinfo.volvo.ui.message.ObtainMessageViewModel
import com.navinfo.volvo.ui.fragments.message.ObtainMessageViewModel
import com.yanzhenjie.recyclerview.*
import com.yanzhenjie.recyclerview.SwipeRecyclerView.LoadMoreListener
import dagger.hilt.android.AndroidEntryPoint
class HomeFragment : Fragment(), OnItemClickListener, OnItemMenuClickListener {
@AndroidEntryPoint
class MessageFragment : BaseFragment(), OnItemClickListener, OnItemMenuClickListener {
private var _binding: FragmentHomeBinding? = null
@ -26,28 +27,26 @@ class HomeFragment : Fragment(), OnItemClickListener, OnItemMenuClickListener {
// onDestroyView.
private val binding get() = _binding!!
private val viewModel by viewModels<MessageViewModel> { viewModelFactoryProvider }
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val homeViewModel =
ViewModelProvider(this).get(HomeViewModel::class.java)
val obtainMessageViewModel = ViewModelProvider(requireActivity()).get(ObtainMessageViewModel::class.java)
// val homeViewModel =
// ViewModelProvider(this)[MessageViewModel::class.java]
// val obtainMessageViewModel =
// ViewModelProvider(requireActivity()).get(ObtainMessageViewModel::class.java)
_binding = FragmentHomeBinding.inflate(inflater, container, false)
val root: View = binding.root
initView()
return root
}
// val textView: TextView = binding.tvNewMessage
// textView.setOnClickListener {
// val message = Message(1, "新建标题", "", "", "", 0, "1", "2", mutableListOf())
// obtainMessageViewModel.setCurrentMessage(message)
// // 跳转到新建Message的Fragment
// Navigation.findNavController(it).navigate(R.id.home_2_obtain_message)
// }
// homeViewModel.text.observe(viewLifecycleOwner) {
//
// }
private fun initView() {
val recyclerview: SwipeRecyclerView = binding.homeMessageRecyclerview
recyclerview.adapter = null //先设置null否则会报错
//创建菜单选项
@ -70,8 +69,6 @@ class HomeFragment : Fragment(), OnItemClickListener, OnItemMenuClickListener {
shareItem.text = context!!.getString(R.string.share)
shareItem.setTextColor(R.color.white)
rightMenu.addMenuItem(shareItem)
}
val layoutManager = LinearLayoutManager(context)
val adapter = MessageAdapter()
@ -84,12 +81,21 @@ class HomeFragment : Fragment(), OnItemClickListener, OnItemMenuClickListener {
}
recyclerview.adapter = adapter
homeViewModel.getMessageList().observe(viewLifecycleOwner, Observer { contacts ->
adapter.setItem(contacts)
})
return root
// homeViewModel.getMessageList().observe(viewLifecycleOwner, Observer { contacts ->
// adapter.setItem(contacts)
// })
}
override fun onStart() {
super.onStart()
getMessageList()
}
private fun getMessageList() {
viewModel.getMessageList()
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null

View File

@ -0,0 +1,47 @@
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.repository.NetworkDataSource
import com.navinfo.volvo.util.NetResult
import com.navinfo.volvo.util.asLiveData
import kotlinx.coroutines.launch
import javax.inject.Inject
class MessageViewModel @Inject constructor(
private val repository: NetworkDataSource
) : ViewModel() {
private val _isLoading = MutableLiveData<Boolean>()
val isLoading = _isLoading.asLiveData()
private val _messageList = MutableLiveData<List<Message>>()
val messageList = _messageList.asLiveData()
fun getMessageList() {
_isLoading.postValue(true)
viewModelScope.launch {
val messagePost = NetworkPostMessage(who = "北京测试", toWho = "volvo测试")
when (val result = repository.getCardList(messagePost)) {
is NetResult.Success -> {
_isLoading.value = false
if (result.data != null) {
val list = result.data
_messageList.value = list
}
}
is NetResult.Error -> {
_isLoading.value = false
}
is NetResult.Loading -> {
_isLoading.postValue(true)
}
}
}
}
}

View File

@ -0,0 +1,51 @@
package com.navinfo.volvo.ui.fragments.login
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.Navigation
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import com.navinfo.volvo.R
import com.navinfo.volvo.databinding.FragmentLoginBinding
import com.navinfo.volvo.ui.BaseFragment
import dagger.hilt.android.AndroidEntryPoint
@AndroidEntryPoint
class LoginFragment : BaseFragment() {
// private var loginViewModel:LoginViewModel by viewModel(get())
private var viewBinding: FragmentLoginBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = viewBinding!!
private val viewModel by viewModels<LoginViewModel> { viewModelFactoryProvider }
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
viewBinding = FragmentLoginBinding.inflate(inflater, container, false)
val root: View = binding.root
binding.loginFragmentRegisterButton.setOnClickListener {
}
binding.loginFragmentLoginButton.setOnClickListener {
findNavController().navigate(R.id.action_login_to_home)
}
return root
}
override fun onDestroyView() {
viewBinding = null
super.onDestroyView()
}
}

View File

@ -0,0 +1,25 @@
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.model.User
import javax.inject.Inject
class LoginViewModel @Inject constructor(private val dataBase: AppDatabase) : ViewModel() {
private val _user = MutableLiveData<User>().apply {
}
val user: LiveData<User> = _user
fun liveDataOnclick(view: View) {
}
fun userRegister(username: String, password: String) {
}
}

View File

@ -1,4 +1,4 @@
package com.navinfo.volvo.ui.message
package com.navinfo.volvo.ui.fragments.message
import android.os.Bundle
import android.view.LayoutInflater
@ -29,13 +29,13 @@ class ObtainMessageFragment: Fragment() {
_binding = FragmentObtainMessageBinding.inflate(inflater, container, false)
val root: View = binding.root
obtainMessageViewModel?.getMessageLiveData()?.observe(
obtainMessageViewModel.getMessageLiveData()?.observe(
viewLifecycleOwner, Observer {
// 初始化界面显示内容
if(it.title!=null)
binding.tvMessageTitle?.setText(it.title)
binding.tvMessageTitle.setText(it.title)
if (it.sendDate!=null) {
binding.btnSendTime.setText(it.sendDate)
binding.btnSendTime.text = it.sendDate
}
}
)
@ -43,7 +43,7 @@ class ObtainMessageFragment: Fragment() {
return root
}
fun initView() {
private fun initView() {
// 设置问候信息提示的红色星号
binding.tiLayoutTitle.markRequiredInRed()
// 设置点击按钮选择发送时间
@ -59,6 +59,9 @@ class ObtainMessageFragment: Fragment() {
}
// 点击按钮选择拍照
binding.edtSendTo.setOnClickListener {
}
}
override fun onDestroyView() {

View File

@ -1,11 +1,9 @@
package com.navinfo.volvo.ui.message
package com.navinfo.volvo.ui.fragments.message
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.liveData
import com.navinfo.volvo.db.dao.entity.Message
import com.navinfo.volvo.db.dao.entity.AttachmentType
import com.navinfo.volvo.model.Message
import com.navinfo.volvo.model.AttachmentType
class ObtainMessageViewModel: ViewModel() {
private val msgLiveData: MutableLiveData<Message> by lazy {

View File

@ -1,4 +1,4 @@
package com.navinfo.volvo.ui.notifications
package com.navinfo.volvo.ui.fragments.notifications
import android.os.Bundle
import android.view.LayoutInflater

View File

@ -1,4 +1,4 @@
package com.navinfo.volvo.ui.notifications
package com.navinfo.volvo.ui.fragments.notifications
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData

View File

@ -1,34 +0,0 @@
package com.navinfo.volvo.ui.home
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.navinfo.volvo.db.dao.entity.Message
class HomeViewModel : ViewModel() {
private val messageList: LiveData<MutableList<Message>> =
MutableLiveData<MutableList<Message>>().apply {
value = mutableListOf<Message>()
value!!.add(Message())
value!!.add(Message())
value!!.add(Message())
value!!.add(Message())
value!!.add(Message())
value!!.add(Message())
value!!.add(Message())
value!!.add(Message())
value!!.add(Message())
value!!.add(Message())
value!!.add(Message())
value!!.add(Message())
value!!.add(Message())
value!!.add(Message())
value!!.add(Message())
value!!.add(Message())
}
fun getMessageList(): LiveData<MutableList<Message>> {
return messageList
}
}

View File

@ -0,0 +1,28 @@
package com.navinfo.volvo.util
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
/**
* This functions helps in transforming a [MutableLiveData] of type [T]
* to a [LiveData] of type [T]
*/
fun <T> MutableLiveData<T>.asLiveData() = this as LiveData<T>
/**
* This function helps to observe a [LiveData] once
*/
fun <T> LiveData<T>.observeOnce(lifecycleOwner: LifecycleOwner, observer: Observer<T>) {
observe(
lifecycleOwner,
object : Observer<T> {
override fun onChanged(t: T?) {
observer.onChanged(t)
removeObserver(this)
}
}
)
}

View File

@ -0,0 +1,24 @@
package com.navinfo.volvo.util
/**
* Created by Mayokun Adeniyi on 23/05/2020.
*/
/**
* A generic class that holds a value with its loading status.
* @param <T>
*/
sealed class NetResult<out R> {
data class Success<out T>(val data: T?) : NetResult<T>()
data class Error(val exception: Exception) : NetResult<Nothing>()
object Loading : NetResult<Nothing>()
override fun toString(): String {
return when (this) {
is Success<*> -> "Success[data=$data]"
is Error -> "Error[exception=$exception]"
is Loading -> "Loading"
}
}
}

View File

@ -0,0 +1,131 @@
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)
// }
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="800">
<translate
android:fromXDelta="-100%"
android:toXDelta="0%" />
</set>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set
android:duration="800"
xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="100%"
android:toXDelta="0%"
/>
</set>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set
android:duration="800"
xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="0%"
android:toXDelta="-100%"
/>
</set>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<set
android:duration="800"
xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="0%"
android:toXDelta="100%"
/>
</set>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:left="10dp" >
<shape android:shape="rectangle">
<solid android:color="#F6F6F6" />
<size android:height="1dp" />
</shape>
</item>
</layer-list>

View File

@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <solid android:color="@color/white" /> <!-- <stroke--> <!-- android:width="1dp"--> <!-- android:color="@color/color_dcdcdc" />--> <corners android:radius="5dp" /> </shape>

View File

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:tint="#000000" android:viewportHeight="24"
android:viewportWidth="24" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M10,6L8.59,7.41 13.17,12l-4.58,4.59L10,18l6,-6z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="8dp" android:tint="#FF0202"
android:viewportHeight="24" android:viewportWidth="24"
android:width="8dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,17.27L18.18,21l-1.64,-7.03L22,9.24l-7.19,-0.61L12,2 9.19,8.63 2,9.24l5.46,4.73L5.82,21z"/>
</vector>

View File

@ -6,6 +6,7 @@
android:layout_height="match_parent">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:visibility="gone"
android:id="@+id/nav_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
@ -31,14 +32,14 @@
app:navGraph="@navigation/mobile_navigation" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_new_message"
android:visibility="gone"
android:id="@+id/new_message_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:src="@drawable/ic_add_24dp"
app:elevation="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:elevation="8dp"
/>
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,10 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.navinfo.volvo.ui.dashboard.DashboardFragment">
tools:context="com.navinfo.volvo.ui.fragments.dashboard.DashboardFragment">
<TextView
android:id="@+id/text_dashboard"

View File

@ -6,5 +6,5 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.home.HomeFragment">
tools:context=".ui.fragments.home.MessageFragment">
</com.yanzhenjie.recyclerview.SwipeRecyclerView>

View File

@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.navinfo.volvo.ui.fragments.login.LoginFragment">
<androidx.constraintlayout.utils.widget.ImageFilterView
android:id="@+id/login_fragment_logo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2"
app:roundPercent="0.2" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/login_fragment_user_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:scrollbarAlwaysDrawHorizontalTrack="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.4">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="用户名" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
app:layout_constraintTop_toBottomOf="@id/login_fragment_user_layout">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="密码" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/login_fragment_register_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="注册"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@id/login_fragment_login_button"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.7" />
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/login_fragment_login_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:text="登录"
app:layout_constraintBaseline_toBaselineOf="@id/login_fragment_register_button"
app:layout_constraintLeft_toRightOf="@id/login_fragment_register_button"
app:layout_constraintRight_toRightOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.notifications.NotificationsFragment">
tools:context=".ui.fragments.notifications.NotificationsFragment">
<TextView
android:id="@+id/text_notifications"

View File

@ -1,19 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/activity_default_padding"
tools:context=".ui.message.ObtainMessageFragment">
tools:context=".ui.fragments.message.ObtainMessageFragment">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:overScrollMode="never"
android:scrollbars="none">
android:scrollbars="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -24,10 +25,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/default_widget_padding"
android:hint="问候信息"
app:counterEnabled="true"
app:counterMaxLength="10"
app:errorEnabled="true"
android:hint="问候信息"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -82,22 +83,24 @@
android:text="上传图片:"></TextView>
<com.google.android.material.button.MaterialButton
style="@style/Widget.Material3.Button.ElevatedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.Material3.Button.ElevatedButton"
app:icon="@drawable/ic_baseline_camera_24"
android:padding="@dimen/default_widget_padding"
android:text="点击拍照"
android:padding="@dimen/default_widget_padding"></com.google.android.material.button.MaterialButton>
app:icon="@drawable/ic_baseline_camera_24"></com.google.android.material.button.MaterialButton>
<Space
android:layout_width="@dimen/default_widget_padding"
android:layout_height="wrap_content"></Space>
<com.google.android.material.button.MaterialButton
style="@style/Widget.Material3.Button.ElevatedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.Material3.Button.ElevatedButton"
app:icon="@drawable/ic_baseline_image_search_24"
android:padding="@dimen/default_widget_padding"
android:text="相册选择"
android:padding="@dimen/default_widget_padding"></com.google.android.material.button.MaterialButton>
app:icon="@drawable/ic_baseline_image_search_24"></com.google.android.material.button.MaterialButton>
</LinearLayout>
<LinearLayout
@ -119,22 +122,24 @@
android:text="上传音频:"></TextView>
<com.google.android.material.button.MaterialButton
style="@style/Widget.Material3.Button.ElevatedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.Material3.Button.ElevatedButton"
app:icon="@drawable/ic_baseline_fiber_manual_record_24"
android:padding="@dimen/default_widget_padding"
android:text="长按录音"
android:padding="@dimen/default_widget_padding"></com.google.android.material.button.MaterialButton>
app:icon="@drawable/ic_baseline_fiber_manual_record_24"></com.google.android.material.button.MaterialButton>
<Space
android:layout_width="@dimen/default_widget_padding"
android:layout_height="wrap_content"></Space>
<com.google.android.material.button.MaterialButton
style="@style/Widget.Material3.Button.ElevatedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.Material3.Button.ElevatedButton"
app:icon="@drawable/ic_baseline_audio_file_24"
android:padding="@dimen/default_widget_padding"
android:text="音频选择"
android:padding="@dimen/default_widget_padding"></com.google.android.material.button.MaterialButton>
app:icon="@drawable/ic_baseline_audio_file_24"></com.google.android.material.button.MaterialButton>
</LinearLayout>
</LinearLayout>
@ -157,8 +162,12 @@
android:id="@+id/layer_send_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true"
android:background="@drawable/shape_radius5_white"
android:divider="@drawable/shape_divider_linear"
android:orientation="vertical"
android:padding="@dimen/default_widget_padding"
android:showDividers="middle"
app:layout_constraintTop_toBottomOf="@id/div_send_info">
<LinearLayout
@ -187,31 +196,17 @@
tools:ignore="TouchTargetSizeCheck,SpeakableTextPresentCheck"></androidx.appcompat.widget.AppCompatEditText>
</LinearLayout>
<LinearLayout
style="@style/default_line"
<TextView
android:id="@+id/edt_send_to"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
android:drawableStart="@drawable/ic_baseline_star_8"
android:drawableEnd="@drawable/ic_baseline_navigate_next_24"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:text="发给谁:" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="*"
android:textColor="@color/red"></TextView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发给谁:"></TextView>
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/edt_send_to"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/selector_bg_4_round_corner"
tools:ignore="SpeakableTextPresentCheck,TouchTargetSizeCheck"></androidx.appcompat.widget.AppCompatEditText>
</LinearLayout>
<LinearLayout
style="@style/default_line"
@ -233,18 +228,19 @@
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_send_time"
style="@style/Widget.Material3.Button.ElevatedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.Material3.Button.ElevatedButton"
app:icon="@drawable/ic_baseline_access_time_24"
android:padding="@dimen/default_widget_padding"
android:text="现在"
android:padding="@dimen/default_widget_padding"></com.google.android.material.button.MaterialButton>
app:icon="@drawable/ic_baseline_access_time_24"></com.google.android.material.button.MaterialButton>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -2,7 +2,7 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/navigation_home"
android:id="@+id/navigation_message"
android:icon="@drawable/ic_home_black_24dp"
android:title="@string/title_home" />
<item

View File

@ -3,40 +3,50 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mobile_navigation"
app:startDestination="@+id/navigation_home">
app:startDestination="@+id/navigation_login">
<fragment
android:id="@+id/navigation_home"
android:name="com.navinfo.volvo.ui.home.HomeFragment"
android:label="@string/title_home"
tools:layout="@layout/fragment_home" >
<action android:id="@+id/home_2_obtain_message"
app:destination="@id/navigation_obtain_message">
</action>
android:id="@+id/navigation_login"
android:name="com.navinfo.volvo.ui.fragments.login.LoginFragment"
android:label="login"
tools:layout="@layout/fragment_login">
<action
android:id="@+id/action_login_to_home"
app:destination="@id/navigation_message"
app:enterAnim="@anim/from_left"
app:exitAnim="@anim/to_right"
app:popEnterAnim="@anim/from_right"
app:popExitAnim="@anim/to_left"
app:popUpTo="@id/navigation_login"
app:popUpToInclusive="true" />
</fragment>
<fragment
android:id="@+id/navigation_message"
android:name="com.navinfo.volvo.ui.fragments.home.MessageFragment"
android:label="@string/title_home"
tools:layout="@layout/fragment_home"></fragment>
<fragment
android:id="@+id/navigation_dashboard"
android:name="com.navinfo.volvo.ui.dashboard.DashboardFragment"
android:name="com.navinfo.volvo.ui.fragments.dashboard.DashboardFragment"
android:label="@string/title_dashboard"
tools:layout="@layout/fragment_dashboard" />
<fragment
android:id="@+id/fab_new_message"
android:name="com.navinfo.volvo.ui.dashboard.DashboardFragment"
android:name="com.navinfo.volvo.ui.fragments.dashboard.DashboardFragment"
android:label="@string/title_dashboard"
tools:layout="@layout/fragment_dashboard" />
<fragment
android:id="@+id/navigation_notifications"
android:name="com.navinfo.volvo.ui.notifications.NotificationsFragment"
android:name="com.navinfo.volvo.ui.fragments.notifications.NotificationsFragment"
android:label="@string/title_notifications"
tools:layout="@layout/fragment_notifications" />
<fragment
android:id="@+id/navigation_obtain_message"
android:name="com.navinfo.volvo.ui.message.ObtainMessageFragment"
android:name="com.navinfo.volvo.ui.fragments.message.ObtainMessageFragment"
android:label="问候编辑"
tools:layout="@layout/fragment_obtain_message" />
</navigation>

View File

@ -1,6 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.NavinfoVolvo" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
<style name="Theme.NavinfoVolvo" parent="Theme.Material3.DynamicColors.DayNight">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_200</item>
<item name="colorPrimaryVariant">@color/purple_700</item>

View File

@ -1,6 +1,6 @@
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Theme.NavinfoVolvo" parent="Theme.Material3.DayNight.NoActionBar">
<style name="Theme.NavinfoVolvo" parent="Theme.Material3.DynamicColors.Light">
<!-- Primary brand color. -->
<item name="colorPrimary">@color/purple_500</item>
<item name="colorPrimaryVariant">@color/purple_700</item>

View File

@ -1,19 +1,22 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
// ext.kotlin_version = '1.7.0'
ext.kotlin_version = '1.6.20'
// ext.kotlin_version = '1.7.20'
dependencies {
// classpath "com.android.tools.build:gradle:4.1.1"
// classpath('androidx.multidex:multidex:2.0.1')
// classpath 'com.android.tools.build:gradle:7.3.1'
classpath('androidx.multidex:multidex:2.0.1')
// classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
// classpath "io.realm:realm-gradle-plugin:10.10.1"
// classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.google.dagger:hilt-android-gradle-plugin:2.41"
}
}
plugins {
id 'com.android.application' version '7.3.1' apply false
id 'com.android.library' version '7.3.1' apply false
id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
id 'com.android.application' version '7.1.2' apply false
id 'com.android.library' version '7.1.2' apply false
id 'org.jetbrains.kotlin.android' version '1.6.10' apply false
// id 'com.google.dagger.hilt.android' version "2.44.2" apply false
// id 'io.realm.kotlin' version '0.10.0' apply false
}
allprojects {
}

View File

@ -1,4 +1,4 @@
#Fri Dec 23 11:23:50 CST 2022
#Wed Jan 04 11:16:08 CST 2023
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists