-
Notifications
You must be signed in to change notification settings - Fork 38
BasicArchitecture homevork1 #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
dc57e5d
2a7cac7
4fed97f
31fefd3
34e2468
68cb4b3
ad0232d
8fbadf6
f8bca7e
507a6a1
9d05dd8
625a009
3f9d746
3aadd8e
3de121f
8933150
97a6bed
421ac90
9e150b0
5e14274
41f8c06
8bd9b21
769cdff
0254932
4b105d8
8b11046
3dbdd4b
e6acadb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| package ru.otus.basicarchitecture.ui.address | ||
|
|
||
| import kotlinx.coroutines.runBlocking | ||
| import okhttp3.mockwebserver.MockResponse | ||
| import okhttp3.mockwebserver.MockWebServer | ||
| import org.junit.After | ||
| import org.junit.Assert.assertEquals | ||
| import org.junit.Before | ||
| import org.junit.Test | ||
| import org.junit.runner.RunWith | ||
| import org.mockito.Mockito.anyString | ||
| import org.mockito.junit.MockitoJUnitRunner | ||
| import retrofit2.Retrofit | ||
| import retrofit2.converter.gson.GsonConverterFactory | ||
| import ru.otus.basicarchitecture.ui.data.AddressData | ||
| import ru.otus.basicarchitecture.ui.data.AddressIP | ||
| import ru.otus.basicarchitecture.ui.data.RetrofitClient | ||
| import ru.otus.basicarchitecture.ui.data.WizardCache | ||
|
|
||
| @RunWith(MockitoJUnitRunner::class) | ||
| class AddressViewModelTest { | ||
| private lateinit var server: MockWebServer | ||
| private lateinit var viewModel: AddressViewModel | ||
| private lateinit var retrofitClient: RetrofitClient | ||
|
|
||
| @Before | ||
| fun set() { | ||
| server = MockWebServer() | ||
| val wizardCache = WizardCache() | ||
| val addressData = AddressData() | ||
| retrofitClient = RetrofitClient() | ||
|
|
||
| retrofitClient.apiService = Retrofit.Builder() | ||
| .baseUrl(server.url("/")) | ||
| .addConverterFactory(GsonConverterFactory.create()) | ||
| .build() | ||
| .create(AddressIP::class.java) | ||
|
|
||
| viewModel = AddressViewModel(wizardCache, addressData, retrofitClient) | ||
| } | ||
|
|
||
| @Test | ||
| fun getDataNotice() { | ||
| runBlocking { | ||
|
|
||
| val response = MockResponse().setResponseCode(200).setBody( | ||
| """ | ||
| { | ||
| "suggestions": [ | ||
| { | ||
| "value": "г Москва, ул Хабаровская", | ||
| }, | ||
| ] | ||
| } | ||
|
|
||
| """.trimIndent() | ||
| ) | ||
| server.enqueue(response) | ||
| viewModel.getDataNotice(anyString()) | ||
|
|
||
| val result = viewModel.addressDataArray.isEmpty() | ||
| val exceptedValue = true | ||
| assertEquals(exceptedValue, result) | ||
| } | ||
| } | ||
|
|
||
| @Test | ||
| fun setAddress() { | ||
|
|
||
| viewModel.setAddress("Москва") | ||
|
|
||
| val result = viewModel.wizardCache.personAddress | ||
| val exceptedValue = "Москва" | ||
| assertEquals(exceptedValue, result) | ||
| } | ||
|
|
||
| @After | ||
| fun shutdown() { | ||
| server.shutdown() | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| package ru.otus.basicarchitecture.ui.authorization | ||
|
|
||
| import androidx.test.ext.junit.runners.AndroidJUnit4 | ||
| import kotlinx.coroutines.Dispatchers | ||
| import kotlinx.coroutines.runBlocking | ||
| import kotlinx.coroutines.withContext | ||
| import org.junit.Assert.assertEquals | ||
| import org.junit.Before | ||
| import org.junit.Test | ||
| import org.junit.runner.RunWith | ||
| import ru.otus.basicarchitecture.ui.data.WizardCache | ||
|
|
||
| @RunWith(AndroidJUnit4::class) | ||
| class AuthorizationViewModelTest { | ||
|
|
||
| private lateinit var viewModel: AuthorizationViewModel | ||
|
|
||
| @Before | ||
| fun set() { | ||
| val wizardCache = WizardCache() | ||
| viewModel = AuthorizationViewModel(wizardCache) | ||
| viewModel.setCurrentDate(1, 1, 2018) | ||
| } | ||
|
|
||
| @Test | ||
| fun ageVerification() { | ||
|
|
||
| runBlocking { | ||
|
|
||
| withContext(Dispatchers.Main) { | ||
| val day = 1 | ||
| val month = 1 | ||
| val year = 2000 | ||
|
|
||
| viewModel.ageVerification(day, month, year) | ||
| val result = viewModel.anAdult.value | ||
|
|
||
| val exceptedValue = true | ||
| assertEquals(exceptedValue, result) | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package ru.otus.basicarchitecture.ui | ||
|
|
||
| import android.app.Application | ||
| import dagger.hilt.android.HiltAndroidApp | ||
| import ru.otus.basicarchitecture.ui.data.WizardCache | ||
| import javax.inject.Inject | ||
|
|
||
| @HiltAndroidApp | ||
| class MyHilt : Application() { | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| package ru.otus.basicarchitecture.ui.address | ||
|
|
||
| import android.os.Bundle | ||
| import android.text.Editable | ||
| import android.text.TextWatcher | ||
| import android.view.LayoutInflater | ||
| import android.view.View | ||
| import android.view.ViewGroup | ||
| import android.widget.ArrayAdapter | ||
| import android.widget.AutoCompleteTextView | ||
| import android.widget.Button | ||
| import androidx.fragment.app.Fragment | ||
| import androidx.fragment.app.viewModels | ||
| import androidx.navigation.fragment.findNavController | ||
| import com.google.android.material.textfield.TextInputLayout | ||
| import dagger.hilt.android.AndroidEntryPoint | ||
| import ru.otus.basicarchitecture.R | ||
|
|
||
|
|
||
| @AndroidEntryPoint | ||
| class AddressFragment : Fragment() { | ||
|
|
||
| companion object { | ||
| fun newInstance() = AddressFragment() | ||
| } | ||
|
|
||
| private val viewModel: AddressViewModel by viewModels() | ||
|
|
||
| override fun onCreateView( | ||
| inflater: LayoutInflater, container: ViewGroup?, | ||
| savedInstanceState: Bundle? | ||
| ): View { | ||
| return inflater.inflate(R.layout.fragment_address, container, false) | ||
| } | ||
|
|
||
| override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | ||
| super.onViewCreated(view, savedInstanceState) | ||
|
|
||
| val addressTextInput = view.findViewById<TextInputLayout>(R.id.addressTextInput) | ||
| val navController = findNavController() | ||
|
|
||
| view.findViewById<AutoCompleteTextView>(R.id.autoCompleteTextView).apply { | ||
| threshold = 4 | ||
| addTextChangedListener(object : | ||
| TextWatcher { | ||
| override fun onTextChanged( | ||
| s: CharSequence, | ||
| start: Int, | ||
| before: Int, | ||
| count: Int | ||
| ) { | ||
|
|
||
| if (s.length > 3) { | ||
| viewModel.getDataNotice(s.toString()) | ||
| val adapter = activity?.let { | ||
| ArrayAdapter( | ||
| it.baseContext, | ||
| android.R.layout.simple_dropdown_item_1line, | ||
| viewModel.addressDataArray | ||
| ) | ||
| } | ||
| setAdapter(adapter) | ||
| } | ||
| } | ||
|
|
||
| override fun beforeTextChanged( | ||
| s: CharSequence, | ||
| start: Int, | ||
| count: Int, | ||
| after: Int | ||
| ) { | ||
| } | ||
|
|
||
| override fun afterTextChanged(s: Editable) {} | ||
| }); | ||
| } | ||
|
|
||
| view.findViewById<Button>(R.id.toInterests).setOnClickListener { | ||
| viewModel.setAddress(addressTextInput.editText?.text.toString()) | ||
|
|
||
| navController.navigate(R.id.action_to_interestsFragment) | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| package ru.otus.basicarchitecture.ui.address | ||
|
|
||
| import android.util.Log | ||
| import androidx.lifecycle.ViewModel | ||
| import androidx.lifecycle.viewModelScope | ||
| import dagger.hilt.android.lifecycle.HiltViewModel | ||
| import kotlinx.coroutines.Dispatchers | ||
| import kotlinx.coroutines.Job | ||
| import kotlinx.coroutines.launch | ||
| import ru.otus.basicarchitecture.ui.data.AddressData | ||
| import ru.otus.basicarchitecture.ui.data.AddressIP | ||
| import ru.otus.basicarchitecture.ui.data.RetrofitClient | ||
| import ru.otus.basicarchitecture.ui.data.WizardCache | ||
| import javax.inject.Inject | ||
|
|
||
| @HiltViewModel | ||
| class AddressViewModel @Inject constructor( | ||
| var wizardCache: WizardCache, | ||
| private var addressData: AddressData, | ||
| private var retrofitClient:RetrofitClient | ||
|
|
||
| ) : ViewModel() { | ||
|
|
||
| var addressDataArray: MutableList<String> = mutableListOf() | ||
| private var postDataJob: Job? = null | ||
|
|
||
| fun setAddress(address: String) { | ||
| wizardCache.personAddress = address | ||
| } | ||
|
|
||
| fun getDataNotice(address: String) { | ||
| addressData.query = address | ||
| postDataJob?.cancel() | ||
|
|
||
| postDataJob = viewModelScope.launch(Dispatchers.IO) { | ||
|
|
||
| try { | ||
| val result = retrofitClient.apiService.postData( | ||
| dataModal = addressData | ||
| ) | ||
| if (result.isSuccessful) { | ||
| result.body()?.let { | ||
| it.suggestions.forEach { address -> | ||
| addressDataArray.add(address.value) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Вы пишите найденные значения в список. А как UI узнает, что список поменялся?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. На сколько я понял, адаптер принимает готовый список строк, потому я просто использую во вью модели список адресов чисто для адаптера. Возможно адаптер может и цеплять лайвдату какую ни будь и менять на лету. Но у меня он не обновлял подсказки, я пофиксил таким образом. Если так, задам вопрос на разборе.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. В момент когда компонент начнёт показывать подсказки, список уже будет получен от сервера. И так далее по шагам при добавлении по одной букве. Если не будет ответа от сервера ничего страшного, мы либо не покажем подсказку или через 2-3 буквы при успешном запросе показываем подсказки. Для такой логики лайвдаты или флоу не нужны. Да и с адаптером у меня не получилось подружить их. |
||
| } | ||
| } | ||
| } | ||
|
|
||
| } catch (e: Exception) { | ||
| Log.d("my", e.toString()) | ||
| } | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
То есть, насколько я понял, у вас список предложений, который сейчас в модели находится, устанавливается в список предложений? Мне кажется, это предложения от прошлого изменения строки поиска (см ниже)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Тут, возможно и прошлое цепанулось гляну по возможности. Тоже не совсем понял вопроса)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Тут логика такая, при вводе больше 3х букв в поле мы кидаем запрос серверу при ответе мы результат пишем в вью модель, наверное смутило то что я использую доп переменную во вью модели для этого, можно и сразу в адаптер написать. После 4х букв мы начинаем показывать подсказки.