structure for api calls

integrated log in api calls
integrated api calls for checking email exist, sending otp, validating otp, validating username.
This commit is contained in:
2024-05-07 21:02:31 +05:30
parent 65c6f4fff1
commit 7e1062f94e
20 changed files with 696 additions and 63 deletions

View File

@@ -3,7 +3,7 @@ package com.woka.networking
sealed class ApiResult<T>(data: T? = null, errorMessage: String? = null) {
class Loading<T>: ApiResult<T>()
class Success<T>(data: T? = null): ApiResult<T>(data)
class Error<T>(errorMessage: String? = null): ApiResult<T>(errorMessage = errorMessage)
class Success<T>(val data: T? = null): ApiResult<T>(data)
class Error<T>(val errorMessage: String? = null): ApiResult<T>(errorMessage = errorMessage)
}

View File

@@ -5,12 +5,17 @@ import android.content.Context
import android.provider.Settings
import com.woka.BuildConfig
import com.woka.WokaApp.Companion.userPrefs
import com.woka.onboard.models.LoginResponse
import com.woka.utils.NO_INTERNET_MESSAGE
import com.woka.utils.UNKNOWN_ERROR_MESSAGE
import okhttp3.Credentials
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.net.UnknownHostException
object RetrofitHelper {
@@ -50,4 +55,30 @@ object RetrofitHelper {
fun getRetrofit(): Retrofit{
return retrofit ?: createRetrofit()
}
// api caller
suspend fun <T>handleApiCall(apiCall: suspend () -> Response<ApiResponse<T>>): ApiResult<T> {
return try {
val response = apiCall() // this api call can throw some exception
handleApiResponse(response) // handling the response
} catch (e: UnknownHostException) {
ApiResult.Error(errorMessage = NO_INTERNET_MESSAGE)
} catch (e: Exception) {
ApiResult.Error(errorMessage = UNKNOWN_ERROR_MESSAGE)
}
}
// api response handler
fun <T>handleApiResponse(response: Response<ApiResponse<T>>): ApiResult<T> {
if (response.isSuccessful) {
val body = response.body() ?: return ApiResult.Error(errorMessage = "Empty Response")
return if (body.success == 1) {
ApiResult.Success(body.data)
} else {
ApiResult.Error(errorMessage = body.message)
}
} else {
return ApiResult.Error(errorMessage = response.message())
}
}
}

View File

@@ -1,16 +1,26 @@
package com.woka.onboard.fragments
import android.os.Bundle
import android.os.CountDownTimer
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.View.GONE
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.widget.addTextChangedListener
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.woka.R
import com.woka.databinding.FragmentGetCodeBinding
import com.woka.networking.ApiResult
import com.woka.onboard.fragments.GetEmailFragment.Companion.IS_RESET_PASSWORD_INTENT
import com.woka.onboard.fragments.GetEmailFragment.Companion.IS_UNDER_16
import com.woka.onboard.mvvm.OnboardViewModel
import com.woka.utils.PARENT_TYPE
import com.woka.utils.ProgressView
import com.woka.utils.closeKeyboard
/*
@@ -22,16 +32,32 @@ import com.woka.utils.closeKeyboard
*/
class GetCodeFragment : Fragment() {
companion object {
const val UNIQUE_STRING_ARG = "unique_str_arg"
const val EMAIL_ARG = "unique_str_arg"
const val OTP_RESEND_COUNT_DOWN_TIME = 10 * 60 * 1000L // 10 min
}
private lateinit var binding: FragmentGetCodeBinding
// args
private var isUnder16: Boolean = false
private var isResetPasswordIntent: Boolean = false
private var uniqueString: String = ""
private var email: String = ""
private lateinit var viewModel: OnboardViewModel
private lateinit var progressView: ProgressView
private lateinit var countDownTimer: CountDownTimer
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
isUnder16 = it.getBoolean(IS_UNDER_16, false)
isResetPasswordIntent = it.getBoolean(IS_RESET_PASSWORD_INTENT, false)
uniqueString = it.getString(UNIQUE_STRING_ARG, "")
email = it.getString(EMAIL_ARG, "")
}
}
@@ -40,6 +66,10 @@ class GetCodeFragment : Fragment() {
savedInstanceState: Bundle?
): View? {
binding = FragmentGetCodeBinding.inflate(inflater, container, false)
activity?.let {
viewModel = ViewModelProvider(it)[OnboardViewModel::class.java]
progressView = ProgressView(it)
}
initViews()
@@ -48,44 +78,105 @@ class GetCodeFragment : Fragment() {
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// count down timer
startCountDown()
// observing live data
viewModel.sendOTPLiveData.observe(viewLifecycleOwner){
when(it){
is ApiResult.Error -> {
progressView.hide()
Toast.makeText(activity, "${it.errorMessage}", Toast.LENGTH_SHORT).show()
}
is ApiResult.Loading -> {
progressView.show("Sending OTP...")
}
is ApiResult.Success -> {
startCountDown()
Toast.makeText(activity, "OTP sent successfully", Toast.LENGTH_SHORT).show()
progressView.hide()
uniqueString = it.data?.unique_string?:""
}
null -> {}
}
}
viewModel.validateOTPLiveData.observe(viewLifecycleOwner) {
when (it) {
is ApiResult.Error -> {
progressView.hide()
Toast.makeText(activity, "${it.errorMessage}", Toast.LENGTH_SHORT).show()
}
is ApiResult.Loading -> {
progressView.show("Validating OTP...")
}
is ApiResult.Success -> {
Toast.makeText(activity, "OTP validation successful.", Toast.LENGTH_SHORT).show()
progressView.hide()
val args = Bundle().apply {
putBoolean(IS_UNDER_16, isUnder16)
putString(EMAIL_ARG, email)
}
findNavController().navigate(
R.id.action_getCodeFragment_to_signUpFragment,
args
)
}
null -> {}
}
}
}
override fun onDestroyView() {
super.onDestroyView()
viewModel.clearValidateOTP()
viewModel.clearSendOTPData()
countDownTimer.cancel()
}
private fun initViews() {
binding.apply {
if (isResetPasswordIntent){
if (isResetPasswordIntent) {
title.text = getString(R.string.please_get_otp_under_16)
infoText.text = getString(R.string.request_them_for_the_code_to_reset_your_password)
}
else if (isUnder16){
} else if (isUnder16) {
title.text = getString(R.string.please_get_otp_under_16)
infoText.text = getString(R.string.request_them_for_verification_)
}
et1.addTextChangedListener {
if (it?.isEmpty() == false){
if (it?.isEmpty() == false) {
et2.requestFocus()
}
}
et2.addTextChangedListener {
if (it?.isEmpty() == false){
if (it?.isEmpty() == false) {
et3.requestFocus()
}else{
} else {
et1.requestFocus()
}
}
et3.addTextChangedListener {
if (it?.isEmpty() == false){
if (it?.isEmpty() == false) {
et4.requestFocus()
}else{
} else {
et2.requestFocus()
}
}
et4.addTextChangedListener {
if (it?.isEmpty() == false){
if (it?.isEmpty() == false) {
// close keyboard
activity?.closeKeyboard()
}else{
} else {
et3.requestFocus()
}
}
@@ -99,16 +190,43 @@ class GetCodeFragment : Fragment() {
}
next.setOnClickListener {
if (isResetPasswordIntent){
if (isResetPasswordIntent) {
findNavController().navigate(R.id.action_getCodeFragment_to_newPasswordFragment2)
}else{
val args = Bundle().apply {
putBoolean(IS_UNDER_16, isUnder16)
}
} else {
viewModel.validateOTP(uniqueString, getOTP())
}
}
findNavController().navigate(R.id.action_getCodeFragment_to_signUpFragment, args)
resend.setOnClickListener {
if (!isUnder16){
viewModel.sendOTP(email, PARENT_TYPE)
}
}
}
}
private fun startCountDown(){
binding.countdown.visibility = VISIBLE
binding.resend.visibility = GONE
countDownTimer = object :CountDownTimer(OTP_RESEND_COUNT_DOWN_TIME, 1000){
override fun onTick(millisUntilFinished: Long) {
val rms = (millisUntilFinished)/1000 // remaining time in second
val time = "%02d:%02d".format(rms/60, rms%60)
val text = "OTP is valid for $time Min"
binding.countdown.text = text
}
override fun onFinish() {
binding.countdown.visibility = GONE
binding.resend.visibility = VISIBLE
}
}.start()
}
private fun getOTP(): String {
binding.apply {
return "${et1.text}${et2.text}${et3.text}${et4.text}"
}
}
}

View File

@@ -8,9 +8,16 @@ import android.view.View
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.Toast
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.woka.R
import com.woka.databinding.FragmentGetEmailBinding
import com.woka.networking.ApiResult
import com.woka.onboard.fragments.GetCodeFragment.Companion.EMAIL_ARG
import com.woka.onboard.fragments.GetCodeFragment.Companion.UNIQUE_STRING_ARG
import com.woka.onboard.mvvm.OnboardViewModel
import com.woka.utils.PARENT_TYPE
import com.woka.utils.ProgressView
/*
This fragment is to get the email user input
@@ -21,13 +28,16 @@ import com.woka.databinding.FragmentGetEmailBinding
*/
class GetEmailFragment : Fragment() {
companion object{
companion object {
const val IS_UNDER_16 = "is_under_16"
const val IS_RESET_PASSWORD_INTENT = "reset_password_intent"
}
private lateinit var binding: FragmentGetEmailBinding
private lateinit var viewModel: OnboardViewModel
private lateinit var progressView: ProgressView
private var isUnder16: Boolean = false
private var isResetPasswordIntent: Boolean = false
@@ -45,6 +55,11 @@ class GetEmailFragment : Fragment() {
): View? {
binding = FragmentGetEmailBinding.inflate(inflater, container, false)
activity?.let {
viewModel = ViewModelProvider(it)[OnboardViewModel::class.java]
progressView = ProgressView(it)
}
initViews()
clickEvents()
@@ -52,17 +67,87 @@ class GetEmailFragment : Fragment() {
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// observing to live data for this fragment
viewModel.checkEmailExistData.observe(viewLifecycleOwner) {
when (it) {
is ApiResult.Error -> {
progressView.hide()
Toast.makeText(activity, "${it.errorMessage}", Toast.LENGTH_SHORT).show()
}
is ApiResult.Loading -> {
progressView.show(title = "Please wait...")
}
is ApiResult.Success -> {
if (!isUnder16) {
viewModel.sendOTP(binding.email.text.toString(), PARENT_TYPE)
}
}
null -> {}
}
}
viewModel.sendOTPLiveData.observe(viewLifecycleOwner) {
when (it) {
is ApiResult.Error -> {
progressView.hide()
Toast.makeText(activity, "${it.errorMessage}", Toast.LENGTH_SHORT).show()
}
is ApiResult.Loading -> {
progressView.show(title = "Sending OTP")
}
is ApiResult.Success -> {
viewModel.clearSendOTPData()
progressView.hide()
val args = if (isResetPasswordIntent) {
Bundle().apply {
putBoolean(IS_RESET_PASSWORD_INTENT, isResetPasswordIntent)
}
} else {
Bundle().apply {
putBoolean(IS_UNDER_16, isUnder16)
putString(UNIQUE_STRING_ARG, it.data?.unique_string)
putString(EMAIL_ARG, binding.email.text.toString())
}
}
findNavController().navigate(
R.id.action_getEmailFragment_to_getCodeFragment,
args
)
}
null -> {}
}
}
}
override fun onDestroyView() {
super.onDestroyView()
// removing values from live data for a fresh data when new instance is created
viewModel.clearCheckEmailExist()
viewModel.clearSendOTPData()
}
private fun initViews() {
binding.apply {
if (isResetPasswordIntent){
if (isResetPasswordIntent) {
// scenario 3
title.text = getString(R.string.forgot_your_password)
can.text = getString(R.string.please_give_us_your_username)
email.hint = getString(R.string.enter_your_username)
verificationTxt.text = getString(R.string.we_will_send_a_reset_code_to_your_parent_s_email)
verificationTxt.text =
getString(R.string.we_will_send_a_reset_code_to_your_parent_s_email)
verificationTxt.visibility = VISIBLE
}else if (isUnder16){
} else if (isUnder16) {
// scenario 2
title.text = getString(R.string.let_s_be_safe)
@@ -77,22 +162,17 @@ class GetEmailFragment : Fragment() {
binding.next.setOnClickListener {
binding.email.error = null
if (!Patterns.EMAIL_ADDRESS.matcher(binding.email.text.toString()).matches()){
if (!Patterns.EMAIL_ADDRESS.matcher(binding.email.text.toString()).matches()) {
binding.email.error = "Invalid email"
return@setOnClickListener
}
val args = if (isResetPasswordIntent){
Bundle().apply {
putBoolean(IS_RESET_PASSWORD_INTENT, isResetPasswordIntent)
}
}else{
Bundle().apply {
putBoolean(IS_UNDER_16, isUnder16)
}
if (!isUnder16) {
// parent
viewModel.checkEmailExist(binding.email.text.toString(), PARENT_TYPE)
} else {
// viewModel.checkEmailExist(binding.email.text.toString(), PARENT_TYPE)
}
findNavController().navigate(R.id.action_getEmailFragment_to_getCodeFragment, args)
}
binding.backBtn.setOnClickListener {

View File

@@ -7,30 +7,74 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.Toast
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.woka.R
import com.woka.databinding.FragmentSignInBinding
import com.woka.networking.ApiResult
import com.woka.onboard.fragments.GetEmailFragment.Companion.IS_RESET_PASSWORD_INTENT
import com.woka.onboard.mvvm.OnboardViewModel
import com.woka.utils.ProgressView
class SignInFragment : Fragment() {
private lateinit var binding: FragmentSignInBinding
private var isUnder16 = false
private lateinit var viewModel: OnboardViewModel
private lateinit var progressView: ProgressView
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentSignInBinding.inflate(inflater, container, false)
activity?.window?.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
activity?.window?.statusBarColor = Color.parseColor("#6ed5fe")
activity?.let {
it.window?.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
it.window?.statusBarColor = Color.parseColor("#6ed5fe")
viewModel = ViewModelProvider(it)[OnboardViewModel::class.java]
progressView = ProgressView(it)
}
clickEvents()
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.loginLiveData.observe(viewLifecycleOwner){ it ->
when(it){
is ApiResult.Error -> {
progressView.hide()
Toast.makeText(activity, "${it.errorMessage}", Toast.LENGTH_SHORT).show()
}
is ApiResult.Loading -> {
progressView.show()
}
is ApiResult.Success -> {
progressView.hide()
it.data?.result?.let {
if (it.already_logged_in){
Toast.makeText(activity, "Already logged in", Toast.LENGTH_SHORT).show()
}else{
Toast.makeText(activity, "Log in successful", Toast.LENGTH_SHORT).show()
}
}
}
null -> {}
}
}
}
override fun onDestroyView() {
super.onDestroyView()
viewModel.clearLoginLiveData()
}
private fun clickEvents() {
binding.apply {
forgotPassword.setOnClickListener {
@@ -47,6 +91,22 @@ class SignInFragment : Fragment() {
createAccount.setOnClickListener {
findNavController().navigate(R.id.action_signInFragment_to_age_select_fragment)
}
login.setOnClickListener {
if (username.text.isEmpty()){
username.error = "Username required"
return@setOnClickListener
}
password.text?.let { password ->
if (password.length < 6){
Toast.makeText(activity, "Password must be at least 6 characters", Toast.LENGTH_SHORT).show()
return@setOnClickListener
}
viewModel.login(username.text.toString(), password.toString())
}?:Toast.makeText(activity, "Something went wrong!", Toast.LENGTH_SHORT).show()
}
}
}
}

View File

@@ -6,22 +6,35 @@ import android.view.LayoutInflater
import android.view.View
import android.view.View.VISIBLE
import android.view.ViewGroup
import android.widget.Toast
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.fragment.findNavController
import com.woka.R
import com.woka.databinding.FragmentSignUpBinding
import com.woka.networking.ApiResult
import com.woka.onboard.fragments.GetCodeFragment.Companion.EMAIL_ARG
import com.woka.onboard.fragments.GetEmailFragment.Companion.IS_UNDER_16
import com.woka.onboard.fragments.GetMoreInfoFragment.Companion.USER_NAME_ARG
import com.woka.onboard.mvvm.OnboardViewModel
import com.woka.utils.CHILD_TYPE
import com.woka.utils.PARENT_TYPE
import com.woka.utils.ProgressView
class SignUpFragment : Fragment() {
private lateinit var binding: FragmentSignUpBinding
private var isUnder16 = false
private var email: String? = null
private lateinit var viewModel: OnboardViewModel
private lateinit var progressView: ProgressView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
isUnder16 = it.getBoolean(IS_UNDER_16, false)
email = it.getString(EMAIL_ARG)
}
}
@@ -31,6 +44,11 @@ class SignUpFragment : Fragment() {
): View? {
binding = FragmentSignUpBinding.inflate(inflater, container, false)
activity?.let {
viewModel = ViewModelProvider(it)[OnboardViewModel::class.java]
progressView = ProgressView(it)
}
initViews()
clickEvents()
@@ -38,9 +56,46 @@ class SignUpFragment : Fragment() {
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// listening to live data
viewModel.checkUserNameExistLiveData.observe(viewLifecycleOwner) {
when (it) {
is ApiResult.Error -> {
progressView.hide()
Toast.makeText(activity, "${it.errorMessage}", Toast.LENGTH_SHORT).show()
}
is ApiResult.Loading -> {
progressView.show("Validating details")
}
is ApiResult.Success -> {
progressView.hide()
val args = Bundle().apply {
putBoolean(IS_UNDER_16, isUnder16)
putString(USER_NAME_ARG, binding.name.text.trim().toString())
}
findNavController().navigate(
R.id.action_signUpFragment_to_getMoreInfoFragment,
args
)
}
null -> {}
}
}
}
override fun onDestroyView() {
super.onDestroyView()
viewModel.clearCheckUserNameExist()
}
private fun initViews() {
binding.apply {
if (isUnder16){
if (isUnder16) {
doNotShare.visibility = VISIBLE
}
}
@@ -53,13 +108,41 @@ class SignUpFragment : Fragment() {
}
next.setOnClickListener {
val args = Bundle().apply {
putBoolean(IS_UNDER_16, isUnder16)
putString(USER_NAME_ARG, "Aditya")
if (allOkay()) {
email?.let {
val userType = if (isUnder16) CHILD_TYPE else PARENT_TYPE
viewModel.checkUserNameExist(it, username.text.toString(), userType)
} ?: Toast.makeText(activity, "Something went wrong!", Toast.LENGTH_SHORT)
.show()
}
findNavController().navigate(R.id.action_signUpFragment_to_getMoreInfoFragment, args)
}
}
}
private fun allOkay(): Boolean {
var allOkay = true
binding.apply {
if (username.text.length < 2) {
allOkay = false
username.error = "Must be at least 3 characters"
}
if (name.text.trim().isEmpty()) {
allOkay = false
name.error = "Required"
}
if (password.text != null && password.text!!.length < 6) {
allOkay = false
Toast.makeText(
activity,
"Password must be at least 6 characters",
Toast.LENGTH_SHORT
).show()
}
}
return allOkay
}
}

View File

@@ -0,0 +1,6 @@
package com.woka.onboard.models
data class Gender(
val gender_name: String,
val id: Int
)

View File

@@ -0,0 +1,6 @@
package com.woka.onboard.models
data class Language(
val id: Int,
val language_name: String
)

View File

@@ -1,4 +1,4 @@
package com.woka.onboard.models
data class LoginResponse(
val result: Result
val result: Result?
)

View File

@@ -2,5 +2,18 @@ package com.woka.onboard.models
data class Result(
val already_logged_in: Boolean,
val is_deactive: Boolean
val avtar: String?,
val birthdate: String?,
val child_detail: Any?,
val email: String?,
val fullname: String?,
val gender: Gender?,
val id: Int?,
val is_active: String?,
val language: Language?,
val language_master_id: Int?,
val last_login: String?,
val remember_token: String?,
val user_type: String?,
val username: String?
)

View File

@@ -0,0 +1,5 @@
package com.woka.onboard.models
data class VerifyEmail(
val unique_string: String?
)

View File

@@ -2,13 +2,30 @@ package com.woka.onboard.mvvm
import com.woka.networking.ApiResponse
import com.woka.onboard.models.LoginResponse
import com.woka.onboard.models.VerifyEmail
import okhttp3.FormBody
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
interface OnboardApiService {
@GET("login")
@POST("login")
suspend fun login(@Body body: FormBody): Response<ApiResponse<LoginResponse>>
@POST("login_proceed")
suspend fun loginProceed(@Body body: FormBody): Response<ApiResponse<LoginResponse>>
@POST("user_email_verification")
suspend fun verifyEmail(@Body body: FormBody): Response<ApiResponse<VerifyEmail>>
@POST("check_exist_email")
suspend fun checkEmailExist(@Body body: FormBody): Response<ApiResponse<Any>>
@POST("validate_otp")
suspend fun verifyOTP(@Body body: FormBody): Response<ApiResponse<Any>>
@POST("check_exist_username")
suspend fun checkUserNameExist(@Body body: FormBody): Response<ApiResponse<Any>>
}

View File

@@ -1,26 +1,83 @@
package com.woka.onboard.mvvm
import com.woka.networking.ApiResponse
import com.woka.networking.ApiResult
import com.woka.networking.RetrofitHelper.handleApiCall
import com.woka.networking.RetrofitHelper.handleApiResponse
import com.woka.onboard.models.LoginResponse
import com.woka.onboard.models.VerifyEmail
import com.woka.utils.NO_INTERNET_MESSAGE
import com.woka.utils.UNKNOWN_ERROR_MESSAGE
import okhttp3.FormBody
import retrofit2.Response
import java.net.UnknownHostException
class OnboardRepository(private val apiService: OnboardApiService) {
suspend fun login(userName: String, password: String): ApiResult<LoginResponse> {
return try {
val response = apiService.login(
return handleApiCall {
apiService.login(
FormBody.Builder()
.add("username", userName)
.add("password", password)
.build()
)
}
}
if (response.body()?.success == 1)
ApiResult.Success(response.body()?.data)
else
ApiResult.Error(errorMessage = response.body()?.message)
} catch (e: Exception) {
ApiResult.Error(errorMessage = e.message)
suspend fun loginProceed(userName: String, password: String): ApiResult<LoginResponse> {
return handleApiCall {
apiService.loginProceed(
FormBody.Builder()
.add("username", userName)
.add("password", password)
.build()
)
}
}
suspend fun checkEmailExit(userType: String, email: String): ApiResult<Any> {
return handleApiCall {
apiService.checkEmailExist(
FormBody.Builder()
.add("email", email)
.add("user_type", userType)
.build()
)
}
}
suspend fun userEmailVerification(userType: String, email: String): ApiResult<VerifyEmail> {
return handleApiCall {
apiService.verifyEmail(
FormBody.Builder()
.add("email", email)
.add("user_type", userType)
.build()
)
}
}
suspend fun validateOTP(uniqueString: String, otp: String): ApiResult<Any> {
return handleApiCall {
apiService.verifyOTP(
FormBody.Builder()
.add("otp", otp)
.add("unique_string", uniqueString)
.build()
)
}
}
suspend fun checkUserNameExist(email: String, userName: String, userType: String): ApiResult<Any>{
return handleApiCall {
apiService.checkUserNameExist(
FormBody.Builder()
.add("email", email)
.add("username", userName)
.add("user_type", userType)
.build()
)
}
}

View File

@@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope
import com.woka.networking.ApiResult
import com.woka.networking.RetrofitHelper
import com.woka.onboard.models.LoginResponse
import com.woka.onboard.models.VerifyEmail
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
@@ -14,15 +15,95 @@ class OnboardViewModel: ViewModel(){
private val repository: OnboardRepository = OnboardRepository(RetrofitHelper.getRetrofit().create(OnboardApiService::class.java))
private val _signInLiveData = MutableLiveData<ApiResult<LoginResponse>>()
val signInLiveData: LiveData<ApiResult<LoginResponse>>
get() = _signInLiveData
// live_data
/*
Login Fragment
*/
private val _loginLiveData = MutableLiveData<ApiResult<LoginResponse>?>()
fun clearLoginLiveData() = _loginLiveData.postValue(null)
val loginLiveData: LiveData<ApiResult<LoginResponse>?>
get() = _loginLiveData
private val _loginProceedLiveData = MutableLiveData<ApiResult<LoginResponse>?>()
fun clearLoginProceedLiveData() = _loginProceedLiveData.postValue(null)
val loginProceedData: LiveData<ApiResult<LoginResponse>?>
get() = _loginProceedLiveData
/*
Send email Fragment
*/
private val _checkEmailExistLiveData = MutableLiveData<ApiResult<Any>?>()
fun clearCheckEmailExist() = _checkEmailExistLiveData.postValue(null)
val checkEmailExistData: LiveData<ApiResult<Any>?>
get() = _checkEmailExistLiveData
private val _sendOTPLiveData = MutableLiveData<ApiResult<VerifyEmail>?>()
fun clearSendOTPData() = _sendOTPLiveData.postValue(null)
val sendOTPLiveData: LiveData<ApiResult<VerifyEmail>?>
get() = _sendOTPLiveData
/*
VerifyOTP Fragment
*/
private val _validateOTPLiveData = MutableLiveData<ApiResult<Any>?>()
fun clearValidateOTP() = _validateOTPLiveData.postValue(null)
val validateOTPLiveData: LiveData<ApiResult<Any>?>
get() = _validateOTPLiveData
/*
SignUp Fragment
*/
private val _checkUserNameExistLiveData = MutableLiveData<ApiResult<Any>?>()
fun clearCheckUserNameExist() = _checkUserNameExistLiveData.postValue(null)
val checkUserNameExistLiveData: LiveData<ApiResult<Any>?>
get() = _checkUserNameExistLiveData
fun login(userName: String, password: String){
viewModelScope.launch {
_signInLiveData.postValue(ApiResult.Loading())
delay(6000)
_signInLiveData.postValue(ApiResult.Success())
_loginLiveData.postValue(ApiResult.Loading())
val response = repository.login(userName, password)
_loginLiveData.postValue(response)
}
}
fun loginProceed(userName: String, password: String){
viewModelScope.launch {
_loginProceedLiveData.postValue(ApiResult.Loading())
val response = repository.loginProceed(userName, password)
_loginProceedLiveData.postValue(response)
}
}
fun checkEmailExist(email: String, userType: String){
viewModelScope.launch {
_checkEmailExistLiveData.postValue(ApiResult.Loading())
val response = repository.checkEmailExit(userType, email)
_checkEmailExistLiveData.postValue(response)
}
}
fun sendOTP(email: String, userType: String){
viewModelScope.launch {
_sendOTPLiveData.postValue(ApiResult.Loading())
val response = repository.userEmailVerification(userType, email)
_sendOTPLiveData.postValue(response)
}
}
fun validateOTP(uniqueString: String, otp: String){
viewModelScope.launch {
_validateOTPLiveData.postValue(ApiResult.Loading())
val response = repository.validateOTP(uniqueString, otp)
_validateOTPLiveData.postValue(response)
}
}
fun checkUserNameExist(email: String, userName: String, userType: String){
viewModelScope.launch {
_checkUserNameExistLiveData.postValue(ApiResult.Loading())
val response = repository.checkUserNameExist(email, userName, userType)
_checkUserNameExistLiveData.postValue(response)
}
}
}

View File

@@ -0,0 +1,7 @@
package com.woka.utils
const val PARENT_TYPE = "2"
const val CHILD_TYPE = "1"
const val NO_INTERNET_MESSAGE = "Make sure you are connected to internet"
const val UNKNOWN_ERROR_MESSAGE = "An unknown error occurred"

View File

@@ -4,9 +4,11 @@ import android.app.Dialog
import android.content.Context
import android.content.ContextWrapper
import android.view.LayoutInflater
import android.view.View.GONE
import android.view.View.VISIBLE
import com.woka.databinding.LayoutProgressViewBinding
class ProgressView(context: Context, title: String): ContextWrapper(context) {
class ProgressView(context: Context, title: String? = null): ContextWrapper(context) {
private val dialog: Dialog = Dialog(this)
private var binding: LayoutProgressViewBinding = LayoutProgressViewBinding.inflate(LayoutInflater.from(this))
@@ -19,10 +21,20 @@ class ProgressView(context: Context, title: String): ContextWrapper(context) {
dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)
// init views
binding.title.text = title
binding.title.visibility = title?.let {
binding.title.text = it
VISIBLE
}?: GONE
}
fun show() = dialog.show()
fun show(title: String? = null) {
binding.title.visibility = title?.let {
binding.title.text = it
VISIBLE
}?: GONE
dialog.show()
}
fun hide() = dialog.dismiss()

View File

@@ -78,6 +78,7 @@
/>
<LinearLayout
android:id="@+id/opt_ll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
@@ -211,6 +212,49 @@
</LinearLayout>
<TextView
android:id="@+id/countdown"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
tools:text="OTP is valid for 10:00 Min"
android:textColor="@color/color_primary"
android:fontFamily="@font/exo_2_medium"
android:textSize="@dimen/_14ssp"
android:textAlignment="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/opt_ll"
app:layout_constraintBottom_toTopOf="@id/next"
app:layout_constraintVertical_bias="0.1"
/>
<TextView
android:id="@+id/resend"
android:visibility="gone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="2dp"
android:text="@string/resend_otp"
android:textColor="@color/color_primary"
android:fontFamily="@font/exo_2_medium"
android:textSize="@dimen/_14ssp"
android:textAlignment="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/opt_ll"
app:layout_constraintBottom_toTopOf="@id/next"
app:layout_constraintVertical_bias="0.1"
/>
<TextView
android:id="@+id/info_text"
android:layout_width="match_parent"

View File

@@ -98,6 +98,9 @@
android:textColorHint="@android:color/darker_gray"
android:textSize="@dimen/_13sdp"
android:digits="@string/alphanumeric"
android:maxLength="16"
/>
<TextView
@@ -152,6 +155,8 @@
android:inputType="textPassword"
android:textSize="@dimen/_13sdp"
android:maxLength="16"
/>
</com.google.android.material.textfield.TextInputLayout>

View File

@@ -111,6 +111,8 @@
android:paddingHorizontal="20dp"
android:paddingVertical="15dp"
android:maxLength="16"
/>
<TextView
@@ -153,6 +155,8 @@
android:paddingHorizontal="20dp"
android:paddingVertical="15dp"
android:maxLength="50"
/>
<TextView
@@ -209,6 +213,8 @@
android:paddingHorizontal="20dp"
android:paddingVertical="15dp"
android:maxLength="16"
/>
</com.google.android.material.textfield.TextInputLayout>

View File

@@ -69,4 +69,6 @@
<string name="back_btn" translatable="false">back_btn</string>
<string name="enter_your_password">Enter your password</string>
<string name="please_wait">Please wait...</string>
<string name="alphanumeric" translatable="false">ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890</string>
<string name="resend_otp">Resend OTP?</string>
</resources>