mirror of
https://github.com/hmalik144/Candy_Space_tech_test.git
synced 2026-01-31 02:41:44 +00:00
Gradle dependencies updates, Api class and handling added.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
@@ -36,4 +37,33 @@ dependencies {
|
||||
testImplementation 'junit:junit:4.12'
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
||||
|
||||
//Retrofit and GSON
|
||||
implementation 'com.squareup.retrofit2:retrofit:2.6.0'
|
||||
implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
|
||||
|
||||
//Kotlin Coroutines
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0"
|
||||
|
||||
// ViewModel and LiveData
|
||||
implementation "androidx.lifecycle:lifecycle-extensions:2.1.0"
|
||||
|
||||
//New Material Design
|
||||
implementation 'com.google.android.material:material:1.1.0-alpha10'
|
||||
|
||||
//Kodein Dependency Injection
|
||||
implementation "org.kodein.di:kodein-di-generic-jvm:6.2.1"
|
||||
implementation "org.kodein.di:kodein-di-framework-android-x:6.2.1"
|
||||
|
||||
//Android Room
|
||||
implementation "androidx.room:room-runtime:2.2.0-rc01"
|
||||
implementation "androidx.room:room-ktx:2.2.0-rc01"
|
||||
kapt "androidx.room:room-compiler:2.2.0-rc01"
|
||||
|
||||
implementation 'com.xwray:groupie:2.3.0'
|
||||
implementation 'com.xwray:groupie-kotlin-android-extensions:2.3.0'
|
||||
implementation 'com.xwray:groupie-databinding:2.3.0'
|
||||
|
||||
implementation "androidx.preference:preference-ktx:1.1.0"
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.example.h_mal.candyspace">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
|
||||
@@ -1,4 +1,37 @@
|
||||
package com.example.h_mal.candyspace.data.api
|
||||
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import retrofit2.Response
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.gson.GsonConverterFactory
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Query
|
||||
|
||||
|
||||
interface ApiClass {
|
||||
|
||||
@GET("users?")
|
||||
suspend fun getUsersFromApi(@Query("inname") inname: String): Response<User>
|
||||
|
||||
companion object{
|
||||
operator fun invoke(
|
||||
networkConnectionInterceptor: NetworkConnectionInterceptor,
|
||||
queryParamsInterceptor: QueryParamsInterceptor
|
||||
) : ApiClass{
|
||||
|
||||
val okkHttpclient = OkHttpClient.Builder()
|
||||
.addNetworkInterceptor(networkConnectionInterceptor)
|
||||
.addInterceptor(queryParamsInterceptor)
|
||||
.build()
|
||||
|
||||
return Retrofit.Builder()
|
||||
.client(okkHttpclient)
|
||||
.baseUrl("https://api.stackexchange.com/2.2/")
|
||||
.addConverterFactory(GsonConverterFactory.create())
|
||||
.build()
|
||||
.create(ApiClass::class.java)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.example.h_mal.candyspace.data.api
|
||||
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import java.io.IOException
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
*/
|
||||
class NetworkConnectionInterceptor(
|
||||
context: Context
|
||||
) : Interceptor {
|
||||
|
||||
private val applicationContext = context.applicationContext
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
if (!isInternetAvailable()){
|
||||
throw IOException("Make sure you have an active data connection")
|
||||
}
|
||||
return chain.proceed(chain.request())
|
||||
}
|
||||
|
||||
private fun isInternetAvailable(): Boolean {
|
||||
var result = false
|
||||
val connectivityManager =
|
||||
applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
|
||||
connectivityManager?.let {
|
||||
it.getNetworkCapabilities(connectivityManager.activeNetwork)?.apply {
|
||||
result = when {
|
||||
hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
|
||||
hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.example.h_mal.candyspace.data.api
|
||||
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
|
||||
|
||||
class QueryParamsInterceptor : Interceptor{
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val original = chain.request()
|
||||
val originalHttpUrl = original.url()
|
||||
|
||||
val url = originalHttpUrl.newBuilder()
|
||||
.addQueryParameter("site", "stackoverflow")
|
||||
.addQueryParameter("pagesize","20")
|
||||
.addQueryParameter("order","desc")
|
||||
.addQueryParameter("sort","reputation")
|
||||
.build()
|
||||
|
||||
// Request customization: add request headers
|
||||
// Request customization: add request headers
|
||||
val requestBuilder: Request.Builder = original.newBuilder()
|
||||
.url(url)
|
||||
|
||||
val request: Request = requestBuilder.build()
|
||||
return chain.proceed(request)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.example.h_mal.candyspace.data.api
|
||||
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import retrofit2.Response
|
||||
import java.io.IOException
|
||||
|
||||
abstract class ResponseUnwrap {
|
||||
|
||||
suspend fun<T: Any> apiRequest(call: suspend () -> Response<T>) : T{
|
||||
|
||||
val response = call.invoke()
|
||||
if(response.isSuccessful){
|
||||
return response.body()!!
|
||||
}else{
|
||||
val error = response.errorBody()?.string()
|
||||
|
||||
val message = StringBuilder()
|
||||
error?.let{
|
||||
try{
|
||||
message.append(JSONObject(it).getString("error_message"))
|
||||
}catch(e: JSONException){ }
|
||||
message.append("\n")
|
||||
}
|
||||
message.append("Error Code: ${response.code()}")
|
||||
throw IOException(message.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.example.h_mal.candyspace.data.api
|
||||
|
||||
import com.google.gson.annotations.Expose
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
|
||||
class User {
|
||||
@SerializedName("last_modified_date")
|
||||
@Expose
|
||||
var lastModifiedDate: Int? = null
|
||||
@SerializedName("reputation")
|
||||
@Expose
|
||||
var reputation: Int? = null
|
||||
@SerializedName("creation_date")
|
||||
@Expose
|
||||
var creationDate: Int? = null
|
||||
@SerializedName("user_type")
|
||||
@Expose
|
||||
var userType: String? = null
|
||||
@SerializedName("user_id")
|
||||
@Expose
|
||||
var userId: Int? = null
|
||||
@SerializedName("location")
|
||||
@Expose
|
||||
var location: String? = null
|
||||
@SerializedName("website_url")
|
||||
@Expose
|
||||
var websiteUrl: String? = null
|
||||
@SerializedName("link")
|
||||
@Expose
|
||||
var link: String? = null
|
||||
@SerializedName("profile_image")
|
||||
@Expose
|
||||
var profileImage: String? = null
|
||||
@SerializedName("display_name")
|
||||
@Expose
|
||||
var displayName: String? = null
|
||||
}
|
||||
@@ -1,5 +1,14 @@
|
||||
package com.example.h_mal.candyspace.data.repositories
|
||||
|
||||
class Repository {
|
||||
import com.example.h_mal.candyspace.data.api.ApiClass
|
||||
import com.example.h_mal.candyspace.data.api.ResponseUnwrap
|
||||
import com.example.h_mal.candyspace.data.api.User
|
||||
|
||||
class Repository(
|
||||
private val api: ApiClass
|
||||
): ResponseUnwrap() {
|
||||
|
||||
suspend fun sdasda(username: String): User {
|
||||
return apiRequest { api.getUsersFromApi(username) }
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,24 @@
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".ui.main.MainFragment">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/message"
|
||||
android:layout_width="wrap_content"
|
||||
<androidx.appcompat.widget.SearchView
|
||||
android:id="@+id/search_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="MainFragment"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"/>
|
||||
|
||||
<view class="androidx.appcompat.app.AlertController$RecycleListView"
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/search_bar"
|
||||
tools:listitem="@android:layout/simple_list_item_2">
|
||||
|
||||
</view>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
Reference in New Issue
Block a user