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: 'com.android.application'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
apply plugin: 'kotlin-android-extensions'
|
||||||
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
compileSdkVersion 29
|
||||||
@@ -36,4 +37,33 @@ dependencies {
|
|||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
|
||||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
|
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"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.example.h_mal.candyspace">
|
package="com.example.h_mal.candyspace">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<application
|
<application
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
|||||||
@@ -1,4 +1,37 @@
|
|||||||
package com.example.h_mal.candyspace.data.api
|
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 {
|
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
|
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"
|
android:layout_height="match_parent"
|
||||||
tools:context=".ui.main.MainFragment">
|
tools:context=".ui.main.MainFragment">
|
||||||
|
|
||||||
<TextView
|
<androidx.appcompat.widget.SearchView
|
||||||
android:id="@+id/message"
|
android:id="@+id/search_bar"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="MainFragment"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="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>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|||||||
Reference in New Issue
Block a user