Aplicación Todo en Kotlin

App en Kotlin que se comunica con el API Rest creado en laravel.alumno.me

¿Esquema de la red?

Aplicación en Kotlin

ApiService

interface ApiService {
    //@POST("api/register")
    @FormUrlEncoded
    @POST("api/register")
    suspend fun register(
        @Field("name") name: String?,
        @Field("email") email: String?,
        @Field("password") password: String?,
        @Field("confirm_password") confirmPassword: String?
    ): Response<RegisterResponse?>


    //@POST("api/login")
    @FormUrlEncoded
    @POST("api/login")
    suspend fun login(
        @Field("email") email: String?,
        @Field("password") password: String?
    ): Response<LoginResponse?>

}

ApiRestClient

object ApiRestClient {
    private var API_SERVICE: ApiService? = null
    const val BASE_URL = Configuration.BASE_URL

    @get:Synchronized
    val instance: ApiService?
        get() {
            if (API_SERVICE == null) {
                val okHttpBuilder: Builder = Builder()
                    .connectTimeout(10, TimeUnit.SECONDS)
                    .readTimeout(10, TimeUnit.SECONDS)
                    .writeTimeout(5, TimeUnit.SECONDS)

                val gson = GsonBuilder()
                    .setDateFormat("dd-MM-yyyy")
                    .create()

                val retrofit = Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create(gson))
                    .client(okHttpBuilder.build())
                    .build()

                API_SERVICE = retrofit.create(ApiService::class.java)
            }
            return API_SERVICE
        }
}

ApiTokenService

interface ApiTokenService {
    @POST("api/logout")
    //@Header("Authorization") String token
    suspend fun logout(): Response<LogoutResponse?>

    // @get:GET("api/tasks")
    //@Header("Authorization") String token
    //val tasks: Response<GetTasksResponse?>

    @GET("api/tasks")
    //@Header("Authorization") String token
    suspend fun getTasks(): Response<GetTasksResponse?>

    @POST("api/tasks")
    //@Header("Authorization") String token,
    suspend fun createTask(
        @Body task: Task?
    ): Response<AddResponse?>

    @PUT("api/tasks/{id}")
    //@Header("Authorization") String token,
    suspend fun updateTask(
        @Body task: Task?,
        @Path("id") id: Long
    ): Response<AddResponse?>

    @DELETE("api/tasks/{id}")
    //@Header("Authorization") String token,
    suspend fun deleteTask(
        @Path("id") id: Long?
    ): Response<DeleteResponse?>

    @POST("api/email")
    suspend fun sendEmail(@Body email: Email?): Response<EmailResponse?>
}

ApiTokenRestClient

object ApiTokenRestClient {
    private var API_SERVICE: ApiTokenService? = null
    const val BASE_URL = Configuration.BASE_URL

    @Synchronized
    fun getInstance(token: String?): ApiTokenService? {

        if (API_SERVICE == null) {
            val interceptor = Interceptor { chain ->
                val newRequest = chain.request().newBuilder()
                    .addHeader("Accept", "application/json")
                    .addHeader("authorization", "Bearer $token")
                    .build()
                chain.proceed(newRequest)
            }

            val okHttpBuilder: Builder = Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(5, TimeUnit.SECONDS)
                .addInterceptor(interceptor)

            val gson = GsonBuilder()
                .setDateFormat("dd-MM-yyyy")
                .create()

            val retrofit = Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .client(okHttpBuilder.build())
                .build()

            API_SERVICE = retrofit.create(ApiTokenService::class.java)
        }
        return API_SERVICE
    }

