Skip to content
Open

ДЗ #262

Show file tree
Hide file tree
Changes from all commits
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
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ dependencies {
implementation 'com.google.android.material:material:1.11.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'androidx.lifecycle:lifecycle-viewmodel-android:2.9.2'
}
8 changes: 8 additions & 0 deletions app/src/main/java/otus/homework/coroutines/Cat.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package otus.homework.coroutines

import android.media.Image

data class Cat(
val fact: String,
val imageUrl: String
)
14 changes: 14 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,14 @@
package otus.homework.coroutines

import com.google.gson.annotations.SerializedName

data class CatImage(
@field:SerializedName("id")
val id: String,
@field:SerializedName("url")
val url: String,
@field:SerializedName("width")
val width: Int,
@field:SerializedName("height")
val height: Int
)
93 changes: 58 additions & 35 deletions app/src/main/java/otus/homework/coroutines/CatsPresenter.kt
Original file line number Diff line number Diff line change
@@ -1,35 +1,58 @@
package otus.homework.coroutines

import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class CatsPresenter(
private val catsService: CatsService
) {

private var _catsView: ICatsView? = null

fun onInitComplete() {
catsService.getCatFact().enqueue(object : Callback<Fact> {

override fun onResponse(call: Call<Fact>, response: Response<Fact>) {
if (response.isSuccessful && response.body() != null) {
_catsView?.populate(response.body()!!)
}
}

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

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

fun detachView() {
_catsView = null
}
}
//package otus.homework.coroutines
//
//import kotlinx.coroutines.CoroutineName
//import kotlinx.coroutines.CoroutineScope
//import kotlinx.coroutines.Dispatchers
//import kotlinx.coroutines.Job
//import kotlinx.coroutines.async
//import kotlinx.coroutines.launch
//import java.net.SocketTimeoutException
//import kotlin.coroutines.cancellation.CancellationException
//
//
//class CatsPresenter(
// private val catsService: CatsService,
// private val catsImagesService: CatsImageService,
// private val presenterScope: CoroutineScope = CoroutineScope(Dispatchers.Main + CoroutineName("CatsCoroutine"))
//) {
//
// private var _catsView: ICatsView? = null
// private var job: Job? = null
//
// fun onInitComplete() {
// job = presenterScope.launch {
// try {
// val fact = async { catsService.getCatFact() }.await()
// val catImage:CatImage = async { catsImagesService.getCatImage()[0] }.await()
// _catsView?.populate(Cat(fact.toString(), catImage.url))
//
// } catch (ex: Exception) {
//
// if (ex is CancellationException) throw ex
// when (ex) {
//
// is SocketTimeoutException -> {
// _catsView?.onError("Unable to get response from server")
// }
// else -> {
// CrashMonitor.trackWarning(ex.message.toString())
// _catsView?.onError(ex.message.toString())
// }
// }
// }
// }
// }
//
// fun onStop() {
// job?.cancel()
// }
//
//
// fun attachView(catsView: ICatsView) {
// _catsView = catsView
// }
//
// fun detachView() {
// _catsView = null
// }
//}
13 changes: 10 additions & 3 deletions app/src/main/java/otus/homework/coroutines/CatsService.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package otus.homework.coroutines

import retrofit2.Call

import retrofit2.http.GET

interface CatsService {

@GET("fact")
fun getCatFact() : Call<Fact>
}
suspend fun getCatFact() : Fact
}

interface CatsImageService {

@GET("v1/images/search")
suspend fun getCatImage() : List<CatImage>

}
38 changes: 28 additions & 10 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,49 @@ package otus.homework.coroutines

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


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

override fun populate(cat: Cat) {
findViewById<TextView>(R.id.fact_textView).text = cat.fact
Picasso.get().load(cat.imageUrl).into(findViewById<ImageView>(R.id.catImageView));
}

override fun onError(text: String) {
Toast.makeText(context, text, Toast.LENGTH_SHORT).show()
}

override fun onFinishInflate() {
super.onFinishInflate()
fun showErrorToast(errorMsg: String) {
Toast.makeText(context, errorMsg, Toast.LENGTH_SHORT).show()
}

fun setOnButtonClick(onButtonClick: () -> Unit) {
findViewById<Button>(R.id.button).setOnClickListener {
presenter?.onInitComplete()
Log.d("TAG", "Button clicked")
onButtonClick()
}
}

override fun populate(fact: Fact) {
findViewById<TextView>(R.id.fact_textView).text = fact.fact
}
}

interface ICatsView {
public interface ICatsView {

fun populate(cat: Cat)

fun onError(errorMsg: String)
}

fun populate(fact: Fact)
}
50 changes: 50 additions & 0 deletions app/src/main/java/otus/homework/coroutines/CatsViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package otus.homework.coroutines

import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.initializer
import androidx.lifecycle.viewmodel.viewModelFactory
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.CoroutineExceptionHandler

class CatsViewModel(
private val catsService: CatsService,
private val catsImageService: CatsImageService
) : ViewModel() {


private val _uiState = MutableLiveData<Result>()

private val exceptionHandler = CoroutineExceptionHandler { _, e ->
CrashMonitor.trackWarning("${e.message}")
_uiState.value = Result.Error( e )
}

val uiState: LiveData<Result>
get() = _uiState

fun populate () {
viewModelScope.launch(exceptionHandler) {
val fact = async { catsService.getCatFact() }
val image = async { catsImageService.getCatImage()[0] }
val cat = Cat(fact.await().fact, image.await().url)

_uiState.value = Result.Success(cat)
}
}

companion object {
fun provideFactory(
catsService: CatsService,
catsImageService: CatsImageService
): ViewModelProvider.Factory = viewModelFactory {
initializer {
CatsViewModel(catsService, catsImageService)
}
}
}
}
5 changes: 4 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,13 @@
package otus.homework.coroutines

import android.util.Log

object CrashMonitor {

/**
* Pretend this is Crashlytics/AppCenter
*/
fun trackWarning() {
fun trackWarning(warningMessage: String) {
Log.d("TAG", "Crash logged: $warningMessage")
}
}
18 changes: 15 additions & 3 deletions app/src/main/java/otus/homework/coroutines/DiContainer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,27 @@ package otus.homework.coroutines

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import kotlin.getValue

class DiContainer {

private val retrofit by lazy {
private val catsFactRetrofit by lazy {
Retrofit.Builder()
.baseUrl("https://catfact.ninja/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}

val service by lazy { retrofit.create(CatsService::class.java) }
}
val catsService by lazy { catsFactRetrofit.create(CatsService::class.java) }

private val catsImageRetrofit by lazy {
Retrofit.Builder()
.baseUrl("https://api.thecatapi.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}

val catsImageService by lazy { catsImageRetrofit.create(CatsImageService::class.java) }


}
57 changes: 46 additions & 11 deletions app/src/main/java/otus/homework/coroutines/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,64 @@ package otus.homework.coroutines

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import otus.homework.coroutines.Result
import kotlin.getValue

class MainActivity : AppCompatActivity() {

lateinit var catsPresenter: CatsPresenter
// lateinit var catsPresenter: CatsPresenter

private val diContainer = DiContainer()

private val viewModel by lazy {
ViewModelProvider(
this,
CatsViewModel.provideFactory(diContainer.catsService, diContainer.catsImageService)
)[CatsViewModel::class.java]
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

val view = layoutInflater.inflate(R.layout.activity_main, null) as CatsView
setContentView(view)

catsPresenter = CatsPresenter(diContainer.service)
view.presenter = catsPresenter
catsPresenter.attachView(view)
catsPresenter.onInitComplete()
}
viewModel.populate()

view.setOnButtonClick {
viewModel.populate()


// catsPresenter = CatsPresenter(diContainer.catsService, diContainer.catsImageService)
// view.presenter = catsPresenter
// catsPresenter.attachView(view)
// catsPresenter.onInitComplete()

override fun onStop() {
if (isFinishing) {
catsPresenter.detachView()
}
super.onStop()


val catObserver = Observer <Result> { catResult ->
when(catResult) {
is Result.Error -> view.showErrorToast(catResult.throwable.message.toString())
is Result.Success<*> -> view.populate(catResult.catData as Cat)


}

}
viewModel.uiState.observe(this, catObserver)

// fun onStart() {
// super.onStart()
// viewModel.populate()
// }
//
// override fun onStop() {
// super.onStop()
// }
}
}
}


7 changes: 7 additions & 0 deletions app/src/main/java/otus/homework/coroutines/Result.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package otus.homework.coroutines


sealed class Result {
data class Success<out T>(val catData: T) : Result()
data class Error(val throwable: Throwable) : Result()
}
Loading