Added OTP support to login

parent 2174f53d
......@@ -41,6 +41,10 @@
android:name=".ui.LoginScreen"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize|stateHidden" />
<activity
android:name=".ui.OtpValidationActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize|stateHidden" />
<activity android:name=".ui.ResetPasswordActivity"
android:screenOrientation="portrait"
android:fitsSystemWindows="true"
......
package com.vsoft.vera.api.interfaces;
import com.vsoft.vera.api.pojos.OtpPostData;
import com.vsoft.vera.utils.Constants;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;
public interface OtpApi {
@POST(Constants.URL_PHONE_NUMBER_VERIFICATION)
Call<ResponseBody> getOtp(@Body OtpPostData otpPostData);
@GET(Constants.URL_PHONE_NUMBER_VALIDATION)
Call<ResponseBody> validateOtp(@Query(value = Constants.PHONE_NUMBER,encoded = true) String phone_number,
@Query(value = Constants.COUNTRY_CODE, encoded = true) String country_code,
@Query(Constants.VERIFICATION_CODE) String verification_code,
@Query(Constants.LANGUAGE) String language);
}
package com.vsoft.vera.api.listeners.get;
import com.vsoft.vera.api.pojos.LoginApiResponse;
public interface GetValidateOtpApiListener {
void onDoneApiCall(String message);
void onFailApiCall(String message);
}
package com.vsoft.vera.api.listeners.post;
public interface PostOtpApiListener {
void onDoneApiCall(String message);
void onFailApiCall(String message);
}
package com.vsoft.vera.api.managers;
import com.google.gson.JsonObject;
import com.vsoft.vera.api.RestClient;
import com.vsoft.vera.api.interfaces.LoginApi;
import com.vsoft.vera.api.interfaces.OtpApi;
import com.vsoft.vera.api.listeners.get.GetValidateOtpApiListener;
import com.vsoft.vera.api.listeners.post.PostOtpApiListener;
import com.vsoft.vera.api.pojos.OtpPostData;
import com.vsoft.vera.db.models.Reference;
import com.vsoft.vera.utils.CatalogueLog;
import com.vsoft.vera.utils.Constants;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
public class OtpApiManager {
private static String error = "Something went Wrong";
public static void getOTP(String mobileNumber, PostOtpApiListener listener){
final Retrofit retrofit = RestClient.getInitializedRestAdapterWithOutAuthorizationHeader();
OtpPostData otpPostData = new OtpPostData();
otpPostData.setPhone_number(mobileNumber);
otpPostData.setVia("sms");
otpPostData.setCountry_code("+91");
otpPostData.setLn("en");
Call<ResponseBody> call = retrofit.create(OtpApi.class).getOtp(otpPostData);
try {
//Retrofit synchronous call
Response<ResponseBody> response = call.execute();
if(response.isSuccessful()){
try{
JSONObject jsonObject = new JSONObject(response.body().string());
if(jsonObject.has(Constants.RESPONSE_SUCCESS)){
boolean success = jsonObject.getBoolean(Constants.RESPONSE_SUCCESS);
if(success){
listener.onDoneApiCall(jsonObject.getString(Constants.RESPONSE_MESSAGE));
}else{
if(jsonObject.has(Constants.RESPONSE_ERRORS)){
JSONObject errors = jsonObject.getJSONObject(Constants.RESPONSE_ERRORS);
if(errors.has(Constants.RESPONSE_MESSAGE)) {
listener.onFailApiCall(jsonObject.getString(Constants.RESPONSE_MESSAGE));
}else{
listener.onFailApiCall(error);
}
}else{
listener.onFailApiCall(error);
}
}
}else{
listener.onFailApiCall(error);
}
}catch (JSONException e) {
CatalogueLog.e("LoginApiManager: submitLoginValues: onResponse: ", e);
listener.onFailApiCall(error);
} catch (IOException e) {
CatalogueLog.e("LoginApiManager: submitLoginValues: onResponse: ", e);
listener.onFailApiCall(error);
}
}else {
JSONObject errorObject = new JSONObject(response.errorBody().string());
if(errorObject.has(Constants.RESPONSE_MESSAGE)){
listener.onFailApiCall(errorObject.getString(Constants.RESPONSE_MESSAGE));
}else{
listener.onFailApiCall(error);
}
}
}catch (IOException e) {
CatalogueLog.e("OtpApiManager: IOException: ", e);
listener.onFailApiCall(error);
} catch (NullPointerException e) {
CatalogueLog.e("OtpApiManager: NullPointerException: ", e);
listener.onFailApiCall(error);
} catch (JSONException e) {
CatalogueLog.e("OtpApiManager: JSONException: ", e);
listener.onFailApiCall(error);
}
}
public static void validateOTP(String mobileNumber,String verificationCode, GetValidateOtpApiListener listener){
final Retrofit retrofit = RestClient.getInitializedRestAdapterWithOutAuthorizationHeader();
Call<ResponseBody> call = retrofit.create(OtpApi.class).validateOtp(mobileNumber,"+91",verificationCode,"en");
try {
//Retrofit synchronous call
Response<ResponseBody> response = call.execute();
if(response.isSuccessful()){
try{
JSONObject jsonObject = new JSONObject(response.body().string());
if(jsonObject.has(Constants.RESPONSE_SUCCESS)){
boolean success = jsonObject.getBoolean(Constants.RESPONSE_SUCCESS);
if(success){
listener.onDoneApiCall(jsonObject.getString(Constants.RESPONSE_MESSAGE));
}else{
if(jsonObject.has(Constants.RESPONSE_ERRORS)){
JSONObject errors = jsonObject.getJSONObject(Constants.RESPONSE_ERRORS);
if(errors.has(Constants.RESPONSE_MESSAGE)) {
listener.onFailApiCall(jsonObject.getString(Constants.RESPONSE_MESSAGE));
}else{
listener.onFailApiCall(error);
}
}else{
listener.onFailApiCall(error);
}
}
}else{
listener.onFailApiCall(error);
}
}catch (JSONException e) {
CatalogueLog.e("LoginApiManager: submitLoginValues: onResponse: ", e);
listener.onFailApiCall(error);
} catch (IOException e) {
CatalogueLog.e("LoginApiManager: submitLoginValues: onResponse: ", e);
listener.onFailApiCall(error);
}
}else {
JSONObject errorObject = new JSONObject(response.errorBody().string());
if(errorObject.has(Constants.RESPONSE_MESSAGE)){
listener.onFailApiCall(errorObject.getString(Constants.RESPONSE_MESSAGE));
}else{
listener.onFailApiCall(error);
}
}
}catch (IOException e) {
CatalogueLog.e("OtpApiManager: IOException: ", e);
listener.onFailApiCall(error);
} catch (NullPointerException e) {
CatalogueLog.e("OtpApiManager: NullPointerException: ", e);
listener.onFailApiCall(error);
} catch (JSONException e) {
CatalogueLog.e("OtpApiManager: JSONException: ", e);
listener.onFailApiCall(error);
}
}
}
package com.vsoft.vera.api.pojos;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class OtpPostData {
@SerializedName("via")
@Expose
private String via;
@SerializedName("phone_number")
@Expose
private String phone_number;
@SerializedName("country_code")
@Expose
private String country_code;
@SerializedName("ln")
@Expose
private String ln;
public String getVia() {
return via;
}
public void setVia(String via) {
this.via = via;
}
public String getPhone_number() {
return phone_number;
}
public void setPhone_number(String phone_number) {
this.phone_number = phone_number;
}
public String getCountry_code() {
return country_code;
}
public void setCountry_code(String country_code) {
this.country_code = country_code;
}
public String getLn() {
return ln;
}
public void setLn(String ln) {
this.ln = ln;
}
}
......@@ -13,6 +13,7 @@ import android.view.KeyEvent;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;
import com.google.android.gms.analytics.Tracker;
import com.vsoft.vera.CatalogueApplication;
......@@ -77,7 +78,7 @@ public class LoginScreen extends Activity {
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_CENTER:
case KeyEvent.KEYCODE_ENTER:
callLoginAPI();
callLoginAPI(false);
return true;
default:
break;
......@@ -113,6 +114,22 @@ public class LoginScreen extends Activity {
Util.sendScreenName(tracker, getString(R.string.login_screen_string));
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == Constants.LOGIN_SCREEN_OTP_REQUEST_CODE){
if(data!=null && data.getExtras()!=null){
String message = data.getExtras().getString(Constants.MESSAGE);
if(message.equalsIgnoreCase(Constants.RESPONSE_SUCCESS)){
callLoginAPI(false);
}else{
Toast.makeText(this,"Something went Wrong",Toast.LENGTH_LONG).show();
}
}
}
}
private void CheckLoginValues() {
String sysId = PrefManager.getSharedPref(LoginScreen.this, PrefManager.PREFERENCE_USER_SYS_ID);
if (!TextUtils.isEmpty(sysId)) {
......@@ -136,7 +153,7 @@ public class LoginScreen extends Activity {
}
}
private void callLoginAPI() {
private void callLoginAPI(boolean withOtp) {
String userNameString = mUserNameEditText.getText().toString().trim();
String passwordString = mPasswordEditText.getText().toString().trim();
......@@ -149,19 +166,38 @@ public class LoginScreen extends Activity {
if (!TextUtils.isEmpty(userNameString) && !TextUtils.isEmpty(passwordString)) {
KeyboardUtil.hideKeyboard(LoginScreen.this);
if (mApplication.isNetConnected()) {
if(withOtp){
launchOptValidationScreen();
}else{
new LoginDetailsSendToServer().execute(mUserNameEditText.getText().toString().trim(), mPasswordEditText.getText().toString().trim());
}
} else {
DialogUtils.showNoConnectionDialog(LoginScreen.this);
}
}
}
@OnClick(R.id.login_screen_login_text_view)
void onLoginClicked() {
callLoginAPI();
@OnClick({R.id.login_screen_login_text_view,R.id.login_screen_login_text_view_twillio})
void onLoginClicked(View mView) {
if(mView.getId()==R.id.login_screen_login_text_view){
callLoginAPI(false);
}else if(mView.getId()==R.id.login_screen_login_text_view_twillio){
callLoginAPI(true);
}
}
private void launchOptValidationScreen(){
Intent intent = new Intent(LoginScreen.this,OtpValidationActivity.class);
startActivityForResult(intent,Constants.LOGIN_SCREEN_OTP_REQUEST_CODE);
}
private class LoginDetailsSendToServer extends AsyncTask<String, Integer, Integer> {
private ProgressDialog progressDialog;
private static final int USER_DETAIL = 1;
......
package com.vsoft.vera.ui;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.content.LocalBroadcastManager;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.vsoft.vera.CatalogueApplication;
import com.vsoft.vera.R;
import com.vsoft.vera.api.listeners.get.GetUserDetailApiListener;
import com.vsoft.vera.api.listeners.get.GetUserLoginApiListener;
import com.vsoft.vera.api.listeners.get.GetValidateOtpApiListener;
import com.vsoft.vera.api.listeners.post.PostOtpApiListener;
import com.vsoft.vera.api.listeners.put.PutDeviceRegistrationApiListener;
import com.vsoft.vera.api.managers.LoginApiManager;
import com.vsoft.vera.api.managers.OtpApiManager;
import com.vsoft.vera.api.managers.UserApiManager;
import com.vsoft.vera.api.pojos.LoginApiResponse;
import com.vsoft.vera.db.managers.ChatBotHistoryManager;
import com.vsoft.vera.db.managers.ChatBotUserManager;
import com.vsoft.vera.db.models.ChatBotUser;
import com.vsoft.vera.db.models.UserApiValues;
import com.vsoft.vera.utils.Constants;
import com.vsoft.vera.utils.DialogUtils;
import com.vsoft.vera.utils.GenerateRandomString;
import com.vsoft.vera.utils.KeyboardUtil;
import com.vsoft.vera.utils.PrefManager;
import com.vsoft.vera.utils.Util;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class OtpValidationActivity extends Activity {
@BindView(R.id.otp_screen_phone_edit_text) EditText mPhoneEditText;
@BindView(R.id.otp_screen_otp_edit_text) EditText mOTPEditText;
@BindView(R.id.phone_validate_layout) RelativeLayout phone_layout;
@BindView(R.id.otp_validate_layout) RelativeLayout otp_validate_layout;
private CatalogueApplication mApplication;
private String phoneString = null;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_otp_validation);
ButterKnife.bind(this);
mApplication = (CatalogueApplication) getApplication();
}
@OnClick(R.id.otp_screen_text_view)
void onLoginClicked() {
callOtpAPI();
}
@OnClick(R.id.otp_screen_validate_text_view)
void onValidateClicked(){
callValidateOtpAPI();
}
private void callOtpAPI() {
phoneString = mPhoneEditText.getText().toString().trim();
if (TextUtils.isEmpty(phoneString)) {
mPhoneEditText.setError(getResources().getString(R.string.phone_error));
}
if (!TextUtils.isEmpty(phoneString) ) {
KeyboardUtil.hideKeyboard(OtpValidationActivity.this);
if (mApplication.isNetConnected()) {
new generateOtp().execute(phoneString);
} else {
DialogUtils.showNoConnectionDialog(OtpValidationActivity.this);
}
}
}
private void callValidateOtpAPI() {
String optCode = mOTPEditText.getText().toString().trim();
if (TextUtils.isEmpty(optCode)) {
mOTPEditText.setError(getResources().getString(R.string.otp_error));
}
if (!TextUtils.isEmpty(phoneString) ) {
KeyboardUtil.hideKeyboard(OtpValidationActivity.this);
if (mApplication.isNetConnected()) {
new validateOtp().execute(phoneString,optCode);
} else {
DialogUtils.showNoConnectionDialog(OtpValidationActivity.this);
}
}
}
private class generateOtp extends AsyncTask<String, Integer, Integer> {
private ProgressDialog progressDialog;
private String apiMessage="Something went Wrong";
private int apiStatus=0;
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(OtpValidationActivity.this);
progressDialog.setMessage(getString(R.string.generating_otp));
progressDialog.show();
progressDialog.setCancelable(false);
}
@Override
protected Integer doInBackground(String... params) {
String phoneString = params[0];
OtpApiManager.getOTP(phoneString, new PostOtpApiListener() {
@Override
public void onDoneApiCall(String message) {
apiMessage = message;
apiStatus = 1;
}
@Override
public void onFailApiCall(String message) {
apiMessage = message;
apiStatus = 0;
}
});
return apiStatus;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(Integer status) {
super.onPostExecute(status);
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
if(apiStatus==1){ // success
showPhoneLayout(false);
}else{
showPhoneLayout(true);
}
Toast.makeText(OtpValidationActivity.this,apiMessage,Toast.LENGTH_LONG).show();
}
}
private class validateOtp extends AsyncTask<String, Integer, String>{
private ProgressDialog progressDialog;
private String apiMessage="Something went Wrong";
private int apiStatus=0;
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(OtpValidationActivity.this);
progressDialog.setMessage(getString(R.string.validating_otp));
progressDialog.show();
progressDialog.setCancelable(false);
}
@Override
protected String doInBackground(String... params) {
String phoneString = params[0];
String otpCode = params[1];
OtpApiManager.validateOTP(phoneString, otpCode,new GetValidateOtpApiListener() {
@Override
public void onDoneApiCall(String message) {
apiMessage = message;
apiStatus = 1;
}
@Override
public void onFailApiCall(String message) {
apiMessage = message;
apiStatus = 0;
}
});
return apiMessage;
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
}
@Override
protected void onPostExecute(String message) {
super.onPostExecute(message);
if (progressDialog != null && progressDialog.isShowing()) {
progressDialog.dismiss();
}
if(apiStatus==1){
setResult();
}else{
Toast.makeText(OtpValidationActivity.this,apiMessage,Toast.LENGTH_LONG).show();
}
}
}
private void showPhoneLayout(boolean show){
if(show){
phone_layout.setVisibility(View.VISIBLE);
otp_validate_layout.setVisibility(View.GONE);
}else{
phone_layout.setVisibility(View.GONE);
otp_validate_layout.setVisibility(View.VISIBLE);
}
}
public void setResult(){
Intent intent=new Intent();
intent.putExtra(Constants.MESSAGE,Constants.RESPONSE_SUCCESS);
setResult(Constants.LOGIN_SCREEN_OTP_REQUEST_CODE,intent);
finish();
}
}
......@@ -53,6 +53,13 @@ public class Constants {
public static final String MESSAGE = "Message";
public static final String PHONE_NUMBER = "phone_number";
public static final String COUNTRY_CODE = "country_code";
public static final String VERIFICATION_CODE = "verification_code";
public static final String LANGUAGE = "ln";
public static final String VIA = "via";
/**
* Broadcast custom intent
*/
......@@ -78,13 +85,14 @@ public class Constants {
public static final String URL_PARAM_FILE_NAME = "file_name";
public static final String URL_PARAM_SYS_ID = "sys_id";
public static final String URL_PARAM_OPENED_BY = "opened_by";
public static String URL_PHONE_NUMBER_VERIFICATION = "https://api.authy.com/protected/json/phones/verification/start?api_key=" + Constants.TWILIO_VALIDATION_KEY;
public static String URL_PHONE_NUMBER_VALIDATION = "https://api.authy.com/protected/json/phones/verification/check?api_key=" + Constants.TWILIO_VALIDATION_KEY;
public static final String URL_PHONE_NUMBER_VERIFICATION = "https://api.authy.com/protected/json/phones/verification/start?api_key=" + Constants.TWILIO_VALIDATION_KEY;
public static final String URL_PHONE_NUMBER_VALIDATION = "https://api.authy.com/protected/json/phones/verification/check?api_key=" + Constants.TWILIO_VALIDATION_KEY;
/**
* Request Code
* */
public static final int LOGIN_SCREEN_REQUEST_CODE = 105;
public static final int LOGIN_SCREEN_OTP_REQUEST_CODE = 112;
/**
* Preference Notification token.
......@@ -158,6 +166,9 @@ public class Constants {
public static final String RESPONSE_VARIABLES_OBJECT_NAME = "variables";
public static final String RESPONSE_CATEGORY_OBJECT_NAME = "Category";
public static final String RESPONSE_VARIABLES_UI_POLICY_ACTIONS = "ui_policy_actions";
public static final String RESPONSE_SUCCESS = "success";
public static final String RESPONSE_MESSAGE = "message";
public static final String RESPONSE_ERRORS = "errors";
/**
* Web services urls
......
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/phone_validate_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TextInputLayout
android:id="@+id/phone_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
android:layout_centerVertical="true">
<EditText
android:id="@+id/otp_screen_phone_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/extra_large_margin"
android:layout_marginRight="@dimen/extra_large_margin"
android:background="@drawable/username_under_bg_box"
android:hint="@string/phone"
android:lines="1"
android:inputType="number"
android:padding="@dimen/normal_margin"
android:singleLine="true" />
</android.support.design.widget.TextInputLayout>
<TextView
android:id="@+id/otp_screen_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/normal_margin"
android:layout_marginLeft="@dimen/extra_large_margin"
android:layout_marginRight="@dimen/extra_large_margin"
android:layout_marginTop="30dp"
android:layout_below="@+id/phone_layout"
android:background="@drawable/login_bg"
android:gravity="center"
android:paddingBottom="@dimen/normal_margin"
android:paddingTop="@dimen/normal_margin"
android:text="@string/generate_otp"
android:textColor="@android:color/white"
android:textSize="@dimen/large_text_size" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/otp_validate_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<android.support.design.widget.TextInputLayout
android:id="@+id/otp_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
android:layout_centerVertical="true">
<EditText
android:id="@+id/otp_screen_otp_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/extra_large_margin"
android:layout_marginRight="@dimen/extra_large_margin"
android:background="@drawable/username_under_bg_box"
android:hint="@string/enter_otp"
android:lines="1"
android:inputType="number"
android:padding="@dimen/normal_margin"
android:singleLine="true" />
</android.support.design.widget.TextInputLayout>
<TextView
android:id="@+id/otp_screen_validate_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/normal_margin"
android:layout_marginLeft="@dimen/extra_large_margin"
android:layout_marginRight="@dimen/extra_large_margin"
android:layout_marginTop="30dp"
android:layout_below="@+id/otp_layout"
android:background="@drawable/login_bg"
android:gravity="center"
android:paddingBottom="@dimen/normal_margin"
android:paddingTop="@dimen/normal_margin"
android:text="@string/validate_otp"
android:textColor="@android:color/white"
android:textSize="@dimen/large_text_size" />
</RelativeLayout>
</RelativeLayout>
\ No newline at end of file
......@@ -47,19 +47,30 @@
<!--Login Screen-->
<string name="prompt_relogin_login_expired">Login expired, please login again&#8230;</string>
<string name="login_screen_login_string">Login</string>
<string name="login_screen_login_string_twillio">Login With Twillio</string>
<string name="login_screen_login_string_twillio">Login With OTP</string>
<string name="login_screen_submit_string">Submit</string>
<string name="login_screen_logging_in_loading_string">Logging in&#8230;</string>
<string name="login_screen_getting_user_detail_loading_string">Getting user details&#8230;</string>
<string name="login_screen_invalid_username_and_password_string">Invalid username and password</string>
<string name="user_detail_not_available">Unable to fetch user details.</string>
<string name="generate_otp">Generate OTP</string>
<string name="generating_otp">Generating OTP</string>
<string name="sending_otp">Sending OTP</string>
<string name="validate_otp">Validate OTP</string>
<string name="validating_otp">Validating OTP</string>
<string name="enter_otp">Enter OTP</string>
<string name="user_error">Please enter username</string>
<string name="pasw_error">Please enter password</string>
<string name="phone_error">Please enter mobile number</string>
<string name="otp_error">Please enter OTP</string>
<string name="username_string">Username</string>
<string name="password_string">Password</string>
<string name="confirm_password_string">Confirm Password</string>
<string name="home_screen_logout_string">Ver: %1$s</string>
<string name="phone">Phone </string>
<!--Variable Screen-->
<string name="variable_form_mandatory_toast_string">Fields marked with an asterisk(*) are mandatory.</string>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment