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