Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 0 additions & 44 deletions app/build.gradle

This file was deleted.

61 changes: 61 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.ksp)
alias(libs.plugins.hilt.android)
alias(libs.plugins.androidx.navigation.safeargs)
}

android {
namespace = "ru.otus.basicarchitecture"
compileSdk = 36

defaultConfig {
applicationId = "ru.otus.basicarchitecture"
minSdk = 24
targetSdk = 36
versionCode = 1
versionName = "1.0"

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
}
buildFeatures {
viewBinding = true
}
}

dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.constraintlayout)

implementation(libs.androidx.navigation.fragment.ktx)
implementation(libs.androidx.navigation.ui.ktx)
implementation(libs.androidx.legacy.support.v4)
implementation(libs.androidx.lifecycle.livedata.ktx)
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.fragment.ktx)
implementation(libs.hilt.android)
ksp(libs.hilt.compiler)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.test.ext.junit)
androidTestImplementation(libs.espresso.core)
}
6 changes: 4 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.BasicArchitecture"
tools:targetApi="31">
tools:targetApi="31"
android:name=".MvvmApp"
>
<activity
android:name=".MainActivity"
android:name=".view.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
Expand Down
11 changes: 0 additions & 11 deletions app/src/main/java/ru/otus/basicarchitecture/MainActivity.kt

This file was deleted.

8 changes: 8 additions & 0 deletions app/src/main/java/ru/otus/basicarchitecture/MvvmApp.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ru.otus.basicarchitecture

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class MvvmApp : Application() {
}
45 changes: 45 additions & 0 deletions app/src/main/java/ru/otus/basicarchitecture/config/ModuleConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package ru.otus.basicarchitecture.config

import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityRetainedComponent
import dagger.hilt.android.components.ViewModelComponent
import dagger.hilt.android.scopes.ActivityRetainedScoped
import dagger.hilt.components.SingletonComponent
import jakarta.inject.Singleton
import ru.otus.basicarchitecture.service.DaDataService
import ru.otus.basicarchitecture.service.InterestsRepository
import ru.otus.basicarchitecture.use_case.AddressSuggestUseCase
import ru.otus.basicarchitecture.use_case.FieldValidationUseCase
import ru.otus.basicarchitecture.view_model.WizardCache

@Module
@InstallIn(SingletonComponent::class)
abstract class AppModule {
@Binds
@Singleton
abstract fun daDataService(impl: DaDataService.Impl): DaDataService

@Binds
@Singleton
abstract fun interestsRepository(impl: InterestsRepository.Impl): InterestsRepository
}

@Module
@InstallIn(ActivityRetainedComponent::class)
abstract class ActivityModule {
@Binds
@ActivityRetainedScoped
abstract fun wizardCache(impl: WizardCache.Impl): WizardCache
}

@Module
@InstallIn(ViewModelComponent::class)
abstract class ViewModelModule {
@Binds
abstract fun fieldValidationUseCase(impl: FieldValidationUseCase.Impl): FieldValidationUseCase

@Binds
abstract fun addressSuggestUseCase(impl: AddressSuggestUseCase.Impl): AddressSuggestUseCase
}
9 changes: 9 additions & 0 deletions app/src/main/java/ru/otus/basicarchitecture/model/Address.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ru.otus.basicarchitecture.model

