diff --git a/app/build.gradle b/app/build.gradle
index 9c99d98..5f8091c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,12 +1,17 @@
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
+ id 'com.google.dagger.hilt.android'
+ id 'kotlin-kapt'
+
}
android {
namespace 'ru.otus.basicarchitecture'
compileSdk 33
-
+ hilt {
+ enableAggregatingTask = true
+ }
defaultConfig {
applicationId "ru.otus.basicarchitecture"
minSdk 24
@@ -24,21 +29,51 @@ android {
}
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
+ sourceCompatibility JavaVersion.VERSION_17
+ targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
- jvmTarget = '1.8'
+ jvmTarget = '17'
+ }
+
+ buildFeatures {
+ dataBinding true
+ viewBinding true
}
}
dependencies {
- implementation 'androidx.core:core-ktx:1.8.0'
+ implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
+ implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.1'
+ implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
+ implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1'
+ implementation 'androidx.databinding:databinding-runtime:8.1.1'
+ implementation 'androidx.legacy:legacy-support-v4:1.0.0'
+ implementation 'androidx.legacy:legacy-support-core-utils:1.0.0'
+ implementation("androidx.navigation:navigation-fragment:2.6.0")
+ implementation("androidx.navigation:navigation-ui:2.6.0")
+ implementation("androidx.navigation:navigation-fragment-ktx:2.6.0")
+ implementation("androidx.navigation:navigation-ui-ktx:2.6.0")
+ implementation("androidx.navigation:navigation-dynamic-features-fragment:2.6.0")
+ androidTestImplementation("androidx.navigation:navigation-testing:2.6.0")
+ implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
-}
\ No newline at end of file
+ implementation 'com.google.dagger:hilt-android:2.46.1'
+ kapt 'com.google.dagger:hilt-compiler:2.46.1'
+
+ implementation "com.squareup.retrofit2:retrofit:2.9.0"
+ implementation "com.squareup.retrofit2:converter-moshi:2.9.0"
+ implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1"
+ implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
+ implementation "com.squareup.retrofit2:converter-gson:2.9.0"
+ implementation "com.squareup.okhttp3:logging-interceptor:3.12.6"
+ implementation 'com.google.code.gson:gson:2.9.1'
+}
+
+
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1e81fea..7ba6e29 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,9 +1,10 @@
-
+
+ tools:targetApi="33">
+ android:exported="true">
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/ru/otus/basicarchitecture/AddressFragment.kt b/app/src/main/java/ru/otus/basicarchitecture/AddressFragment.kt
new file mode 100644
index 0000000..0c3b301
--- /dev/null
+++ b/app/src/main/java/ru/otus/basicarchitecture/AddressFragment.kt
@@ -0,0 +1,72 @@
+package ru.otus.basicarchitecture
+import android.os.Build
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import dagger.hilt.android.AndroidEntryPoint
+import ru.otus.basicarchitecture.databinding.FragmentAddressBinding
+import androidx.navigation.fragment.findNavController
+import ru.otus.basicarchitecture.viewmodel.AddressViewModel
+import androidx.fragment.app.viewModels
+
+import android.text.Editable
+import android.text.TextWatcher
+import android.widget.ArrayAdapter
+import ru.otus.basicarchitecture.model.AddressService
+import ru.otus.basicarchitecture.model.AddressValue
+import java.util.stream.Collectors
+
+@AndroidEntryPoint
+class AddressFragment : Fragment(R.layout.fragment_address) {
+ private lateinit var binding: FragmentAddressBinding
+ private val viewModel : AddressViewModel by viewModels()
+ private val service = AddressService()
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ binding = FragmentAddressBinding.inflate(inflater)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.fullAddress.addTextChangedListener(object: TextWatcher {
+ override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
+ override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
+ override fun afterTextChanged(editable: Editable?) {
+ viewModel.search(editable.toString())
+ }
+ })
+
+ viewModel.getResultAddressLive().observe(viewLifecycleOwner) {
+ if(it!=null) {
+ val list = it.stream().map(AddressValue::value).collect(Collectors.toList())
+ val adapter = ArrayAdapter(
+ requireContext(),
+ android.R.layout.simple_list_item_1,
+ list
+ )
+ binding.fullAddress.setAdapter(adapter)
+ }
+ }
+
+ binding.next.setOnClickListener() {
+ viewModel.saveData(binding.fullAddress.text.toString())
+ findNavController().navigate(R.id.action_addressFragment_to_interestsFragment)
+ }
+
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ viewModel.cancel()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/otus/basicarchitecture/DateMask.kt b/app/src/main/java/ru/otus/basicarchitecture/DateMask.kt
new file mode 100644
index 0000000..9cd0988
--- /dev/null
+++ b/app/src/main/java/ru/otus/basicarchitecture/DateMask.kt
@@ -0,0 +1,21 @@
+package ru.otus.basicarchitecture
+
+import android.os.Build
+import android.text.Editable
+import android.text.TextWatcher
+import androidx.annotation.RequiresApi
+import ru.otus.basicarchitecture.viewmodel.UserViewModel
+
+class DateMask(var vm: UserViewModel) :TextWatcher {
+ override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
+ // TODO("Not yet implemented")
+ }
+ override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
+ //TODO("Not yet implemented")
+ }
+ @RequiresApi(Build.VERSION_CODES.O)
+ override fun afterTextChanged(editable: Editable?) {
+ vm.onDateChanged(editable)
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/otus/basicarchitecture/InterestsFragment.kt b/app/src/main/java/ru/otus/basicarchitecture/InterestsFragment.kt
new file mode 100644
index 0000000..e8c60d5
--- /dev/null
+++ b/app/src/main/java/ru/otus/basicarchitecture/InterestsFragment.kt
@@ -0,0 +1,60 @@
+package ru.otus.basicarchitecture
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.fragment.app.Fragment
+import dagger.hilt.android.AndroidEntryPoint
+import ru.otus.basicarchitecture.databinding.FragmentInterestsBinding
+import androidx.navigation.fragment.findNavController
+import ru.otus.basicarchitecture.viewmodel.InterestsViewModel
+import com.google.android.material.chip.Chip
+import java.util.stream.Collectors
+import androidx.fragment.app.viewModels
+
+@AndroidEntryPoint
+class InterestsFragment : Fragment(R.layout.fragment_interests) {
+
+ private lateinit var binding: FragmentInterestsBinding
+ private val viewModel: InterestsViewModel by viewModels()
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ binding = FragmentInterestsBinding.inflate(inflater)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.next.setOnClickListener() {
+ val tags = binding.tagGroup
+ var interests = tags.checkedChipIds.stream()
+ .map { id -> tags.findViewById(id) }
+ .map { chip -> chip.text.toString() }
+ .collect(Collectors.toList())
+
+ viewModel.saveData(interests)
+
+ findNavController().navigate(R.id.action_interestsFragment_to_resultFragment)
+ }
+
+ viewModel.loadData()
+
+ viewModel.getResultInterestsLive().observe(viewLifecycleOwner) {
+ val tags = binding.tagGroup
+ it?.forEach { tag ->
+ val chip = Chip(tags.context)
+ chip.text= tag
+ chip.isClickable = true
+ chip.isCheckable = true
+ chip.textSize = 25F
+ tags.addView(chip)
+ }
+ }
+
+ }
+ }
\ No newline at end of file
diff --git a/app/src/main/java/ru/otus/basicarchitecture/MainActivity.kt b/app/src/main/java/ru/otus/basicarchitecture/MainActivity.kt
index 623aba9..c2a5777 100644
--- a/app/src/main/java/ru/otus/basicarchitecture/MainActivity.kt
+++ b/app/src/main/java/ru/otus/basicarchitecture/MainActivity.kt
@@ -2,10 +2,29 @@ package ru.otus.basicarchitecture
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
+import androidx.navigation.findNavController
+import androidx.navigation.fragment.NavHostFragment
+import androidx.navigation.ui.setupActionBarWithNavController
+import dagger.hilt.android.AndroidEntryPoint
+import ru.otus.basicarchitecture.databinding.ActivityMainBinding
+
+@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityMainBinding
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_main)
+ binding = ActivityMainBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+
+ val navHostFragment =
+ supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
+ val navController = navHostFragment.navController
+ setupActionBarWithNavController(navController)
+ }
+ override fun onSupportNavigateUp(): Boolean {
+ val navController = this.findNavController(R.id.nav_host_fragment)
+ return navController.navigateUp()
}
}
\ No newline at end of file
diff --git a/app/src/main/java/ru/otus/basicarchitecture/MyApp.kt b/app/src/main/java/ru/otus/basicarchitecture/MyApp.kt
new file mode 100644
index 0000000..c24d0a9
--- /dev/null
+++ b/app/src/main/java/ru/otus/basicarchitecture/MyApp.kt
@@ -0,0 +1,9 @@
+package ru.otus.basicarchitecture
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+@HiltAndroidApp
+class MyApp : Application() {
+
+ }
diff --git a/app/src/main/java/ru/otus/basicarchitecture/Repository.kt b/app/src/main/java/ru/otus/basicarchitecture/Repository.kt
new file mode 100644
index 0000000..33a2f45
--- /dev/null
+++ b/app/src/main/java/ru/otus/basicarchitecture/Repository.kt
@@ -0,0 +1,11 @@
+package ru.otus.basicarchitecture
+
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton
+class Repository @Inject constructor(){
+ fun getInterests() :List {
+ return mutableListOf("Еда","Работа","Отдых", "Кино", "Спорт")
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/otus/basicarchitecture/ResultFragment.kt b/app/src/main/java/ru/otus/basicarchitecture/ResultFragment.kt
new file mode 100644
index 0000000..28ca004
--- /dev/null
+++ b/app/src/main/java/ru/otus/basicarchitecture/ResultFragment.kt
@@ -0,0 +1,57 @@
+package ru.otus.basicarchitecture
+
+import android.app.Activity
+import android.os.Build
+import android.os.Bundle
+import androidx.fragment.app.Fragment
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import com.google.android.material.chip.Chip
+import dagger.hilt.android.AndroidEntryPoint
+import java.time.format.DateTimeFormatter
+import ru.otus.basicarchitecture.databinding.FragmentResultsBinding
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class ResultFragment : Fragment(R.layout.fragment_results) {
+ private lateinit var binding: FragmentResultsBinding
+ @Inject
+ lateinit var wizardCache: WizardCache
+ private lateinit var listOfInterests : List
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ binding = FragmentResultsBinding.inflate(inflater)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.nameTextView.text = wizardCache.name
+ binding.surnameTextView.text = wizardCache.surname
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ binding.birthdayTextView.text = wizardCache.date.format(DateTimeFormatter.ofPattern("dd.MM.yyyy"))
+ }
+ listOfInterests = wizardCache.interests
+ listOfInterests.forEach { tag ->
+ val chip = Chip(binding.checkedChipGroup.context)
+ chip.text= tag
+ chip.isClickable = false
+ chip.isCheckable = false
+ chip.textSize = 25F
+ binding.checkedChipGroup.addView(chip)
+ }
+
+ binding.addressTextView.text = wizardCache.address
+ }
+}
+
+
diff --git a/app/src/main/java/ru/otus/basicarchitecture/UserFragment.kt b/app/src/main/java/ru/otus/basicarchitecture/UserFragment.kt
new file mode 100644
index 0000000..b222b9c
--- /dev/null
+++ b/app/src/main/java/ru/otus/basicarchitecture/UserFragment.kt
@@ -0,0 +1,53 @@
+package ru.otus.basicarchitecture
+
+import androidx.fragment.app.Fragment
+import dagger.hilt.android.AndroidEntryPoint
+import ru.otus.basicarchitecture.databinding.FragmentUserBinding
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.navigation.fragment.findNavController
+import ru.otus.basicarchitecture.viewmodel.UserViewModel
+import androidx.fragment.app.viewModels
+
+@AndroidEntryPoint
+class UserFragment : Fragment(R.layout.fragment_user) {
+ private lateinit var binding: FragmentUserBinding
+ private val viewModel: UserViewModel by viewModels()
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ binding = FragmentUserBinding.inflate(inflater)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ binding.next.isEnabled = false
+ binding.next.setOnClickListener() {
+ viewModel.onNext(binding.name.editText!!.text.toString(), binding.surname.editText!!.text.toString())
+ findNavController().navigate(R.id.action_nameFragment_to_addressFragment)
+ }
+ binding.date.editText!!.addTextChangedListener(DateMask(viewModel))
+
+ viewModel.getResultValidDateLive().observe(viewLifecycleOwner) {
+ if(it == null) {
+ binding.next.isEnabled = false
+ binding.next.text = "Введите корректную дату"
+ return@observe
+ }
+ if (it == true) {
+ binding.next.text = "Далее"
+ binding.next.isEnabled = true
+
+ } else {
+ binding.next.isEnabled = false
+ binding.next.text = "Вам нет 18 лет"
+ }
+ }
+ }
+ }
diff --git a/app/src/main/java/ru/otus/basicarchitecture/WizardCache.kt b/app/src/main/java/ru/otus/basicarchitecture/WizardCache.kt
new file mode 100644
index 0000000..5c457e7
--- /dev/null
+++ b/app/src/main/java/ru/otus/basicarchitecture/WizardCache.kt
@@ -0,0 +1,32 @@
+package ru.otus.basicarchitecture
+
+import dagger.hilt.android.scopes.ActivityRetainedScoped
+import javax.inject.Inject
+import java.time.LocalDate
+
+@ActivityRetainedScoped
+class WizardCache @Inject constructor() {
+
+ var name: String = ""
+ var surname: String = ""
+ lateinit var date:LocalDate
+ var country: String = ""
+ var city: String = ""
+ var address: String = ""
+ var interests: List = listOf()
+
+ fun saveNameData(name: String, surname:String, date: LocalDate) {
+ this.name = name
+ this.surname = surname
+ this.date = date
+ }
+
+ fun saveInterests(interests: List) {
+ this.interests = interests
+ }
+
+ fun saveAddressData(address: String) {
+ this.address = address
+ }
+
+}
diff --git a/app/src/main/java/ru/otus/basicarchitecture/model/AddressData.kt b/app/src/main/java/ru/otus/basicarchitecture/model/AddressData.kt
new file mode 100644
index 0000000..e30eed1
--- /dev/null
+++ b/app/src/main/java/ru/otus/basicarchitecture/model/AddressData.kt
@@ -0,0 +1,11 @@
+package ru.otus.basicarchitecture.model
+
+import com.squareup.moshi.Json
+
+data class AddressData(
+ @field:Json(name="suggestions")
+ val suggestions:List)
+
+data class AddressValue(
+ @field:Json(name="value")
+ val value:String)
\ No newline at end of file
diff --git a/app/src/main/java/ru/otus/basicarchitecture/model/AddressQuery.kt b/app/src/main/java/ru/otus/basicarchitecture/model/AddressQuery.kt
new file mode 100644
index 0000000..a924c3a
--- /dev/null
+++ b/app/src/main/java/ru/otus/basicarchitecture/model/AddressQuery.kt
@@ -0,0 +1,7 @@
+package ru.otus.basicarchitecture.model
+
+import com.squareup.moshi.Json
+
+data class AddressQuery(
+ @field:Json(name="query")
+ val query:String)
\ No newline at end of file
diff --git a/app/src/main/java/ru/otus/basicarchitecture/model/AddressService.kt b/app/src/main/java/ru/otus/basicarchitecture/model/AddressService.kt
new file mode 100644
index 0000000..92e2c68
--- /dev/null
+++ b/app/src/main/java/ru/otus/basicarchitecture/model/AddressService.kt
@@ -0,0 +1,45 @@
+package ru.otus.basicarchitecture.model
+
+import okhttp3.OkHttpClient
+import retrofit2.Response
+import retrofit2.Retrofit
+import retrofit2.converter.moshi.MoshiConverterFactory
+import retrofit2.http.Body
+import retrofit2.http.Headers
+import retrofit2.http.POST
+import javax.inject.Inject
+import javax.inject.Singleton
+import android.util.Log
+
+@Singleton
+class AddressService @Inject constructor(){
+
+ private val client = OkHttpClient()
+
+ private val retrofit = Retrofit.Builder()
+ .baseUrl("https://suggestions.dadata.ru/suggestions/")
+ .client(client)
+ .addConverterFactory(MoshiConverterFactory.create())
+ .build()
+
+ private val service = retrofit.create(DaDataService::class.java)
+
+ suspend fun request(query:String, callback: (response:AddressData?) -> Unit) {
+ val response = service.getAddressHint(AddressQuery(query))
+ if(response.isSuccessful) {
+ callback(response.body())
+ }
+ else {
+ Log.e("Ошибка Retrofit", "${response.code()} ${response.message()}")
+ }
+ }
+
+ interface DaDataService {
+ @POST("api/4_1/rs/suggest/address")
+ @Headers("Content-Type:application/json",
+ "Accept:application/json",
+ "Authorization:Token 628a6b883336f402594f379b42e80e567ba3a12c")
+ suspend fun getAddressHint(@Body query: AddressQuery):Response
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/otus/basicarchitecture/viewmodel/AddressViewModel.kt b/app/src/main/java/ru/otus/basicarchitecture/viewmodel/AddressViewModel.kt
new file mode 100644
index 0000000..7d62c82
--- /dev/null
+++ b/app/src/main/java/ru/otus/basicarchitecture/viewmodel/AddressViewModel.kt
@@ -0,0 +1,44 @@
+package ru.otus.basicarchitecture.viewmodel
+
+import androidx.lifecycle.ViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import ru.otus.basicarchitecture.WizardCache
+import javax.inject.Inject
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import ru.otus.basicarchitecture.model.AddressService
+import ru.otus.basicarchitecture.model.AddressValue
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+
+@HiltViewModel
+class AddressViewModel @Inject constructor(): ViewModel() {
+ @Inject lateinit var wizardCache: WizardCache
+ private val resultAddressLive = MutableLiveData?>()
+ @Inject lateinit var service : AddressService
+ private var activeJob: Job? = null
+ fun saveData(address: String) {
+ wizardCache.saveAddressData(address)
+ }
+
+ fun search(query: String) {
+ activeJob = viewModelScope.launch {
+ try {
+ service.request(query) { response ->
+ resultAddressLive.value = response?.suggestions
+ }
+ }
+ catch (e: Exception) {
+ println("Ошибка Coroutine")
+ }
+ }
+ }
+ fun cancel() {
+ activeJob?.cancel()
+ activeJob = null
+ }
+ fun getResultAddressLive(): LiveData?> {
+ return resultAddressLive
+}
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/otus/basicarchitecture/viewmodel/InterestsViewModel.kt b/app/src/main/java/ru/otus/basicarchitecture/viewmodel/InterestsViewModel.kt
new file mode 100644
index 0000000..a753956
--- /dev/null
+++ b/app/src/main/java/ru/otus/basicarchitecture/viewmodel/InterestsViewModel.kt
@@ -0,0 +1,28 @@
+package ru.otus.basicarchitecture.viewmodel
+
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import ru.otus.basicarchitecture.WizardCache
+import ru.otus.basicarchitecture.Repository
+import javax.inject.Inject
+
+@HiltViewModel
+class InterestsViewModel @Inject constructor(private val repository: Repository): ViewModel() {
+ @Inject lateinit var wizardCache: WizardCache
+
+ private val resultInterestsLive = MutableLiveData>()
+
+ fun loadData () {
+ resultInterestsLive.value = repository.getInterests()
+ }
+
+ fun saveData(interests :List) {
+ wizardCache.saveInterests(interests)
+ }
+
+ fun getResultInterestsLive(): LiveData?> {
+ return resultInterestsLive
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ru/otus/basicarchitecture/viewmodel/UserViewModel.kt b/app/src/main/java/ru/otus/basicarchitecture/viewmodel/UserViewModel.kt
new file mode 100644
index 0000000..ac1ee81
--- /dev/null
+++ b/app/src/main/java/ru/otus/basicarchitecture/viewmodel/UserViewModel.kt
@@ -0,0 +1,106 @@
+package ru.otus.basicarchitecture.viewmodel
+
+import android.os.Build
+import android.text.Editable
+import androidx.annotation.RequiresApi
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import dagger.hilt.android.lifecycle.HiltViewModel
+import ru.otus.basicarchitecture.WizardCache
+import java.time.LocalDate
+import java.time.Period
+import java.time.format.DateTimeFormatter
+import java.time.format.DateTimeParseException
+import javax.inject.Inject
+
+@HiltViewModel
+class UserViewModel @Inject constructor(): ViewModel() {
+ @Inject lateinit var wizardCache: WizardCache
+
+ private val resultValidDateLive = MutableLiveData()
+
+ private var date:LocalDate? = null
+
+ var ignore = false
+ var sb = StringBuilder()
+ private val numPlace = 'X'
+
+ fun onNext(name:String, surname:String) {
+ wizardCache.saveNameData(name, surname, date!!)
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ private fun onSaveDate(date: LocalDate?) {
+ this.date = date
+ if(date == null) {
+ resultValidDateLive.value = null
+ return
+ }
+ resultValidDateLive.value = Period.between(date, LocalDate.now()).years >= 18
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ fun onDateChanged(editable: Editable?) {
+ if (!ignore) {
+ removeFormat(editable.toString());
+ applyFormat(sb.toString());
+ ignore = true;
+ editable?.replace(0, editable.toString().length, sb.toString());
+ if(editable.toString().length == getTemplate().length) {
+ toDate(editable.toString())
+ onSaveDate(toDate(editable.toString()))
+ } else {
+ onSaveDate(null)
+ }
+ ignore = false;
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ private fun toDate(dateStr:String): LocalDate? {
+ var date: LocalDate? = null
+ try {
+ date = LocalDate.parse(dateStr, DateTimeFormatter.ofPattern("dd.MM.yyyy"))
+ } catch (e : DateTimeParseException) {
+
+ }
+ return date
+ }
+
+ private fun removeFormat(text: String) {
+ sb.setLength(0)
+ for (element in text) {
+ if (isNumberChar(element)) {
+ sb.append(element)
+ }
+ }
+ }
+ private fun applyFormat(text: String) {
+ val template: String = getTemplate()
+ sb.setLength(0)
+ var i = 0
+ var textIndex = 0
+ while (i < template.length && textIndex < text.length) {
+ if (template[i] == numPlace) {
+ sb.append(text[textIndex])
+ textIndex++
+ } else {
+ sb.append(template[i])
+ }
+ i++
+ }
+ }
+
+ private fun isNumberChar(c: Char): Boolean {
+ return c in '0'..'9'
+ }
+
+ private fun getTemplate(): String {
+ return "XX.XX.XXXX";
+ }
+
+ fun getResultValidDateLive(): LiveData {
+ return resultValidDateLive
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 0b15a20..a4bb856 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,9 +1,17 @@
-
+
+
+
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_address.xml b/app/src/main/res/layout/fragment_address.xml
new file mode 100644
index 0000000..e5f191c
--- /dev/null
+++ b/app/src/main/res/layout/fragment_address.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_interests.xml b/app/src/main/res/layout/fragment_interests.xml
new file mode 100644
index 0000000..fa295af
--- /dev/null
+++ b/app/src/main/res/layout/fragment_interests.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_results.xml b/app/src/main/res/layout/fragment_results.xml
new file mode 100644
index 0000000..28b2799
--- /dev/null
+++ b/app/src/main/res/layout/fragment_results.xml
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_user.xml b/app/src/main/res/layout/fragment_user.xml
new file mode 100644
index 0000000..a42d2ab
--- /dev/null
+++ b/app/src/main/res/layout/fragment_user.xml
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml
new file mode 100644
index 0000000..4f12d97
--- /dev/null
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f26b6d3..daa2237 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,20 @@
+
BasicArchitecture
+ Name
+ Surname
+ Birthdate
+ Country
+ City
+ Street, Building
+ Далее
+ Выход
+ Address
+ Interests
+ Персональные данные
+ Адрес
+ Интересы
+ Результат
+ Date of Birth
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index c84cccf..dd54b53 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,6 +1,12 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
- id 'com.android.application' version '8.0.0' apply false
- id 'com.android.library' version '8.0.0' apply false
+ id 'com.android.application' version '8.0.1' apply false
+ id 'com.android.library' version '8.0.1' apply false
id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
+ id 'com.google.dagger.hilt.android' version '2.46.1' apply false
+ id 'org.jetbrains.kotlin.plugin.serialization' version "1.8.10"
+ }
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
}
\ No newline at end of file