添加了顶部时间更新
This commit is contained in:
@@ -78,4 +78,8 @@ dependencies {
|
|||||||
implementation(libs.gson)
|
implementation(libs.gson)
|
||||||
// 日志打印
|
// 日志打印
|
||||||
implementation(libs.timber)
|
implementation(libs.timber)
|
||||||
|
// 协程
|
||||||
|
implementation(libs.kotlinx.coroutines.android)
|
||||||
|
implementation(libs.androidx.lifecycle.viewmodel.ktx)
|
||||||
|
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,12 @@ import android.view.WindowManager
|
|||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
|
import com.sw.inbound.utils.DateTimeUtils
|
||||||
|
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* activity 基类
|
* activity 基类
|
||||||
@@ -14,7 +20,9 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
|||||||
|
|
||||||
protected lateinit var binding: VB
|
protected lateinit var binding: VB
|
||||||
private set
|
private set
|
||||||
|
private var headerBinding: ItemTitleTimeBinding? = null
|
||||||
protected lateinit var context: Context
|
protected lateinit var context: Context
|
||||||
|
private var timeJob: Job? = null
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -25,16 +33,33 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
|
|||||||
)
|
)
|
||||||
context = this
|
context = this
|
||||||
binding = inflateViewBinding()
|
binding = inflateViewBinding()
|
||||||
|
headerBinding = inflateTitleBinding()
|
||||||
setContentView(binding.root)
|
setContentView(binding.root)
|
||||||
|
updateTime()
|
||||||
initialize()
|
initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updateTime() {
|
||||||
|
headerBinding?.let {
|
||||||
|
val scope = CoroutineScope(Dispatchers.Main)
|
||||||
|
timeJob = scope.launch {
|
||||||
|
DateTimeUtils.realTimeChineseDateFlow()
|
||||||
|
.collect { (date, time) ->
|
||||||
|
headerBinding!!.tvLeftDate.text = date
|
||||||
|
headerBinding!!.tvRightTime.text = time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract fun inflateViewBinding(): VB
|
protected abstract fun inflateViewBinding(): VB
|
||||||
|
|
||||||
|
protected abstract fun inflateTitleBinding(): ItemTitleTimeBinding?
|
||||||
|
|
||||||
protected abstract fun initialize()
|
protected abstract fun initialize()
|
||||||
|
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
|
timeJob?.cancel()
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,6 +10,7 @@ import androidx.camera.lifecycle.ProcessCameraProvider
|
|||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.google.common.util.concurrent.ListenableFuture
|
import com.google.common.util.concurrent.ListenableFuture
|
||||||
import com.sw.platecabinet.databinding.ActivityLoginFaceBinding
|
import com.sw.platecabinet.databinding.ActivityLoginFaceBinding
|
||||||
|
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -22,6 +23,10 @@ class LoginByFaceActivity : BaseActivity<ActivityLoginFaceBinding>() {
|
|||||||
return ActivityLoginFaceBinding.inflate(layoutInflater)
|
return ActivityLoginFaceBinding.inflate(layoutInflater)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun inflateTitleBinding(): ItemTitleTimeBinding {
|
||||||
|
return binding.includeHeader
|
||||||
|
}
|
||||||
|
|
||||||
override fun initialize() {
|
override fun initialize() {
|
||||||
initView()
|
initView()
|
||||||
startCamera()
|
startCamera()
|
||||||
|
|||||||
@@ -2,12 +2,17 @@ package com.sw.platecabinet.activity
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import com.sw.platecabinet.databinding.ActivityLoginByPwdBinding
|
import com.sw.platecabinet.databinding.ActivityLoginByPwdBinding
|
||||||
|
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
|
||||||
|
|
||||||
class LoginByPwdActivity : BaseActivity<ActivityLoginByPwdBinding>() {
|
class LoginByPwdActivity : BaseActivity<ActivityLoginByPwdBinding>() {
|
||||||
override fun inflateViewBinding(): ActivityLoginByPwdBinding {
|
override fun inflateViewBinding(): ActivityLoginByPwdBinding {
|
||||||
return ActivityLoginByPwdBinding.inflate(layoutInflater)
|
return ActivityLoginByPwdBinding.inflate(layoutInflater)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun inflateTitleBinding(): ItemTitleTimeBinding {
|
||||||
|
return binding.includeHeader
|
||||||
|
}
|
||||||
|
|
||||||
override fun initialize() {
|
override fun initialize() {
|
||||||
binding.tvFaceRec.setOnClickListener {
|
binding.tvFaceRec.setOnClickListener {
|
||||||
val intent = Intent(this, LoginByFaceActivity::class.java)
|
val intent = Intent(this, LoginByFaceActivity::class.java)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.sw.platecabinet.activity
|
package com.sw.platecabinet.activity
|
||||||
|
|
||||||
import com.sw.platecabinet.databinding.ActivityMainBinding
|
import com.sw.platecabinet.databinding.ActivityMainBinding
|
||||||
|
import com.sw.platecabinet.databinding.ItemTitleTimeBinding
|
||||||
|
|
||||||
class MainActivity : BaseActivity<ActivityMainBinding>() {
|
class MainActivity : BaseActivity<ActivityMainBinding>() {
|
||||||
|
|
||||||
@@ -8,6 +9,10 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
|
|||||||
return ActivityMainBinding.inflate(layoutInflater)
|
return ActivityMainBinding.inflate(layoutInflater)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun inflateTitleBinding(): ItemTitleTimeBinding {
|
||||||
|
return binding.includeHeader
|
||||||
|
}
|
||||||
|
|
||||||
override fun initialize() {
|
override fun initialize() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package com.sw.inbound.utils
|
||||||
|
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.flow.flow
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 时间格式化工具类
|
||||||
|
*/
|
||||||
|
object DateTimeUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取完整中文日期格式(示例:2025年6月11日 星期三)
|
||||||
|
*/
|
||||||
|
fun getChineseDateString(date: Date = Date()): String {
|
||||||
|
return SimpleDateFormat("yyyy年M月d日 EEEE", Locale.CHINA).format(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取带时间的完整中文格式(示例:2025年6月11日 星期三 14:30)
|
||||||
|
*/
|
||||||
|
fun getChineseDateTimeString(date: Date = Date()): String {
|
||||||
|
return SimpleDateFormat("yyyy年M月d日 EEEE HH:mm:ss", Locale.CHINA).format(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用线程安全的日期格式化(避免 SimpleDateFormat 的线程安全问题)
|
||||||
|
private val dateFormat by lazy {
|
||||||
|
SimpleDateFormat("yyyy年M月d日 EEEE", Locale.CHINA)
|
||||||
|
}
|
||||||
|
private val timeFormat by lazy {
|
||||||
|
SimpleDateFormat("HH:mm:ss", Locale.CHINA)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getChineseDateTimePair(date: Date = Date()): Pair<String, String> {
|
||||||
|
return dateFormat.format(date) to timeFormat.format(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 实时时间流(每秒更新)
|
||||||
|
* @param intervalMillis 更新间隔(默认1秒)
|
||||||
|
*/
|
||||||
|
fun realTimeChineseDateFlow(intervalMillis: Long = 1000) = flow {
|
||||||
|
while (true) {
|
||||||
|
emit(getChineseDateTimePair())
|
||||||
|
delay(intervalMillis)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
package com.sw.inbound.utils
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.GsonBuilder
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
|
import java.lang.reflect.Type
|
||||||
|
|
||||||
|
object GsonUtils {
|
||||||
|
|
||||||
|
// 默认的 Gson 实例
|
||||||
|
private val defaultGson: Gson by lazy {
|
||||||
|
GsonBuilder()
|
||||||
|
.setDateFormat("yyyy-MM-dd HH:mm:ss") // 设置日期格式
|
||||||
|
.disableHtmlEscaping() // 禁止转义HTML标签
|
||||||
|
.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取默认配置的 Gson 实例
|
||||||
|
*/
|
||||||
|
fun getGson(): Gson = defaultGson
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象转换为 JSON 字符串
|
||||||
|
* @param obj 要转换的对象
|
||||||
|
* @return JSON 字符串
|
||||||
|
*/
|
||||||
|
fun toJson(obj: Any?): String {
|
||||||
|
return if (obj == null) "" else defaultGson.toJson(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 JSON 字符串转换为对象
|
||||||
|
* @param json JSON 字符串
|
||||||
|
* @param clazz 目标类
|
||||||
|
* @return 转换后的对象
|
||||||
|
*/
|
||||||
|
fun <T> fromJson(json: String?, clazz: Class<T>): T? {
|
||||||
|
if (json.isNullOrEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return try {
|
||||||
|
defaultGson.fromJson(json, clazz)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 JSON 字符串转换为对象 (支持泛型)
|
||||||
|
* @param json JSON 字符串
|
||||||
|
* @param type 类型令牌,用于获取泛型类型
|
||||||
|
* @return 转换后的对象
|
||||||
|
*/
|
||||||
|
fun <T> fromJson(json: String?, type: Type): T? {
|
||||||
|
if (json.isNullOrEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return try {
|
||||||
|
defaultGson.fromJson(json, type)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 JSON 字符串转换为 List 对象
|
||||||
|
* @param json JSON 字符串
|
||||||
|
* @param clazz List 中的元素类型
|
||||||
|
* @return 转换后的 List 对象
|
||||||
|
*/
|
||||||
|
fun <T> fromJsonList(json: String?, clazz: Class<T>): List<T>? {
|
||||||
|
if (json.isNullOrEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return try {
|
||||||
|
val type = TypeToken.getParameterized(List::class.java, clazz).type
|
||||||
|
defaultGson.fromJson<List<T>>(json, type)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将 JSON 字符串转换为 Map 对象
|
||||||
|
* @param json JSON 字符串
|
||||||
|
* @param keyClazz Map 的 key 类型
|
||||||
|
* @param valueClazz Map 的 value 类型
|
||||||
|
* @return 转换后的 Map 对象
|
||||||
|
*/
|
||||||
|
fun <K, V> fromJsonMap(
|
||||||
|
json: String?,
|
||||||
|
keyClazz: Class<K>,
|
||||||
|
valueClazz: Class<V>
|
||||||
|
): Map<K, V>? {
|
||||||
|
if (json.isNullOrEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return try {
|
||||||
|
val type = TypeToken.getParameterized(Map::class.java, keyClazz, valueClazz).type
|
||||||
|
defaultGson.fromJson<Map<K, V>>(json, type)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将对象转换为另一种类型的对象
|
||||||
|
* @param obj 源对象
|
||||||
|
* @param clazz 目标类型
|
||||||
|
* @return 转换后的对象
|
||||||
|
*/
|
||||||
|
fun <T> convert(obj: Any?, clazz: Class<T>): T? {
|
||||||
|
if (obj == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return fromJson(toJson(obj), clazz)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,111 @@
|
|||||||
|
package com.sw.inbound.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import com.sw.plate.App
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
import kotlin.properties.ReadWriteProperty
|
||||||
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
class SPUtil private constructor(context: Context, private val spName: String) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@Volatile
|
||||||
|
private var instance: SPUtil? = null
|
||||||
|
|
||||||
|
fun getInstance(
|
||||||
|
context: Context = App.getContext(),
|
||||||
|
spName: String = "default_sp"
|
||||||
|
): SPUtil {
|
||||||
|
return instance ?: synchronized(this) {
|
||||||
|
instance ?: SPUtil(context.applicationContext, spName).also { instance = it }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val sharedPreferences by lazy {
|
||||||
|
context.getSharedPreferences(spName, Context.MODE_PRIVATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 基础存储方法
|
||||||
|
fun put(key: String, value: Any?) {
|
||||||
|
when (value) {
|
||||||
|
null -> remove(key) // 存入null视为删除
|
||||||
|
is String -> sharedPreferences.edit { putString(key, value) }
|
||||||
|
is Int -> sharedPreferences.edit { putInt(key, value) }
|
||||||
|
is Long -> sharedPreferences.edit { putLong(key, value) }
|
||||||
|
is Float -> sharedPreferences.edit { putFloat(key, value) }
|
||||||
|
is Boolean -> sharedPreferences.edit { putBoolean(key, value) }
|
||||||
|
is Set<*> -> sharedPreferences.edit { putStringSet(key, value as Set<String>) }
|
||||||
|
else -> throw IllegalArgumentException("Unsupported type: ${value.javaClass.name}")
|
||||||
|
}
|
||||||
|
notifyDataChanged(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
fun <T> get(key: String, defaultValue: T? = null): T? {
|
||||||
|
return when (defaultValue) {
|
||||||
|
is String -> sharedPreferences.getString(key, defaultValue) as T
|
||||||
|
is Int -> sharedPreferences.getInt(key, defaultValue) as T
|
||||||
|
is Long -> sharedPreferences.getLong(key, defaultValue) as T
|
||||||
|
is Float -> sharedPreferences.getFloat(key, defaultValue) as T
|
||||||
|
is Boolean -> sharedPreferences.getBoolean(key, defaultValue) as T
|
||||||
|
is Set<*> -> sharedPreferences.getStringSet(key, defaultValue as Set<String>) as T
|
||||||
|
null -> when {
|
||||||
|
sharedPreferences.contains(key) -> get(key, "") as? T // 尝试作为String获取
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> throw IllegalArgumentException("Unsupported type: ${defaultValue.javaClass.name}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun remove(key: String) {
|
||||||
|
if (sharedPreferences.contains(key)) {
|
||||||
|
sharedPreferences.edit { remove(key) }
|
||||||
|
notifyDataChanged(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clear() {
|
||||||
|
sharedPreferences.edit { clear() }
|
||||||
|
notifyDataChanged(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun contains(key: String): Boolean {
|
||||||
|
return sharedPreferences.contains(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听变化
|
||||||
|
private val dataChangeFlow = MutableStateFlow(0)
|
||||||
|
|
||||||
|
private fun notifyDataChanged(key: String?) {
|
||||||
|
dataChangeFlow.value++
|
||||||
|
}
|
||||||
|
|
||||||
|
fun observeKey(key: String): Flow<Any?> {
|
||||||
|
return dataChangeFlow.map { get(key) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 属性委托支持
|
||||||
|
fun int(key: String, default: Int = 0) = SpProperty(key, default)
|
||||||
|
fun long(key: String, default: Long = 0L) = SpProperty(key, default)
|
||||||
|
fun float(key: String, default: Float = 0f) = SpProperty(key, default)
|
||||||
|
fun boolean(key: String, default: Boolean = false) = SpProperty(key, default)
|
||||||
|
fun string(key: String, default: String = "") = SpProperty(key, default)
|
||||||
|
fun stringSet(key: String, default: Set<String> = emptySet()) = SpProperty(key, default)
|
||||||
|
|
||||||
|
inner class SpProperty<T>(private val key: String, private val defaultValue: T) :
|
||||||
|
ReadWriteProperty<Any?, T> {
|
||||||
|
|
||||||
|
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||||
|
return get(key, defaultValue) ?: defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
|
||||||
|
put(key, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,9 @@
|
|||||||
android:background="@mipmap/bg"
|
android:background="@mipmap/bg"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<include layout="@layout/item_title_time" />
|
<include
|
||||||
|
android:id="@+id/includeHeader"
|
||||||
|
layout="@layout/item_title_time" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -8,7 +8,9 @@
|
|||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
tools:context=".activity.LoginByFaceActivity">
|
tools:context=".activity.LoginByFaceActivity">
|
||||||
|
|
||||||
<include layout="@layout/item_title_time" />
|
<include
|
||||||
|
android:id="@+id/includeHeader"
|
||||||
|
layout="@layout/item_title_time" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -6,5 +6,7 @@
|
|||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".activity.MainActivity">
|
tools:context=".activity.MainActivity">
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/includeHeader"
|
||||||
|
layout="@layout/item_title_time" />
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -6,6 +6,9 @@ junit = "4.13.2"
|
|||||||
junitVersion = "1.1.5"
|
junitVersion = "1.1.5"
|
||||||
espressoCore = "3.5.1"
|
espressoCore = "3.5.1"
|
||||||
appcompat = "1.6.1"
|
appcompat = "1.6.1"
|
||||||
|
kotlinxCoroutinesAndroid = "1.6.4"
|
||||||
|
lifecycleViewmodelKtx = "2.8.3"
|
||||||
|
lifecycleRuntimeKtx = "2.8.3"
|
||||||
material = "1.10.0"
|
material = "1.10.0"
|
||||||
activity = "1.8.0"
|
activity = "1.8.0"
|
||||||
constraintlayout = "2.1.4"
|
constraintlayout = "2.1.4"
|
||||||
@@ -20,10 +23,13 @@ hiltAndroid = "2.56.2"
|
|||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
|
androidx-lifecycle-runtime-ktx = { module = "androidx.lifecycle:lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
|
||||||
|
androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "lifecycleViewmodelKtx" }
|
||||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||||
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
||||||
|
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutinesAndroid" }
|
||||||
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||||
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
|
androidx-activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
|
||||||
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
|
androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
|
||||||
|
|||||||
Reference in New Issue
Block a user