Login API
URL: http://androindian.com/test/Login_raw.php
Request Type: POST
request:
{
“username”: “xyz@gmail.com”,
“password”: “1234”
}
Response:
{“key”:”Login Successfully”,”status”:”success”}
Add below gradle on build.gradle
Build.gradle
implementation("com.squareup.retrofit2:retrofit:2.9.0")
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
api ("com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2")
//lifecycle components
implementation ("androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1")
implementation ("androidx.lifecycle:lifecycle-livedata-ktx:2.3.1")
implementation ("androidx.lifecycle:lifecycle-common-java8:2.3.1")
activity_login.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:orientation="vertical">
<EditText
android:id="@+id/editTextEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:hint="EMail"
android:inputType="textEmailAddress"
android:padding="12dp"
android:textColor="@color/black"
android:layout_marginTop="32dp"
android:autofillHints="emailAddress" />
<EditText
android:id="@+id/editTextPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:hint="Password"
android:inputType="textPassword"
android:padding="12dp"
android:textColor="@color/black"
android:layout_marginTop="16dp"
android:autofillHints="password" />
<Button
android:id="@+id/buttonLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:text="Login"
android:textColor="@android:color/white"
android:padding="12dp"
android:layout_marginTop="32dp" />
</LinearLayout>
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:id="@+id/progress"
android:visibility="gone"/>
</RelativeLayout>
</layout>
Create one new package on name ui and move LoginActivity.kt in Ui
LoginActivity.kt
package com.example.mvvmreg
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.view.WindowManager
import android.widget.Toast
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProvider
import com.example.mvvmreg.databinding.ActivityMainBinding
import com.example.mvvmreg.helper.SharedHelper
import com.example.mvvmreg.helper.Utils
import com.example.mvvmreg.ui.DashboardView
import com.example.mvvmreg.viewmodel.LoginViewModel
import com.google.gson.JsonObject
class LoginActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var viewModel: LoginViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
hideStatusBar()
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
setupViewModel()
setupObserver()
binding.buttonLogin.setOnClickListener {
if (vaild()) {
binding.progress.visibility = View.VISIBLE
val requestObject = HashMap<String,String>()
requestObject.put("username", binding.editTextEmail.text.toString())
requestObject.put("password", binding.editTextPassword.text.toString())
viewModel.doLogin(requestObject)
}
}
}
@Suppress("DEPRECATION")
private fun hideStatusBar() {
val decorView = window.decorView
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
supportActionBar?.hide()
window.setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN
)
}
private fun setupObserver() {
viewModel.loginResponse.observe(this) {
binding.progress.visibility = View.GONE
Toast.makeText(this@LoginActivity, "Login Successful", Toast.LENGTH_LONG)
.show()
startActivity(
Intent(
this@LoginActivity,
DashboardView::class.java
)
)
}
viewModel.error.observe(this) {
binding.progress.visibility = View.GONE
Toast.makeText(this, it, Toast.LENGTH_LONG).show()
}
}
private fun setupViewModel() {
viewModel = ViewModelProvider(this)[LoginViewModel::class.java]
}
private fun vaild(): Boolean {
if (TextUtils.isEmpty(binding.editTextEmail.text.toString())) {
binding.editTextEmail.error = "Please enter email"
return false
}
if (!Utils.isValidEmail(binding.editTextEmail.text.toString())) {
binding.editTextEmail.error = "Please enter valid email"
return false
} else if (TextUtils.isEmpty(binding.editTextPassword.text.toString())) {
binding.editTextPassword.error = "Please enter password"
return false
}
return true
}
}
Create one new package on name helper and create one class AppConstants.kt
AppConstants.kt
package com.example.mvvmreg.helper
import java.text.DecimalFormat
class AppConstants {
companion object {
const val SUCCESS = "Success"
const val TOKEN_EXP = "Token Expired"
const val BAD_REQUEST = "Bad Request"
const val BAD_METHOD = "Bad Method"
const val INTERNAL_ERROR = "Internal Server Error"
const val UNAUTHORIZED = "Authorization Required"
const val NOT_FOUND = "Not Found"
const val GATEWAY_TIMEOUT = "Gateway Timed Out"
object Responses {
var SUCCESS = "SUCCESS"
}
}
}
NetworkState.kt
package com.example.mvvmreg.helper
class NetworkState(val status: Status, val msg: String) {
enum class Status {
RUNNING,
SUCCESS,
FAILED
}
companion object {
var LOADED: NetworkState? = null
var LOADING: NetworkState? = null
init {
LOADED = NetworkState(Status.SUCCESS, "Success")
LOADING = NetworkState(Status.RUNNING, "Running")
}
}
}
SharedHelper.kt
package com.example.mvvmreg.helper
import android.content.Context
import android.content.SharedPreferences
object SharedHelper {
public final var sharedPreferences: SharedPreferences? = null
lateinit var editor: SharedPreferences.Editor;
fun init(context: Context) {
sharedPreferences = context.getSharedPreferences("Cache", Context.MODE_PRIVATE)
}
fun putKey(context: Context?, Key: String?, Value: String?) {
// sharedPreferences = context.getSharedPreferences("Cache", Context.MODE_PRIVATE);
editor = sharedPreferences!!.edit()
editor.putString(Key, Value)
editor.apply()
}
fun writeString(Key: String?, Value: String?) {
editor = sharedPreferences!!.edit()
editor.putString(Key, Value)
editor.apply()
}
fun writeBoolean(context: Context?, Key: String?, Value: Boolean?) {
//sharedPreferences = context.getSharedPreferences("Cache", Context.MODE_PRIVATE);
editor = sharedPreferences!!.edit()
editor.putBoolean(Key, Value!!)
editor.apply()
}
fun getKey(contextGetKey: Context?, Key: String?): String? {
//sharedPreferences = contextGetKey.getSharedPreferences("Cache", Context.MODE_PRIVATE);
return sharedPreferences!!.getString(Key, "")
}
fun getString(key: String?): String? {
return sharedPreferences!!.getString(key, null)
}
fun getBoolean(contextGetKey: Context?, Key: String?): Boolean {
// sharedPreferences = contextGetKey.getSharedPreferences("Cache", Context.MODE_PRIVATE);
return sharedPreferences!!.getBoolean(Key, false)
}
fun clearSharedPreferences(context: Context?) {
//sharedPreferences = context.getSharedPreferences("Cache", Context.MODE_PRIVATE);
sharedPreferences!!.edit().clear().apply()
}
object PreferredString {
const val user_email = "user_email"
}
}
URLHelper.kt
package com.example.mvvmreg.helper
class URLHelper {
companion object{
val base = " http://androindian.com/test/"
val login = base + "Login_raw.php"
}
}
Create one new package on name Model and create one class LoginResponseModel.kt
LoginResponseModel.kt
package com.example.mvvmreg.model
import com.google.gson.annotations.SerializedName
data class LoginResponseModel(
val key: String,
val status: String,
)
Create one new package on name network and create one class ApiClient.kt
ApiClient.kt
package com.example.mvvmreg.network
import com.google.gson.JsonObject
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.Headers
import retrofit2.http.POST
import retrofit2.http.QueryMap
import retrofit2.http.Url
interface ApiClient {
@Headers("Content-Type:application/json")
@POST
fun getLoginResponse(@Url url: String?, @QueryMap body: HashMap<String,String>?): Call<JsonObject?>?
}
RetrofitClient.kt
package com.example.mvvmreg.network
import com.google.gson.GsonBuilder
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.lang.reflect.Modifier
class RetrofitClient {
private val BASE_URL = ""
private val client: OkHttpClient =
UnsafeOkHttpClient.unsafeOkHttpClient
/*private static Gson gson = new GsonBuilder()
.setLenient()
.create();*/
var builder2 = GsonBuilder().excludeFieldsWithModifiers(
Modifier.FINAL,
Modifier.TRANSIENT,
Modifier.STATIC
)
var gson = builder2.create()
private val builder: Retrofit.Builder = Retrofit.Builder()
.client(client)
.baseUrl(BASE_URL)
.addConverterFactory(
GsonConverterFactory.create(
GsonBuilder()
.excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC)
.excludeFieldsWithoutExposeAnnotation()
.serializeNulls()
.create()
)
)
public val retrofit = builder.build()
fun <S> createService(serviceClass: Class<S>?): S {
return retrofit.create(serviceClass)
}
}
ServiceGenerator.kt
package com.example.mvvmreg.network
import com.example.mvvmreg.helper.SharedHelper
import com.example.mvvmreg.helper.URLHelper
import com.google.gson.GsonBuilder
import okhttp3.Call
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
class ServiceGenerator {
private val client1 = getClient()
private val client: OkHttpClient = UnsafeOkHttpClient.unsafeOkHttpClient
private val call: Call? = null
private val url = getUrl()
companion object{
private var setToken: String? = null
}
private fun getUrl(): String {
return URLHelper.base
}
var gson = GsonBuilder()
.setLenient()
.create()
private val builder = Retrofit.Builder()
.client(client)
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create(gson))
private val retrofit = builder.build()
fun <S> createService(serviceClass: Class<S>?): S {
return retrofit.create(serviceClass)
}
private fun getClient(): OkHttpClient {
val httpclient = OkHttpClient.Builder();
httpclient.addInterceptor(Interceptor { chain: Interceptor.Chain ->
val original = chain.request()
val request = original.newBuilder()
.header("X-Requested-With", "XMLHttpRequest")
.header("Content-Type", "application/json")
.header("Authorization", "Bearer " + SharedHelper.getString("access_token"))
.method(original.method, original.body)
.build()
chain.proceed(request)
})
httpclient.connectTimeout(300, TimeUnit.SECONDS)
return httpclient.build()
}
private fun getToken(): String? {
return setToken
}
fun setSetToken(setToken: String) {
ServiceGenerator.setToken = setToken
}
}
UnsafeOkHttpClient.kt
package com.example.mvvmreg.network
import android.annotation.SuppressLint
import okhttp3.Interceptor
import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.logging.HttpLoggingInterceptor
import java.security.SecureRandom
import java.security.cert.X509Certificate
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLSession
object UnsafeOkHttpClient {
val unsafeOkHttpClient: OkHttpClient
get() = try {
// Create a trust manager that does not validate certificate chains
@SuppressLint("CustomX509TrustManager") val trustAllCerts = arrayOf<TrustManager>(
object : X509TrustManager {
@SuppressLint("TrustAllX509TrustManager")
override fun checkClientTrusted(
chain: Array<X509Certificate>,
authType: String
) {
}
@SuppressLint("TrustAllX509TrustManager")
override fun checkServerTrusted(
chain: Array<X509Certificate>,
authType: String
) {
}
override fun getAcceptedIssuers(): Array<X509Certificate> {
return arrayOf()
}
}
)
// Install the all-trusting trust manager
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, trustAllCerts, SecureRandom())
// Create an ssl socket factory with our all-trusting manager
val sslSocketFactory = sslContext.socketFactory
val builder = OkHttpClient.Builder()
builder.cache(null)
builder.sslSocketFactory(sslSocketFactory, trustAllCerts[0] as X509TrustManager)
builder.hostnameVerifier(HostnameVerifier { hostname: String?, session: SSLSession? -> true })
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
builder.addInterceptor(interceptor)
builder.addInterceptor(Interceptor { chain: Interceptor.Chain ->
val original = chain.request()
val request: Request.Builder = original.newBuilder()
request.method(original.method, original.body)
request.addHeader("Accept", "*/*")
chain.proceed(request.build())
})
builder.connectTimeout(2, TimeUnit.MINUTES)
.readTimeout(120, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
builder.build()
} catch (e: Exception) {
throw RuntimeException(e)
}
}
Create one new package on name network and create one class LoginRepository.kt
LoginRepository.kt
package com.example.mvvmreg.repository
import com.example.mvvmreg.helper.URLHelper
import com.example.mvvmreg.network.ApiClient
import com.example.mvvmreg.network.ServiceGenerator
import com.google.gson.JsonObject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import retrofit2.Call
class LoginRepository {
private val retrofitClient = ServiceGenerator().createService(ApiClient::class.java)
suspend fun doLogin(requestBody: HashMap<String,String>): Call<JsonObject?>? = withContext(Dispatchers.IO) {
retrofitClient.getLoginResponse(URLHelper.login, requestBody)
}
}
Create one new package on name Viewmodel and create one class LoginViewModel.kt
LoginViewModel.kt
package com.example.mvvmreg.viewmodel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.mvvmreg.model.LoginResponseModel
import com.example.mvvmreg.repository.LoginRepository
import com.google.gson.Gson
import com.google.gson.JsonObject
import kotlinx.coroutines.launch
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class LoginViewModel : ViewModel(){
private val repository = LoginRepository()
val loginResponse = MutableLiveData<LoginResponseModel>()
val error = MutableLiveData<String>()
fun doLogin(jsonObject: HashMap<String,String>) {
viewModelScope.launch {
val response = repository.doLogin(jsonObject)
response?.enqueue(object: Callback<JsonObject?> {
override fun onResponse(call: Call<JsonObject?>, response: Response<JsonObject?>) {
if (response.code() == 200) {
loginResponse.value = Gson().fromJson(response.body().toString(),LoginResponseModel::class.java)
} else {
error.value = "Invalid Login Credentials"
}
}
override fun onFailure(call: Call<JsonObject?>, t: Throwable) {
error.value = "Invalid Login Credentials"
}
})
}
}
}
MyApplication.kt
package com.example.mvvmreg
import android.app.Application
import com.example.mvvmreg.helper.SharedHelper
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
SharedHelper.init(this)
}
}
androidmanifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MvvmReg"
android:usesCleartextTraffic="true"
tools:targetApi="31">
<activity
android:name=".LoginActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.example.mvvmreg.ui.DashboardView" />
</application>
</manifest>