<repo_name>JagdishParyani/RetrofitWithApiArchitecture<file_sep>/ApiService.kt
package com.example.retrofit_kotlin

import com.example.apiarchitecture.model.BaseModel
import retrofit2.Call
import retrofit2.http.GET

interface ApiService {

    @GET("/json/movies.json")
    fun getMoviesData() : Call<String>

    @GET("/contacts")
    fun getAllContacts() : Call<String>
    //https://api.androidhive.info/contacts/

}<file_sep>/ApiCLient.kt
package com.example.retrofit_kotlin

import com.google.gson.*
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.lang.reflect.Type

class ApiCLient() {

        private lateinit var mRetrofit: Retrofit
        private val mBaseUrl : String = "https://api.androidhive.info"

        fun getClient(): ApiService {
            val gson = GsonBuilder()
                .registerTypeAdapter(String::class.java, StringDesirializer())
                .create()
            mRetrofit = Retrofit.Builder()
                .baseUrl(mBaseUrl)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build()

            return mRetrofit.create(ApiService::class.java)
        }
    }

class StringDesirializer : JsonDeserializer<String> {
    @Throws(JsonParseException::class)
    override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): String {
        return json.toString()
    }
}
<file_sep>/README.md
# RetrofitWithApiArchitecture
This is a simple Retrofit Api calling Demo with simple Architecture
Here I have uploaded my files directly and not in any folder.
So to follow Structure I suggest you to create relevant multiple packages.
For Eg : All Controller files should be in controller packade.
Thanks
<file_sep>/BaseController.kt
package com.example.apiarchitecture.controller

import android.util.Log
import com.example.apiarchitecture.model.BaseModel
import com.example.retrofit_kotlin.ApiCLient
import com.example.retrofit_kotlin.ApiService
import org.json.JSONArray
import org.json.JSONObject
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

abstract open class BaseController {

    val TAG = "BaseController"
    lateinit var mCallBackListener: CallBackListener
    lateinit var mBaseModel: BaseModel
    lateinit var mApiCLient: ApiCLient
    lateinit var mApiService: ApiService


    fun callRequestToServer(modelCall: Call<String>) {
        //var modelCall: Call<String> = mApiService.getMoviesData()

        modelCall.enqueue(object : Callback<String> {
            override fun onFailure(call: Call<String>, t: Throwable) {
                mCallBackListener.networkConnectionError()
                Log.e(TAG, t.message)
            }

            override fun onResponse(call: Call<String>, response: Response<String>) {
                if (response.code() == 200) {

                     var obj : JSONObject = JSONObject()
                     var jsonResp = JSONArray(response.body())
                     obj.put("data", jsonResp)

                     onPopulate(obj)

                    //onPopulate(JSONObject(response.body()))
                } else {
                    Log.e(TAG, response.code().toString())
                }
            }
        })
    }

    open fun startFetching(callBackListner: CallBackListener) {
        //Log.e(TAG, "Request :" + Gson().toJson(model))
        this.mCallBackListener = callBackListner
        mApiCLient = ApiCLient()
        mApiService = mApiCLient.getClient()
    }

