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:
@@ -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)
|
||||
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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}"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
6
app/src/main/java/com/woka/onboard/models/Gender.kt
Normal file
6
app/src/main/java/com/woka/onboard/models/Gender.kt
Normal file
@@ -0,0 +1,6 @@
|
||||
package com.woka.onboard.models
|
||||
|
||||
data class Gender(
|
||||
val gender_name: String,
|
||||
val id: Int
|
||||
)
|
||||
6
app/src/main/java/com/woka/onboard/models/Language.kt
Normal file
6
app/src/main/java/com/woka/onboard/models/Language.kt
Normal file
@@ -0,0 +1,6 @@
|
||||
package com.woka.onboard.models
|
||||
|
||||
data class Language(
|
||||
val id: Int,
|
||||
val language_name: String
|
||||
)
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.woka.onboard.models
|
||||
data class LoginResponse(
|
||||
val result: Result
|
||||
val result: Result?
|
||||
)
|
||||
@@ -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?
|
||||
)
|
||||
5
app/src/main/java/com/woka/onboard/models/VerifyEmail.kt
Normal file
5
app/src/main/java/com/woka/onboard/models/VerifyEmail.kt
Normal file
@@ -0,0 +1,5 @@
|
||||
package com.woka.onboard.models
|
||||
|
||||
data class VerifyEmail(
|
||||
val unique_string: String?
|
||||
)
|
||||
@@ -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>>
|
||||
|
||||
}
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
7
app/src/main/java/com/woka/utils/Constants.kt
Normal file
7
app/src/main/java/com/woka/utils/Constants.kt
Normal 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"
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user