-
Notifications
You must be signed in to change notification settings - Fork 1
TE7-T893: Add OkHttp and GSON #24
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: feature/TE7-T1049_WebServiceWithoutLibrary
Are you sure you want to change the base?
Changes from all commits
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 |
|---|---|---|
|
|
@@ -28,6 +28,13 @@ class MainActivity : AppCompatActivity() { | |
| installSplashScreen() | ||
| setupTheme() | ||
| setContentView(binding.root) | ||
| setupHostFragment() | ||
| } | ||
|
|
||
| private fun setupHostFragment() { | ||
| supportFragmentManager.commit { | ||
| replace(R.id.hostFragmentContainer, HostFragment::class.java, null) | ||
| } | ||
| } | ||
|
|
||
| private fun setupTheme() { | ||
|
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. 🤖 AIReviewRadar Here are my comments on the code changes:
Overall, the code changes look good, but please make the necessary adjustments mentioned above. |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,6 +2,19 @@ package com.krunal.demo.utils | |
|
|
||
| object AppConstants { | ||
|
|
||
| /** | ||
| * Log Tag | ||
| */ | ||
| const val TAG = "Demo" | ||
|
|
||
| /** | ||
| * News | ||
| */ | ||
| const val NEWS_API_KEY = "fa3d5d7db3f8448dac9f98e82f1108ce" | ||
| const val NEST_BASE_URL = "https://newsapi.org/v2" | ||
| const val NEWS_BASE_URL = "https://newsapi.org/v2" | ||
|
|
||
| /** | ||
| * User | ||
| */ | ||
| const val MOCKAPI_BASE_URL = "https://6482a62bf2e76ae1b95b5f48.mockapi.io/v1" | ||
| } | ||
|
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. 🤖 AIReviewRadar The code changes look good. Here are a few suggestions:
Updated code: /**
* News Base URL
*/
const val NEWS_BASE_URL = "https://newsapi.org/v2"Other than that, everything looks fine. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| package com.krunal.demo.webservices.gsonokhttp.data.apis | ||
|
|
||
| import com.google.gson.GsonBuilder | ||
| import com.google.gson.JsonParseException | ||
| import com.krunal.demo.utils.AppConstants | ||
| import com.krunal.demo.webservices.gsonokhttp.data.models.api.UserDetail | ||
| import com.krunal.demo.webservices.utils.Resource | ||
| import kotlinx.coroutines.Dispatchers | ||
| import kotlinx.coroutines.flow.flow | ||
| import kotlinx.coroutines.flow.flowOn | ||
| import kotlinx.coroutines.withContext | ||
| import okhttp3.MediaType.Companion.toMediaType | ||
| import okhttp3.OkHttpClient | ||
| import okhttp3.Request | ||
| import okhttp3.RequestBody.Companion.toRequestBody | ||
| import java.io.IOException | ||
|
|
||
| object UserProfileApi { | ||
|
|
||
| private const val USER_URL = "${AppConstants.MOCKAPI_BASE_URL}/users" | ||
| private const val DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ssZ" | ||
|
|
||
| private val client = OkHttpClient() | ||
|
|
||
| suspend fun getAllUsers() = flow<Resource<List<UserDetail>>> { | ||
| emit(Resource.Loading()) | ||
| val request = Request.Builder().url(USER_URL).get().build() | ||
|
|
||
| try { | ||
| val response = client.newCall(request).execute() | ||
| Resource.Success("") | ||
|
|
||
| if (!response.isSuccessful) { | ||
| emit(Resource.Error(response.message)) | ||
| } | ||
|
|
||
| response.body?.string()?.let { body -> | ||
| val gson = GsonBuilder().setDateFormat(DATE_FORMAT).create() | ||
|
|
||
| val users = gson.fromJson(body, Array<UserDetail>::class.java).toList() | ||
| emit(Resource.Success(users)) | ||
| } | ||
|
|
||
| } catch (e: JsonParseException) { | ||
| emit(Resource.Error(e.message ?: "Can't parse response")) | ||
| } catch (e: IOException) { | ||
| emit(Resource.Error(e.message ?: "Can't make request")) | ||
| } | ||
| }.flowOn(Dispatchers.IO) | ||
|
|
||
| suspend fun getUser(userId: Int) = flow<Resource<UserDetail>> { | ||
| val request = Request.Builder().url("$USER_URL/$userId").get().build() | ||
|
|
||
| try { | ||
| val response = client.newCall(request).execute() | ||
| Resource.Success("") | ||
|
|
||
| if (!response.isSuccessful) { | ||
| emit(Resource.Error(response.message)) | ||
| } | ||
|
|
||
| response.body?.string()?.let { body -> | ||
| val gson = GsonBuilder().setDateFormat(DATE_FORMAT).create() | ||
|
|
||
| val user = gson.fromJson(body, UserDetail::class.java) | ||
| emit(Resource.Success(user)) | ||
| } | ||
|
|
||
| } catch (e: JsonParseException) { | ||
| emit(Resource.Error(e.message ?: "Can't parse response")) | ||
| } catch (e: IOException) { | ||
| emit(Resource.Error(e.message ?: "Can't make request")) | ||
| } | ||
| }.flowOn(Dispatchers.IO) | ||
|
|
||
| suspend fun registerUser(userDetail: UserDetail) { | ||
| withContext(Dispatchers.IO) { | ||
| val gson = GsonBuilder().setDateFormat(DATE_FORMAT).create() | ||
| val user = gson.toJson(userDetail, UserDetail::class.java) | ||
| val body = user.toRequestBody("application/json".toMediaType()) | ||
| val request = Request.Builder().url(USER_URL).post(body) | ||
| .addHeader("Content-Type", "application/json").build() | ||
|
|
||
| client.newCall(request).execute() | ||
| } | ||
| } | ||
|
|
||
| suspend fun updateUser(userDetail: UserDetail) { | ||
| withContext(Dispatchers.IO) { | ||
| val gson = GsonBuilder().setDateFormat(DATE_FORMAT).create() | ||
| val user = gson.toJson(userDetail, UserDetail::class.java) | ||
| val body = user.toRequestBody("application/json".toMediaType()) | ||
| val request = Request.Builder().url("$USER_URL/${userDetail.userId}") | ||
| .put(body) | ||
| .addHeader("Content-Type", "application/json").build() | ||
|
|
||
| client.newCall(request).execute() | ||
| } | ||
| } | ||
|
|
||
| suspend fun deleteUser(userId: Int) { | ||
| withContext(Dispatchers.IO) { | ||
| val request = Request.Builder().url("$USER_URL/${userId}") | ||
| .delete() | ||
| .build() | ||
|
|
||
| client.newCall(request).execute() | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package com.krunal.demo.webservices.gsonokhttp.data.models.api | ||
|
|
||
| data class Movie( | ||
| val name: String | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package com.krunal.demo.webservices.gsonokhttp.data.models.api | ||
|
|
||
| import com.google.gson.annotations.SerializedName | ||
| import java.util.Date | ||
|
|
||
| data class UserDetail( | ||
| @SerializedName("id") | ||
| val userId: Int? = null, | ||
| val name: String? = null, | ||
| @SerializedName("avatar") | ||
| val avatarUrl: String? = null, | ||
| val email: String? = null, | ||
| val dob: Date? = null, | ||
| val favoriteMovies: List<Movie> = emptyList() | ||
| ) | ||
|
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. 🤖 AIReviewRadar The code changes look good. There are no syntax errors or logic errors in the code. However, I noticed that there is no newline at the end of the file. It's a good practice to have a newline at the end of each file. Please add a newline at the end of the file. Other than that, the code looks fine. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| package com.krunal.demo.webservices.gsonokhttp.data.models.local | ||
|
|
||
| import androidx.databinding.BaseObservable | ||
| import androidx.databinding.Bindable | ||
| import com.krunal.demo.BR | ||
| import java.util.Date | ||
|
|
||
| data class UserRegistration( | ||
| var userId: Int? = null, | ||
| private var _name: String? = null, | ||
| private var _email: String? = null, | ||
| private var _dob: Date? = null, | ||
| private var _movies: String? = null | ||
| ) : BaseObservable() { | ||
|
|
||
| @get:Bindable | ||
| var name: String? = _name | ||
| set(value) { | ||
| _name = value | ||
| field = value | ||
| notifyPropertyChanged(BR.name) | ||
| } | ||
|
|
||
| @get:Bindable | ||
| var email: String? = _email | ||
| set(value) { | ||
| _email = value | ||
| field = value | ||
| notifyPropertyChanged(BR.email) | ||
| } | ||
|
|
||
| @get:Bindable | ||
| var dob: Date? = _dob | ||
| set(value) { | ||
| _dob = value | ||
| field = value | ||
| notifyPropertyChanged(BR.dob) | ||
| } | ||
|
|
||
| @get:Bindable | ||
| var movies: String? = _movies | ||
| set(value) { | ||
| _movies = value | ||
| field = value | ||
| notifyPropertyChanged(BR.movies) | ||
| } | ||
| } | ||
|
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. 🤖 AIReviewRadar The code changes look good. Here are a few suggestions:
Other than these suggestions, the code looks fine. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| package com.krunal.demo.webservices.gsonokhttp.repositories | ||
|
|
||
| import com.krunal.demo.webservices.gsonokhttp.data.apis.UserProfileApi | ||
| import com.krunal.demo.webservices.gsonokhttp.data.models.api.UserDetail | ||
| import com.krunal.demo.webservices.utils.Resource | ||
| import kotlinx.coroutines.flow.Flow | ||
|
|
||
| object UserRepository { | ||
|
|
||
| suspend fun getAllUsers(): Flow<Resource<List<UserDetail>>> { | ||
| return UserProfileApi.getAllUsers() | ||
| } | ||
|
|
||
| suspend fun getUser(userId: Int): Flow<Resource<UserDetail>> { | ||
| return UserProfileApi.getUser(userId) | ||
| } | ||
|
|
||
| suspend fun registerUser(userDetail: UserDetail) { | ||
| UserProfileApi.registerUser(userDetail) | ||
| } | ||
|
|
||
| suspend fun updateUser(userDetail: UserDetail) { | ||
| UserProfileApi.updateUser(userDetail) | ||
| } | ||
|
|
||
| suspend fun deleteUser(userId: Int) { | ||
| UserProfileApi.deleteUser(userId) | ||
| } | ||
| } | ||
|
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. 🤖 AIReviewRadar The code changes in the Here are a few suggestions:
Other than these suggestions, the code looks fine. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| package com.krunal.demo.webservices.gsonokhttp.ui.adapters | ||
|
|
||
| import android.annotation.SuppressLint | ||
| import android.view.LayoutInflater | ||
| import android.view.ViewGroup | ||
| import androidx.recyclerview.widget.RecyclerView | ||
| import com.krunal.demo.databinding.ItemUserDetailBinding | ||
| import com.krunal.demo.webservices.gsonokhttp.data.models.api.UserDetail | ||
|
|
||
| class UserAdapter(private val onClick: (userDetail: UserDetail) -> Unit) : RecyclerView.Adapter<UserAdapter.UserDetailHolder>() { | ||
|
|
||
| private val newsList: MutableList<UserDetail> = mutableListOf() | ||
|
|
||
| class UserDetailHolder( | ||
| private val binding: ItemUserDetailBinding, | ||
| val onClick: (UserDetail) -> Unit | ||
| ) : RecyclerView.ViewHolder(binding.root) { | ||
|
|
||
| fun bind(userDetail: UserDetail) { | ||
| binding.userDetail = userDetail | ||
| binding.root.setOnClickListener { | ||
| onClick(userDetail) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): UserDetailHolder { | ||
| val layoutInflater = LayoutInflater.from(parent.context) | ||
| val binding = ItemUserDetailBinding.inflate(layoutInflater, parent, false) | ||
| return UserDetailHolder(binding, onClick) | ||
| } | ||
|
|
||
| override fun getItemCount(): Int = newsList.count() | ||
|
|
||
| override fun onBindViewHolder(holder: UserDetailHolder, position: Int) { | ||
| holder.bind(newsList[position]) | ||
| } | ||
|
|
||
| @SuppressLint("NotifyDataSetChanged") | ||
| fun submitList(list: List<UserDetail>) { | ||
| newsList.clear() | ||
| newsList.addAll(list) | ||
| notifyDataSetChanged() | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| package com.krunal.demo.webservices.gsonokhttp.ui.dialogs | ||
|
|
||
| import android.app.Dialog | ||
| import android.os.Bundle | ||
| import androidx.appcompat.app.AlertDialog | ||
| import androidx.fragment.app.DialogFragment | ||
| import com.krunal.demo.R | ||
|
|
||
| class DeleteConfirmationDialog(private val onConfirm: () -> Unit) : DialogFragment() { | ||
|
|
||
| override fun onCreateDialog(savedInstanceState: Bundle?): Dialog = | ||
| AlertDialog.Builder(requireContext()) | ||
| .setMessage(getString(R.string.delete_confirmation)) | ||
| .setCancelable(true) | ||
| .setPositiveButton(getString(R.string.ok)) { _, _ -> onConfirm() } | ||
| .create() | ||
|
|
||
| companion object { | ||
| const val TAG = "DeleteConfirmationDialog" | ||
| } | ||
| } | ||
|
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. 🤖 AIReviewRadar The code changes in the However, I noticed a couple of potential improvements:
Here's the updated code with these improvements: @@ -9,7 +9,7 @@ import androidx.fragment.app.DialogFragment
import com.krunal.demo.R
class DeleteConfirmationDialog(private val onConfirm: () -> Unit) : DialogFragment() {
- override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
return AlertDialog.Builder(context)
.setMessage(getString(R.string.delete_confirmation))
.setCancelable(true)
@@ -17,6 +17,7 @@ class DeleteConfirmationDialog(private val onConfirm: () -> Unit) : DialogFragme
.setPositiveButton(getString(R.string.ok)) { _, _ -> onConfirm() }
+ .setNegativeButton(getString(R.string.cancel)) { _, _ -> }
.create()
}
Other than that, the code looks good and is ready for review. |
||
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.
🤖 AIReviewRadar
The code changes in the
build.gradlefile look good. The added dependencies for Gson and OkHttp3 seem appropriate and necessary for the application. There are no syntax errors or other issues in this code.However, it's worth noting that the version numbers for Gson (2.10.1) and OkHttp3 (4.10.0) may become outdated over time. It's a good practice to periodically check for updates to these libraries and use the latest stable versions to ensure compatibility and take advantage of any bug fixes or new features.
Overall, this change seems fine and can be merged.