diff --git a/app/src/main/java/com/woka/networking/ApiResult.kt b/app/src/main/java/com/woka/networking/ApiResult.kt index 0b92cc6..2158a71 100644 --- a/app/src/main/java/com/woka/networking/ApiResult.kt +++ b/app/src/main/java/com/woka/networking/ApiResult.kt @@ -3,7 +3,7 @@ package com.woka.networking sealed class ApiResult(data: T? = null, errorMessage: String? = null) { class Loading: ApiResult() - class Success(data: T? = null): ApiResult(data) - class Error(errorMessage: String? = null): ApiResult(errorMessage = errorMessage) + class Success(val data: T? = null): ApiResult(data) + class Error(val errorMessage: String? = null): ApiResult(errorMessage = errorMessage) } \ No newline at end of file diff --git a/app/src/main/java/com/woka/networking/RetrofitHelper.kt b/app/src/main/java/com/woka/networking/RetrofitHelper.kt index 5318cc7..7018f6a 100644 --- a/app/src/main/java/com/woka/networking/RetrofitHelper.kt +++ b/app/src/main/java/com/woka/networking/RetrofitHelper.kt @@ -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 handleApiCall(apiCall: suspend () -> Response>): ApiResult { + 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 handleApiResponse(response: Response>): ApiResult { + 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()) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/woka/onboard/fragments/GetCodeFragment.kt b/app/src/main/java/com/woka/onboard/fragments/GetCodeFragment.kt index f79f55a..b75f56b 100644 --- a/app/src/main/java/com/woka/onboard/fragments/GetCodeFragment.kt +++ b/app/src/main/java/com/woka/onboard/fragments/GetCodeFragment.kt @@ -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}" + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/woka/onboard/fragments/GetEmailFragment.kt b/app/src/main/java/com/woka/onboard/fragments/GetEmailFragment.kt index bb3b229..daa4c93 100644 --- a/app/src/main/java/com/woka/onboard/fragments/GetEmailFragment.kt +++ b/app/src/main/java/com/woka/onboard/fragments/GetEmailFragment.kt @@ -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 { diff --git a/app/src/main/java/com/woka/onboard/fragments/SignInFragment.kt b/app/src/main/java/com/woka/onboard/fragments/SignInFragment.kt index a556a36..cd6259f 100644 --- a/app/src/main/java/com/woka/onboard/fragments/SignInFragment.kt +++ b/app/src/main/java/com/woka/onboard/fragments/SignInFragment.kt @@ -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() + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/woka/onboard/fragments/SignUpFragment.kt b/app/src/main/java/com/woka/onboard/fragments/SignUpFragment.kt index 89765fd..af6c056 100644 --- a/app/src/main/java/com/woka/onboard/fragments/SignUpFragment.kt +++ b/app/src/main/java/com/woka/onboard/fragments/SignUpFragment.kt @@ -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 + } } \ No newline at end of file diff --git a/app/src/main/java/com/woka/onboard/models/Gender.kt b/app/src/main/java/com/woka/onboard/models/Gender.kt new file mode 100644 index 0000000..4ff6541 --- /dev/null +++ b/app/src/main/java/com/woka/onboard/models/Gender.kt @@ -0,0 +1,6 @@ +package com.woka.onboard.models + +data class Gender( + val gender_name: String, + val id: Int +) \ No newline at end of file diff --git a/app/src/main/java/com/woka/onboard/models/Language.kt b/app/src/main/java/com/woka/onboard/models/Language.kt new file mode 100644 index 0000000..fb6f42c --- /dev/null +++ b/app/src/main/java/com/woka/onboard/models/Language.kt @@ -0,0 +1,6 @@ +package com.woka.onboard.models + +data class Language( + val id: Int, + val language_name: String +) \ No newline at end of file diff --git a/app/src/main/java/com/woka/onboard/models/LoginResponse.kt b/app/src/main/java/com/woka/onboard/models/LoginResponse.kt index a15c35a..03ffc62 100644 --- a/app/src/main/java/com/woka/onboard/models/LoginResponse.kt +++ b/app/src/main/java/com/woka/onboard/models/LoginResponse.kt @@ -1,4 +1,4 @@ package com.woka.onboard.models data class LoginResponse( - val result: Result + val result: Result? ) \ No newline at end of file diff --git a/app/src/main/java/com/woka/onboard/models/Result.kt b/app/src/main/java/com/woka/onboard/models/Result.kt index f900c1f..debf7c4 100644 --- a/app/src/main/java/com/woka/onboard/models/Result.kt +++ b/app/src/main/java/com/woka/onboard/models/Result.kt @@ -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? ) \ No newline at end of file diff --git a/app/src/main/java/com/woka/onboard/models/VerifyEmail.kt b/app/src/main/java/com/woka/onboard/models/VerifyEmail.kt new file mode 100644 index 0000000..ecc1015 --- /dev/null +++ b/app/src/main/java/com/woka/onboard/models/VerifyEmail.kt @@ -0,0 +1,5 @@ +package com.woka.onboard.models + +data class VerifyEmail( + val unique_string: String? +) \ No newline at end of file diff --git a/app/src/main/java/com/woka/onboard/mvvm/OnboardApiService.kt b/app/src/main/java/com/woka/onboard/mvvm/OnboardApiService.kt index b9d0200..839c93a 100644 --- a/app/src/main/java/com/woka/onboard/mvvm/OnboardApiService.kt +++ b/app/src/main/java/com/woka/onboard/mvvm/OnboardApiService.kt @@ -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> + + @POST("login_proceed") + suspend fun loginProceed(@Body body: FormBody): Response> + + @POST("user_email_verification") + suspend fun verifyEmail(@Body body: FormBody): Response> + + @POST("check_exist_email") + suspend fun checkEmailExist(@Body body: FormBody): Response> + + @POST("validate_otp") + suspend fun verifyOTP(@Body body: FormBody): Response> + + @POST("check_exist_username") + suspend fun checkUserNameExist(@Body body: FormBody): Response> + } \ No newline at end of file diff --git a/app/src/main/java/com/woka/onboard/mvvm/OnboardRepository.kt b/app/src/main/java/com/woka/onboard/mvvm/OnboardRepository.kt index 55c9b63..ffeaa2c 100644 --- a/app/src/main/java/com/woka/onboard/mvvm/OnboardRepository.kt +++ b/app/src/main/java/com/woka/onboard/mvvm/OnboardRepository.kt @@ -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 { - 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 { + return handleApiCall { + apiService.loginProceed( + FormBody.Builder() + .add("username", userName) + .add("password", password) + .build() + ) + } + } + + suspend fun checkEmailExit(userType: String, email: String): ApiResult { + return handleApiCall { + apiService.checkEmailExist( + FormBody.Builder() + .add("email", email) + .add("user_type", userType) + .build() + ) + } + } + + suspend fun userEmailVerification(userType: String, email: String): ApiResult { + return handleApiCall { + apiService.verifyEmail( + FormBody.Builder() + .add("email", email) + .add("user_type", userType) + .build() + ) + } + } + + suspend fun validateOTP(uniqueString: String, otp: String): ApiResult { + return handleApiCall { + apiService.verifyOTP( + FormBody.Builder() + .add("otp", otp) + .add("unique_string", uniqueString) + .build() + ) + } + } + + suspend fun checkUserNameExist(email: String, userName: String, userType: String): ApiResult{ + return handleApiCall { + apiService.checkUserNameExist( + FormBody.Builder() + .add("email", email) + .add("username", userName) + .add("user_type", userType) + .build() + ) } } diff --git a/app/src/main/java/com/woka/onboard/mvvm/OnboardViewModel.kt b/app/src/main/java/com/woka/onboard/mvvm/OnboardViewModel.kt index 877e274..9d8e6a4 100644 --- a/app/src/main/java/com/woka/onboard/mvvm/OnboardViewModel.kt +++ b/app/src/main/java/com/woka/onboard/mvvm/OnboardViewModel.kt @@ -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>() - val signInLiveData: LiveData> - get() = _signInLiveData + // live_data + /* + Login Fragment + */ + private val _loginLiveData = MutableLiveData?>() + fun clearLoginLiveData() = _loginLiveData.postValue(null) + val loginLiveData: LiveData?> + get() = _loginLiveData + + private val _loginProceedLiveData = MutableLiveData?>() + fun clearLoginProceedLiveData() = _loginProceedLiveData.postValue(null) + val loginProceedData: LiveData?> + get() = _loginProceedLiveData + + /* + Send email Fragment + */ + private val _checkEmailExistLiveData = MutableLiveData?>() + fun clearCheckEmailExist() = _checkEmailExistLiveData.postValue(null) + val checkEmailExistData: LiveData?> + get() = _checkEmailExistLiveData + + private val _sendOTPLiveData = MutableLiveData?>() + fun clearSendOTPData() = _sendOTPLiveData.postValue(null) + val sendOTPLiveData: LiveData?> + get() = _sendOTPLiveData + + /* + VerifyOTP Fragment + */ + private val _validateOTPLiveData = MutableLiveData?>() + fun clearValidateOTP() = _validateOTPLiveData.postValue(null) + val validateOTPLiveData: LiveData?> + get() = _validateOTPLiveData + + /* + SignUp Fragment + */ + private val _checkUserNameExistLiveData = MutableLiveData?>() + fun clearCheckUserNameExist() = _checkUserNameExistLiveData.postValue(null) + val checkUserNameExistLiveData: LiveData?> + 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) } } } \ No newline at end of file diff --git a/app/src/main/java/com/woka/utils/Constants.kt b/app/src/main/java/com/woka/utils/Constants.kt new file mode 100644 index 0000000..3f98762 --- /dev/null +++ b/app/src/main/java/com/woka/utils/Constants.kt @@ -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" \ No newline at end of file diff --git a/app/src/main/java/com/woka/utils/ProgressView.kt b/app/src/main/java/com/woka/utils/ProgressView.kt index 9929bc5..9454215 100644 --- a/app/src/main/java/com/woka/utils/ProgressView.kt +++ b/app/src/main/java/com/woka/utils/ProgressView.kt @@ -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() diff --git a/app/src/main/res/layout/fragment_get_code.xml b/app/src/main/res/layout/fragment_get_code.xml index 62b067e..a1f1559 100644 --- a/app/src/main/res/layout/fragment_get_code.xml +++ b/app/src/main/res/layout/fragment_get_code.xml @@ -78,6 +78,7 @@ /> + + + + diff --git a/app/src/main/res/layout/fragment_sign_up.xml b/app/src/main/res/layout/fragment_sign_up.xml index e865585..9c8969e 100644 --- a/app/src/main/res/layout/fragment_sign_up.xml +++ b/app/src/main/res/layout/fragment_sign_up.xml @@ -111,6 +111,8 @@ android:paddingHorizontal="20dp" android:paddingVertical="15dp" + android:maxLength="16" + /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 08a459a..3da095a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -69,4 +69,6 @@ back_btn Enter your password Please wait... + ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890 + Resend OTP? \ No newline at end of file