SDPepe/AppArt

View on GitHub
app/src/main/java/ch/epfl/sdp/appart/user/UserViewModel.java

Summary

Maintainability
A
0 mins
Test Coverage
C
77%
package ch.epfl.sdp.appart.user;

import android.net.Uri;
import android.util.Log;
import android.util.Pair;

import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;

import java.util.concurrent.CompletableFuture;

import javax.inject.Inject;

import ch.epfl.sdp.appart.database.DatabaseService;
import ch.epfl.sdp.appart.database.firebaselayout.FirebaseLayout;
import ch.epfl.sdp.appart.database.local.LocalDatabaseService;
import ch.epfl.sdp.appart.login.LoginService;
import ch.epfl.sdp.appart.utils.DatabaseSync;
import ch.epfl.sdp.appart.utils.StoragePathBuilder;
import dagger.hilt.android.lifecycle.HiltViewModel;


@HiltViewModel
public class UserViewModel extends ViewModel {

    private final MutableLiveData<Boolean> mPutUserConfirmed = new MutableLiveData<>();
    private final MutableLiveData<Boolean> mUpdateUserConfirmed = new MutableLiveData<>();
    private final MutableLiveData<Boolean> mUpdateImageConfirmed = new MutableLiveData<>();
    private final MutableLiveData<Boolean> mDeleteImageConfirmed = new MutableLiveData<>();
    private final MutableLiveData<Pair<User, Boolean>> mUser = new MutableLiveData<>();

    private Uri profileImageUri;

    final DatabaseService db;
    final LoginService ls;
    final LocalDatabaseService localdb;

    @Inject
    public UserViewModel(DatabaseService database, LoginService loginService,
                         LocalDatabaseService localdb) {

        this.db = database;
        this.ls = loginService;
        this.localdb = localdb;
    }

    /**
     * Puts the user in the database and updates the LiveData
     *
     * @param user the user to store in database
     */
    public void putUser(User user) {
        CompletableFuture<Boolean> putUser = db.putUser(user);
        putUser.exceptionally(e -> {
            Log.d("PUT USER", "DATABASE FAIL");
            return null;
        });
        putUser.thenAccept(mPutUserConfirmed::setValue);
    }

    /**
     * Update the user in the database and updates the LiveData
     *
     * @param user the user to update in database
     */
    public void updateUser(User user) {
        CompletableFuture<Boolean> updateUser = db.updateUser(user);
        updateUser.exceptionally(e -> {
            Log.d("UPDATE USER", "DATABASE FAIL");
            return null;
        });
        updateUser.thenAccept(mUpdateUserConfirmed::setValue);
    }

    /**
     * Update the user image the database and updates the LiveData
     * the uri for the image is stored in profileImageUri attribute above
     *
     * @param userId the id of the user
     */
    public void updateImage(String userId) {
        String imagePathAndName = new StoragePathBuilder()
                .toUsersStorageDirectory()
                .toDirectory(userId)
                .withFile(FirebaseLayout.PROFILE_IMAGE_NAME +
                        System.currentTimeMillis() +
                        FirebaseLayout.JPEG);

        CompletableFuture<Boolean> updateImage = db.putImage(profileImageUri, imagePathAndName);
        updateImage.exceptionally(e -> {
            Log.d("UPDATE IMAGE", "DATABASE FAIL");
            return null;
        });
        updateImage.thenAccept(mUpdateImageConfirmed::setValue);
    }

    /**
     * Deletes the user image the database and updates the LiveData
     * !! USE - user.getProfileImage() when calling this method
     *
     * @param profilePicture this is the complete path for the user's image: user.getProfileImage()
     */
    public void deleteImage(String profilePicture) {
        CompletableFuture<Boolean> deleteImage = db.deleteImage(profilePicture);
        deleteImage.exceptionally(e -> {
            Log.d("DELETE IMAGE", "DATABASE FAIL");
            return null;
        });
        deleteImage.thenAccept(mDeleteImageConfirmed::setValue);
    }

    /**
     * Get the user from the database and updates the LiveData.
     *
     * @param userId the unique Id of the user to retrieve from database
     * @return a completable future telling whether the operation was successful
     */
    public CompletableFuture<Void> getUser(String userId) {
        CompletableFuture<Void> result = new CompletableFuture<>();
        CompletableFuture<User> localUserRes = localdb.getUser(userId);
        localUserRes.exceptionally(e -> {
            getFromDBAndSetUser(userId, result);
            return null;
        });
        localUserRes.thenAccept(u -> {
            if (u != null) mUser.setValue(new Pair<>(u, true));
            getFromDBAndSetUser(userId, result);
        });
        return result;
    }

    /**
     * Gets the current user and updates the values with the user info.
     * <p>
     * It first tries to load the user from the local database. Independently from the result,
     * it then tries to fetch the user from the database.
     *
     * @return a completable future telling if the server fetch was successful
     */
    public CompletableFuture<Void> getCurrentUser() {
        CompletableFuture<Void> result = new CompletableFuture<>();
        User currentUser;
        try {
            currentUser = localdb.getCurrentUser();
        } catch (IllegalStateException e){
            e.printStackTrace();
            currentUser = null;
        }

        if (currentUser != null)
            mUser.setValue(new Pair<>(currentUser, true));

        currentUser = ls.getCurrentUser();
        if (currentUser != null) {
            getFromDBAndSetUser(currentUser.getUserId(), result);
        } else
            result.completeExceptionally(new IllegalStateException("Current user cannot be null!"));

        return result;
    }

    private void getFromDBAndSetUser(String userId, CompletableFuture<Void> result) {
        CompletableFuture<User> userRes = db.getUser(userId);
        userRes.exceptionally(e -> {
            Log.d("USER_VM", "Failed to fetch user from DB");
            result.completeExceptionally(e);
            return null;
        });
        userRes.thenAccept(cu -> {
            mUser.setValue(new Pair<>(cu, false));
            result.complete(null);
        });
    }

    /*
     * Getters for MutableLiveData instances declared above
     */
    public MutableLiveData<Boolean> getPutUserConfirmed() {
        return mPutUserConfirmed;
    }

    public MutableLiveData<Boolean> getUpdateUserConfirmed() {
        return mUpdateUserConfirmed;
    }

    public MutableLiveData<Boolean> getUpdateImageConfirmed() {
        return mUpdateImageConfirmed;
    }

    public MutableLiveData<Boolean> getDeleteImageConfirmed() {
        return mDeleteImageConfirmed;
    }

    public MutableLiveData<Pair<User, Boolean>> getUser() {
        return mUser;
    }

    /*
     * Setters
     */
    public void setUri(Uri uri) {
        profileImageUri = uri;
    }

    /*
     * Getters
     */
    public Uri getUri() {
        return profileImageUri;
    }

}