Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix/user upload/delete profile picture logic #93

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 61 additions & 22 deletions app/src/main/java/com/example/scanpal/EditProfileFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.Toast;

import androidx.activity.result.ActivityResultLauncher;
Expand Down Expand Up @@ -37,8 +38,11 @@
*/
public class EditProfileFragment extends Fragment {

protected User existingUser;
private ImageView profileImageView;
private ProgressBar progressBar;
private TextInputEditText username, firstName, lastName;
private boolean isDeleteIntent = false;
private ImageController imageController;
private Uri imageUri;
private final ActivityResultLauncher<Intent> pickImageLauncher = registerForActivityResult(
Expand All @@ -47,7 +51,6 @@ public class EditProfileFragment extends Fragment {
if (result.getResultCode() == Activity.RESULT_OK && result.getData() != null) {
imageUri = result.getData().getData();
profileImageView.setImageURI(imageUri);
uploadImageToFirebase(imageUri);
}
});
private UserController userController;
Expand Down Expand Up @@ -77,6 +80,7 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
Button saveButton = view.findViewById(R.id.save_button);
FloatingActionButton goBack = view.findViewById(R.id.button_go_back);
Button resetButton = view.findViewById(R.id.reset_button);
progressBar = view.findViewById(R.id.progressBar);

username = (TextInputEditText) ((TextInputLayout) view.findViewById(R.id.username)).getEditText();
if (username != null) {
Expand All @@ -90,7 +94,15 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
attendeeController = new AttendeeController(FirebaseFirestore.getInstance(), getContext());

uploadButton.setOnClickListener(v -> openGallery());
deleteButton.setOnClickListener(v -> profileImageView.setImageDrawable(null));

deleteButton.setOnClickListener(v -> {
imageUri = null;
isDeleteIntent = true;
Glide.with(EditProfileFragment.this)
.load(R.drawable.ic_launcher_background)
.apply(new RequestOptions().circleCrop())
.into(profileImageView);
});

saveButton.setOnClickListener(v -> saveUserDetails());
goBack.setOnClickListener(v -> {
Expand All @@ -110,18 +122,6 @@ private void openGallery() {
pickImageLauncher.launch(intent);
}


/**
* Uploads the selected image to Firebase Storage and updates the user's profile image URL.
*
* @param imageUri The URI of the image selected by the user.
*/
private void uploadImageToFirebase(Uri imageUri) {
imageController.uploadImage(imageUri,
taskSnapshot -> Toast.makeText(getContext(), "Image Uploaded Successfully", Toast.LENGTH_SHORT).show(),
e -> Toast.makeText(getContext(), "Upload failed: " + e.getMessage(), Toast.LENGTH_SHORT).show());
}

/**
* Fetches the current details of the user from Firestore/Internal storage and displays them in the UI components.
*/
Expand All @@ -131,6 +131,7 @@ private void fetchUserDetails() {
userController.getUser(storedUsername, new UserFetchCallback() {
@Override
public void onSuccess(User user) {
existingUser = user;
username.setText(user.getUsername());
firstName.setText(user.getFirstName());
lastName.setText(user.getLastName());
Expand All @@ -145,31 +146,69 @@ public void onSuccess(User user) {

@Override
public void onError(Exception e) {
Toast.makeText(getContext(), "Failed to fetch user details: " + e.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
}

/**
* Saves the updated user details to Firestore and updates the local user serialization.
* If a new image was selected, uploads it to Firebase Storage and updates the user's profile image URL.
* Otherwise, uses the existing photo URL.
*/
private void saveUserDetails() {
User updatedUser = new User(Objects.requireNonNull(username.getText()).toString(), Objects.requireNonNull(firstName.getText()).toString(), Objects.requireNonNull(lastName.getText()).toString(),null);//because don't change device token
if (imageUri != null) {
updatedUser.setPhoto(imageUri.toString());
}
userController.updateUser(updatedUser, new UserUpdateCallback() {
progressBar.setVisibility(View.VISIBLE);

String storedUsername = userController.fetchStoredUsername();
userController.getUser(storedUsername, new UserFetchCallback() {
@Override
public void onSuccess(User existingUser) {
User updatedUser = new User(Objects.requireNonNull(username.getText()).toString(),
Objects.requireNonNull(firstName.getText()).toString(),
Objects.requireNonNull(lastName.getText()).toString(),
existingUser.getDeviceToken());

if (imageUri != null) {
imageController.uploadImage(imageUri, uri -> {
updatedUser.setPhoto(uri.toString());
updateUserInFirestore(updatedUser);
}, e -> progressBar.setVisibility(View.GONE));
} else if (isDeleteIntent) {
String defaultImageUrl = existingUser.createProfileImage(existingUser.getUsername());
updatedUser.setPhoto(defaultImageUrl);
updateUserInFirestore(updatedUser);
} else {
updatedUser.setPhoto(existingUser.getPhoto());
updateUserInFirestore(updatedUser);
}
}

@Override
public void onError(Exception e) {
progressBar.setVisibility(View.GONE);
}
});
}


/**
* Updates the user details in Firestore and handles success or failure.
*
* @param user The user object containing updated details.
*/
private void updateUserInFirestore(User user) {
userController.updateUser(user, new UserUpdateCallback() {
@Override
public void onSuccess() {
Toast.makeText(getContext(), "User details updated successfully", Toast.LENGTH_SHORT).show();
progressBar.setVisibility(View.GONE);
Toast.makeText(getContext(), "User details updated successfully 🎉", Toast.LENGTH_SHORT).show();
NavController navController = NavHostFragment.findNavController(EditProfileFragment.this);
navController.navigate(R.id.save_profile_edits);
}

@Override
public void onError(Exception e) {
Toast.makeText(getContext(), "Failed to update user details: " + e.getMessage(), Toast.LENGTH_LONG).show();
progressBar.setVisibility(View.GONE);
}
});
}
Expand Down
32 changes: 12 additions & 20 deletions app/src/main/java/com/example/scanpal/EventController.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,11 @@
import android.view.View;
import android.widget.Toast;

import androidx.annotation.NonNull;

import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.DocumentReference;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.QueryDocumentSnapshot;
import com.google.firebase.firestore.QuerySnapshot;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageMetadata;
import com.google.firebase.storage.StorageReference;
Expand Down Expand Up @@ -287,7 +282,7 @@ public void getEventById(String EventID, EventFetchCallback callback) {
Uri imageURI = Uri.parse(Objects.requireNonNull(eventDoc.get("photo")).toString());
event.setPosterURI(imageURI);
event.setId(EventID);
event.setAnnouncementCount( (long) eventDoc.get("announcementCount") );
event.setAnnouncementCount((long) eventDoc.get("announcementCount"));

// Access the data using eventDoc.getData() or convert it to an object
fetchEventOrganizerByRef((DocumentReference) Objects.requireNonNull(eventDoc.get("organizer")),
Expand Down Expand Up @@ -381,24 +376,21 @@ public void getAllEventIds(EventIDsFetchCallback callback) {
CollectionReference eventsRef = database.collection("Events");
List<String> documentIds = new ArrayList<>();

eventsRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
eventsRef.get().addOnCompleteListener(task -> {
if (task.isSuccessful()) {

for (DocumentSnapshot document : task.getResult()) {
String documentId = document.getId();
documentIds.add(documentId);
}
for (DocumentSnapshot document : task.getResult()) {
String documentId = document.getId();
documentIds.add(documentId);
}

callback.onSuccess(documentIds);
callback.onSuccess(documentIds);

for (String id : documentIds) {
Log.d("Document ID", id);
}
} else {
Log.d("Firestore", "Error getting documents: ", task.getException());
for (String id : documentIds) {
Log.d("Document ID", id);
}
} else {
Log.d("Firestore", "Error getting documents: ", task.getException());
}
});

Expand Down
45 changes: 18 additions & 27 deletions app/src/main/java/com/example/scanpal/EventDetailsFragment.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@

import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;

import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.firebase.firestore.CollectionReference;
Expand Down Expand Up @@ -214,22 +211,18 @@ public void onSuccess() {
Toast.makeText(getContext(), "RSVP successful.", Toast.LENGTH_SHORT).show();

FirebaseMessaging.getInstance().subscribeToTopic(eventID)
.addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
String msg = "Subscribed";
if (!task.isSuccessful()) {
msg = "Subscribe failed";

}
else {
setJoinButton(true);
onResume();
Log.d("Subscribing", msg);
}

//Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
.addOnCompleteListener(task -> {
String msg = "Subscribed";
if (!task.isSuccessful()) {
msg = "Subscribe failed";

} else {
setJoinButton(true);
onResume();
Log.d("Subscribing", msg);
}

//Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
});

//setJoinButton(true);
Expand Down Expand Up @@ -283,8 +276,8 @@ private void fetchOrganizer(DocumentReference userRef) {
getEventOrganizerUserName = organizerDoc.getId();

//Hide edit button?
if( !(userDetails.getUsername().equals(getEventOrganizerUserName)) ||
!(userDetails.getUsername().equals(getEventOrganizerUserName)) && !(userDetails.isAdministrator()) ) {
if (!(userDetails.getUsername().equals(getEventOrganizerUserName)) ||
!(userDetails.getUsername().equals(getEventOrganizerUserName)) && !(userDetails.isAdministrator())) {
eventEditButton.hide(); //just hide the edit button
}

Expand Down Expand Up @@ -444,8 +437,8 @@ private void setJoinButton(boolean isRsvp) {
}

/**
*
* A function call that will navigate to the edit events page if conditions are met
*
* @param view The current view
*/
void navToEditDetails(View view) {
Expand All @@ -469,9 +462,9 @@ void navToEditDetails(View view) {
}

/**
*
* This function creates a dialogbox so that the organizer may send an announcement
* to their attendees
*
* @param view The current view
*/
void newAnnouncement(View view) {
Expand All @@ -488,7 +481,7 @@ void newAnnouncement(View view) {
eventController.getEventById(eventID, new EventFetchCallback() {
@Override
public void onSuccess(Event event) {
eventAnnouncementCount = event.getAnnouncementCount();//incase multiple announcements at a time
eventAnnouncementCount = event.getAnnouncementCount();//incase multiple announcements at a time
}

@Override
Expand All @@ -501,7 +494,7 @@ public void onError(Exception e) {
announcementDialog.setTitle("Event Announcement");

announcementDialog.setPositiveButton("Send", (DialogInterface.OnClickListener) (dialog, which) -> {
if(messageBox.getText().toString().isEmpty()) {
if (messageBox.getText().toString().isEmpty()) {
Toast.makeText(getContext(), "Error: Can't make empty Announcement", Toast.LENGTH_LONG).show();
dialog.cancel();
return;//return to prevent creating a new announcement
Expand All @@ -523,9 +516,7 @@ public void onError(Exception e) {
});

// Set the Negative button with No name Lambda OnClickListener method is use of DialogInterface interface.
announcementDialog.setNegativeButton("Cancel", (DialogInterface.OnClickListener) (dialog, which) -> {
dialog.cancel();
});
announcementDialog.setNegativeButton("Cancel", (DialogInterface.OnClickListener) (dialog, which) -> dialog.cancel());

announcementDialog.show();

Expand Down
9 changes: 5 additions & 4 deletions app/src/main/java/com/example/scanpal/ImageController.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
* Controller class for managing image uploads and retrievals with Firebase Storage.
*/
public class ImageController {
private final FirebaseStorage storage = FirebaseStorage.getInstance();
protected FirebaseStorage storage = FirebaseStorage.getInstance();

/**
* Uploads an image file to Firebase Storage.
Expand All @@ -21,14 +21,15 @@ public class ImageController {
* @param onSuccessListener Listener for successful upload operations.
* @param onFailureListener Listener for failed upload operations.
*/
public void uploadImage(Uri fileUri, OnSuccessListener<UploadTask.TaskSnapshot> onSuccessListener, OnFailureListener onFailureListener) {
String fileName = System.currentTimeMillis() + ".jpg"; // Generates a unique file name based on the current timestamp.
public void uploadImage(Uri fileUri, OnSuccessListener<Uri> onSuccessListener, OnFailureListener onFailureListener) {
String fileName = "profiles/" + System.currentTimeMillis() + ".jpg";

StorageReference storageRef = storage.getReference();
StorageReference imageRef = storageRef.child(fileName);
UploadTask uploadTask = imageRef.putFile(fileUri);

uploadTask.addOnSuccessListener(onSuccessListener).addOnFailureListener(onFailureListener);
uploadTask.addOnSuccessListener(taskSnapshot -> imageRef.getDownloadUrl().addOnSuccessListener(onSuccessListener).addOnFailureListener(onFailureListener))
.addOnFailureListener(onFailureListener);
}

/**
Expand Down
7 changes: 0 additions & 7 deletions app/src/main/java/com/example/scanpal/MainActivity.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
package com.example.scanpal;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationCompat;
import androidx.core.splashscreen.SplashScreen;
import androidx.navigation.NavController;
import androidx.navigation.fragment.NavHostFragment;
Expand Down Expand Up @@ -43,5 +37,4 @@ private void setupNavController() {
navController.navigate(R.id.signupFragment);
}
}

}
Loading
Loading