Skip to content

Commit

Permalink
Implemented MVVM architecture to the application
Browse files Browse the repository at this point in the history
  • Loading branch information
ayanchavand committed Dec 27, 2023
1 parent 398f543 commit 2a1b8b1
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 117 deletions.
7 changes: 7 additions & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ dependencies {

//gson
implementation("com.google.code.gson:gson:2.8.7")

implementation ("androidx.room:room-runtime:2.4.0")
annotationProcessor ("androidx.room:room-compiler:2.4.0")


implementation ("androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0")

implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.11.0")
Expand Down
109 changes: 109 additions & 0 deletions app/src/main/java/com/example/app/CatViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package com.example.app

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.IOException

class CatViewModel: ViewModel() {


var URL: String =""
// Function to make an asynchronous HTTP request
private suspend fun httpReq(apiKey: String, url: String): String = withContext(Dispatchers.IO) {
val client = OkHttpClient()
val request = Request.Builder().url(url).build()

return@withContext try {
// Execute the HTTP request synchronously and get the response
client.newCall(request).execute().use { response ->
if (response.isSuccessful) {
// Return the response body as a string
response.body!!.string()
} else { // Throw an exception for unexpected HTTP codes
throw IOException("Unexpected HTTP code: ${response.code}")
}
}
} catch (e: IOException) {
// Throw an exception for errors during the HTTP request
throw IOException("Error during HTTP request", e)
}
}

// Function to parse JSON response for cat image
private fun jsonParserCat(responseString: String): String {
val gson = Gson()
val catDataArray = gson.fromJson(responseString, Array<CatData>::class.java)

// Check if the array is not null and not empty
if (catDataArray != null && catDataArray.isNotEmpty()) {
// Assuming you want the first element of the array
val imageUrl = catDataArray[0].url
Log.d("LOG", imageUrl)
return imageUrl
} else {
// Handle the case when the array is null or empty
return ""
}
}

// Function to parse JSON response for dog image
private fun jsonParserDog(responseString: String): String {
val gson = Gson()
val dogData = gson.fromJson(responseString, DogData::class.java)

// Return the dog image URL
return dogData.message
}

fun dogButtonClick(
onSuccess: (String) -> Unit,
onError: (String) -> Unit) {

viewModelScope.launch {
try {
// Make an asynchronous HTTP request for dog image
val response = httpReq("", "https://dog.ceo/api/breeds/image/random")
val imageUrl = jsonParserDog(response)
Log.d("LOG!", imageUrl)
URL = imageUrl
onSuccess(imageUrl)
} catch (e: Exception) {
// Handle exceptions, e.g., network errors
Log.e("LOG!", "Error fetching data", e)
onError("Error fetching data")

}
}
}

fun catButtonHandler(
onSuccess: (String) -> Unit,
onError: (String) -> Unit){

viewModelScope.launch {
try {
// Make an asynchronous HTTP request for cat image
val response = httpReq("null", "https://api.thecatapi.com/v1/images/search")
Log.d("LOG!", response)
// Parse the JSON response to get the image URL
val imageUrl = jsonParserCat(response)
Log.d("LOG!", imageUrl)
URL = imageUrl
onSuccess(imageUrl)
} catch (e: Exception) {
// Handle exceptions, e.g., network errors
Log.e("LOG!", "Error fetching data", e)
onError("Error fetching data")
}
}

}

}
143 changes: 28 additions & 115 deletions app/src/main/java/com/example/app/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,14 @@ import android.widget.Switch
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.ViewModelProvider
import com.bumptech.glide.Glide
import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import okhttp3.Request
import java.io.IOException


class MainActivity : AppCompatActivity() {

private lateinit var catViewModel: CatViewModel

override fun onCreate(savedInstanceState: Bundle?) {
// Log message for debugging
Log.d("LOG", "Hello")
Expand All @@ -39,8 +34,11 @@ class MainActivity : AppCompatActivity() {
val apiToggle: Switch = findViewById(R.id.apiToggle)
val apiText: TextView = findViewById(R.id.apiText)
val download: ImageButton = findViewById(R.id.download)
val like: Button = findViewById(R.id.like)

var URL: String = ""

var URL: String = "";
catViewModel = ViewModelProvider(this)[CatViewModel::class.java]

// Function to display Toast messages
fun showToast(message: String) {
Expand All @@ -49,124 +47,39 @@ class MainActivity : AppCompatActivity() {

// Click listener for the "Submit Cat" button
submitCat.setOnClickListener {
// Coroutine launched on the main thread
lifecycleScope.launch(Dispatchers.Main) {
// Clear the image
Glide.with(this@MainActivity).clear(image)

if (apiToggle.isChecked()) {
// API toggle is checked, load cat image from "cataas.com"
apiText.text = "API: cataas.com"
val imageUrl = "https://cataas.com/cat?timestamp=${System.currentTimeMillis()}"
Glide.with(this@MainActivity).load(imageUrl).into(image)
} else {
// API toggle is not checked, load cat image from "thecatapi.com"
apiText.text = "API: thecatapi.com"
try {
// Make an asynchronous HTTP request for cat image
val response = httpReq("null", "https://api.thecatapi.com/v1/images/search")
Log.d("LOG!", response)

// Parse the JSON response to get the image URL
val imageUrl = jsonParserCat(response)
Log.d("LOG!", imageUrl)

// Load the cat image using Glide
Glide.with(this@MainActivity).load(imageUrl).into(image)
URL = imageUrl
} catch (e: Exception) {
// Handle exceptions, e.g., network errors
Log.e("LOG!", "Error fetching data", e)

// Show a Toast message for error notification
showToast("Something went wrong: Error fetching data")
}
apiText.text = "API: thecatapi.com"
catViewModel.catButtonHandler(
onSuccess = {imageUrl ->
Glide.with(this).load(imageUrl).into(image)
},
onError = { error ->
// Show a Toast message for error notification
showToast("Something went wrong: $error")
}
}
)
}

// Click listener for the "Submit Dog" button
submitDog.setOnClickListener {
// Coroutine launched on the main thread
lifecycleScope.launch(Dispatchers.Main) {
// Update the API text
apiText.text = "API: dog.ceo"
try {
// Make an asynchronous HTTP request for dog image
val response = httpReq("", "https://dog.ceo/api/breeds/image/random")
val imageUrl = jsonParserDog(response)
Log.d("LOG!", imageUrl)

// Load the dog image using Glide
Glide.with(this@MainActivity).load(imageUrl).into(image)
URL = imageUrl
} catch (e: Exception) {
// Handle exceptions, e.g., network errors
Log.e("LOG!", "Error fetching data", e)

// Update the API text
apiText.text = "API: dog.ceo"
catViewModel.dogButtonClick(
onSuccess = { imageUrl ->
Glide.with(this@MainActivity).load(imageUrl).into(image)},
onError = {error ->
// Show a Toast message for error notification
showToast("Something went wrong: Error fetching data")
showToast("Something went wrong: $error")
}
}
)
}

download.setOnClickListener {
if(URL == ""){
showToast("No image loaded")
}
else{
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(URL))
if (catViewModel.URL.isBlank()) {
showToast("No image loaded")
} else {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(catViewModel.URL))
startActivity(intent)
}

}
}
}

// Function to make an asynchronous HTTP request
private suspend fun httpReq(apiKey: String, url: String): String = withContext(Dispatchers.IO) {
val client = OkHttpClient()
val request = Request.Builder().url(url).build()

return@withContext try {
// Execute the HTTP request synchronously and get the response
client.newCall(request).execute().use { response ->
if (response.isSuccessful) {
// Return the response body as a string
response.body!!.string()
} else { // Throw an exception for unexpected HTTP codes
throw IOException("Unexpected HTTP code: ${response.code}")
}
}
} catch (e: IOException) {
// Throw an exception for errors during the HTTP request
throw IOException("Error during HTTP request", e)
}
}

// Function to parse JSON response for cat image
private fun jsonParserCat(responseString: String): String {
val gson = Gson()
val catDataArray = gson.fromJson(responseString, Array<CatData>::class.java)

// Check if the array is not null and not empty
if (catDataArray != null && catDataArray.isNotEmpty()) {
// Assuming you want the first element of the array
val imageUrl = catDataArray[0].url
Log.d("LOG", imageUrl)
return imageUrl
} else {
// Handle the case when the array is null or empty
return ""
}
}

// Function to parse JSON response for dog image
private fun jsonParserDog(responseString: String): String {
val gson = Gson()
val dogData = gson.fromJson(responseString, DogData::class.java)

// Return the dog image URL
return dogData.message
}

14 changes: 12 additions & 2 deletions app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,22 @@

<ImageButton
android:id="@+id/download"
android:layout_width="67dp"
android:layout_height="61dp"
android:layout_width="91dp"
android:layout_height="60dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.52"
app:layout_constraintStart_toEndOf="@+id/submitCat"
app:srcCompat="@android:drawable/stat_sys_download"
tools:layout_editor_absoluteY="533dp" />

<Button
android:id="@+id/like"
android:layout_width="96dp"
android:layout_height="53dp"
android:text=" 💗"
app:layout_constraintEnd_toStartOf="@+id/submitCat"
app:layout_constraintHorizontal_bias="0.433"
app:layout_constraintStart_toStartOf="parent"
tools:layout_editor_absoluteY="540dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

0 comments on commit 2a1b8b1

Please sign in to comment.