From ce0a40cc8d6d18b1bf85eaa1321a1aadeaa45380 Mon Sep 17 00:00:00 2001 From: LexAndro3723 Date: Mon, 4 Sep 2023 15:04:50 +0300 Subject: [PATCH 1/2] dz mvvm --- app/build.gradle | 40 +++++- app/src/main/AndroidManifest.xml | 11 +- .../otus/basicarchitecture/AddressFragment.kt | 46 +++++++ .../ru/otus/basicarchitecture/DateMask.kt | 21 ++++ .../basicarchitecture/InterestsFragment.kt | 60 +++++++++ .../ru/otus/basicarchitecture/MainActivity.kt | 21 +++- .../java/ru/otus/basicarchitecture/MyApp.kt | 9 ++ .../ru/otus/basicarchitecture/Repository.kt | 11 ++ .../otus/basicarchitecture/ResultFragment.kt | 57 +++++++++ .../ru/otus/basicarchitecture/UserFragment.kt | 53 ++++++++ .../ru/otus/basicarchitecture/WizardCache.kt | 35 ++++++ .../viewmodel/AddressViewModel.kt | 14 +++ .../viewmodel/InterestsViewModel.kt | 28 +++++ .../viewmodel/UserViewModel.kt | 106 ++++++++++++++++ app/src/main/res/layout/activity_main.xml | 22 ++-- app/src/main/res/layout/fragment_address.xml | 64 ++++++++++ .../main/res/layout/fragment_interests.xml | 27 +++++ app/src/main/res/layout/fragment_results.xml | 114 ++++++++++++++++++ app/src/main/res/layout/fragment_user.xml | 65 ++++++++++ app/src/main/res/navigation/nav_graph.xml | 42 +++++++ app/src/main/res/values/strings.xml | 17 +++ build.gradle | 10 +- 22 files changed, 855 insertions(+), 18 deletions(-) create mode 100644 app/src/main/java/ru/otus/basicarchitecture/AddressFragment.kt create mode 100644 app/src/main/java/ru/otus/basicarchitecture/DateMask.kt create mode 100644 app/src/main/java/ru/otus/basicarchitecture/InterestsFragment.kt create mode 100644 app/src/main/java/ru/otus/basicarchitecture/MyApp.kt create mode 100644 app/src/main/java/ru/otus/basicarchitecture/Repository.kt create mode 100644 app/src/main/java/ru/otus/basicarchitecture/ResultFragment.kt create mode 100644 app/src/main/java/ru/otus/basicarchitecture/UserFragment.kt create mode 100644 app/src/main/java/ru/otus/basicarchitecture/WizardCache.kt create mode 100644 app/src/main/java/ru/otus/basicarchitecture/viewmodel/AddressViewModel.kt create mode 100644 app/src/main/java/ru/otus/basicarchitecture/viewmodel/InterestsViewModel.kt create mode 100644 app/src/main/java/ru/otus/basicarchitecture/viewmodel/UserViewModel.kt create mode 100644 app/src/main/res/layout/fragment_address.xml create mode 100644 app/src/main/res/layout/fragment_interests.xml create mode 100644 app/src/main/res/layout/fragment_results.xml create mode 100644 app/src/main/res/layout/fragment_user.xml create mode 100644 app/src/main/res/navigation/nav_graph.xml diff --git a/app/build.gradle b/app/build.gradle index 9c99d98..622f3fd 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,44 @@ 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' + +} + + diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1e81fea..465e4b1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -4,6 +4,7 @@ + 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..d9e23c5 --- /dev/null +++ b/app/src/main/java/ru/otus/basicarchitecture/AddressFragment.kt @@ -0,0 +1,46 @@ +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 java.time.format.DateTimeFormatter +import javax.inject.Inject + +@AndroidEntryPoint +class AddressFragment : Fragment(R.layout.fragment_address) { + private lateinit var binding: FragmentAddressBinding + private val viewModel : AddressViewModel by viewModels() + + 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.next.setOnClickListener() { + viewModel.saveData( + binding.country.editText!!.text.toString(), + binding.city.editText!!.text.toString(), + binding.address.editText!!.text.toString() + ) + findNavController().navigate(R.id.action_addressFragment_to_interestsFragment) + } + + } +} \ 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..26f5c74 --- /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.country}, ${wizardCache.city}, ${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..d453529 --- /dev/null +++ b/app/src/main/java/ru/otus/basicarchitecture/WizardCache.kt @@ -0,0 +1,35 @@ +package ru.otus.basicarchitecture + +import dagger.hilt.android.scopes.ActivityRetainedScoped +//import java.util.Date +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(country: String, city:String, address: String) { + this.country = country + this.city = city + this.address = address + } + +} 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..fc7c352 --- /dev/null +++ b/app/src/main/java/ru/otus/basicarchitecture/viewmodel/AddressViewModel.kt @@ -0,0 +1,14 @@ +package ru.otus.basicarchitecture.viewmodel + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import ru.otus.basicarchitecture.WizardCache +import javax.inject.Inject + +@HiltViewModel +class AddressViewModel @Inject constructor(): ViewModel() { + @Inject lateinit var wizardCache: WizardCache + fun saveData(country: String, city:String, address: String) { + wizardCache.saveAddressData(country,city,address) + } +} \ 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..bdca8b6 --- /dev/null +++ b/app/src/main/res/layout/fragment_address.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + \ 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..c13bf5f 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 + +} + +task clean(type: Delete) { + delete rootProject.buildDir } \ No newline at end of file From d0048d003dc6331c96542c8d0055084f8cc20f85 Mon Sep 17 00:00:00 2001 From: LexAndro3723 Date: Tue, 5 Sep 2023 12:29:35 +0300 Subject: [PATCH 2/2] dz retrofit --- app/build.gradle | 7 +++ app/src/main/AndroidManifest.xml | 2 +- .../otus/basicarchitecture/AddressFragment.kt | 42 +++++++++++++--- .../otus/basicarchitecture/ResultFragment.kt | 2 +- .../ru/otus/basicarchitecture/WizardCache.kt | 5 +- .../basicarchitecture/model/AddressData.kt | 11 +++++ .../basicarchitecture/model/AddressQuery.kt | 7 +++ .../basicarchitecture/model/AddressService.kt | 45 +++++++++++++++++ .../viewmodel/AddressViewModel.kt | 34 ++++++++++++- app/src/main/res/layout/fragment_address.xml | 49 ++++--------------- build.gradle | 4 +- 11 files changed, 151 insertions(+), 57 deletions(-) create mode 100644 app/src/main/java/ru/otus/basicarchitecture/model/AddressData.kt create mode 100644 app/src/main/java/ru/otus/basicarchitecture/model/AddressQuery.kt create mode 100644 app/src/main/java/ru/otus/basicarchitecture/model/AddressService.kt diff --git a/app/build.gradle b/app/build.gradle index 622f3fd..5f8091c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -67,6 +67,13 @@ dependencies { 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 465e4b1..7ba6e29 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ - + ( + requireContext(), + android.R.layout.simple_list_item_1, + list + ) + binding.fullAddress.setAdapter(adapter) + } + } + binding.next.setOnClickListener() { - viewModel.saveData( - binding.country.editText!!.text.toString(), - binding.city.editText!!.text.toString(), - binding.address.editText!!.text.toString() - ) + 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/ResultFragment.kt b/app/src/main/java/ru/otus/basicarchitecture/ResultFragment.kt index 26f5c74..28ca004 100644 --- a/app/src/main/java/ru/otus/basicarchitecture/ResultFragment.kt +++ b/app/src/main/java/ru/otus/basicarchitecture/ResultFragment.kt @@ -50,7 +50,7 @@ class ResultFragment : Fragment(R.layout.fragment_results) { binding.checkedChipGroup.addView(chip) } - binding.addressTextView.text = "${wizardCache.country}, ${wizardCache.city}, ${wizardCache.address}"; + binding.addressTextView.text = wizardCache.address } } diff --git a/app/src/main/java/ru/otus/basicarchitecture/WizardCache.kt b/app/src/main/java/ru/otus/basicarchitecture/WizardCache.kt index d453529..5c457e7 100644 --- a/app/src/main/java/ru/otus/basicarchitecture/WizardCache.kt +++ b/app/src/main/java/ru/otus/basicarchitecture/WizardCache.kt @@ -1,7 +1,6 @@ package ru.otus.basicarchitecture import dagger.hilt.android.scopes.ActivityRetainedScoped -//import java.util.Date import javax.inject.Inject import java.time.LocalDate @@ -26,9 +25,7 @@ class WizardCache @Inject constructor() { this.interests = interests } - fun saveAddressData(country: String, city:String, address: String) { - this.country = country - this.city = city + 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 index fc7c352..7d62c82 100644 --- a/app/src/main/java/ru/otus/basicarchitecture/viewmodel/AddressViewModel.kt +++ b/app/src/main/java/ru/otus/basicarchitecture/viewmodel/AddressViewModel.kt @@ -4,11 +4,41 @@ 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 - fun saveData(country: String, city:String, address: String) { - wizardCache.saveAddressData(country,city,address) + 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/res/layout/fragment_address.xml b/app/src/main/res/layout/fragment_address.xml index bdca8b6..e5f191c 100644 --- a/app/src/main/res/layout/fragment_address.xml +++ b/app/src/main/res/layout/fragment_address.xml @@ -7,49 +7,20 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:padding="16dp"> - - - - - - - + android:text="@string/addressFragment" + android:textSize="25sp"/> - - - + app:layout_constraintTop_toBottomOf="@+id/addressName" + android:hint="Введите адрес"/>