    fun deleteInstance() {
        API_SERVICE = null
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/linearLayout3"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:fitsSystemWindows="true">

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:layout_marginStart="104dp"
        android:layout_marginTop="40dp"
        android:layout_marginEnd="100dp"
        android:layout_marginBottom="65dp"
        android:src="@drawable/tasks_image"
        app:layout_constraintBottom_toTopOf="@+id/email"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.611"
        app:layout_constraintStart_toStartOf="@+id/textViewUpdate"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="12dp"
        android:layout_marginEnd="7dp"
        android:text="Email"
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        app:layout_constraintEnd_toStartOf="@+id/email"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@+id/email" />

    <EditText
        android:id="@+id/email"
        android:layout_width="315dp"
        android:layout_height="51dp"
        android:layout_marginEnd="11dp"
        android:layout_marginBottom="24dp"
        android:ems="10"
        android:inputType="textEmailAddress"
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        app:layout_constraintBottom_toTopOf="@+id/password"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textViewUpdate"
        app:layout_constraintTop_toBottomOf="@+id/imageView"
        android:text="paco.portada@protonmail.com" />

    <TextView
        android:id="@+id/textViewUpdate"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="12dp"
        android:layout_marginBottom="12dp"
        android:text="Password"
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        app:layout_constraintBottom_toBottomOf="@+id/password"
        app:layout_constraintEnd_toStartOf="@+id/password"
        app:layout_constraintStart_toStartOf="parent" />

    <EditText
        android:id="@+id/password"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="15dp"
        android:layout_marginBottom="94dp"
        android:ems="10"
        android:inputType="textPassword"
        android:text="123456"
        android:textAppearance="@style/TextAppearance.AppCompat.Large"
        app:layout_constraintBottom_toTopOf="@+id/login"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/textViewUpdate"
        app:layout_constraintTop_toBottomOf="@+id/email" />

    <Button
        android:id="@+id/login"
        android:layout_width="319dp"
        android:layout_height="57dp"
        android:layout_marginStart="51dp"
        android:layout_marginTop="48dp"
        android:layout_marginEnd="51dp"
        android:background="@color/design_default_color_primary_dark"
        android:padding="12dp"
        android:text="Login"
        android:textColor="@color/white"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/password" />

    <Button
        android:id="@+id/register"
        android:layout_width="193dp"
        android:layout_height="53dp"
        android:layout_marginBottom="172dp"
        android:background="@color/colorAccent"
        android:padding="12dp"
        android:text="Register"
        android:textColor="@android:color/white"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.541"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/login"
        app:layout_constraintVertical_bias="0.756" />

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity

class MainActivity : AppCompatActivity(), View.OnClickListener {
    lateinit var preferences: SharedPreferencesManager
    private lateinit var progressDialog: ProgressDialog
    private lateinit var binding: ActivityMainBinding

    companion object {
        const val APP = "ToDo App"
        const val EMAIL = "email"
        const val PASSWORD = "password"
        const val TOKEN = "token"
        private const val TAG = "LoginActivity"
        private const val REQUEST_REGISTER = 1
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //activity_main.xml -> ActivityMainBinding
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view: View = binding!!.root
        setContentView(view)
        preferences = SharedPreferencesManager(this)
        binding!!.email.setText(preferences!!.email)
        binding!!.password.setText(preferences!!.password)
        binding!!.login.setOnClickListener(this)
        binding!!.register.setOnClickListener(this)
    }

    override fun onClick(v: View) {
        hideSoftKeyboard()
        if (v === binding!!.login) {
            if (validate() == false) {
                showMessage("Error al validar los datos")
            } else {
                loginByServer()
            }
        } else if (v === binding!!.register) {
            // Start the Register activity
            val intent = Intent(this, RegisterActivity::class.java)
            startActivityForResult(intent, REQUEST_REGISTER)
            //finish();
            //overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out);
        }
    }

    private fun loginByServer() {
        progressDialog = ProgressDialog(this)
        progressDialog!!.isIndeterminate = true
        progressDialog!!.setMessage("Login ...")
        progressDialog!!.setCancelable(false)
        progressDialog!!.show()
        binding!!.login.isEnabled = false

        val email = binding!!.email.text.toString()
        val password = binding!!.password.text.toString()

        lifecycleScope.launch {
            try {
                val response = ApiRestClient.instance!!.login(email, password)

                launch(Dispatchers.Main) {
                    progressDialog!!.dismiss()
                    hideSoftKeyboard()
                    binding!!.login.isEnabled = true
                    if (response.isSuccessful) {
                        val loginResponse = response.body()
                        if (loginResponse!!.success!!) {
                            Log.d("onResponse", "" + response.body().toString())
                            //showMessage(response.body().getToken());
                            //guardar token en shared preferences
                            preferences.save(
                                binding.email.text.toString(),
                                binding.password.text.toString(),
                                loginResponse!!.data!!.token
                            )
                            startActivity(Intent(applicationContext, PanelActivity::class.java))
                            finish()
                        } else {
                            showMessage("Error in login: Email/Password incorrectos")
                            showMessage(loginResponse!!.message)
                            Log.d("Login error", loginResponse!!.message.toString())
                        }
                    } else {
                        val message = StringBuilder()
                        message.append("Failure in login: ")
                        if (response.body() != null) {
                            val loginResponse = response.body()
                            message.append("\n" + loginResponse!!.message);
                        }
                        if (response.errorBody() != null)
                            try {
                                message.append("\n" + response.errorBody()!!.toString())
                            } catch (e: IOException) {
                                e.printStackTrace()
                            }
                        showMessage(message.toString())
                    }
                }
            } catch (e: Exception) {
                launch(Dispatchers.Main) {
                    hideSoftKeyboard()
                    progressDialog!!.dismiss()
                    binding!!.login.isEnabled = true
                    binding!!.register.isEnabled = true
                    var message: String = "Failure in the communication\n"
                    if (e != null) {
                        Log.d("onFailure", e.message.toString())
                        message += e.message.toString()
                    }
                    showMessage(message)
                }
            }
        }
    }

    private fun showMessage(s: String?) {
        Toast.makeText(this, s, Toast.LENGTH_SHORT).show()
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_REGISTER) {
            if (resultCode == RESULT_OK) {
                // TODO: Implement successful signup logic here
                // Por defecto se hace login automáticamente después del registro
                // Habría que validar el email antes de realizar login

                //Guardar token y lanzar Panel
                preferences!!.save(
                    data!!.extras!!.getString("email"),
                    data.extras!!.getString("password"),
                    data.extras!!.getString("token")
                )
                startActivity(Intent(this, PanelActivity::class.java))
                finish()
                //binding.inputEmail.setText(data.getExtras().getString("email"));
                //binding.inputPassword.setText(data.getExtras().getString("password"));
            } else if (requestCode == RESULT_CANCELED) {
                //no hacer nada, volver al login
                showMessage("Registro cancelado")
            }
        }
    }

    fun validate(): Boolean {
        var valid = true
        val email = binding!!.email.text.toString()
        val password = binding!!.password.text.toString()

        if (email.isEmpty() || !Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
            binding!!.email.error = "Enter a valid email address"
            requestFocus(binding!!.email)
            valid = false
        } else {
            binding!!.email.error = null
        }
        if (password.isEmpty()) {
            binding!!.password.error = "Password is empty"
            requestFocus(binding!!.password)
            valid = false
        } else {
            binding!!.password.error = null
        }
        return valid
    }

    private fun requestFocus(view: View) {
        if (view.requestFocus()) {
            window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
        }
    }

    fun hideSoftKeyboard() {
        if (currentFocus != null) {
            val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager
            inputMethodManager.hideSoftInputFromWindow(currentFocus!!.windowToken, 0)
        }
    }

}

activity_panel.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/ConstraintLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <com.google.android.material.circularreveal.coordinatorlayout.CircularRevealCoordinatorLayout
        android:id="@+id/coordinatorLayout"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <com.google.android.material.floatingactionbutton.FloatingActionButton
            android:id="@+id/floatingActionButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:contentDescription="Add task"
            android:layout_gravity="bottom|right"
            android:layout_marginRight="30sp"
            android:layout_marginBottom="30sp"
            android:clickable="true"
            app:backgroundTint="@color/colorDefault"
            app:srcCompat="@drawable/pen_plus" />

