Commit f5c98440 authored by Chamod Ishankha's avatar Chamod Ishankha

login register, screen development and api call

parent f95aa25c
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AppInsightsSettings">
<option name="selectedTabId" value="Android Vitals" />
<option name="tabSettings">
<map>
<entry key="Firebase Crashlytics">
......
......@@ -3,7 +3,20 @@
<component name="deploymentTargetDropDown">
<value>
<entry key="app">
<State />
<State>
<runningDeviceTargetSelectedWithDropDown>
<Target>
<type value="RUNNING_DEVICE_TARGET" />
<deviceKey>
<Key>
<type value="SERIAL_NUMBER" />
<value value="adb-AYAV6R3925006878-kh1m4J._adb-tls-connect._tcp" />
</Key>
</deviceKey>
</Target>
</runningDeviceTargetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2024-05-17T19:35:30.624445300Z" />
</State>
</entry>
</value>
</component>
......
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
......
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
......
......@@ -38,7 +38,14 @@ dependencies {
implementation(libs.constraintlayout)
implementation(libs.navigation.fragment)
implementation(libs.navigation.ui)
implementation(libs.activity)
implementation(libs.android.spinkit)
implementation(libs.retrofit2)
implementation(libs.convertor.gson)
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
compileOnly(libs.projectlombok)
annotationProcessor(libs.projectlombok)
}
\ No newline at end of file
......@@ -2,7 +2,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:networkSecurityConfig="@xml/network_security_config"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
......@@ -12,6 +16,15 @@
android:supportsRtl="true"
android:theme="@style/Theme.BabyCare"
tools:targetApi="31">
<activity
android:name=".activities.DashboardActivity"
android:exported="false" />
<activity
android:name=".activities.auth.RegisterActivity"
android:exported="false" />
<activity
android:name=".activities.auth.LoginActivity"
android:exported="false" />
<activity
android:name=".MainActivity"
android:exported="true"
......
package com.kaluwa.enterprises.babycare;
import android.content.Intent;
import android.os.Bundle;
import com.google.android.material.snackbar.Snackbar;
......@@ -13,10 +14,12 @@ import androidx.navigation.Navigation;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import com.kaluwa.enterprises.babycare.activities.auth.LoginActivity;
import com.kaluwa.enterprises.babycare.databinding.ActivityMainBinding;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
......@@ -25,5 +28,12 @@ public class MainActivity extends AppCompatActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button startedBtn = findViewById(R.id.m_btn_get_started);
startedBtn.setOnClickListener(v -> {
Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
});
}
}
\ No newline at end of file
package com.kaluwa.enterprises.babycare.activities;
import android.os.Bundle;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.kaluwa.enterprises.babycare.R;
public class DashboardActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dashboard);
}
}
\ No newline at end of file
package com.kaluwa.enterprises.babycare.activities.auth;
import static com.kaluwa.enterprises.babycare.utils.Utils.emailAddressValidation;
import static com.kaluwa.enterprises.babycare.utils.Utils.loader;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.github.ybq.android.spinkit.SpinKitView;
import com.google.gson.Gson;
import com.kaluwa.enterprises.babycare.R;
import com.kaluwa.enterprises.babycare.config.ApiConfig;
import com.kaluwa.enterprises.babycare.dto.AuthenticationDto;
import com.kaluwa.enterprises.babycare.dto.LoginRequest;
import com.kaluwa.enterprises.babycare.dto.UserDto;
import com.kaluwa.enterprises.babycare.error.ErrorDto;
import com.kaluwa.enterprises.babycare.service.AuthApiService;
import java.io.IOException;
import java.util.Objects;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class LoginActivity extends AppCompatActivity {
private static final String TAG = "LoginActivity";
private EditText etEmail, etPassword;
private Button btnLogin;
private SpinKitView progressBar;
private View overlay;
// auth api service
private final AuthApiService authApiService = ApiConfig.getInstance().getAuthApi();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
// progress
progressBar = findViewById(R.id.progress_bar);
overlay = findViewById(R.id.overlay);
TextView tvRegister = findViewById(R.id.l_tv_register);
tvRegister.setOnClickListener(v -> {
Intent intent = new Intent(this, RegisterActivity.class);
startActivity(intent);
});
etEmail = findViewById(R.id.l_et_username);
etPassword = findViewById(R.id.l_et_password);
btnLogin = findViewById(R.id.l_btn_login);
btnLogin.setOnClickListener(v -> {
LoginRequest request = validate();
// call api()
if (!TextUtils.isEmpty(request.getEmail())) {
loader(overlay, progressBar, true);
Call<AuthenticationDto> call = authApiService.userLogin(request);
call.enqueue(new Callback<AuthenticationDto>() {
@Override
public void onResponse(Call<AuthenticationDto> call, Response<AuthenticationDto> response) {
if (response.isSuccessful()) {
AuthenticationDto authDto = response.body();
Toast.makeText(LoginActivity.this, "Success: "+authDto.getTokenDto().getToken(), Toast.LENGTH_LONG).show();
loader(overlay, progressBar, false);
} else {
try {
Gson gson = new Gson();
ErrorDto errorDto = gson.fromJson(response.errorBody().string(), ErrorDto.class);
Toast.makeText(LoginActivity.this, errorDto.getMessage(), Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(LoginActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
loader(overlay, progressBar, false);
}
}
@Override
public void onFailure(Call<AuthenticationDto> call, Throwable t) {
Toast.makeText(LoginActivity.this, "Error to Failure", Toast.LENGTH_LONG).show();
loader(overlay, progressBar, false);
}
});
}
});
}
private LoginRequest validate() {
LoginRequest request = new LoginRequest();
String email, password;
email = etEmail.getText().toString();
password = etPassword.getText().toString();
if (TextUtils.isEmpty(email)) {
etEmail.setError("Email is required.");
etEmail.requestFocus();
} else if (!emailAddressValidation(email)) {
etEmail.setError("Invalid email address, Please re-check & try again.");
etEmail.requestFocus();
} else if (TextUtils.isEmpty(password)) {
etPassword.setError("Password is required.");
etPassword.requestFocus();
} else {
request.setEmail(email);
request.setPassword(password);
}
return request;
}
}
\ No newline at end of file
package com.kaluwa.enterprises.babycare.activities.auth;
import static com.kaluwa.enterprises.babycare.utils.Utils.emailAddressValidation;
import static com.kaluwa.enterprises.babycare.utils.Utils.loader;
import static com.kaluwa.enterprises.babycare.utils.Utils.mobileNumberValidation;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.github.ybq.android.spinkit.SpinKitView;
import com.google.gson.Gson;
import com.kaluwa.enterprises.babycare.R;
import com.kaluwa.enterprises.babycare.config.ApiConfig;
import com.kaluwa.enterprises.babycare.dto.RegisterRequest;
import com.kaluwa.enterprises.babycare.dto.UserDto;
import com.kaluwa.enterprises.babycare.error.ErrorDto;
import com.kaluwa.enterprises.babycare.service.AuthApiService;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class RegisterActivity extends AppCompatActivity {
private static final String TAG = "RegisterActivity";
private EditText etFirstName, etLastName, etMobileNumber, etEmail, etPassword, etConfPassword;
private Button btnRegister;
private SpinKitView progressBar;
private View overlay;
// auth api service
private final AuthApiService authApiService = ApiConfig.getInstance().getAuthApi();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
// progress
progressBar = findViewById(R.id.progress_bar);
overlay = findViewById(R.id.overlay);
// values
etFirstName = findViewById(R.id.r_et_first_name);
etLastName = findViewById(R.id.r_et_last_name);
etMobileNumber = findViewById(R.id.r_et_mobile);
etEmail = findViewById(R.id.r_et_username);
etPassword = findViewById(R.id.r_et_password);
etConfPassword = findViewById(R.id.r_et_conf_password);
btnRegister = findViewById(R.id.r_btn_register);
btnRegister.setOnClickListener(v -> {
RegisterRequest request = validate();
// call api()
if (request.getEmail() != null) {
loader(overlay, progressBar, true);
Call<UserDto> regCall = authApiService.userRegister(request);
regCall.enqueue(new Callback<UserDto>() {
@Override
public void onResponse(Call<UserDto> call, Response<UserDto> response) {
if (response.isSuccessful()) {
UserDto userDto = response.body();
System.out.println("UserId: " + userDto.getUserId());
Toast.makeText(RegisterActivity.this, "User Registration is successful, Please login now.", Toast.LENGTH_LONG).show();
loader(overlay, progressBar, false);
Intent intent = new Intent(RegisterActivity.this, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
} else {
try {
Gson gson = new Gson();
ErrorDto errorDto = gson.fromJson(response.errorBody().string(), ErrorDto.class);
Toast.makeText(RegisterActivity.this, errorDto.getMessage(), Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(RegisterActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
loader(overlay, progressBar, false);
}
}
@Override
public void onFailure(Call<UserDto> call, Throwable t) {
Toast.makeText(RegisterActivity.this, "Error to Failure", Toast.LENGTH_LONG).show();
loader(overlay, progressBar, false);
}
});
}
});
}
private RegisterRequest validate() {
RegisterRequest request = new RegisterRequest();
String firstname, lastname, mobile, email, password, confPassword;
firstname = etFirstName.getText().toString();
lastname = etLastName.getText().toString();
mobile = etMobileNumber.getText().toString();
email = etEmail.getText().toString();
password = etPassword.getText().toString();
confPassword = etConfPassword.getText().toString();
if (TextUtils.isEmpty(firstname)) {
etFirstName.setError("First name is required.");
etFirstName.requestFocus();
} else if (TextUtils.isEmpty(lastname)) {
etLastName.setError("Last name is required.");
etLastName.requestFocus();
} else if (TextUtils.isEmpty(mobile)) {
etMobileNumber.setError("Mobile number is required.");
etMobileNumber.requestFocus();
} else if (!mobileNumberValidation(mobile)) {
etMobileNumber.setError("Invalid mobile number format, use - (+94*********)");
etMobileNumber.requestFocus();
} else if (TextUtils.isEmpty(email)) {
etEmail.setError("Email address is required.");
etEmail.requestFocus();
} else if (!emailAddressValidation(email)) {
etEmail.setError("Invalid email address, Please re-check & try again.");
etEmail.requestFocus();
} else if (TextUtils.isEmpty(password)) {
etPassword.setError("Password is required");
etPassword.requestFocus();
} else if (password.length() < 6) {
etPassword.setError("Password must be at least 6 characters long.");
etPassword.requestFocus();
} else if (!password.equals(confPassword)) {
etConfPassword.setError("Password and confirm password do not match, Please re-check & try again.");
etConfPassword.requestFocus();
} else {
request.setFirstName(firstname);
request.setLastName(lastname);
request.setPhone(mobile);
request.setEmail(email);
request.setPassword(password);
}
return request;
}
}
\ No newline at end of file
package com.kaluwa.enterprises.babycare.config;
import com.kaluwa.enterprises.babycare.service.AuthApiService;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class ApiConfig {
private static final String BASE_URL = "http://192.168.1.2:8080/api/v1/baby-care/";
private static ApiConfig instance;
private static Retrofit retrofit = null;
private ApiConfig() {
OkHttpClient httpClient = new OkHttpClient.Builder().build();
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient)
.build();
}
public static synchronized ApiConfig getInstance() {
if (instance == null) {
instance = new ApiConfig();
}
return instance;
}
public AuthApiService getAuthApi() {
return retrofit.create(AuthApiService.class);
}
}
package com.kaluwa.enterprises.babycare.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AuthenticationDto {
private Long userId;
private String firstName;
private String lastName;
private String email;
private String phone;
private String role;
private String status;
private TokenDto tokenDto;
}
\ No newline at end of file
package com.kaluwa.enterprises.babycare.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LoginRequest {
private String email;
private String password;
}
\ No newline at end of file
package com.kaluwa.enterprises.babycare.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class RegisterRequest {
private String firstName;
private String lastName;
private String phone;
private String email;
private String password;
}
package com.kaluwa.enterprises.babycare.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class TokenDto {
private String tokenType;
private long expiresIn;
private String token;
private String refreshToken;
}
\ No newline at end of file
package com.kaluwa.enterprises.babycare.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDto {
private Long userId;
private String firstName;
private String lastName;
private String email;
private String phone;
private String role;
private String status;
}
\ No newline at end of file
package com.kaluwa.enterprises.babycare.error;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ErrorDto {
private String timestamp;
private String message;
private String error;
}
package com.kaluwa.enterprises.babycare.service;
import com.kaluwa.enterprises.babycare.dto.AuthenticationDto;
import com.kaluwa.enterprises.babycare.dto.LoginRequest;
import com.kaluwa.enterprises.babycare.dto.RegisterRequest;
import com.kaluwa.enterprises.babycare.dto.UserDto;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.http.Body;
import retrofit2.http.POST;
public interface AuthApiService {
@POST("auth/register")
Call<UserDto> userRegister(@Body RegisterRequest request);
@POST("auth/login")
Call<AuthenticationDto> userLogin(@Body LoginRequest request);
}
package com.kaluwa.enterprises.babycare.utils;
import android.view.View;
import com.github.ybq.android.spinkit.SpinKitView;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Utils {
public static void loader(View overlay, SpinKitView spinKitView, boolean status) {
if (status) {
overlay.setVisibility(View.VISIBLE);
spinKitView.setVisibility(View.VISIBLE);
} else {
overlay.setVisibility(View.GONE);
spinKitView.setVisibility(View.GONE);
}
}
public static boolean mobileNumberValidation(String mobileNumber) {
Pattern p = Pattern.compile("\\+94\\d\\d\\d\\d\\d\\d\\d\\d\\d");
Matcher m = p.matcher(mobileNumber);
return m.matches();
}
public static boolean emailAddressValidation(String emailAddress) {
Pattern p = Pattern.compile("[-A-Za-z0-9!#$%&'*+/=?^_`{|}~]+(?:\\.[-A-Za-z0-9!#$%&'*+/=?^_`{|}~]+)*@(?:[A-Za-z0-9](?:[-A-Za-z0-9]*[A-Za-z0-9])?\\.)+[A-Za-z0-9](?:[-A-Za-z0-9]*[A-Za-z0-9])?");
Matcher m = p.matcher(emailAddress);
return m.matches();
}
}
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="51.549297dp" android:viewportHeight="122" android:viewportWidth="142" android:width="60dp">
<path android:fillColor="#73108B" android:pathData="M106,10C118.92,20.33 129.08,33.31 132,50C133.58,67.84 131.19,84.14 119.96,98.63C112.01,107.83 103.43,114.7 92,119C91.22,119.32 90.44,119.64 89.63,119.97C74.47,125.2 56.57,122.9 42.13,116.79C26.96,109.36 15.77,95.7 10,80C5.05,63.7 7.17,46.38 14.69,31.31C22.28,18.22 33.88,8.31 48,3C48.78,2.68 49.56,2.36 50.37,2.03C68.22,-4.13 90.65,-0.62 106,10Z"/>
<path android:fillColor="#FDFDFE" android:pathData="M78,41C82.7,41.35 85.33,43.49 88.94,46.38C89.49,46.81 90.04,47.25 90.61,47.7C91.79,48.63 92.97,49.57 94.14,50.51C96.72,52.57 99.31,54.6 101.91,56.64C104.61,58.75 107.31,60.88 110,63C109.81,66.78 109.11,67.9 106.3,70.54C105.13,71.44 103.94,72.32 102.75,73.19C101.48,74.14 100.2,75.1 98.93,76.06C97.95,76.78 97.95,76.78 96.95,77.52C95.05,78.96 93.2,80.45 91.36,81.97C90.49,82.67 90.49,82.67 89.61,83.39C88.52,84.28 87.43,85.18 86.35,86.09C84.84,87.3 84.84,87.3 82,89C80.35,88.67 78.7,88.34 77,88C77,83.38 77,78.76 77,74C75.12,74.03 75.12,74.03 73.19,74.06C68.54,74.14 63.88,74.18 59.22,74.22C57.2,74.24 55.19,74.27 53.17,74.3C50.27,74.35 47.38,74.37 44.48,74.39C43.58,74.41 42.67,74.43 41.74,74.45C35.51,74.46 35.51,74.46 32.93,72.14C31.76,69.45 31.6,67.37 31.63,64.44C31.62,63.49 31.61,62.54 31.6,61.56C32.07,58.55 32.64,57.85 35,56C36.96,55.64 36.96,55.64 39.2,55.66C40.46,55.66 40.46,55.66 41.74,55.66C42.65,55.68 43.55,55.69 44.48,55.71C45.41,55.71 46.34,55.72 47.29,55.72C50.26,55.74 53.22,55.77 56.19,55.81C58.2,55.83 60.21,55.84 62.22,55.85C67.14,55.89 72.07,55.94 77,56C76.99,55 76.98,54 76.96,52.97C76.96,51.68 76.95,50.39 76.94,49.06C76.93,47.77 76.91,46.49 76.9,45.16C77,42 77,42 78,41Z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="30dp"
android:height="30dp"
android:tint="#000000"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z" />
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"