diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4925314b..c4d9d0c2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -46,6 +46,16 @@ + + + + \ No newline at end of file diff --git a/app/src/main/java/com/example/petstoremobile/fragments/ProfileFragment.java b/app/src/main/java/com/example/petstoremobile/fragments/ProfileFragment.java index ea98e150..73a811ac 100644 --- a/app/src/main/java/com/example/petstoremobile/fragments/ProfileFragment.java +++ b/app/src/main/java/com/example/petstoremobile/fragments/ProfileFragment.java @@ -1,24 +1,252 @@ package com.example.petstoremobile.fragments; +import android.Manifest; +import android.app.Activity; +import android.content.Intent; +import android.content.pm.PackageManager; +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.text.InputType; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; import com.example.petstoremobile.R; +import com.example.petstoremobile.activities.MainActivity; + +import java.io.File; public class ProfileFragment extends Fragment { + //initialize the view/controls + private ImageView imgProfile; + private TextView tvProfileName, tvProfileEmail, tvProfilePhone, tvProfileRole; + private Button btnChangePhoto, btnEditEmail, btnEditPhone, btnLogout; + private Uri photoUri; - //TODO: Create functionality for profile fragment + //Initialize the launchers for camera and gallery + private ActivityResultLauncher galleryLauncher; + private ActivityResultLauncher cameraLauncher; + private ActivityResultLauncher permissionLauncher; + + //Called when the fragment is created, sets up the launchers is set profile image + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Launcher to open gallery to select profile image + galleryLauncher = registerForActivityResult( + //open gallery + new ActivityResultContracts.StartActivityForResult(), + result -> { + //if the user selects an image and its not null + if (result.getResultCode() == Activity.RESULT_OK + && result.getData() != null) { + //get the selected image and set the image to the profile + Uri selectedImage = result.getData().getData(); + imgProfile.setImageURI(selectedImage); + //TODO: SAVE CHANGED PHOTO TO DATABASE + } + } + ); + + // Launcher for camera to open and capture profile image + cameraLauncher = registerForActivityResult( + //open camera + new ActivityResultContracts.TakePicture(), + success -> { + //if a photo is taken set the image profile to it otherwise do nothing + if (success) { + //Clear the old image and set the new one + imgProfile.setImageURI(null); + imgProfile.setImageURI(photoUri); + //TODO: SAVE CHANGED PHOTO TO DATABASE + } + } + ); + + // Launcher to request camera permission + permissionLauncher = registerForActivityResult( + //ask user for camera permission + new ActivityResultContracts.RequestPermission(), + granted -> { + //if the permission is granted launch the camera + if (granted) { + launchCamera(); + } + else { + //if the permission is denied then tell the user to grant it + new AlertDialog.Builder(requireContext()) + .setTitle("Permission Permission Required") + .setMessage("Please grant camera permission to use this feature") + .setPositiveButton("Open Settings", (dialog, which) ->{ + //open the settings page to grant the permission when they click open settings + Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + intent.setData(Uri.fromParts("package", requireContext().getPackageName(), null)); + startActivity(intent); + }) + //close the dialog when the user clicks cancel + .setNegativeButton("Cancel", null) + .show(); + } + } + ); + } + + //TODO: MAKE PROFILE VIEW DISPLAY PROFILE DATA FROM DATABASE @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_profile, container, false); + //get all the controls from the view + imgProfile = view.findViewById(R.id.imgProfile); + tvProfileName = view.findViewById(R.id.tvProfileName); + tvProfileEmail = view.findViewById(R.id.tvProfileEmail); + tvProfilePhone = view.findViewById(R.id.tvProfilePhone); + tvProfileRole = view.findViewById(R.id.tvProfileRole); + btnChangePhoto = view.findViewById(R.id.btnChangePhoto); + btnEditEmail = view.findViewById(R.id.btnEditEmail); + btnEditPhone = view.findViewById(R.id.btnEditPhone); + btnLogout = view.findViewById(R.id.btnLogout); + + //Set up listeners for the buttons + //Change photo button + btnChangePhoto.setOnClickListener(v -> { + //Show alert dialog to user to select from gallery or camera + new AlertDialog.Builder(requireContext()) + .setTitle("Change Profile Photo") + //set the options for the alert dialog + .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 { + // Choose Gallery + Intent intent = new Intent(Intent.ACTION_PICK, + MediaStore.Images.Media.EXTERNAL_CONTENT_URI); + galleryLauncher.launch(intent); + } + }) + .show(); + }); + + //Edit email button + //When clicked open a dialog to change email + btnEditEmail.setOnClickListener(v -> { + //Make a text field for the user to enter the new email + EditText input = new EditText(requireContext()); + input.setPadding(30,30,30,30); + input.setText(tvProfileEmail.getText().toString()); + + //set input type to email + input.setInputType(android.text.InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); + + + //Show alert dialog to user to enter new email + new AlertDialog.Builder(requireContext()) + .setTitle("Edit Email") + .setView(input) + .setPositiveButton("Save", (dialog, which) -> { + String newEmail = input.getText().toString(); + //if the new value is a valid email then set the email to the new value + if (android.util.Patterns.EMAIL_ADDRESS.matcher(newEmail).matches()) { + tvProfileEmail.setText(newEmail); + //TODO: UPDATE THE EMAIL IN DATABASE + } + else { + //tell the user to email is invalid + new AlertDialog.Builder(requireContext()) + .setTitle("Error") + .setMessage("Email is invalid") + .setPositiveButton("OK", null) + .show(); + } + }) + .setNegativeButton("Cancel", null) + .show(); + }); + + //Edit phone button + //When clicked open a dialog to change phone + btnEditPhone.setOnClickListener(v -> { + //Make a text field for the user to enter the new email + EditText input = new EditText(requireContext()); + input.setPadding(30,30,30,30); + input.setText(tvProfilePhone.getText().toString()); + + //set input type to phone number + input.setInputType(InputType.TYPE_CLASS_PHONE); + + //add canada phone number formatting to input (XXX) XXX-XXXX + input.addTextChangedListener(new android.telephony.PhoneNumberFormattingTextWatcher("CA")); + input.setFilters(new android.text.InputFilter[]{new android.text.InputFilter.LengthFilter(14)}); + + + //Show alert dialog to user to enter new phone + new AlertDialog.Builder(requireContext()) + .setTitle("Edit Phone Number") + .setView(input) + .setPositiveButton("Save", (dialog, which) -> { + String newPhone = input.getText().toString(); + //if the new value is format: (XXX) XXX-XXXX then set the phone to the new value + if (newPhone.matches("\\(\\d{3}\\) \\d{3}-\\d{4}")) { //TODO MAKE VALIDATION CLASS INSTEAD FOR THIS + tvProfilePhone.setText(newPhone); + //TODO: UPDATE PHONE IN DATABASE + } + else { + //tell the user to email cannot be empty + new AlertDialog.Builder(requireContext()) + .setTitle("Error") + .setMessage("Phone number is invalid. Format: (XXX) XXX-XXXX") + .setPositiveButton("OK", null) + .show(); + } + }) + .setNegativeButton("Cancel", null) + .show(); + }); + + //Logout button + btnLogout.setOnClickListener(v -> { + //get the intent to the main activity and clear the back stack so the back button won't allow the user to go back to the previous screen + Intent intent = new Intent(getActivity(), MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); + //start the activity to go to login page and finish the current activity + startActivity(intent); + requireActivity().finish(); + }); + return view; } + + //Helper function create a file in the cache directory to store the photo in then launch the camera to capture the photo + private void launchCamera() { + //create a file in the cache directory to store the photo in + File photoFile = new File(requireContext().getCacheDir(), "profile_photo.jpg"); + //get the uri for the file made + photoUri = FileProvider.getUriForFile(requireContext(), requireContext().getPackageName() + ".fileprovider", photoFile); + //launch the camera to capture the photo and save the photo to photoUri + cameraLauncher.launch(photoUri); + } } \ No newline at end of file diff --git a/app/src/main/res/drawable/circle_image.xml b/app/src/main/res/drawable/circle_image.xml new file mode 100644 index 00000000..8635e87b --- /dev/null +++ b/app/src/main/res/drawable/circle_image.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/rounded_card.xml b/app/src/main/res/drawable/rounded_card.xml new file mode 100644 index 00000000..125ee629 --- /dev/null +++ b/app/src/main/res/drawable/rounded_card.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_profile.xml b/app/src/main/res/layout/fragment_profile.xml index 6f86ca85..0342a165 100644 --- a/app/src/main/res/layout/fragment_profile.xml +++ b/app/src/main/res/layout/fragment_profile.xml @@ -1,88 +1,183 @@ - + android:background="#F5F5F5"> - - -