        <androidx.recyclerview.widget.RecyclerView
            android:id="@+id/recyclerView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:backgroundTint="@color/design_default_color_primary" />

    </com.google.android.material.circularreveal.coordinatorlayout.CircularRevealCoordinatorLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

PanelActivity

class PanelActivity : AppCompatActivity(), View.OnClickListener {
    var positionClicked = 0
    lateinit var progressDialog: ProgressDialog
    companion object {
        const val ADD_CODE = 100
        const val UPDATE_CODE = 200
        const val OK = 1
    }

    //ApiService apiService;
    lateinit var preferences: SharedPreferencesManager
    private lateinit var binding: ActivityPanelBinding
    private lateinit var adapter: TodoAdapter
    // private val listTasks = mutableListOf<Task>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //activity_main.xml -> ActivityMainBinding
        binding = ActivityPanelBinding.inflate(layoutInflater)
        val view: View = binding!!.root
        setContentView(view)
        
        binding!!.floatingActionButton.setOnClickListener(this)
        preferences = SharedPreferencesManager(this)
        //showMessage("panel: " + preferences.getToken());
        
        initRecyclerView();

        //Destruir la instancia de Retrofit para que se cree una con el nuevo token
        ApiTokenRestClient.deleteInstance()
        downloadTasks()

    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        val menuInflater = menuInflater
        menuInflater.inflate(R.menu.menu_toolbar, menu)
        // super.onCreateOptionsMenu(menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.refresh ->
                //petición al servidor para descargar de nuevo los sitios
                downloadTasks()
            R.id.email -> {
                //send an email
                val i = Intent(this, EmailActivity::class.java)
                startActivity(i)
            }
            R.id.exit -> {
                //petición al servidor para anular el token (a la ruta /api/logout)
                logout()

                preferences!!.saveToken(null, null)
                startActivity(Intent(applicationContext, MainActivity::class.java))
                finish()
            }
        }
        return true
    }

    private fun initRecyclerView() {

        adapter = TodoAdapter()
        // binding.rvDogs.setHasFixedSize(true)
        binding.recyclerView.layoutManager = LinearLayoutManager(this)
        binding.recyclerView.adapter = adapter

        binding!!.recyclerView.addOnItemTouchListener(
            RecyclerTouchListener(
                this,
                binding!!.recyclerView,
                object : ClickListener {
                    override fun onClick(view: View?, position: Int) {
                        showMessage("Single Click on task with id: " + adapter!!.getAt(position).id)
                        modify(adapter!!.getAt(position))
                        positionClicked = position
                    }

                    override fun onLongClick(view: View?, position: Int) {
                        showMessage("Long press on position :$position")
                    }
                })
        )

        val itemSwipe = object : SimpleCallback(0, RIGHT) {
            override fun onMove(
                recyclerView: RecyclerView,
                viewHolder: RecyclerView.ViewHolder,
                target: RecyclerView.ViewHolder
            ): Boolean {
                return false
            }

            override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
                if (binding.recyclerView.isEnabled) {
                    val position = viewHolder.adapterPosition
                    val id = adapter?.getId(position)
                    confirmDialog(id, position)
                } else {
                    binding.recyclerView.adapter?.notifyItemChanged(viewHolder.position)
                }
            }
        }
        val swap = ItemTouchHelper(itemSwipe)
        swap.attachToRecyclerView(binding.recyclerView)
    }


    override fun onClick(v: View) {
        if (v === binding!!.floatingActionButton) {
            val i = Intent(this, AddActivity::class.java)
            startActivityForResult(i, ADD_CODE)
        }
    }

    private fun downloadTasks() {
        progressDialog = ProgressDialog(this)
        progressDialog!!.setProgressStyle(ProgressDialog.STYLE_SPINNER)
        progressDialog!!.setMessage("Connecting . . .")
        progressDialog!!.setCancelable(false)
        progressDialog!!.show()

        lifecycleScope.launch {
            try {
                val response = ApiTokenRestClient.getInstance(preferences!!.token)!!.getTasks()

                launch(Dispatchers.Main) {
                    progressDialog!!.dismiss()
                    if (response.isSuccessful) {
                        val getTasksResponse = response.body()
                        if (getTasksResponse!!.success!!) {
                            adapter!!.setTasks(getTasksResponse.data!!)
                            showMessage("Tasks downloaded ok")
                        } else {
                            showMessage("Error downloading the tasks: " + getTasksResponse.message)
                        }
                    } else {
                            val message = StringBuilder()
                            message.append("Error downloading the tasks: ")
                            if (response.body() != null)
                                message.append("\n" + response.body()!!.toString());
                            if (response.errorBody() != null)
                                try {
                                    message.append("\n" + response.errorBody()!!.toString())
                                } catch (e: IOException) {
                                    e.printStackTrace()
                                }
                            showMessage(message.toString())
                        }
                    }
            } catch (e: Exception) {
                launch(Dispatchers.Main) {
                    // hideSoftKeyboard()
                    // progressDialog!!.dismiss()
                    var message: String = "Failure in the communication\n"
                    if (e != null) {
                        Log.d("onFailure", e.message.toString())
                        message += e.message.toString()
                    }
                    showMessage(message)
                }
            }
        }
    }

    private fun showMessage(s: String?) {
        Toast.makeText(this, s, Toast.LENGTH_SHORT).show()
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        val task = Task()
        if (requestCode == ADD_CODE) if (resultCode == OK) {
            task.id = data!!.getIntExtra("id", 1).toLong()
            task.description = data.getStringExtra("description")
            task.createdAt = data.getStringExtra("createdAt")
            adapter!!.add(task)
        }
        if (requestCode == UPDATE_CODE) if (resultCode == OK) {
            task.id = data!!.getIntExtra("id", 1).toLong()
            task.description = data.getStringExtra("description")
            task.createdAt = data.getStringExtra("createdAt")
            adapter!!.modifyAt(task, positionClicked)
        }
    }
    private fun modify(task: Task) {
        var i = Intent(this, UpdateActivity::class.java)
        i.putExtra("task", task)
        startActivityForResult(i, UPDATE_CODE)
    }

    // private fun confirmDialog(idTask: Int, description: String, position: Int) {
    private fun confirmDialog(id: Long?, position: Int) {
        val builder = AlertDialog.Builder(this)
        val description = adapter.getAt(position).description
        builder.setMessage("$description\n Do you want to delete?")
            .setTitle("Delete")
            .setPositiveButton("Confirm") { dialog, which ->
                connection(id, position)
                dialog.dismiss()
            }
            .setNegativeButton("Cancel") {  dialog, which ->
                binding.recyclerView.adapter?.notifyItemChanged(position)
            }
        builder.show()
    }

    private fun connection(id: Long?, position: Int) {

        progressDialog!!.setProgressStyle(ProgressDialog.STYLE_SPINNER)
        progressDialog!!.setMessage("Connecting . . .")
        progressDialog!!.setCancelable(false)
        progressDialog!!.show()

        lifecycleScope.launch {
            try {
                val response = ApiTokenRestClient.getInstance(preferences!!.token)!!.deleteTask(id)

                launch(Dispatchers.Main) {
                    // hideSoftKeyboard()
                    progressDialog!!.dismiss()
                    if (response.isSuccessful) {
                        val deleteResponse = response.body()
                        if (deleteResponse!!.success!!) {
                            adapter!!.removeAt(position)
                            showMessage("Task deleted OK")
                        } else
                            showMessage("Error deleting the task")
                    } else {
                        val message = StringBuilder()
                        message.append("Error downloading the tasks: ")
                        if (response.body() != null)
                            message.append("\n" + response.body()!!.toString());
                        if (response.errorBody() != null)
                            try {
                                message.append("\n" + response.errorBody()!!.toString())
                            } catch (e: IOException) {
                                e.printStackTrace()
                            }
                        showMessage(message.toString())
                    }
                }
            } catch (e: Exception) {
                launch(Dispatchers.Main) {
                    // hideSoftKeyboard()
                    progressDialog!!.dismiss()
                    var message: String = "Failure in the communication\n"
                    if (e != null) {
                        Log.d("onFailure", e.message.toString())
                        message += e.message.toString()
                    }
                    showMessage(message)
                }
            }
        }
    }

    private fun logout() {
        lifecycleScope.launch {
            try {
                val response = ApiTokenRestClient.getInstance(preferences!!.token)!!.logout()

                launch(Dispatchers.Main) {
                    progressDialog!!.dismiss()
                    if (response.isSuccessful) {
                        val logoutResponse = response.body()
                        if (logoutResponse!!.success!!) {
                            showMessage("Logout OK")
                        } else showMessage("Error in logout")
                    } else {
                        val message = StringBuilder()
                        message.append("Error in logout: ")
                        if (response.body() != null)
                            message.append("\n" + response.body()!!.toString());
                        if (response.errorBody() != null)
                            try {
                                message.append("\n" + response.errorBody()!!.toString())
                            } catch (e: IOException) {
                                e.printStackTrace()
                            }
                        showMessage(message.toString())
                    }
                }
            } catch (e: Exception) {
                launch(Dispatchers.Main) {
                    // hideSoftKeyboard()
                    // progressDialog!!.dismiss()
                    var message: String = "Failure in the communication\n"
                    if (e != null) {
                        Log.d("onFailure", e.message.toString())
                        message += e.message.toString()
                    }
                    showMessage(message)
                }
            }
        }
    }
}

 

 

Repositorio en Github

Deja una respuesta