    abstract fun onPopulate(objJson: JSONObject?)
}<file_sep>/MainActivity.kt
package com.example.apiarchitecture

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager
import android.widget.Toast
import com.example.apiarchitecture.adapter.ContactsAdapter
import com.example.apiarchitecture.adapter.MoviesAdapter
import com.example.apiarchitecture.controller.CallBackListener
import com.example.apiarchitecture.controller.ContactsController
import com.example.apiarchitecture.controller.MoviesController
import com.example.apiarchitecture.model.BaseModel
import com.example.apiarchitecture.model.Movies
import com.example.apiarchitecture.model.ResModelContacts
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity(), CallBackListener {

    override fun handleSuccessData(resModel: BaseModel) {

        when (resModel) {
            is Movies -> {
                rcv.apply {
                    layoutManager = LinearLayoutManager(this@MainActivity)
                    adapter = MoviesAdapter((resModel as Movies).data, this@MainActivity)
                }
            }
            is ResModelContacts -> {
                rcv.apply {
                    layoutManager = LinearLayoutManager(this@MainActivity)
                    adapter = ContactsAdapter((resModel as ResModelContacts).contacts, this@MainActivity)
                }
            }
        }
        /*if (resModel is ResModelMovies) {
            rcv.apply {
                layoutManager = LinearLayoutManager(this@MainActivity)
                adapter = MoviesAdapter((resModel as Movies).data, this@MainActivity)
            }
        }
        else if (resModel is ResModelContacts){

            rcv.apply {
                layoutManager = LinearLayoutManager(this@MainActivity)
                adapter = ContactsAdapter((resModel as ResModelContacts).contacts,this@MainActivity)
            }
        }*/
    }

    override fun networkConnectionError() {
        ShowToast("Network Connection Error")
    }

    override fun onserverConnectionError() {
        ShowToast("Server Connection Error")
    }

    override fun handleErrorDataFromServer(errorModel: BaseModel) {
        ShowToast("Error Data From Server")
    }

    fun ShowToast(msg: String) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        btn.setOnClickListener {
            callAPI()
        }

        btn_cont.setOnClickListener {
            callContactsApi()
        }
    }

    private fun callContactsApi() {
        ContactsController().startFetching(this)
    }

    private fun callAPI() {
        MoviesController().startFetching(this)
    }
}
<file_sep>/ContactsController.kt
package com.example.apiarchitecture.controller

import com.example.apiarchitecture.model.Contacts
import com.example.apiarchitecture.model.ResModelContacts
import com.google.gson.Gson
import org.json.JSONObject

class ContactsController : BaseController() {
    override fun onPopulate(objJson: JSONObject?) {
        var contacts : ResModelContacts = Gson().fromJson(objJson.toString(),ResModelContacts::class.java)
        this.mCallBackListener.handleSuccessData(contacts)
    }

    override fun startFetching(callBackListner: CallBackListener) {
        super.startFetching(callBackListner)
        this.mCallBackListener = callBackListner
        callRequestToServer(mApiService.getAllContacts())
    }
}<file_sep>/MoviesAdapter.kt
package com.example.apiarchitecture.adapter

import android.content.Context
import android.support.v7.widget.RecyclerView

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import android.widget.Toast
import com.bumptech.glide.Glide
import com.example.apiarchitecture.R
import com.example.apiarchitecture.model.ResModelMovies

class MoviesAdapter(private val result: List<ResModelMovies>, private val mContext: Context) :
    RecyclerView.Adapter<MoviesAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, position: Int): ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        val v = inflater.inflate(R.layout.list_item, null)
        return ViewHolder(v)
    }

    override fun getItemCount(): Int = result.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        val movie: ResModelMovies = result[position]
        holder.bind(movie, mContext, position)

        holder.titlesTxt.setOnClickListener {
            Toast.makeText(mContext,position.toString(),Toast.LENGTH_SHORT).show()
        }
    }

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var titlesTxt: TextView
        var ratingsTxt: TextView
        var releaseYearsTxt: TextView
        var genresTxt: TextView
        var imgs: ImageView

        init {
            titlesTxt = itemView.findViewById(R.id.titleTxt)
            ratingsTxt = itemView.findViewById(R.id.ratingTxt)
            releaseYearsTxt = itemView.findViewById(R.id.releaseTxt)
            genresTxt = itemView.findViewById(R.id.genreTxt)
            imgs = itemView.findViewById(R.id.img)
        }

        fun bind(movie: ResModelMovies, mContext: Context,pos : Int) {
            titlesTxt.text = "$pos  "+(movie.title)
            ratingsTxt.text = "Rating :" + movie.rating.toString()
            releaseYearsTxt.text = "Year :"+ movie.releaseYear.toString()
            var s = ""
            for (i in movie.genre!!) {
                s = s + i + ","
            }
            s = s.substring(0, s.length - 1)

            genresTxt.text = s

            Glide.with(mContext).load(movie.image).into(imgs);
        }
    }
}<file_sep>/CallBackListener.kt
package com.example.apiarchitecture.controller

