add pet profile to pet list

This commit is contained in:
Alex
2026-03-09 22:38:56 -06:00
parent 2628f63f8c
commit 03ce5ca090
6 changed files with 468 additions and 40 deletions

View File

@@ -23,7 +23,7 @@
android:theme="@style/Theme.PetStoreMobile">
<activity
android:name=".activities.HomeActivity"
android:windowSoftInputMode="adjustNothing"
android:windowSoftInputMode="adjustResize"
android:exported="false" />
<activity
android:name=".activities.MainActivity"

View File

@@ -7,7 +7,9 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.core.view.WindowInsetsControllerCompat;
import androidx.fragment.app.Fragment;
import com.example.petstoremobile.R;
@@ -38,7 +40,7 @@ public class HomeActivity extends AppCompatActivity {
loadFragment(new ListFragment());
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 -> {
if (item.getItemId() == R.id.nav_list) {

View File

@@ -9,7 +9,6 @@ import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

View File

@@ -15,6 +15,7 @@ import com.example.petstoremobile.R;
import com.example.petstoremobile.adapters.PetAdapter;
import com.example.petstoremobile.fragments.ListFragment;
import com.example.petstoremobile.fragments.listfragments.detailfragments.PetDetailFragment;
import com.example.petstoremobile.fragments.listfragments.listprofilefragments.PetProfileFragment;
import com.example.petstoremobile.models.Pet;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
@@ -54,31 +55,35 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen
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) {
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
ListFragment listFragment = (ListFragment) getParentFragment();
if (listFragment != null) {
@@ -87,25 +92,26 @@ public class PetFragment extends Fragment implements PetAdapter.OnPetClickListen
}
// Called by PetDetailFragment when save or delete is done
public void onPetSaved(int position, Pet pet) {
if (position == -1) {
petList.add(pet);
adapter.notifyItemInserted(petList.size() - 1);
} else {
petList.set(position, pet);
adapter.notifyItemChanged(position);
}
}
public void onPetDeleted(int position) {
petList.remove(position);
adapter.notifyItemRemoved(position);
}
//TODO: REPLACE THIS WITH JUST RELOADING THE LIST BY FETCHING FROM THE BACKEND
// public void onPetSaved(int position, Pet pet) {
// if (position == -1) {
// petList.add(pet);
// adapter.notifyItemInserted(petList.size() - 1);
// } else {
// petList.set(position, pet);
// adapter.notifyItemChanged(position);
// }
// }
//
// public void onPetDeleted(int position) {
// petList.remove(position);
// adapter.notifyItemRemoved(position);
// }
// Called by PetAdapter when a row is clicked to open the details view
@Override
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

View File

@@ -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);
}
}

View 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>