data class Address(
var country: String = "",
var city: String = "",
var street: String = ""
) {
override fun toString() = "$country, $city, $street"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package ru.otus.basicarchitecture.model

interface FieldValueDto<T> {
val fValue: T
val isValid: Boolean
}
30 changes: 30 additions & 0 deletions app/src/main/java/ru/otus/basicarchitecture/model/Interest.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package ru.otus.basicarchitecture.model

data class Interest (
val id: Int,
val title: String,
)

val interests = setOf(
Interest(1, "IT"),
Interest(2, "Sport"),
Interest(3, "Music"),
Interest(4, "Reading"),
Interest(5, "Travel"),
Interest(6, "Photography"),
Interest(7, "Cooking"),
Interest(8, "Dancing"),
Interest(9, "Art"),
Interest(10, "Gaming"),
Interest(11, "Movies"),
Interest(12, "Fitness"),
Interest(13, "Yoga"),
Interest(14, "Fashion"),
Interest(15, "Programming"),
Interest(16, "Science"),
Interest(17, "Nature"),
Interest(18, "Cars"),
Interest(19, "History"),
Interest(20, "Languages"),
Interest(21, "Writing")
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package ru.otus.basicarchitecture.model

class LongFiledDto(override val fValue: Long, override val isValid: Boolean) : FieldValueDto<Long?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package ru.otus.basicarchitecture.model

class StringFiledDto(override val fValue: String, override val isValid: Boolean) :
FieldValueDto<String>
9 changes: 9 additions & 0 deletions app/src/main/java/ru/otus/basicarchitecture/model/UserData.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package ru.otus.basicarchitecture.model

data class UserData(
val name: String,
val surname: String,
val birthDate: Long,
val address: Address,
val tags: Set<Interest>,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package ru.otus.basicarchitecture.model

sealed interface ValidationEvent {
object InvalidName : ValidationEvent
object ValidName : ValidationEvent
object InvalidSurname : ValidationEvent
object ValidSurname : ValidationEvent
object InvalidAge : ValidationEvent
object ValidAge : ValidationEvent
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package ru.otus.basicarchitecture.service

import jakarta.inject.Inject


interface DaDataService {
class Impl @Inject constructor() : DaDataService {

}

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package ru.otus.basicarchitecture.service

import dagger.hilt.android.scopes.ViewModelScoped
import jakarta.inject.Inject
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import ru.otus.basicarchitecture.model.Interest
import ru.otus.basicarchitecture.model.interests


@ViewModelScoped
interface InterestsRepository {
fun getInterests(): Flow<Set<Interest>>

class Impl @Inject constructor() : InterestsRepository {
override fun getInterests(): Flow<Set<Interest>> {
return flow {
delay(NETWORK_DELAY)
emit(interests)
}
}
companion object {
const val NETWORK_DELAY = 1000L
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package ru.otus.basicarchitecture.use_case

import dagger.hilt.android.scopes.ViewModelScoped
import jakarta.inject.Inject
import ru.otus.basicarchitecture.service.DaDataService

@ViewModelScoped
interface AddressSuggestUseCase {
class Impl @Inject constructor(
private val daDataService: DaDataService
) : AddressSuggestUseCase {

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package ru.otus.basicarchitecture.use_case

import dagger.hilt.android.scopes.ViewModelScoped
import jakarta.inject.Inject
import java.util.regex.Pattern


@ViewModelScoped
interface FieldValidationUseCase {
fun isNameInvalid(name: String): Boolean
fun isSurnameInvalid(surname: String): Boolean
fun isAgeInvalid(birthDate: Long?): Boolean


class Impl @Inject constructor() : FieldValidationUseCase {
override fun isNameInvalid(name: String) =
name.length > 2 && !pattern.toRegex().matches(name)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Возвращает true, когда имя валидно (длина > 2 и соответствует паттерну). Сейчас короткие имена (≤2 символа) считаются валидными, хотя должны отклоняться. Нужно изменить логику

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Переработал в другой ветке
https://github.com/uatilman/BasicArchitecture/blob/task2/app/src/main/java/ru/otus/basicarchitecture/use_case/FieldValidationUseCase.kt
Написал с ИИ на пару юнит тесты на эту валидацию и по результатам переработал варианты, которые должны проходить.


override fun isSurnameInvalid(surname: String) =
surname.length > 2 && !pattern.toRegex().matches(surname)

override fun isAgeInvalid(birthDate: Long?) =
birthDate == null || birthDate > eighteenYearsAgo

companion object {
private const val USERNAME_PATTERN = "^[A-ZА-Я]([._-](?![._-])|[a-zа-я]){1,18}[a-zа-я]$"
private val eighteenYearsAgo = System.currentTimeMillis() - (18 * 365.25 * 24 * 60 * 60 * 1000).toLong()

private val pattern: Pattern =
Pattern.compile(USERNAME_PATTERN, Pattern.CASE_INSENSITIVE)

}
}
}
Loading