Skip to content

home work has been done #169

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

Open
wants to merge 2 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ plugins {
}

android {
compileSdkVersion 30
compileSdkVersion 34
buildToolsVersion "30.0.3"

defaultConfig {
applicationId "otus.homework.coroutines"
minSdkVersion 23
targetSdkVersion 30
targetSdkVersion 34
versionCode 1
versionName "1.0"

Expand All @@ -34,12 +34,16 @@ android {

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.10.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
}
8 changes: 8 additions & 0 deletions app/src/main/java/otus/homework/coroutines/CatImage.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package otus.homework.coroutines

import com.google.gson.annotations.SerializedName

data class CatImage(
@field:SerializedName("image")
val image: String,
)
67 changes: 67 additions & 0 deletions app/src/main/java/otus/homework/coroutines/CatViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package otus.homework.coroutines

import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.*

class CatViewModel(
private val catsService: CatsService,
private val imageCatsService: ImageCatsService,
private val application: Application,
private val catsMapper: CatsMapper
): ViewModel() {

companion object {

private const val SOCKET_TIMEOUT_EXCEPTION = "Не удалось получить ответ от сервера"
private const val ERROR_MESSAGE = "Произошла ошибка"
}

private var _catsView: ICatsView? = null

private val errorHandler = CoroutineExceptionHandler { _, exception ->
CrashMonitor.trackWarning(application, exception.message ?: ERROR_MESSAGE)
}

fun onInitComplete() {
viewModelScope.launch(errorHandler) {
when(val responseResult = onInitCompleteResponse()) {
is Success -> {
_catsView?.populate(responseResult.data)
}
is Error -> {
CrashMonitor.trackWarning(application, responseResult.message)
}
}
}
}

private suspend fun onInitCompleteResponse(): Result<FactAndImageModel> {
return try {
val response = catsService.getCatFact()
Copy link
Collaborator

Choose a reason for hiding this comment

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

Также последовательные запросы

val imageResponse = imageCatsService.getCatImage()
if ((response.isSuccessful && response.body() != null) && (imageResponse.isSuccessful && imageResponse.body() != null)) {
val factAndImage = catsMapper.toFactAndImage(
fact = response.body()?.fact,
image = imageResponse.body()?.image
)
Success(factAndImage)
} else {
Error(SOCKET_TIMEOUT_EXCEPTION)
}
} catch (e: java.net.SocketTimeoutException) {
Error(SOCKET_TIMEOUT_EXCEPTION)
} catch (e: Exception) {
Error(e.message ?: ERROR_MESSAGE)
}
}

fun attachView(catsView: ICatsView) {
_catsView = catsView
}

fun detachView() {
_catsView = null
}
}
9 changes: 9 additions & 0 deletions app/src/main/java/otus/homework/coroutines/CatsMapper.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package otus.homework.coroutines

class CatsMapper {

fun toFactAndImage(fact: String?, image: String?): FactAndImageModel = FactAndImageModel(
fact = fact.orEmpty(),
image = image.orEmpty()
)
}
43 changes: 32 additions & 11 deletions app/src/main/java/otus/homework/coroutines/CatsPresenter.kt
Original file line number Diff line number Diff line change
@@ -1,28 +1,48 @@
package otus.homework.coroutines

import android.content.Context
import kotlinx.coroutines.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class CatsPresenter(
private val catsService: CatsService
private val catsService: CatsService,
private val imageCatsService: ImageCatsService,
private val context: Context,
private val catMapper: CatsMapper
) {

companion object {

private const val CATS_COROUTINES = "CatsCoroutine"
private const val SOCKET_TIMEOUT_EXCEPTION = "Не удалось получить ответ от сервера"
private const val ERROR_MESSAGE = "Произошла ошибка"
}

private var _catsView: ICatsView? = null

fun onInitComplete() {
catsService.getCatFact().enqueue(object : Callback<Fact> {
private val presenterScope = CoroutineScope(Dispatchers.Main + CoroutineName(CATS_COROUTINES))

override fun onResponse(call: Call<Fact>, response: Response<Fact>) {
if (response.isSuccessful && response.body() != null) {
_catsView?.populate(response.body()!!)
fun onInitComplete() {
presenterScope.launch {
try {
val response = catsService.getCatFact()
Copy link
Collaborator

Choose a reason for hiding this comment

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

У тебя тут последовательные запросы, нужно корутины запустить

val imageResponse = imageCatsService.getCatImage()
if ((response.isSuccessful && response.body() != null) && (imageResponse.isSuccessful &&
imageResponse.body() != null)) {
val factAndImage = catMapper.toFactAndImage(
fact = response.body()?.fact,
image = imageResponse.body()?.image
)
_catsView?.populate(factAndImage)
}
} catch (e: java.net.SocketTimeoutException) {
CrashMonitor.trackWarning(context, SOCKET_TIMEOUT_EXCEPTION)
} catch (e: Exception) {
CrashMonitor.trackWarning(context, e.message ?: ERROR_MESSAGE)
}

override fun onFailure(call: Call<Fact>, t: Throwable) {
CrashMonitor.trackWarning()
}
})
}
}

fun attachView(catsView: ICatsView) {
Expand All @@ -31,5 +51,6 @@ class CatsPresenter(

fun detachView() {
_catsView = null
presenterScope.cancel()
}
}
4 changes: 2 additions & 2 deletions app/src/main/java/otus/homework/coroutines/CatsService.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package otus.homework.coroutines

import retrofit2.Call
import retrofit2.Response
import retrofit2.http.GET

interface CatsService {

@GET("fact")
fun getCatFact() : Call<Fact>
suspend fun getCatFact() : Response<Fact>
}
17 changes: 10 additions & 7 deletions app/src/main/java/otus/homework/coroutines/CatsView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,34 @@ package otus.homework.coroutines

import android.content.Context
import android.util.AttributeSet
import android.widget.Button
import android.widget.TextView
import android.widget.*
import androidx.constraintlayout.widget.ConstraintLayout
import com.squareup.picasso.Picasso

class CatsView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), ICatsView {

var presenter :CatsPresenter? = null
// var presenter: CatsPresenter? = null
var viewModel: CatViewModel? = null

override fun onFinishInflate() {
super.onFinishInflate()
findViewById<Button>(R.id.button).setOnClickListener {
presenter?.onInitComplete()
// presenter?.onInitComplete()
viewModel?.onInitComplete()
}
}

override fun populate(fact: Fact) {
findViewById<TextView>(R.id.fact_textView).text = fact.text
override fun populate(fact: FactAndImageModel) {
findViewById<TextView>(R.id.fact_textView).text = fact.fact
Picasso.get().load(fact.image).into(findViewById<ImageView>(R.id.image))
}
}

interface ICatsView {

fun populate(fact: Fact)
fun populate(fact: FactAndImageModel)
}
6 changes: 5 additions & 1 deletion app/src/main/java/otus/homework/coroutines/CrashMonitor.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package otus.homework.coroutines

import android.content.Context
import android.widget.Toast

object CrashMonitor {

/**
* Pretend this is Crashlytics/AppCenter
*/
fun trackWarning() {
fun trackWarning(context: Context, message: String) {
Toast.makeText(context, message, Toast.LENGTH_LONG).show()
}
}
8 changes: 8 additions & 0 deletions app/src/main/java/otus/homework/coroutines/DiContainer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,13 @@ class DiContainer {
.build()
}

private val retrofitImage by lazy {
Retrofit.Builder()
.baseUrl("https://aws.random.cat/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}

val service by lazy { retrofit.create(CatsService::class.java) }
val serviceImage by lazy { retrofitImage.create(ImageCatsService::class.java) }
}
41 changes: 23 additions & 18 deletions app/src/main/java/otus/homework/coroutines/Fact.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,28 @@ package otus.homework.coroutines

import com.google.gson.annotations.SerializedName

//data class Fact(
// @field:SerializedName("createdAt")
// val createdAt: String,
// @field:SerializedName("deleted")
// val deleted: Boolean,
// @field:SerializedName("_id")
// val id: String,
// @field:SerializedName("text")
// val text: String,
// @field:SerializedName("source")
// val source: String,
// @field:SerializedName("used")
// val used: Boolean,
// @field:SerializedName("type")
// val type: String,
// @field:SerializedName("user")
// val user: String,
// @field:SerializedName("updatedAt")
// val updatedAt: String
//)

data class Fact(
@field:SerializedName("createdAt")
val createdAt: String,
@field:SerializedName("deleted")
val deleted: Boolean,
@field:SerializedName("_id")
val id: String,
@field:SerializedName("text")
val text: String,
@field:SerializedName("source")
val source: String,
@field:SerializedName("used")
val used: Boolean,
@field:SerializedName("type")
val type: String,
@field:SerializedName("user")
val user: String,
@field:SerializedName("updatedAt")
val updatedAt: String
@field:SerializedName("fact")
val fact: String,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package otus.homework.coroutines

data class FactAndImageModel(
val fact: String,
val image: String
)
10 changes: 10 additions & 0 deletions app/src/main/java/otus/homework/coroutines/ImageCatsService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package otus.homework.coroutines

import retrofit2.Response
import retrofit2.http.GET

interface ImageCatsService {

@GET("meow")
suspend fun getCatImage(): Response<CatImage>
Copy link
Collaborator

Choose a reason for hiding this comment

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

А зачем тебе Response, можно оставить просто CatImage, если будет неуспешный статус то тебе дефолтный КоллАдаптер выбросит исключение

}
Loading