auth tests fix
This commit is contained in:
parent
fba10fa426
commit
14e2b420e2
1
api-core/.gitignore
vendored
Normal file
1
api-core/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build
|
52
api-core/build.gradle.kts
Normal file
52
api-core/build.gradle.kts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
plugins {
|
||||||
|
alias(libs.plugins.android.library)
|
||||||
|
alias(libs.plugins.kotlin.android)
|
||||||
|
alias(libs.plugins.kotlin.serialization)
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "com.example.api.core"
|
||||||
|
compileSdk = 35
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdk = 33
|
||||||
|
|
||||||
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
consumerProguardFiles("consumer-rules.pro")
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
isMinifyEnabled = false
|
||||||
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
"proguard-rules.pro"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
|
targetCompatibility = JavaVersion.VERSION_11
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "11"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
implementation(libs.androidx.datastore.preferences)
|
||||||
|
implementation(libs.kotlinx.serialization.json)
|
||||||
|
implementation(libs.retrofit2.kotlinx.serialization.converter)
|
||||||
|
implementation(libs.retrofit2)
|
||||||
|
implementation(libs.okhttp)
|
||||||
|
implementation(libs.logging.interceptor)
|
||||||
|
|
||||||
|
implementation(libs.androidx.core.ktx)
|
||||||
|
implementation(libs.androidx.appcompat)
|
||||||
|
implementation(libs.material)
|
||||||
|
testImplementation(libs.junit)
|
||||||
|
testImplementation(libs.mockwebserver)
|
||||||
|
androidTestImplementation(libs.androidx.junit)
|
||||||
|
androidTestImplementation(libs.androidx.espresso.core)
|
||||||
|
}
|
0
api-core/consumer-rules.pro
Normal file
0
api-core/consumer-rules.pro
Normal file
21
api-core/proguard-rules.pro
vendored
Normal file
21
api-core/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
@ -0,0 +1,24 @@
|
|||||||
|
package com.example.api.core
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
|
||||||
|
import org.junit.Assert.*
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* See [testing documentation](http://d.android.com/tools/testing).
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class ApiRepositoryTest {
|
||||||
|
@Test
|
||||||
|
fun useAppContext() {
|
||||||
|
// Context of the app under test.
|
||||||
|
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
assertEquals("com.example.api.core.test", appContext.packageName)
|
||||||
|
}
|
||||||
|
}
|
4
api-core/src/main/AndroidManifest.xml
Normal file
4
api-core/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
</manifest>
|
@ -0,0 +1,27 @@
|
|||||||
|
package com.example.api.core.data.core
|
||||||
|
|
||||||
|
import com.example.api.core.domain.ApiRepository
|
||||||
|
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.create
|
||||||
|
|
||||||
|
object ApiFactory {
|
||||||
|
|
||||||
|
fun provideRepository(dataStoreRepository: DataStoreRepository): ApiRepository {
|
||||||
|
val json = Json { ignoreUnknownKeys = true }
|
||||||
|
val retrofit = Retrofit.Builder()
|
||||||
|
.baseUrl("https://api.matule.ru/api/")
|
||||||
|
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
||||||
|
.client(OkHttpClient.Builder().addInterceptor(HttpLoggingInterceptor().apply {
|
||||||
|
level = HttpLoggingInterceptor.Level.BODY
|
||||||
|
}).build())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
|
||||||
|
return BaseApiRepository(retrofit.create<ApiService>(), dataStoreRepository)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.example.api.core.data.core
|
||||||
|
|
||||||
|
import com.example.api.core.data.dto.AuthUserResponseDto
|
||||||
|
import com.example.api.core.data.dto.RegisterUserDto
|
||||||
|
import com.example.api.core.data.dto.SalesAndActionsDto
|
||||||
|
import com.example.api.core.data.dto.SignInUserDto
|
||||||
|
import com.example.api.core.data.dto.UserResponseDto
|
||||||
|
import retrofit2.http.Body
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.POST
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Автор: Манякин Дмитрий (user5)
|
||||||
|
* Дата создания: 27.05.2025
|
||||||
|
* */
|
||||||
|
|
||||||
|
internal interface ApiService {
|
||||||
|
|
||||||
|
@POST("collections/users/records")
|
||||||
|
suspend fun register(@Body registerUserDto: RegisterUserDto): UserResponseDto
|
||||||
|
|
||||||
|
@POST("collections/users/auth-with-password")
|
||||||
|
suspend fun auth(@Body signInUserDto: SignInUserDto): AuthUserResponseDto
|
||||||
|
|
||||||
|
@GET("collections/project/records")
|
||||||
|
suspend fun salesAndProjects(): SalesAndActionsDto
|
||||||
|
|
||||||
|
// @GET("collections/products/records")
|
||||||
|
// suspend fun products():
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.example.api.core.data.core
|
||||||
|
|
||||||
|
import com.example.api.core.domain.ApiRepository
|
||||||
|
import com.example.api.core.domain.AuthUserResponse
|
||||||
|
import com.example.api.core.domain.FetchResult
|
||||||
|
import com.example.api.core.domain.RegisterUser
|
||||||
|
import retrofit2.HttpException
|
||||||
|
import java.net.UnknownHostException
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Автор: Манякин Дмитрий (user5)
|
||||||
|
* Дата создания: 27.05.2025
|
||||||
|
* */
|
||||||
|
|
||||||
|
internal class BaseApiRepository(
|
||||||
|
private val service: ApiService,
|
||||||
|
private val dataStoreRepository: DataStoreRepository
|
||||||
|
) : RemoteMapper(), ApiRepository {
|
||||||
|
|
||||||
|
override suspend fun auth(registerUser: RegisterUser): FetchResult<AuthUserResponse> {
|
||||||
|
return try {
|
||||||
|
service.register(registerUser.toRegisterUserDto())
|
||||||
|
val response = service.auth(registerUser.toSignInUserDto())
|
||||||
|
dataStoreRepository.saveToken(response.token)
|
||||||
|
|
||||||
|
FetchResult.Success(response.toUserResponse())
|
||||||
|
} catch (e: UnknownHostException) {
|
||||||
|
FetchResult.Error(null, "no internet connection")
|
||||||
|
} catch (e: HttpException) {
|
||||||
|
FetchResult.Error(null, e.message())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
FetchResult.Error(null, e.message!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
package com.example.api.core.data.core
|
||||||
|
|
||||||
|
import androidx.datastore.core.DataStore
|
||||||
|
import androidx.datastore.preferences.core.Preferences
|
||||||
|
import androidx.datastore.preferences.core.edit
|
||||||
|
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.map
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Автор: Манякин Дмитрий (user5)
|
||||||
|
* Дата создания: 27.05.2025
|
||||||
|
* */
|
||||||
|
|
||||||
|
interface DataStoreRepository {
|
||||||
|
|
||||||
|
suspend fun saveToken(token: String)
|
||||||
|
|
||||||
|
fun token(): Flow<String>
|
||||||
|
|
||||||
|
class Base(private val preferences: DataStore<Preferences>) : DataStoreRepository {
|
||||||
|
override suspend fun saveToken(token: String) {
|
||||||
|
preferences.edit { settings ->
|
||||||
|
settings[TOKEN_KEY] = token
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun token(): Flow<String> {
|
||||||
|
return preferences.data.map { preferences ->
|
||||||
|
preferences[TOKEN_KEY] ?: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
val TOKEN_KEY = stringPreferencesKey("token_key")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,58 @@
|
|||||||
|
package com.example.api.core.data.core
|
||||||
|
|
||||||
|
import com.example.api.core.data.dto.AuthUserResponseDto
|
||||||
|
import com.example.api.core.data.dto.RegisterUserDto
|
||||||
|
import com.example.api.core.data.dto.SignInUserDto
|
||||||
|
import com.example.api.core.data.dto.SignInUserResponseDto
|
||||||
|
import com.example.api.core.data.dto.UserResponseDto
|
||||||
|
import com.example.api.core.domain.AuthUserResponse
|
||||||
|
import com.example.api.core.domain.RegisterUser
|
||||||
|
import com.example.api.core.domain.SignInUserResponse
|
||||||
|
import com.example.api.core.domain.UserResponse
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Автор: Манякин Дмитрий (user5)
|
||||||
|
* Дата создания: 27.05.2025
|
||||||
|
* */
|
||||||
|
|
||||||
|
internal abstract class RemoteMapper {
|
||||||
|
protected fun RegisterUser.toRegisterUserDto(): RegisterUserDto {
|
||||||
|
return RegisterUserDto(
|
||||||
|
email = email,
|
||||||
|
password = password,
|
||||||
|
passwordConfirm = passwordConfirm
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun RegisterUser.toSignInUserDto(): SignInUserDto {
|
||||||
|
return SignInUserDto(
|
||||||
|
identity = email,
|
||||||
|
password = password
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun AuthUserResponseDto.toUserResponse(): AuthUserResponse {
|
||||||
|
return AuthUserResponse(
|
||||||
|
record = record.toUserResponse(),
|
||||||
|
token = token
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun SignInUserResponseDto.toUserResponse(): SignInUserResponse {
|
||||||
|
return SignInUserResponse(
|
||||||
|
collectionId = collectionId,
|
||||||
|
collectionName = collectionName,
|
||||||
|
created = created,
|
||||||
|
dateBirthday = dateBirthday,
|
||||||
|
emailVisibility = emailVisibility,
|
||||||
|
email = email,
|
||||||
|
firstname = firstname,
|
||||||
|
gender = gender,
|
||||||
|
id = id,
|
||||||
|
lastname = lastname,
|
||||||
|
secondname = secondname,
|
||||||
|
updated = updated,
|
||||||
|
verified = verified
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.example.api.core.data.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal data class AuthUserResponseDto(
|
||||||
|
val record: SignInUserResponseDto,
|
||||||
|
val token: String
|
||||||
|
)
|
@ -0,0 +1,8 @@
|
|||||||
|
package com.example.api.core.data.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal data class CatalogResponseDto(
|
||||||
|
val items: List<SaleItemDto>
|
||||||
|
)
|
@ -0,0 +1,3 @@
|
|||||||
|
package com.example.api.core.data.dto
|
||||||
|
|
||||||
|
//data class ProductDto()
|
@ -0,0 +1,10 @@
|
|||||||
|
package com.example.api.core.data.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal data class RegisterUserDto(
|
||||||
|
val email: String,
|
||||||
|
val password: String,
|
||||||
|
val passwordConfirm: String
|
||||||
|
)
|
@ -0,0 +1,21 @@
|
|||||||
|
package com.example.api.core.data.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal data class SaleItemDto(
|
||||||
|
val id: String,
|
||||||
|
val collectionId: String,
|
||||||
|
val collectionName: String,
|
||||||
|
val created: String,
|
||||||
|
val updated: String,
|
||||||
|
val title: String,
|
||||||
|
val dateStart: String,
|
||||||
|
val dateEnd: String,
|
||||||
|
val gender: String,
|
||||||
|
@SerialName("description_source") val descriptionSource: String,
|
||||||
|
val category: String,
|
||||||
|
val image: String,
|
||||||
|
@SerialName("user_id") val userId: String
|
||||||
|
)
|
@ -0,0 +1,12 @@
|
|||||||
|
package com.example.api.core.data.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal data class SalesAndActionsDto(
|
||||||
|
val page: Int,
|
||||||
|
val perPage: Int,
|
||||||
|
val totalPage: Int,
|
||||||
|
val totalItems: Int,
|
||||||
|
val items: List<SaleItemDto>
|
||||||
|
)
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.example.api.core.data.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal data class SignInUserDto(
|
||||||
|
val identity: String,
|
||||||
|
val password: String
|
||||||
|
)
|
@ -0,0 +1,20 @@
|
|||||||
|
package com.example.api.core.data.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SignInUserResponseDto(
|
||||||
|
val collectionId: String,
|
||||||
|
val collectionName: String,
|
||||||
|
val created: String,
|
||||||
|
val dateBirthday: String,
|
||||||
|
val email: String,
|
||||||
|
val emailVisibility: Boolean,
|
||||||
|
val firstname: String,
|
||||||
|
val gender: String,
|
||||||
|
val id: String,
|
||||||
|
val lastname: String,
|
||||||
|
val secondname: String,
|
||||||
|
val updated: String,
|
||||||
|
val verified: Boolean
|
||||||
|
)
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.example.api.core.data.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal data class UserResponseDto(
|
||||||
|
val collectionId: String,
|
||||||
|
val collectionName: String,
|
||||||
|
val created: String,
|
||||||
|
val dateBirthday: String,
|
||||||
|
val emailVisibility: Boolean,
|
||||||
|
val firstname: String,
|
||||||
|
val gender: String,
|
||||||
|
val id: String,
|
||||||
|
val lastname: String,
|
||||||
|
val secondname: String,
|
||||||
|
val updated: String,
|
||||||
|
val verified: Boolean
|
||||||
|
)
|
@ -0,0 +1,11 @@
|
|||||||
|
package com.example.api.core.domain
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Автор: Манякин Дмитрий (user5)
|
||||||
|
* Дата создания: 27.05.2025
|
||||||
|
* */
|
||||||
|
|
||||||
|
interface ApiRepository {
|
||||||
|
|
||||||
|
suspend fun auth(registerUser: RegisterUser): FetchResult<AuthUserResponse>
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package com.example.api.core.domain
|
||||||
|
|
||||||
|
data class AuthUserResponse(
|
||||||
|
val record: SignInUserResponse,
|
||||||
|
val token: String
|
||||||
|
)
|
@ -0,0 +1,5 @@
|
|||||||
|
package com.example.api.core.domain
|
||||||
|
|
||||||
|
data class CatalogResponse(
|
||||||
|
val items: List<SaleItem>
|
||||||
|
)
|
@ -0,0 +1,31 @@
|
|||||||
|
package com.example.api.core.domain
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Автор: Манякин Дмитрий (user5)
|
||||||
|
* Дата создания: 27.05.2025
|
||||||
|
* */
|
||||||
|
|
||||||
|
interface FetchResult<D> {
|
||||||
|
|
||||||
|
fun <Ui> map(mapper: Mapper<D, Ui>): Ui
|
||||||
|
|
||||||
|
interface Mapper<D, Ui> {
|
||||||
|
|
||||||
|
fun mapSuccess(data: D): Ui
|
||||||
|
|
||||||
|
fun mapError(data: D?, message: String): Ui
|
||||||
|
}
|
||||||
|
|
||||||
|
class Success<D>(private val data: D) : FetchResult<D> {
|
||||||
|
override fun <Ui> map(mapper: Mapper<D, Ui>): Ui {
|
||||||
|
return mapper.mapSuccess(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Error<D>(private val data: D?, private val message: String) : FetchResult<D> {
|
||||||
|
override fun <Ui> map(mapper: Mapper<D, Ui>): Ui {
|
||||||
|
return mapper.mapError(data, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.example.api.core.domain
|
||||||
|
|
||||||
|
data class RegisterUser(
|
||||||
|
val email: String,
|
||||||
|
val password: String,
|
||||||
|
val passwordConfirm: String
|
||||||
|
)
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.example.api.core.domain
|
||||||
|
|
||||||
|
data class SaleItem(
|
||||||
|
val id: String,
|
||||||
|
val collectionId: String,
|
||||||
|
val collectionName: String,
|
||||||
|
val created: String,
|
||||||
|
val updated: String,
|
||||||
|
val title: String,
|
||||||
|
val dateStart: String,
|
||||||
|
val dateEnd: String,
|
||||||
|
val gender: String,
|
||||||
|
val descriptionSource: String,
|
||||||
|
val category: String,
|
||||||
|
val image: String,
|
||||||
|
val userId: String
|
||||||
|
)
|
@ -0,0 +1,9 @@
|
|||||||
|
package com.example.api.core.domain
|
||||||
|
|
||||||
|
internal data class SalesAndActions(
|
||||||
|
val page: Int,
|
||||||
|
val perPage: Int,
|
||||||
|
val totalPage: Int,
|
||||||
|
val totalItems: Int,
|
||||||
|
val items: List<SaleItem>
|
||||||
|
)
|
@ -0,0 +1,6 @@
|
|||||||
|
package com.example.api.core.domain
|
||||||
|
|
||||||
|
data class SignInUser(
|
||||||
|
val identity: String,
|
||||||
|
val password: String
|
||||||
|
)
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.example.api.core.domain
|
||||||
|
|
||||||
|
data class SignInUserResponse(
|
||||||
|
val collectionId: String,
|
||||||
|
val collectionName: String,
|
||||||
|
val created: String,
|
||||||
|
val dateBirthday: String,
|
||||||
|
val emailVisibility: Boolean,
|
||||||
|
val email: String,
|
||||||
|
val firstname: String,
|
||||||
|
val gender: String,
|
||||||
|
val id: String,
|
||||||
|
val lastname: String,
|
||||||
|
val secondname: String,
|
||||||
|
val updated: String,
|
||||||
|
val verified: Boolean
|
||||||
|
)
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.example.api.core.domain
|
||||||
|
|
||||||
|
data class UserResponse(
|
||||||
|
val collectionId: String,
|
||||||
|
val collectionName: String,
|
||||||
|
val created: String,
|
||||||
|
val dateBirthday: String,
|
||||||
|
val emailVisibility: Boolean,
|
||||||
|
val firstname: String,
|
||||||
|
val gender: String,
|
||||||
|
val id: String,
|
||||||
|
val lastname: String,
|
||||||
|
val secondname: String,
|
||||||
|
val updated: String,
|
||||||
|
val verified: Boolean
|
||||||
|
)
|
133
api-core/src/test/java/com/example/api/core/ServiceTest.kt
Normal file
133
api-core/src/test/java/com/example/api/core/ServiceTest.kt
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
package com.example.api.core
|
||||||
|
|
||||||
|
import com.example.api.core.data.core.ApiService
|
||||||
|
import com.example.api.core.data.dto.RegisterUserDto
|
||||||
|
import com.example.api.core.data.dto.SignInUserDto
|
||||||
|
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
|
||||||
|
import junit.framework.TestCase.assertEquals
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
import okhttp3.mockwebserver.MockResponse
|
||||||
|
import okhttp3.mockwebserver.MockWebServer
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import retrofit2.Retrofit
|
||||||
|
import retrofit2.create
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Автор: Манякин Дмитрий (user5)
|
||||||
|
* Дата создания: 27.05.2025
|
||||||
|
* */
|
||||||
|
|
||||||
|
class ServiceTest {
|
||||||
|
|
||||||
|
private lateinit var mockWebServer: MockWebServer
|
||||||
|
private lateinit var service: ApiService
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
mockWebServer = MockWebServer()
|
||||||
|
mockWebServer.start()
|
||||||
|
|
||||||
|
val json = Json { ignoreUnknownKeys = true }
|
||||||
|
|
||||||
|
service = Retrofit.Builder()
|
||||||
|
.baseUrl(mockWebServer.url("/"))
|
||||||
|
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
|
||||||
|
.client(OkHttpClient.Builder().addInterceptor(HttpLoggingInterceptor().apply {
|
||||||
|
level = HttpLoggingInterceptor.Level.BODY
|
||||||
|
}).build())
|
||||||
|
.build().create<ApiService>()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_registration() = runBlocking {
|
||||||
|
val response = """
|
||||||
|
{
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"collectionName": "users",
|
||||||
|
"created": "2025-05-27 06:08:13.833Z",
|
||||||
|
"dateBirthday": "",
|
||||||
|
"emailVisibility": false,
|
||||||
|
"firstname": "",
|
||||||
|
"gender": "",
|
||||||
|
"id": "w20q0pj1e2824oz",
|
||||||
|
"lastname": "",
|
||||||
|
"secondname": "",
|
||||||
|
"updated": "2025-05-27 06:08:13.833Z",
|
||||||
|
"verified": false
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody(response))
|
||||||
|
|
||||||
|
val responseResult = service.register(
|
||||||
|
RegisterUserDto(
|
||||||
|
email = "email@test.com",
|
||||||
|
password = "12345678",
|
||||||
|
passwordConfirm = "12345678"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val request = mockWebServer.takeRequest()
|
||||||
|
|
||||||
|
assertEquals("w20q0pj1e2824oz", responseResult.id)
|
||||||
|
assertEquals("2025-05-27 06:08:13.833Z", responseResult.created)
|
||||||
|
|
||||||
|
assertEquals("POST", request.method)
|
||||||
|
assertEquals("/collections/users/records", request.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun test_sign_in() = runBlocking {
|
||||||
|
val response = """
|
||||||
|
{
|
||||||
|
"record": {
|
||||||
|
"collectionId": "_pb_users_auth_",
|
||||||
|
"collectionName": "users",
|
||||||
|
"created": "2025-05-27 06:08:13.833Z",
|
||||||
|
"dateBirthday": "",
|
||||||
|
"email": "example123@test.ru",
|
||||||
|
"emailVisibility": false,
|
||||||
|
"firstname": "",
|
||||||
|
"gender": "",
|
||||||
|
"id": "w20q0pj1e2824oz",
|
||||||
|
"lastname": "",
|
||||||
|
"secondname": "",
|
||||||
|
"updated": "2025-05-27 06:08:13.833Z",
|
||||||
|
"verified": false
|
||||||
|
},
|
||||||
|
"token": "eyJhbGciOiJIUzIqwwe1NiIsInR5cCI6IkpXVCJg9.eyJjb2xsZWN0aW9uSWheQiOiJfqcGggJfdXNlcnNfYXV0aFasd8iLCJleHAiOjE3NDg5MzA5MjAsImlkIjoidzIwcTBwajFlMjgyNG96IiwicmVmcmVzaGFibGUiOnRydWUsInR5cGUiOiJhdXRoIn0.7Sc_NB_CgnwEfXWp0NjsnDT35gGVXzFJwwLUVD730Gw"
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
|
||||||
|
mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody(response))
|
||||||
|
|
||||||
|
val responseResult = service.auth(
|
||||||
|
SignInUserDto(
|
||||||
|
identity = "example123@test.ru",
|
||||||
|
password = "12345678"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
val request = mockWebServer.takeRequest()
|
||||||
|
|
||||||
|
assertEquals("example123@test.ru", responseResult.record.email)
|
||||||
|
assertEquals(
|
||||||
|
"eyJhbGciOiJIUzIqwwe1NiIsInR5cCI6IkpXVCJg9.eyJjb2xsZWN0aW9uSWheQiOiJfqcGggJfdXNlcnNfYXV0aFasd8iLCJleHAiOjE3NDg5MzA5MjAsImlkIjoidzIwcTBwajFlMjgyNG96IiwicmVmcmVzaGFibGUiOnRydWUsInR5cGUiOiJhdXRoIn0.7Sc_NB_CgnwEfXWp0NjsnDT35gGVXzFJwwLUVD730Gw",
|
||||||
|
responseResult.token
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals("POST", request.method)
|
||||||
|
assertEquals("/collections/users/auth-with-password", request.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
fun teardown() {
|
||||||
|
mockWebServer.shutdown()
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,8 @@ plugins {
|
|||||||
alias(libs.plugins.android.application)
|
alias(libs.plugins.android.application)
|
||||||
alias(libs.plugins.kotlin.android)
|
alias(libs.plugins.kotlin.android)
|
||||||
alias(libs.plugins.kotlin.compose)
|
alias(libs.plugins.kotlin.compose)
|
||||||
|
alias(libs.plugins.dagger.hilt.android)
|
||||||
|
kotlin("kapt")
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -40,6 +42,10 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation(libs.androidx.datastore.preferences)
|
||||||
|
kapt(libs.hilt.android.compiler)
|
||||||
|
implementation(libs.hilt.android)
|
||||||
|
implementation(libs.hilt.navigation.compose)
|
||||||
|
|
||||||
implementation(libs.androidx.core.ktx)
|
implementation(libs.androidx.core.ktx)
|
||||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||||
@ -56,4 +62,6 @@ dependencies {
|
|||||||
androidTestImplementation(libs.androidx.ui.test.junit4)
|
androidTestImplementation(libs.androidx.ui.test.junit4)
|
||||||
debugImplementation(libs.androidx.ui.tooling)
|
debugImplementation(libs.androidx.ui.tooling)
|
||||||
debugImplementation(libs.androidx.ui.test.manifest)
|
debugImplementation(libs.androidx.ui.test.manifest)
|
||||||
|
|
||||||
|
implementation(project(":api-core"))
|
||||||
}
|
}
|
@ -2,7 +2,9 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<application
|
<application
|
||||||
|
android:name=".App"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
|
12
app/src/main/java/com/example/api/App.kt
Normal file
12
app/src/main/java/com/example/api/App.kt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package com.example.api
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Автор: Манякин Дмитрий (user5)
|
||||||
|
* Дата создания: 27.05.2025
|
||||||
|
* */
|
||||||
|
|
||||||
|
@HiltAndroidApp
|
||||||
|
class App : Application()
|
51
app/src/main/java/com/example/api/CoreModule.kt
Normal file
51
app/src/main/java/com/example/api/CoreModule.kt
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package com.example.api
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.datastore.core.DataStore
|
||||||
|
import androidx.datastore.preferences.core.Preferences
|
||||||
|
import androidx.datastore.preferences.preferencesDataStore
|
||||||
|
import com.example.api.core.data.core.ApiFactory
|
||||||
|
import com.example.api.core.data.core.DataStoreRepository
|
||||||
|
import com.example.api.core.domain.ApiRepository
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Автор: Манякин Дмитрий (user5)
|
||||||
|
* Дата создания: 27.05.2025
|
||||||
|
* */
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
class CoreModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideContent(@ApplicationContext context: Context): Context = context
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideDataStore(context: Context): DataStore<Preferences> {
|
||||||
|
return context.dataStore
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideDataStoreRepository(preferences: DataStore<Preferences>): DataStoreRepository {
|
||||||
|
return DataStoreRepository.Base(preferences)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideRepository(dataStoreRepository: DataStoreRepository): ApiRepository {
|
||||||
|
return ApiFactory.provideRepository(dataStoreRepository)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val Context.dataStore by preferencesDataStore("settings")
|
||||||
|
}
|
||||||
|
}
|
18
app/src/main/java/com/example/api/FetchResultMapper.kt
Normal file
18
app/src/main/java/com/example/api/FetchResultMapper.kt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package com.example.api
|
||||||
|
|
||||||
|
import com.example.api.core.domain.FetchResult
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Автор: Манякин Дмитрий (user5)
|
||||||
|
* Дата создания: 27.05.2025
|
||||||
|
* */
|
||||||
|
|
||||||
|
class FetchResultMapper<T> : FetchResult.Mapper<T, FetchResultUiState<T>> {
|
||||||
|
override fun mapSuccess(data: T): FetchResultUiState<T> {
|
||||||
|
return FetchResultUiState.Success(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mapError(data: T?, message: String): FetchResultUiState<T> {
|
||||||
|
return FetchResultUiState.Error(data, message)
|
||||||
|
}
|
||||||
|
}
|
62
app/src/main/java/com/example/api/FetchResultUiState.kt
Normal file
62
app/src/main/java/com/example/api/FetchResultUiState.kt
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
package com.example.api
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Автор: Манякин Дмитрий (user5)
|
||||||
|
* Дата создания: 27.05.2025
|
||||||
|
* */
|
||||||
|
|
||||||
|
interface FetchResultUiState<T> {
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Show(
|
||||||
|
onSuccess: @Composable (T) -> Unit,
|
||||||
|
onError: @Composable (T?, String) -> Unit,
|
||||||
|
onLoading: @Composable (T?) -> Unit
|
||||||
|
)
|
||||||
|
|
||||||
|
class Success<T>(val data: T) : FetchResultUiState<T> {
|
||||||
|
@Composable
|
||||||
|
override fun Show(
|
||||||
|
onSuccess: @Composable (T) -> Unit,
|
||||||
|
onError: @Composable (T?, String) -> Unit,
|
||||||
|
onLoading: @Composable (T?) -> Unit
|
||||||
|
) {
|
||||||
|
onSuccess(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Error<T>(private val data: T?, private val message: String) : FetchResultUiState<T> {
|
||||||
|
@Composable
|
||||||
|
override fun Show(
|
||||||
|
onSuccess: @Composable (T) -> Unit,
|
||||||
|
onError: @Composable (T?, String) -> Unit,
|
||||||
|
onLoading: @Composable (T?) -> Unit
|
||||||
|
) {
|
||||||
|
onError(data, message)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class Loading<T>(private val data: T? = null) : FetchResultUiState<T> {
|
||||||
|
@Composable
|
||||||
|
override fun Show(
|
||||||
|
onSuccess: @Composable (T) -> Unit,
|
||||||
|
onError: @Composable (T?, String) -> Unit,
|
||||||
|
onLoading: @Composable (T?) -> Unit
|
||||||
|
) {
|
||||||
|
onLoading(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Initial<T> : FetchResultUiState<T> {
|
||||||
|
@Composable
|
||||||
|
override fun Show(
|
||||||
|
onSuccess: @Composable (T) -> Unit,
|
||||||
|
onError: @Composable (T?, String) -> Unit,
|
||||||
|
onLoading: @Composable (T?) -> Unit
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,44 +4,18 @@ import android.os.Bundle
|
|||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material3.Scaffold
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import com.example.api.ui.theme.ApiTheme
|
import com.example.api.ui.theme.ApiTheme
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
setContent {
|
setContent {
|
||||||
ApiTheme {
|
ApiTheme {
|
||||||
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
|
TestScreen()
|
||||||
Greeting(
|
|
||||||
name = "Android",
|
|
||||||
modifier = Modifier.padding(innerPadding)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun Greeting(name: String, modifier: Modifier = Modifier) {
|
|
||||||
Text(
|
|
||||||
text = "Hello $name!",
|
|
||||||
modifier = modifier
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
|
||||||
@Composable
|
|
||||||
fun GreetingPreview() {
|
|
||||||
ApiTheme {
|
|
||||||
Greeting("Android")
|
|
||||||
}
|
|
||||||
}
|
|
47
app/src/main/java/com/example/api/MainViewModel.kt
Normal file
47
app/src/main/java/com/example/api/MainViewModel.kt
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
package com.example.api
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.example.api.core.domain.ApiRepository
|
||||||
|
import com.example.api.core.domain.AuthUserResponse
|
||||||
|
import com.example.api.core.domain.RegisterUser
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Автор: Манякин Дмитрий (user5)
|
||||||
|
* Дата создания: 27.05.2025
|
||||||
|
* */
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class MainViewModel @Inject constructor(
|
||||||
|
private val apiRepository: ApiRepository
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
|
private val _loadResultUiState =
|
||||||
|
MutableStateFlow<FetchResultUiState<AuthUserResponse>>(FetchResultUiState.Initial())
|
||||||
|
val loadResultUiState: StateFlow<FetchResultUiState<AuthUserResponse>>
|
||||||
|
get() = _loadResultUiState.asStateFlow()
|
||||||
|
|
||||||
|
fun auth(email: String, password: String) {
|
||||||
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
val result = apiRepository.auth(
|
||||||
|
RegisterUser(
|
||||||
|
email = email,
|
||||||
|
password = password,
|
||||||
|
passwordConfirm = password
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
_loadResultUiState.value = result.map(FetchResultMapper())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
app/src/main/java/com/example/api/TestScreen.kt
Normal file
41
app/src/main/java/com/example/api/TestScreen.kt
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package com.example.api
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Автор: Манякин Дмитрий (user5)
|
||||||
|
* Дата создания: 27.05.2025
|
||||||
|
* */
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun TestScreen(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
viewModel: MainViewModel = hiltViewModel()
|
||||||
|
) {
|
||||||
|
val state by viewModel.loadResultUiState.collectAsState()
|
||||||
|
|
||||||
|
Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
|
||||||
|
Column {
|
||||||
|
Button(onClick = { viewModel.auth("someemael@te3st1.com", "12345678") }) {
|
||||||
|
Text("register")
|
||||||
|
}
|
||||||
|
|
||||||
|
state.Show(
|
||||||
|
onSuccess = { Text(text = it.token) },
|
||||||
|
onError = { _, message -> Text(text = message) },
|
||||||
|
onLoading = { CircularProgressIndicator() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,4 +3,6 @@ plugins {
|
|||||||
alias(libs.plugins.android.application) apply false
|
alias(libs.plugins.android.application) apply false
|
||||||
alias(libs.plugins.kotlin.android) apply false
|
alias(libs.plugins.kotlin.android) apply false
|
||||||
alias(libs.plugins.kotlin.compose) apply false
|
alias(libs.plugins.kotlin.compose) apply false
|
||||||
|
alias(libs.plugins.android.library) apply false
|
||||||
|
alias(libs.plugins.dagger.hilt.android) apply false
|
||||||
}
|
}
|
@ -8,8 +8,30 @@ espressoCore = "3.6.1"
|
|||||||
lifecycleRuntimeKtx = "2.9.0"
|
lifecycleRuntimeKtx = "2.9.0"
|
||||||
activityCompose = "1.10.1"
|
activityCompose = "1.10.1"
|
||||||
composeBom = "2024.09.00"
|
composeBom = "2024.09.00"
|
||||||
|
appcompat = "1.7.0"
|
||||||
|
material = "1.12.0"
|
||||||
|
retrofit = "2.11.0"
|
||||||
|
okhttp3 = "4.12.0"
|
||||||
|
kotlinxSerializationConverter = "1.0.0"
|
||||||
|
kotlinxSerializationJson = "1.8.0"
|
||||||
|
kotlinxCoroutinesTest = "1.10.2"
|
||||||
|
datastorePreferences = "1.1.6"
|
||||||
|
dagger = "2.55"
|
||||||
|
hiltNavigationCompose = "1.2.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "dagger" }
|
||||||
|
hilt-android-compiler = { group = "com.google.dagger", name = "hilt-android-compiler", version.ref = "dagger" }
|
||||||
|
hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hiltNavigationCompose" }
|
||||||
|
androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastorePreferences" }
|
||||||
|
mockwebserver = { group = "com.squareup.okhttp3", name = "mockwebserver", version.ref = "okhttp3" }
|
||||||
|
kotlinx-coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinxCoroutinesTest" }
|
||||||
|
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
||||||
|
retrofit2-kotlinx-serialization-converter = { group = "com.jakewharton.retrofit", name = "retrofit2-kotlinx-serialization-converter", version.ref = "kotlinxSerializationConverter" }
|
||||||
|
logging-interceptor = { group = "com.squareup.okhttp3", name = "logging-interceptor", version.ref = "okhttp3" }
|
||||||
|
okhttp = { group = "com.squareup.okhttp3", name = "okhttp", version.ref = "okhttp3" }
|
||||||
|
retrofit2 = { group = "com.squareup.retrofit2", name = "retrofit", version.ref = "retrofit" }
|
||||||
|
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
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" }
|
||||||
@ -24,9 +46,14 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin
|
|||||||
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
||||||
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||||
|
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
|
||||||
|
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
|
dagger-hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "dagger" }
|
||||||
|
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||||
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||||
|
android-library = { id = "com.android.library", version.ref = "agp" }
|
||||||
|
|
||||||
|
@ -21,4 +21,4 @@ dependencyResolutionManagement {
|
|||||||
|
|
||||||
rootProject.name = "api"
|
rootProject.name = "api"
|
||||||
include(":app")
|
include(":app")
|
||||||
|
include(":api-core")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user