Merge branch 'master' into store
This commit is contained in:
@@ -37,6 +37,13 @@ dependencies {
|
|||||||
implementation(libs.activity)
|
implementation(libs.activity)
|
||||||
implementation(libs.constraintlayout)
|
implementation(libs.constraintlayout)
|
||||||
|
|
||||||
|
|
||||||
|
implementation("com.squareup.retrofit2:retrofit:2.9.0")
|
||||||
|
implementation("com.squareup.retrofit2:converter-gson:2.9.0")
|
||||||
|
implementation("com.squareup.okhttp3:logging-interceptor:4.9.1")
|
||||||
|
implementation("com.squareup.okhttp3:okhttp:4.12.0")
|
||||||
|
|
||||||
|
|
||||||
implementation("com.google.android.material:material:1.11.0")
|
implementation("com.google.android.material:material:1.11.0")
|
||||||
implementation("androidx.viewpager2:viewpager2:1.1.0")
|
implementation("androidx.viewpager2:viewpager2:1.1.0")
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission
|
<uses-permission
|
||||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
android:required="false" />
|
android:required="false" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
@@ -23,7 +25,7 @@
|
|||||||
android:theme="@style/Theme.PetStoreMobile">
|
android:theme="@style/Theme.PetStoreMobile">
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.HomeActivity"
|
android:name=".activities.HomeActivity"
|
||||||
android:windowSoftInputMode="adjustNothing"
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.MainActivity"
|
android:name=".activities.MainActivity"
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||||||
import androidx.core.content.ContextCompat;
|
import androidx.core.content.ContextCompat;
|
||||||
import androidx.core.graphics.Insets;
|
import androidx.core.graphics.Insets;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
|
import androidx.core.view.WindowCompat;
|
||||||
import androidx.core.view.WindowInsetsCompat;
|
import androidx.core.view.WindowInsetsCompat;
|
||||||
|
import androidx.core.view.WindowInsetsControllerCompat;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import com.example.petstoremobile.R;
|
import com.example.petstoremobile.R;
|
||||||
@@ -38,7 +40,7 @@ public class HomeActivity extends AppCompatActivity {
|
|||||||
loadFragment(new ListFragment());
|
loadFragment(new ListFragment());
|
||||||
bottomNav.setSelectedItemId(R.id.nav_list);
|
bottomNav.setSelectedItemId(R.id.nav_list);
|
||||||
|
|
||||||
//when an item in the bar is selected, load the corresponding fragment //TODO REPLACE THIS WITH DRAWER MENU
|
//when an item in the bar is selected, load the corresponding fragment
|
||||||
bottomNav.setOnItemSelectedListener(item -> {
|
bottomNav.setOnItemSelectedListener(item -> {
|
||||||
|
|
||||||
if (item.getItemId() == R.id.nav_list) {
|
if (item.getItemId() == R.id.nav_list) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.example.petstoremobile.activities;
|
|||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
@@ -9,13 +10,21 @@ import android.widget.Toast;
|
|||||||
|
|
||||||
import androidx.activity.EdgeToEdge;
|
import androidx.activity.EdgeToEdge;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.core.graphics.Insets;
|
import androidx.core.graphics.Insets;
|
||||||
import androidx.core.view.ViewCompat;
|
import androidx.core.view.ViewCompat;
|
||||||
import androidx.core.view.WindowInsetsCompat;
|
import androidx.core.view.WindowInsetsCompat;
|
||||||
|
|
||||||
import com.example.petstoremobile.R;
|
import com.example.petstoremobile.R;
|
||||||
|
import com.example.petstoremobile.api.Auth.AuthApi;
|
||||||
|
import com.example.petstoremobile.api.Auth.TokenManager;
|
||||||
|
import com.example.petstoremobile.api.RetrofitClient;
|
||||||
|
import com.example.petstoremobile.dtos.AuthDTO;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
//The login screen activity
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private EditText etUser;
|
private EditText etUser;
|
||||||
@@ -57,17 +66,47 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check if username and password are correct TODO: Replace with actual login
|
AuthApi authApi = RetrofitClient.getAuthApi(this);
|
||||||
if (username.equals("admin") && password.equals("admin")) {
|
|
||||||
Intent intent = new Intent(this, HomeActivity.class);
|
//Call login from api and get response
|
||||||
startActivity(intent);
|
authApi.login(new AuthDTO.LoginRequest(username,password)).enqueue(new Callback<AuthDTO.LoginResponse>() {
|
||||||
Toast.makeText(this, "Login successful", Toast.LENGTH_SHORT).show();
|
@Override
|
||||||
finish();
|
public void onResponse(Call<AuthDTO.LoginResponse> call, Response<AuthDTO.LoginResponse> response) {
|
||||||
}
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
else {
|
//save login data in shared preferences
|
||||||
Toast.makeText(this, "Login failed", Toast.LENGTH_SHORT).show();
|
TokenManager.getInstance(MainActivity.this).saveLoginData(
|
||||||
tvLoginStatus.setText("Login failed");
|
response.body().getToken(),
|
||||||
}
|
response.body().getUsername(),
|
||||||
|
response.body().getRole()
|
||||||
|
);
|
||||||
|
//go to home activity after login
|
||||||
|
Intent intent = new Intent(MainActivity.this, HomeActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
Toast.makeText(MainActivity.this, "Login successful", Toast.LENGTH_SHORT).show();
|
||||||
|
finish();
|
||||||
|
} else {
|
||||||
|
// Toast.makeText(MainActivity.this, "Login failed", Toast.LENGTH_SHORT).show();
|
||||||
|
// tvLoginStatus.setText("Login failed");
|
||||||
|
|
||||||
|
try {
|
||||||
|
String errorBody = response.errorBody().string();
|
||||||
|
Log.e("LOGIN", "Code: " + response.code() + " Error: " + errorBody);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("LOGIN", "Code: " + response.code());
|
||||||
|
}
|
||||||
|
Toast.makeText(MainActivity.this,
|
||||||
|
"Login failed: " + response.code(),
|
||||||
|
Toast.LENGTH_SHORT).show();
|
||||||
|
tvLoginStatus.setText("Login failed: " + response.code());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<AuthDTO.LoginResponse> call, Throwable t) {
|
||||||
|
Toast.makeText(MainActivity.this, "Login failed", Toast.LENGTH_SHORT).show();
|
||||||
|
tvLoginStatus.setText("Login failed");
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.example.petstoremobile.api.Auth;
|
||||||
|
|
||||||
|
import com.example.petstoremobile.dtos.AuthDTO;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.http.Body;
|
||||||
|
import retrofit2.http.POST;
|
||||||
|
|
||||||
|
//Api for logging in
|
||||||
|
public interface AuthApi {
|
||||||
|
@POST("v1/auth/login")
|
||||||
|
Call<AuthDTO.LoginResponse> login(@Body AuthDTO.LoginRequest loginRequest);
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.example.petstoremobile.api.Auth;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import okhttp3.Interceptor;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
|
||||||
|
//Used to get the token from the backend for authenticated api calls
|
||||||
|
public class AuthInterceptor implements Interceptor {
|
||||||
|
|
||||||
|
private final TokenManager tokenManager;
|
||||||
|
|
||||||
|
public AuthInterceptor(Context context) {
|
||||||
|
this.tokenManager = TokenManager.getInstance(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public Response intercept(@NonNull Chain chain) throws IOException {
|
||||||
|
String token = tokenManager.getToken();
|
||||||
|
|
||||||
|
//If we have a token then add it to the request
|
||||||
|
if (token != null) {
|
||||||
|
Request request = chain.request().newBuilder()
|
||||||
|
.addHeader("Authorization", "Bearer " + token)
|
||||||
|
.build();
|
||||||
|
return chain.proceed(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
//If no token then just pass the request
|
||||||
|
return chain.proceed(chain.request());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
package com.example.petstoremobile.api.Auth;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
//Store login token in shared preferences
|
||||||
|
public class TokenManager {
|
||||||
|
private static final String TOKEN_KEY = "token";
|
||||||
|
private static final String USERNAME_KEY = "username";
|
||||||
|
private static final String ROLE_KEY = "role";
|
||||||
|
private static final String PREFS_NAME = "auth_prefs";
|
||||||
|
|
||||||
|
private static TokenManager instance;
|
||||||
|
private SharedPreferences prefs;
|
||||||
|
|
||||||
|
private TokenManager(Context context) {
|
||||||
|
prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TokenManager getInstance(Context context) {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new TokenManager(context);
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
//save login data after login
|
||||||
|
public void saveLoginData(String token, String username, String role) {
|
||||||
|
prefs.edit()
|
||||||
|
.putString(TOKEN_KEY, token)
|
||||||
|
.putString(USERNAME_KEY, username)
|
||||||
|
.putString(ROLE_KEY, role)
|
||||||
|
.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Getters
|
||||||
|
public String getToken() {
|
||||||
|
return prefs.getString(TOKEN_KEY, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() {
|
||||||
|
return prefs.getString(USERNAME_KEY, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRole() {
|
||||||
|
return prefs.getString(ROLE_KEY, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if logged in
|
||||||
|
public boolean isLoggedIn() {
|
||||||
|
return getToken() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Clear login data
|
||||||
|
public void clearLoginData() {
|
||||||
|
prefs.edit().clear().apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
39
app/src/main/java/com/example/petstoremobile/api/PetApi.java
Normal file
39
app/src/main/java/com/example/petstoremobile/api/PetApi.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package com.example.petstoremobile.api;
|
||||||
|
|
||||||
|
import com.example.petstoremobile.dtos.PageResponse;
|
||||||
|
import com.example.petstoremobile.dtos.PetDTO;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.http.Body;
|
||||||
|
import retrofit2.http.DELETE;
|
||||||
|
import retrofit2.http.GET;
|
||||||
|
import retrofit2.http.POST;
|
||||||
|
import retrofit2.http.PUT;
|
||||||
|
import retrofit2.http.Path;
|
||||||
|
import retrofit2.http.Query;
|
||||||
|
|
||||||
|
public interface PetApi {
|
||||||
|
// Get all pets
|
||||||
|
@GET("v1/pets")
|
||||||
|
Call<PageResponse<PetDTO>> getAllPets(
|
||||||
|
@Query("page") int page,
|
||||||
|
@Query("size") int size
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get pet by id
|
||||||
|
@GET("v1/pets/{id}")
|
||||||
|
Call<PetDTO> getPetById(@Path("id") Long id);
|
||||||
|
|
||||||
|
// Create pet
|
||||||
|
@POST("v1/pets")
|
||||||
|
Call<PetDTO> createPet(@Body PetDTO pet);
|
||||||
|
|
||||||
|
// Update pet
|
||||||
|
@PUT("v1/pets/{id}")
|
||||||
|
Call<PetDTO> updatePet(@Path("id") Long id, @Body PetDTO pet);
|
||||||
|
|
||||||
|
// Delete pet
|
||||||
|
@DELETE("v1/pets/{id}")
|
||||||
|
Call<Void> deletePet(@Path("id") Long id);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.example.petstoremobile.api;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import com.example.petstoremobile.api.Auth.AuthApi;
|
||||||
|
import com.example.petstoremobile.api.Auth.AuthInterceptor;
|
||||||
|
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.logging.HttpLoggingInterceptor;
|
||||||
|
import retrofit2.Retrofit;
|
||||||
|
import retrofit2.converter.gson.GsonConverterFactory;
|
||||||
|
|
||||||
|
public class RetrofitClient {
|
||||||
|
//base URL
|
||||||
|
public static final String BASE_URL = "http://10.0.2.2:8080/api/"; //for emulator testing change to computer ip if using hardware to test
|
||||||
|
|
||||||
|
|
||||||
|
private static Retrofit retrofit = null;
|
||||||
|
|
||||||
|
public static Retrofit getClient(Context context) {
|
||||||
|
//create an http logging using an interceptor
|
||||||
|
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
|
||||||
|
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
|
||||||
|
|
||||||
|
OkHttpClient client = new OkHttpClient.Builder()
|
||||||
|
.addInterceptor(interceptor)
|
||||||
|
.addInterceptor(new AuthInterceptor(context))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
//build the retrofit object with all needed properties
|
||||||
|
retrofit = new Retrofit.Builder()
|
||||||
|
.baseUrl(BASE_URL)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create()) //JSON converter
|
||||||
|
.client(client) //logging interceptor - OkHttpClient
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return retrofit;
|
||||||
|
}
|
||||||
|
|
||||||
|
//associate the retrofit object with the API interface
|
||||||
|
public static PetApi getPetApi(Context context) {
|
||||||
|
return getClient(context).create(PetApi.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServiceApi getServiceApi(Context context) {
|
||||||
|
return getClient(context).create(ServiceApi.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SupplierApi getSupplierApi(Context context) {
|
||||||
|
return getClient(context).create(SupplierApi.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AuthApi getAuthApi(Context context) {
|
||||||
|
return getClient(context).create(AuthApi.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.example.petstoremobile.api;
|
||||||
|
|
||||||
|
import com.example.petstoremobile.dtos.PageResponse;
|
||||||
|
import com.example.petstoremobile.dtos.ServiceDTO;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.http.Body;
|
||||||
|
import retrofit2.http.DELETE;
|
||||||
|
import retrofit2.http.GET;
|
||||||
|
import retrofit2.http.POST;
|
||||||
|
import retrofit2.http.PUT;
|
||||||
|
import retrofit2.http.Path;
|
||||||
|
import retrofit2.http.Query;
|
||||||
|
|
||||||
|
public interface ServiceApi {
|
||||||
|
// Get all services
|
||||||
|
@GET("v1/services")
|
||||||
|
Call<PageResponse<ServiceDTO>> getAllServices(
|
||||||
|
@Query("page") int page,
|
||||||
|
@Query("size") int size
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get service by id
|
||||||
|
@GET("v1/services/{id}")
|
||||||
|
Call<ServiceDTO> getServiceById(@Path("id") Long id);
|
||||||
|
|
||||||
|
// Create service
|
||||||
|
@POST("v1/services")
|
||||||
|
Call<ServiceDTO> createService(@Body ServiceDTO service);
|
||||||
|
|
||||||
|
// Update service
|
||||||
|
@PUT("v1/services/{id}")
|
||||||
|
Call<ServiceDTO> updateService(@Path("id") Long id, @Body ServiceDTO service);
|
||||||
|
|
||||||
|
// Delete service
|
||||||
|
@DELETE("v1/services/{id}")
|
||||||
|
Call<Void> deleteService(@Path("id") Long id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.example.petstoremobile.api;
|
||||||
|
|
||||||
|
import com.example.petstoremobile.dtos.PageResponse;
|
||||||
|
import com.example.petstoremobile.dtos.SupplierDTO;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.http.Body;
|
||||||
|
import retrofit2.http.DELETE;
|
||||||
|
import retrofit2.http.GET;
|
||||||
|
import retrofit2.http.POST;
|
||||||
|
import retrofit2.http.PUT;
|
||||||
|
import retrofit2.http.Path;
|
||||||
|
import retrofit2.http.Query;
|
||||||
|
|
||||||
|
public interface SupplierApi {
|
||||||
|
// Get all suppliers
|
||||||
|
@GET("v1/suppliers")
|
||||||
|
Call<PageResponse<SupplierDTO>> getAllSuppliers(
|
||||||
|
@Query("page") int page,
|
||||||
|
@Query("size") int size
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get supplier by id
|
||||||
|
@GET("v1/suppliers/{id}")
|
||||||
|
Call<SupplierDTO> getSupplierById(@Path("id") Long id);
|
||||||
|
|
||||||
|
// Create supplier
|
||||||
|
@POST("v1/suppliers")
|
||||||
|
Call<SupplierDTO> createSupplier(@Body SupplierDTO supplier);
|
||||||
|
|
||||||
|
// Update supplier
|
||||||
|
@PUT("v1/suppliers/{id}")
|
||||||
|
Call<SupplierDTO> updateSupplier(@Path("id") Long id, @Body SupplierDTO supplier);
|
||||||
|
|
||||||
|
// Delete supplier
|
||||||
|
@DELETE("v1/suppliers/{id}")
|
||||||
|
Call<Void> deleteSupplier(@Path("id") Long id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package com.example.petstoremobile.dtos;
|
||||||
|
|
||||||
|
//Used to send login data to the backend
|
||||||
|
public class AuthDTO {
|
||||||
|
public static class LoginRequest {
|
||||||
|
private String username;
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
public LoginRequest(String username, String password) {
|
||||||
|
this.username = username;
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsername() { return username; }
|
||||||
|
public String getPassword() { return password; }
|
||||||
|
}
|
||||||
|
|
||||||
|
//Used to receive login data from the backend
|
||||||
|
public static class LoginResponse {
|
||||||
|
private String token;
|
||||||
|
private String username;
|
||||||
|
private String role;
|
||||||
|
|
||||||
|
public String getToken() { return token; }
|
||||||
|
public String getUsername() { return username; }
|
||||||
|
public String getRole() { return role; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package com.example.petstoremobile.dtos;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
//Used to get data from the API
|
||||||
|
public class PageResponse<T> {
|
||||||
|
private List<T> content;
|
||||||
|
private int totalPages;
|
||||||
|
private long totalElements;
|
||||||
|
private int number;
|
||||||
|
private int size;
|
||||||
|
private boolean last;
|
||||||
|
|
||||||
|
public List<T> getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
public int getTotalPages() {
|
||||||
|
return totalPages;
|
||||||
|
}
|
||||||
|
public long getTotalElements() {
|
||||||
|
return totalElements;
|
||||||
|
}
|
||||||
|
public int getNumber() {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
public int getSize() {
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
public boolean isLast() {
|
||||||
|
return last;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package com.example.petstoremobile.dtos;
|
||||||
|
|
||||||
|
public class PetDTO {
|
||||||
|
private Long petId;
|
||||||
|
private String petName;
|
||||||
|
private String petSpecies;
|
||||||
|
private String petBreed;
|
||||||
|
private Integer petAge;
|
||||||
|
private String petStatus;
|
||||||
|
private String petPrice;
|
||||||
|
private String createdAt;
|
||||||
|
private String updatedAt;
|
||||||
|
|
||||||
|
public Long getPetId() { return petId; }
|
||||||
|
public String getPetName() { return petName; }
|
||||||
|
public String getPetSpecies() { return petSpecies; }
|
||||||
|
public String getPetBreed() { return petBreed; }
|
||||||
|
public Integer getPetAge() { return petAge; }
|
||||||
|
public String getPetStatus() { return petStatus; }
|
||||||
|
public String getPetPrice() { return petPrice; }
|
||||||
|
public String getCreatedAt() { return createdAt; }
|
||||||
|
public String getUpdatedAt() { return updatedAt; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.example.petstoremobile.dtos;
|
||||||
|
|
||||||
|
public class ServiceDTO {
|
||||||
|
private Long serviceId;
|
||||||
|
private String serviceName;
|
||||||
|
private String serviceDesc;
|
||||||
|
private Integer serviceDuration;
|
||||||
|
private Double servicePrice;
|
||||||
|
private String createdAt;
|
||||||
|
private String updatedAt;
|
||||||
|
|
||||||
|
public Long getServiceId() { return serviceId; }
|
||||||
|
public String getServiceName() { return serviceName; }
|
||||||
|
public String getServiceDesc() { return serviceDesc; }
|
||||||
|
public Integer getServiceDuration() { return serviceDuration; }
|
||||||
|
public Double getServicePrice() { return servicePrice; }
|
||||||
|
public String getCreatedAt() { return createdAt; }
|
||||||
|
public String getUpdatedAt() { return updatedAt; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package com.example.petstoremobile.dtos;
|
||||||
|
|
||||||
|
public class SupplierDTO {
|
||||||
|
private Long supId;
|
||||||
|
private String supCompany;
|
||||||
|
private String supContactFirstName;
|
||||||
|
private String supContactLastName;
|
||||||
|
private String supEmail;
|
||||||
|
private String supPhone;
|
||||||
|
private String createdAt;
|
||||||
|
private String updatedAt;
|
||||||
|
|
||||||
|
public Long getSupId() { return supId; }
|
||||||
|
public String getSupCompany() { return supCompany; }
|
||||||
|
public String getSupContactFirstName() { return supContactFirstName; }
|
||||||
|
public String getSupContactLastName() { return supContactLastName; }
|
||||||
|
public String getSupEmail() { return supEmail; }
|
||||||
|
public String getSupPhone() { return supPhone; }
|
||||||
|
public String getCreatedAt() { return createdAt; }
|
||||||
|
public String getUpdatedAt() { return updatedAt; }
|
||||||
|
}
|
||||||
@@ -6,26 +6,37 @@ import androidx.fragment.app.Fragment;
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.example.petstoremobile.R;
|
import com.example.petstoremobile.R;
|
||||||
import com.example.petstoremobile.adapters.PetAdapter;
|
import com.example.petstoremobile.adapters.PetAdapter;
|
||||||
|
import com.example.petstoremobile.api.PetApi;
|
||||||
|
import com.example.petstoremobile.api.RetrofitClient;
|
||||||
|
import com.example.petstoremobile.dtos.PageResponse;
|
||||||
|
import com.example.petstoremobile.dtos.PetDTO;
|
||||||
import com.example.petstoremobile.fragments.ListFragment;
|
import com.example.petstoremobile.fragments.ListFragment;
|
||||||
import com.example.petstoremobile.fragments.listfragments.detailfragments.PetDetailFragment;
|
import com.example.petstoremobile.fragments.listfragments.detailfragments.PetDetailFragment;
|
||||||
|
import com.example.petstoremobile.fragments.listfragments.listprofilefragments.PetProfileFragment;
|
||||||
import com.example.petstoremobile.models.Pet;
|
import com.example.petstoremobile.models.Pet;
|
||||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class PetFragment extends Fragment implements PetAdapter.OnPetClickListener {
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
|
public class PetFragment extends Fragment implements PetAdapter.OnPetClickListener {
|
||||||
private List<Pet> petList = new ArrayList<>();
|
private List<Pet> petList = new ArrayList<>();
|
||||||
private PetAdapter adapter;
|
|
||||||
private ImageButton hamburger;
|
private ImageButton hamburger;
|
||||||
|
private PetAdapter adapter;
|
||||||
|
private PetApi api;
|
||||||
|
|
||||||
//load pet view
|
//load pet view
|
||||||
@Override
|
@Override
|
||||||
@@ -33,10 +44,14 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen
|
|||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
View view = inflater.inflate(R.layout.fragment_pet, container, false);
|
View view = inflater.inflate(R.layout.fragment_pet, container, false);
|
||||||
|
|
||||||
|
//get retrofit
|
||||||
|
api = RetrofitClient.getPetApi(requireContext());
|
||||||
|
|
||||||
hamburger = view.findViewById(R.id.btnHamburger);
|
hamburger = view.findViewById(R.id.btnHamburger);
|
||||||
|
|
||||||
loadPetData(); //TODO: Replace this with actual data when backend is working
|
|
||||||
setupRecyclerView(view);
|
setupRecyclerView(view);
|
||||||
|
loadPetData(); //TODO: Replace this with actual data when backend is working
|
||||||
|
|
||||||
|
|
||||||
//Add button to opens the add dialog
|
//Add button to opens the add dialog
|
||||||
FloatingActionButton fabAddPet = view.findViewById(R.id.fabAddPet);
|
FloatingActionButton fabAddPet = view.findViewById(R.id.fabAddPet);
|
||||||
@@ -54,31 +69,35 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen
|
|||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Open the pet detail view depending on the mode
|
//Open pet profile
|
||||||
|
private void openPetProfile(int position) {
|
||||||
|
PetProfileFragment profileFragment = new PetProfileFragment();
|
||||||
|
|
||||||
|
//Make a bundle to pass data to the profile fragment
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
Pet pet = petList.get(position);
|
||||||
|
args.putInt("petId", pet.getPetId());
|
||||||
|
args.putString("petName", pet.getPetName());
|
||||||
|
args.putString("petSpecies", pet.getPetSpecies());
|
||||||
|
args.putString("petBreed", pet.getPetBreed());
|
||||||
|
args.putInt("petAge", pet.getPetAge());
|
||||||
|
args.putString("petStatus", pet.getPetStatus());
|
||||||
|
args.putDouble("petPrice", pet.getPetPrice());
|
||||||
|
|
||||||
|
//send the bundle to the profile fragment to display
|
||||||
|
profileFragment.setArguments(args);
|
||||||
|
|
||||||
|
//get ListFragment to load the the pet profile view
|
||||||
|
ListFragment listFragment = (ListFragment) getParentFragment();
|
||||||
|
if (profileFragment != null) {
|
||||||
|
listFragment.loadFragment(profileFragment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Open the pet detail view for adding
|
||||||
private void openPetDetails(int position) {
|
private void openPetDetails(int position) {
|
||||||
PetDetailFragment detailFragment = new PetDetailFragment();
|
PetDetailFragment detailFragment = new PetDetailFragment();
|
||||||
|
|
||||||
//Make a bundle to pass data to the detail fragment
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putInt("position", position);
|
|
||||||
|
|
||||||
//if editing a pet, add the pet data to the bundle
|
|
||||||
if (position != -1) {
|
|
||||||
Pet pet = petList.get(position);
|
|
||||||
args.putInt("petId", pet.getPetId());
|
|
||||||
args.putString("petName", pet.getPetName());
|
|
||||||
args.putString("petSpecies", pet.getPetSpecies());
|
|
||||||
args.putString("petBreed", pet.getPetBreed());
|
|
||||||
args.putInt("petAge", pet.getPetAge());
|
|
||||||
args.putString("petStatus", pet.getPetStatus());
|
|
||||||
args.putDouble("petPrice", pet.getPetPrice());
|
|
||||||
}
|
|
||||||
|
|
||||||
//send the bundle to the detail fragment to display
|
|
||||||
detailFragment.setArguments(args);
|
|
||||||
//set the pet fragment to the parent so we refer back to pet view when save or delete is done
|
|
||||||
detailFragment.setPetFragment(this);
|
|
||||||
|
|
||||||
//get ListFragment to load the the detail view
|
//get ListFragment to load the the detail view
|
||||||
ListFragment listFragment = (ListFragment) getParentFragment();
|
ListFragment listFragment = (ListFragment) getParentFragment();
|
||||||
if (listFragment != null) {
|
if (listFragment != null) {
|
||||||
@@ -87,36 +106,57 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Called by PetDetailFragment when save or delete is done
|
// Called by PetDetailFragment when save or delete is done
|
||||||
public void onPetSaved(int position, Pet pet) {
|
//TODO: REPLACE THIS WITH JUST RELOADING THE LIST BY FETCHING FROM THE BACKEND
|
||||||
if (position == -1) {
|
// public void onPetSaved(int position, Pet pet) {
|
||||||
petList.add(pet);
|
// if (position == -1) {
|
||||||
adapter.notifyItemInserted(petList.size() - 1);
|
// petList.add(pet);
|
||||||
} else {
|
// adapter.notifyItemInserted(petList.size() - 1);
|
||||||
petList.set(position, pet);
|
// } else {
|
||||||
adapter.notifyItemChanged(position);
|
// petList.set(position, pet);
|
||||||
}
|
// adapter.notifyItemChanged(position);
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
public void onPetDeleted(int position) {
|
//
|
||||||
petList.remove(position);
|
// public void onPetDeleted(int position) {
|
||||||
adapter.notifyItemRemoved(position);
|
// petList.remove(position);
|
||||||
}
|
// adapter.notifyItemRemoved(position);
|
||||||
|
// }
|
||||||
|
|
||||||
// Called by PetAdapter when a row is clicked to open the details view
|
// Called by PetAdapter when a row is clicked to open the details view
|
||||||
@Override
|
@Override
|
||||||
public void onPetClick(int position) {
|
public void onPetClick(int position) {
|
||||||
openPetDetails(position);
|
openPetProfile(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to get a list of all pets (Loads hardcoded sample data for now) TODO: REPLACE THIS WITH A METHOD THAT GETS DATA FROM THE DATABASE
|
// Helper function to get a list of all pets from the backend
|
||||||
private void loadPetData() {
|
private void loadPetData() {
|
||||||
petList.clear();
|
api.getAllPets(0, 100).enqueue(new Callback<PageResponse<PetDTO>>() {
|
||||||
petList.add(new Pet(1, "Buddy","Dog", "Labrador",2, "Available", 500.00));
|
@Override
|
||||||
petList.add(new Pet(2, "Milo", "Cat", "Persian",1, "Available", 300.00));
|
public void onResponse(Call<PageResponse<PetDTO>> call, Response<PageResponse<PetDTO>> response) {
|
||||||
petList.add(new Pet(3, "Charlie","Dog", "Golden Retriever", 3, "Available", 550.00));
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
petList.add(new Pet(4, "Luna", "Cat", "Siamese",2, "Adopted", 350.00));
|
petList.clear();
|
||||||
petList.add(new Pet(5, "Max", "Dog", "Beagle",1, "Available", 450.00));
|
|
||||||
petList.add(new Pet(6, "Bella", "Cat", "Maine Coon",4, "Available", 400.00));
|
// Convert to pets
|
||||||
|
List<Pet> pets = response.body().getContent()
|
||||||
|
.stream()
|
||||||
|
.map(Pet::new)
|
||||||
|
.collect(java.util.stream.Collectors.toList());
|
||||||
|
|
||||||
|
petList.addAll(pets);
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.e("onResponse: ", response.message());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<PageResponse<PetDTO>> call, Throwable t) { // 4. here
|
||||||
|
Toast.makeText(getContext(),
|
||||||
|
"Failed to load pets", Toast.LENGTH_SHORT).show();
|
||||||
|
Log.e("onFailure: ", t.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//set up the recyclerview and adapter
|
//set up the recyclerview and adapter
|
||||||
|
|||||||
@@ -6,13 +6,19 @@ import androidx.fragment.app.Fragment;
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.example.petstoremobile.R;
|
import com.example.petstoremobile.R;
|
||||||
import com.example.petstoremobile.adapters.ServiceAdapter;
|
import com.example.petstoremobile.adapters.ServiceAdapter;
|
||||||
|
import com.example.petstoremobile.api.RetrofitClient;
|
||||||
|
import com.example.petstoremobile.api.ServiceApi;
|
||||||
|
import com.example.petstoremobile.dtos.PageResponse;
|
||||||
|
import com.example.petstoremobile.dtos.ServiceDTO;
|
||||||
import com.example.petstoremobile.fragments.ListFragment;
|
import com.example.petstoremobile.fragments.ListFragment;
|
||||||
import com.example.petstoremobile.fragments.listfragments.detailfragments.ServiceDetailFragment;
|
import com.example.petstoremobile.fragments.listfragments.detailfragments.ServiceDetailFragment;
|
||||||
import com.example.petstoremobile.models.Service;
|
import com.example.petstoremobile.models.Service;
|
||||||
@@ -21,11 +27,16 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
public class ServiceFragment extends Fragment implements ServiceAdapter.OnServiceClickListener {
|
public class ServiceFragment extends Fragment implements ServiceAdapter.OnServiceClickListener {
|
||||||
|
|
||||||
private List<Service> serviceList = new ArrayList<>();
|
private List<Service> serviceList = new ArrayList<>();
|
||||||
private ServiceAdapter adapter;
|
private ServiceAdapter adapter;
|
||||||
private ImageButton hamburger;
|
private ImageButton hamburger;
|
||||||
|
private ServiceApi api;
|
||||||
|
|
||||||
//load service view
|
//load service view
|
||||||
@Override
|
@Override
|
||||||
@@ -33,10 +44,11 @@ public class ServiceFragment extends Fragment implements ServiceAdapter.OnServic
|
|||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
View view = inflater.inflate(R.layout.fragment_service, container, false);
|
View view = inflater.inflate(R.layout.fragment_service, container, false);
|
||||||
|
|
||||||
|
api = RetrofitClient.getServiceApi(requireContext());
|
||||||
hamburger = view.findViewById(R.id.btnHamburger);
|
hamburger = view.findViewById(R.id.btnHamburger);
|
||||||
|
|
||||||
loadServiceData(); //TODO: Replace this with actual data when backend is working
|
|
||||||
setupRecyclerView(view);
|
setupRecyclerView(view);
|
||||||
|
loadServiceData();
|
||||||
|
|
||||||
//Add button to opens the add dialog
|
//Add button to opens the add dialog
|
||||||
FloatingActionButton fabAddService = view.findViewById(R.id.fabAddService);
|
FloatingActionButton fabAddService = view.findViewById(R.id.fabAddService);
|
||||||
@@ -106,14 +118,37 @@ public class ServiceFragment extends Fragment implements ServiceAdapter.OnServic
|
|||||||
openServiceDetails(position);
|
openServiceDetails(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to get a list of all services (Loads hardcoded sample data for now) TODO: REPLACE THIS WITH A METHOD THAT GETS DATA FROM THE DATABASE
|
// Helper function to get a list of all services from the backend
|
||||||
private void loadServiceData() {
|
private void loadServiceData() {
|
||||||
serviceList.clear();
|
api.getAllServices(0, 100).enqueue(new Callback<PageResponse<ServiceDTO>>() {
|
||||||
serviceList.add(new Service(1, "Grooming", "Full grooming for your pet", 60, 50.00));
|
@Override
|
||||||
serviceList.add(new Service(2, "Vaccination", "Standard vaccinations", 30, 75.00));
|
public void onResponse(Call<PageResponse<ServiceDTO>> call, Response<PageResponse<ServiceDTO>> response) {
|
||||||
serviceList.add(new Service(3, "Health Checkup", "Comprehensive health exam", 45, 100.00));
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
serviceList.add(new Service(4, "Pet Sitting", "Overnight stay for your pet", 1440, 40.00));
|
serviceList.clear();
|
||||||
serviceList.add(new Service(5, "Training", "Basic obedience training session", 60, 60.00));
|
|
||||||
|
// Convert to services
|
||||||
|
List<Service> services = response.body().getContent()
|
||||||
|
.stream()
|
||||||
|
.map(Service::new)
|
||||||
|
.collect(java.util.stream.Collectors.toList());
|
||||||
|
|
||||||
|
serviceList.addAll(services);
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.e("onResponse: ", response.message());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<PageResponse<ServiceDTO>> call, Throwable t) {
|
||||||
|
if (getContext() != null) {
|
||||||
|
Toast.makeText(getContext(),
|
||||||
|
"Failed to load services", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
Log.e("onFailure: ", t.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//set up the recyclerview and adapter
|
//set up the recyclerview and adapter
|
||||||
|
|||||||
@@ -6,13 +6,19 @@ import androidx.fragment.app.Fragment;
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.ImageButton;
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
import com.example.petstoremobile.R;
|
import com.example.petstoremobile.R;
|
||||||
import com.example.petstoremobile.adapters.SupplierAdapter;
|
import com.example.petstoremobile.adapters.SupplierAdapter;
|
||||||
|
import com.example.petstoremobile.api.RetrofitClient;
|
||||||
|
import com.example.petstoremobile.api.SupplierApi;
|
||||||
|
import com.example.petstoremobile.dtos.PageResponse;
|
||||||
|
import com.example.petstoremobile.dtos.SupplierDTO;
|
||||||
import com.example.petstoremobile.fragments.ListFragment;
|
import com.example.petstoremobile.fragments.ListFragment;
|
||||||
import com.example.petstoremobile.fragments.listfragments.detailfragments.SupplierDetailFragment;
|
import com.example.petstoremobile.fragments.listfragments.detailfragments.SupplierDetailFragment;
|
||||||
import com.example.petstoremobile.models.Supplier;
|
import com.example.petstoremobile.models.Supplier;
|
||||||
@@ -21,11 +27,16 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import retrofit2.Call;
|
||||||
|
import retrofit2.Callback;
|
||||||
|
import retrofit2.Response;
|
||||||
|
|
||||||
public class SupplierFragment extends Fragment implements SupplierAdapter.OnSupplierClickListener {
|
public class SupplierFragment extends Fragment implements SupplierAdapter.OnSupplierClickListener {
|
||||||
|
|
||||||
private List<Supplier> supplierList = new ArrayList<>();
|
private List<Supplier> supplierList = new ArrayList<>();
|
||||||
private SupplierAdapter adapter;
|
private SupplierAdapter adapter;
|
||||||
private ImageButton hamburger;
|
private ImageButton hamburger;
|
||||||
|
private SupplierApi api;
|
||||||
|
|
||||||
//load supplier view
|
//load supplier view
|
||||||
@Override
|
@Override
|
||||||
@@ -33,10 +44,11 @@ public class SupplierFragment extends Fragment implements SupplierAdapter.OnSupp
|
|||||||
Bundle savedInstanceState) {
|
Bundle savedInstanceState) {
|
||||||
View view = inflater.inflate(R.layout.fragment_supplier, container, false);
|
View view = inflater.inflate(R.layout.fragment_supplier, container, false);
|
||||||
|
|
||||||
|
api = RetrofitClient.getSupplierApi(requireContext());
|
||||||
hamburger = view.findViewById(R.id.btnHamburger);
|
hamburger = view.findViewById(R.id.btnHamburger);
|
||||||
|
|
||||||
loadSupplierData(); //TODO: Replace this with actual data when backend is working
|
|
||||||
setupRecyclerView(view);
|
setupRecyclerView(view);
|
||||||
|
loadSupplierData();
|
||||||
|
|
||||||
//Add button to opens the add dialog
|
//Add button to opens the add dialog
|
||||||
FloatingActionButton fabAddSupplier = view.findViewById(R.id.fabAddSupplier);
|
FloatingActionButton fabAddSupplier = view.findViewById(R.id.fabAddSupplier);
|
||||||
@@ -107,14 +119,37 @@ public class SupplierFragment extends Fragment implements SupplierAdapter.OnSupp
|
|||||||
openSupplierDetails(position);
|
openSupplierDetails(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to get a list of all suppliers (Loads hardcoded sample data for now) TODO: REPLACE THIS WITH A METHOD THAT GETS DATA FROM THE DATABASE
|
// Helper function to get a list of all suppliers from the backend
|
||||||
private void loadSupplierData() {
|
private void loadSupplierData() {
|
||||||
supplierList.clear();
|
api.getAllSuppliers(0, 100).enqueue(new Callback<PageResponse<SupplierDTO>>() {
|
||||||
supplierList.add(new Supplier(1, "Pet Food Co.", "John", "Doe", "john@petfood.com", "123-456-7890"));
|
@Override
|
||||||
supplierList.add(new Supplier(2, "Toy Kingdom", "Jane", "Smith", "jane@toykingdom.com", "987-654-3210"));
|
public void onResponse(Call<PageResponse<SupplierDTO>> call, Response<PageResponse<SupplierDTO>> response) {
|
||||||
supplierList.add(new Supplier(3, "HealthPet", "Robert", "Brown", "robert@healthpet.com", "555-0199-234"));
|
if (response.isSuccessful() && response.body() != null) {
|
||||||
supplierList.add(new Supplier(4, "Groomers Choice", "Emily", "Davis", "emily@groomers.com", "444-555-6666"));
|
supplierList.clear();
|
||||||
supplierList.add(new Supplier(5, "Birdy Haven", "Michael", "Wilson", "michael@birdyhaven.com", "111-222-3333"));
|
|
||||||
|
// Convert to suppliers
|
||||||
|
List<Supplier> suppliers = response.body().getContent()
|
||||||
|
.stream()
|
||||||
|
.map(Supplier::new)
|
||||||
|
.collect(java.util.stream.Collectors.toList());
|
||||||
|
|
||||||
|
supplierList.addAll(suppliers);
|
||||||
|
adapter.notifyDataSetChanged();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Log.e("onResponse: ", response.message());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<PageResponse<SupplierDTO>> call, Throwable t) {
|
||||||
|
if (getContext() != null) {
|
||||||
|
Toast.makeText(getContext(),
|
||||||
|
"Failed to load suppliers", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
Log.e("onFailure: ", t.getMessage());
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//set up the recyclerview and adapter
|
//set up the recyclerview and adapter
|
||||||
|
|||||||
@@ -0,0 +1,177 @@
|
|||||||
|
package com.example.petstoremobile.fragments.listfragments.listprofilefragments;
|
||||||
|
|
||||||
|
import android.Manifest;
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
|
||||||
|
import androidx.activity.result.ActivityResultLauncher;
|
||||||
|
import androidx.activity.result.contract.ActivityResultContracts;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.core.content.FileProvider;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
|
import android.provider.MediaStore;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import com.example.petstoremobile.R;
|
||||||
|
import com.example.petstoremobile.fragments.ListFragment;
|
||||||
|
import com.example.petstoremobile.fragments.listfragments.detailfragments.PetDetailFragment;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
public class PetProfileFragment extends Fragment {
|
||||||
|
|
||||||
|
private TextView tvPetName, tvPetSpecies, tvPetBreed, tvPetAge, tvPetPrice;
|
||||||
|
private Button btnBack, btnEditPet, btnChangePhoto;
|
||||||
|
private ImageView imgPet;
|
||||||
|
private Uri photoUri;
|
||||||
|
|
||||||
|
// launchers for camera and gallery
|
||||||
|
private ActivityResultLauncher<Intent> galleryLauncher;
|
||||||
|
private ActivityResultLauncher<Uri> cameraLauncher;
|
||||||
|
private ActivityResultLauncher<String> permissionLauncher;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
// Launcher to open gallery to select image
|
||||||
|
galleryLauncher = registerForActivityResult(
|
||||||
|
new ActivityResultContracts.StartActivityForResult(),
|
||||||
|
result -> {
|
||||||
|
if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
|
||||||
|
Uri selectedImage = result.getData().getData();
|
||||||
|
imgPet.setImageURI(selectedImage);
|
||||||
|
// TODO: SAVE CHANGED PHOTO TO DATABASE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Launcher for camera to open and capture image
|
||||||
|
cameraLauncher = registerForActivityResult(
|
||||||
|
new ActivityResultContracts.TakePicture(),
|
||||||
|
success -> {
|
||||||
|
if (success) {
|
||||||
|
imgPet.setImageURI(null);
|
||||||
|
imgPet.setImageURI(photoUri);
|
||||||
|
// TODO: SAVE CHANGED PHOTO TO DATABASE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Launcher to request camera permission
|
||||||
|
permissionLauncher = registerForActivityResult(
|
||||||
|
new ActivityResultContracts.RequestPermission(),
|
||||||
|
granted -> {
|
||||||
|
if (granted) {
|
||||||
|
launchCamera();
|
||||||
|
} else {
|
||||||
|
new AlertDialog.Builder(requireContext())
|
||||||
|
.setTitle("Permission Required")
|
||||||
|
.setMessage("Please grant camera permission to use this feature")
|
||||||
|
.setPositiveButton("Open Settings", (dialog, which) -> {
|
||||||
|
Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||||
|
intent.setData(Uri.fromParts("package", requireContext().getPackageName(), null));
|
||||||
|
startActivity(intent);
|
||||||
|
})
|
||||||
|
.setNegativeButton("Cancel", null)
|
||||||
|
.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
View view = inflater.inflate(R.layout.fragment_pet_profile, container, false);
|
||||||
|
|
||||||
|
// Initialize views
|
||||||
|
tvPetName = view.findViewById(R.id.tvPetName);
|
||||||
|
tvPetSpecies = view.findViewById(R.id.tvPetSpecies);
|
||||||
|
tvPetBreed = view.findViewById(R.id.tvPetBreed);
|
||||||
|
tvPetAge = view.findViewById(R.id.tvPetAge);
|
||||||
|
tvPetPrice = view.findViewById(R.id.tvPetPrice);
|
||||||
|
btnBack = view.findViewById(R.id.btnBack);
|
||||||
|
btnEditPet = view.findViewById(R.id.btnEditPet);
|
||||||
|
btnChangePhoto = view.findViewById(R.id.btnChangePhoto);
|
||||||
|
imgPet = view.findViewById(R.id.imgPet);
|
||||||
|
|
||||||
|
|
||||||
|
// Set pet details to display
|
||||||
|
if (getArguments() != null) {
|
||||||
|
tvPetName.setText(getArguments().getString("petName"));
|
||||||
|
tvPetSpecies.setText(getArguments().getString("petSpecies"));
|
||||||
|
tvPetBreed.setText(getArguments().getString("petBreed"));
|
||||||
|
tvPetAge.setText(String.format(Locale.getDefault(), "%d yr(s)", getArguments().getInt("petAge")));
|
||||||
|
tvPetPrice.setText(String.format(Locale.getDefault(), "$%.2f", getArguments().getDouble("petPrice")));
|
||||||
|
}
|
||||||
|
|
||||||
|
//set button click listeners
|
||||||
|
btnBack.setOnClickListener(v -> {
|
||||||
|
//get the list fragment and pop the back stack to return to the previous view (PetFragment)
|
||||||
|
ListFragment listFragment = (ListFragment) getParentFragment();
|
||||||
|
if (listFragment != null) {
|
||||||
|
listFragment.getChildFragmentManager().popBackStack();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Make the edit button go to the pet detail view
|
||||||
|
btnEditPet.setOnClickListener(v -> {
|
||||||
|
if (getArguments() == null) return;
|
||||||
|
|
||||||
|
PetDetailFragment detailFragment = new PetDetailFragment();
|
||||||
|
//send the bundle to the pet detail fragment
|
||||||
|
detailFragment.setArguments(getArguments());
|
||||||
|
|
||||||
|
//get ListFragment to load the the detail view
|
||||||
|
ListFragment listFragment = (ListFragment) getParentFragment();
|
||||||
|
if (listFragment != null) {
|
||||||
|
listFragment.loadFragment(detailFragment);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Make change photo button ask user to select a new photo
|
||||||
|
btnChangePhoto.setOnClickListener(v -> {
|
||||||
|
new AlertDialog.Builder(requireContext())
|
||||||
|
.setTitle("Change Pet Photo")
|
||||||
|
.setItems(new String[]{"Take Photo", "Choose from Gallery"}, (dialog, which) -> {
|
||||||
|
if (which == 0) {
|
||||||
|
// Choose Camera
|
||||||
|
//Checks if the user has granted the camera permission already
|
||||||
|
if (ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
//if the permission is already granted then launch the camera
|
||||||
|
launchCamera();
|
||||||
|
} else {
|
||||||
|
//otherwise request the permission
|
||||||
|
permissionLauncher.launch(Manifest.permission.CAMERA);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
|
||||||
|
galleryLauncher.launch(intent);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.show();
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void launchCamera() {
|
||||||
|
File photoFile = new File(requireContext().getCacheDir(), "pet_photo.jpg");
|
||||||
|
photoUri = FileProvider.getUriForFile(requireContext(), requireContext().getPackageName() + ".fileprovider", photoFile);
|
||||||
|
cameraLauncher.launch(photoUri);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.example.petstoremobile.models;
|
package com.example.petstoremobile.models;
|
||||||
|
|
||||||
|
import com.example.petstoremobile.dtos.PetDTO;
|
||||||
|
|
||||||
public class Pet {
|
public class Pet {
|
||||||
private int petId;
|
private int petId;
|
||||||
private String petName;
|
private String petName;
|
||||||
@@ -20,6 +22,17 @@ public class Pet {
|
|||||||
this.petPrice = petPrice;
|
this.petPrice = petPrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//contructor to convert PetDTO to Pet
|
||||||
|
public Pet(PetDTO dto) {
|
||||||
|
this.petId = dto.getPetId().intValue();
|
||||||
|
this.petName = dto.getPetName();
|
||||||
|
this.petSpecies = dto.getPetSpecies();
|
||||||
|
this.petBreed = dto.getPetBreed();
|
||||||
|
this.petAge = dto.getPetAge();
|
||||||
|
this.petStatus = dto.getPetStatus();
|
||||||
|
this.petPrice = Double.parseDouble(dto.getPetPrice());
|
||||||
|
}
|
||||||
|
|
||||||
//getter and setters
|
//getter and setters
|
||||||
public int getPetId() {
|
public int getPetId() {
|
||||||
return petId;
|
return petId;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.example.petstoremobile.models;
|
package com.example.petstoremobile.models;
|
||||||
|
|
||||||
|
import com.example.petstoremobile.dtos.ServiceDTO;
|
||||||
|
|
||||||
public class Service {
|
public class Service {
|
||||||
private int serviceId;
|
private int serviceId;
|
||||||
private String serviceName;
|
private String serviceName;
|
||||||
@@ -16,15 +18,19 @@ public class Service {
|
|||||||
this.servicePrice = servicePrice;
|
this.servicePrice = servicePrice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Service(ServiceDTO dto) {
|
||||||
|
this.serviceId = dto.getServiceId().intValue();
|
||||||
|
this.serviceName = dto.getServiceName();
|
||||||
|
this.serviceDesc = dto.getServiceDesc();
|
||||||
|
this.serviceDuration = dto.getServiceDuration();
|
||||||
|
this.servicePrice = dto.getServicePrice();
|
||||||
|
}
|
||||||
|
|
||||||
//getter and setters
|
//getter and setters
|
||||||
public int getServiceId() {
|
public int getServiceId() {
|
||||||
return serviceId;
|
return serviceId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void setServiceId(int serviceId) {
|
|
||||||
// this.serviceId = serviceId;
|
|
||||||
// }
|
|
||||||
|
|
||||||
public String getServiceName() {
|
public String getServiceName() {
|
||||||
return serviceName;
|
return serviceName;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.example.petstoremobile.models;
|
package com.example.petstoremobile.models;
|
||||||
|
|
||||||
|
import com.example.petstoremobile.dtos.SupplierDTO;
|
||||||
|
|
||||||
public class Supplier {
|
public class Supplier {
|
||||||
private int supId;
|
private int supId;
|
||||||
private String supCompany;
|
private String supCompany;
|
||||||
@@ -18,16 +20,21 @@ public class Supplier {
|
|||||||
this.supPhone = supPhone;
|
this.supPhone = supPhone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Supplier(SupplierDTO dto) {
|
||||||
|
this.supId = dto.getSupId().intValue();
|
||||||
|
this.supCompany = dto.getSupCompany();
|
||||||
|
this.supContactFirstName = dto.getSupContactFirstName();
|
||||||
|
this.supContactLastName = dto.getSupContactLastName();
|
||||||
|
this.supEmail = dto.getSupEmail();
|
||||||
|
this.supPhone = dto.getSupPhone();
|
||||||
|
}
|
||||||
|
|
||||||
//getter and setters
|
//getter and setters
|
||||||
|
|
||||||
public int getSupId() {
|
public int getSupId() {
|
||||||
return supId;
|
return supId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// public void setSupId(int supId) {
|
|
||||||
// this.supId = supId;
|
|
||||||
// }
|
|
||||||
|
|
||||||
public String getSupCompany() {
|
public String getSupCompany() {
|
||||||
return supCompany;
|
return supCompany;
|
||||||
}
|
}
|
||||||
|
|||||||
244
app/src/main/res/layout/fragment_pet_profile.xml
Normal file
244
app/src/main/res/layout/fragment_pet_profile.xml
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/background_grey">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/primary_dark">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="56dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:paddingStart="16dp"
|
||||||
|
android:paddingEnd="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:text="Pet Profile"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnEditPet"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Edit"
|
||||||
|
android:backgroundTint="@color/accent_coral"
|
||||||
|
android:textColor="@color/white"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/imgPet"
|
||||||
|
android:layout_width="146dp"
|
||||||
|
android:layout_height="140dp"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:background="@drawable/circle_image"
|
||||||
|
android:clipToOutline="true"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
android:src="@drawable/placeholder" />
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnChangePhoto"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Change Photo"
|
||||||
|
style="@style/Widget.Material3.Button.TextButton"
|
||||||
|
android:textColor="@color/text_light"
|
||||||
|
android:layout_marginBottom="8dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvPetName"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="NAME"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="26sp"
|
||||||
|
android:textStyle="bold"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="120dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginBottom="8dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:layout_marginEnd="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="SPECIES"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textColor="#888888"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvPetSpecies"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Dog"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/text_dark"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:layout_marginStart="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="BREED"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textColor="#888888"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvPetBreed"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Labrador"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/text_dark"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="120dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginTop="8dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:layout_marginEnd="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="AGE"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textColor="#888888"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvPetAge"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="2 yr(s)"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/text_dark"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="@color/white"
|
||||||
|
android:layout_marginStart="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="PRICE"
|
||||||
|
android:textSize="11sp"
|
||||||
|
android:textColor="#888888"
|
||||||
|
android:textAllCaps="true"
|
||||||
|
android:layout_marginBottom="4dp"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvPetPrice"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="$500.00"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/accent_coral"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/btnBack"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="Back"
|
||||||
|
android:backgroundTint="@color/primary_medium"
|
||||||
|
android:textColor="@color/white"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
8
app/src/main/res/xml/network_security_config.xml
Normal file
8
app/src/main/res/xml/network_security_config.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<network-security-config>
|
||||||
|
<base-config cleartextTrafficPermitted="true">
|
||||||
|
<trust-anchors>
|
||||||
|
<certificates src="system" />
|
||||||
|
</trust-anchors>
|
||||||
|
</base-config>
|
||||||
|
</network-security-config>
|
||||||
Reference in New Issue
Block a user