import com.example.apiarchitecture.model.BaseModel

interface CallBackListener {

    fun handleSuccessData(resModel: BaseModel)
    fun networkConnectionError()
    fun onserverConnectionError()
    fun handleErrorDataFromServer(errorModel: BaseModel)
}<file_sep>/ReqModelContacts.kt
package com.example.apiarchitecture.model

class ReqModelContacts {
}<file_sep>/ContactsAdapter.kt
package com.example.apiarchitecture.adapter

import android.content.Context
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.example.apiarchitecture.R
import com.example.apiarchitecture.model.Contacts

class ContactsAdapter(private val result: List<Contacts>, private val mContext: Context) :
    RecyclerView.Adapter<ContactsAdapter.ContactsViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, pos: Int): ContactsAdapter.ContactsViewHolder {
        val v = LayoutInflater.from(parent.context).inflate(R.layout.list_contacts, null)
        return ContactsViewHolder(v)
    }

    override fun getItemCount(): Int = result.size

    override fun onBindViewHolder(holder: ContactsViewHolder, pos: Int) {
        val contacts : Contacts =result.get(pos)
        holder.bind(contacts)
    }

    class ContactsViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        var id: TextView
        var name: TextView
        var email: TextView
        var gender: TextView
        var mobile: TextView

        init {
            id = itemView.findViewById(R.id.ids)
            name = itemView.findViewById(R.id.name)
            email = itemView.findViewById(R.id.email)
            gender = itemView.findViewById(R.id.gender)
            mobile = itemView.findViewById(R.id.mobile)
        }

        fun bind(contacts: Contacts) {
            id.text = contacts.id
            name.text = contacts.name
            email.text = contacts.email
            gender.text = contacts.gender
            mobile.text = contacts.phone.mobile
        }
    }
}
<file_sep>/ResModelContacts.kt
package com.example.apiarchitecture.model


data class ResModelContacts(var contacts : List<Contacts>) : BaseModel()

data class Contacts (
    var id : String,
    var name : String,
    var email : String,
    var address : String,
    var gender : String,
    var phone : Phone
) : BaseModel()

data class Phone (
    var mobile : String,
    var home : String,
    var office : String
) : BaseModel()<file_sep>/ReqModelMovies.kt
package com.example.apiarchitecture.model

class ReqModelMovies : BaseModel(){
}<file_sep>/BaseModel.kt
package com.example.apiarchitecture.model

import java.io.Serializable

open class BaseModel : Serializable {
}<file_sep>/ResModelMovies.kt
package com.example.apiarchitecture.model


data class Movies(var data: ArrayList<ResModelMovies>) : BaseModel()

data class ResModelMovies(
    var title: String, var image: String,
    var rating: String, var releaseYear: String,
    var genre: List<String>
) : BaseModel()<file_sep>/MoviesController.kt
package com.example.apiarchitecture.controller

import com.example.apiarchitecture.model.BaseModel
import com.example.apiarchitecture.model.Movies
import com.example.apiarchitecture.model.ReqModelMovies
import com.example.apiarchitecture.model.ResModelMovies
import com.google.gson.Gson
import org.json.JSONArray
import org.json.JSONObject

class MoviesController : BaseController() {

    override fun onPopulate(objJson: JSONObject?) {
        //var objArr: JSONArray = objJson!!.getJSONArray("data")
        var resModelMovies : Movies = Gson().fromJson(objJson.toString(),Movies::class.java)
        this.mCallBackListener.handleSuccessData(resModelMovies)
    }

    override fun startFetching(callBackListner: CallBackListener) {
        super.startFetching(callBackListner)
        this.mCallBackListener = callBackListner
        callRequestToServer(mApiService.getMoviesData())
    }
}