diff --git a/.idea/androidTestResultsUserPreferences.xml b/.idea/androidTestResultsUserPreferences.xml
index a1723b9b..b6d7ae07 100644
--- a/.idea/androidTestResultsUserPreferences.xml
+++ b/.idea/androidTestResultsUserPreferences.xml
@@ -98,6 +98,19 @@
+
+
+
+
+
+
+
diff --git a/app/src/androidTest/java/com/github/sdp/mediato/FeedFragmentTest.java b/app/src/androidTest/java/com/github/sdp/mediato/FeedFragmentTest.java
index 6c015b14..5b1263ae 100644
--- a/app/src/androidTest/java/com/github/sdp/mediato/FeedFragmentTest.java
+++ b/app/src/androidTest/java/com/github/sdp/mediato/FeedFragmentTest.java
@@ -78,6 +78,7 @@ public void setUp() throws ExecutionException, InterruptedException, TimeoutExce
// Pass the username to the fragment
Bundle bundle = new Bundle();
bundle.putString("username", user1.getUsername());
+ bundle.putSerializable("feedType", FeedFragment.FeedType.FEED);
feedFragment.setArguments(bundle);
fragmentManager.beginTransaction().replace(R.id.main_container, feedFragment)
.commitAllowingStateLoss();
diff --git a/app/src/androidTest/java/com/github/sdp/mediato/MyReviewsFragmentTest.java b/app/src/androidTest/java/com/github/sdp/mediato/MyReviewsFragmentTest.java
new file mode 100644
index 00000000..7e2a0475
--- /dev/null
+++ b/app/src/androidTest/java/com/github/sdp/mediato/MyReviewsFragmentTest.java
@@ -0,0 +1,170 @@
+package com.github.sdp.mediato;
+
+import static androidx.test.espresso.Espresso.onView;
+import static androidx.test.espresso.assertion.ViewAssertions.matches;
+import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant;
+import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static androidx.test.espresso.matcher.ViewMatchers.withId;
+import static androidx.test.espresso.matcher.ViewMatchers.withText;
+import static com.adevinta.android.barista.assertion.BaristaRecyclerViewAssertions.assertRecyclerViewItemCount;
+import static com.adevinta.android.barista.interaction.BaristaListInteractions.clickListItemChild;
+import static com.adevinta.android.barista.internal.matcher.HelperMatchers.atPosition;
+
+import static org.hamcrest.Matchers.allOf;
+
+import android.os.Bundle;
+
+import androidx.fragment.app.FragmentManager;
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.espresso.ViewInteraction;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.github.sdp.mediato.DatabaseTests.DataBaseTestUtil;
+import com.github.sdp.mediato.data.CollectionsDatabase;
+import com.github.sdp.mediato.data.UserDatabase;
+import com.github.sdp.mediato.model.Location;
+import com.github.sdp.mediato.model.Review;
+import com.github.sdp.mediato.model.User;
+import com.github.sdp.mediato.model.media.Collection;
+import com.github.sdp.mediato.model.media.Media;
+import com.github.sdp.mediato.model.media.MediaType;
+import com.github.sdp.mediato.ui.FeedFragment;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+@RunWith(AndroidJUnit4.class)
+public class MyReviewsFragmentTest {
+ private final static int STANDARD_USER_TIMEOUT = 10;
+ private User user1;
+ private User user2;
+ private User user3;
+ private Collection collection1;
+ private Collection collection2;
+ private Collection collection3;
+
+ ViewInteraction feedText = onView(withId(R.id.text_feed));
+
+ @Before
+ public void setUp() throws ExecutionException, InterruptedException, TimeoutException {
+ try {
+ DataBaseTestUtil.useEmulator();
+ } catch (Exception ignored) {
+ }
+
+ //Setup test data
+ createUsers();
+ createReviews();
+ addReviews();
+ Thread.sleep(1000);
+ UserDatabase.followUser(user1.getUsername(), user2.getUsername());
+ Thread.sleep(1000);
+
+ // Launch the MainActivity
+ ActivityScenario scenario = ActivityScenario.launch(MainActivity.class);
+ // Set up the MainActivity to display the FeedFragment
+ scenario.onActivity(activity -> {
+ FragmentManager fragmentManager = activity.getSupportFragmentManager();
+ FeedFragment feedFragment = new FeedFragment();
+
+ // Pass the username to the fragment
+ Bundle bundle = new Bundle();
+ bundle.putString("username", user1.getUsername());
+ bundle.putSerializable("feedType", FeedFragment.FeedType.MY_REVIEWS);
+ feedFragment.setArguments(bundle);
+ fragmentManager.beginTransaction().replace(R.id.main_container, feedFragment)
+ .commitAllowingStateLoss();
+ });
+ }
+
+ @AfterClass
+ public static void cleanDatabase() {
+ DataBaseTestUtil.cleanDatabase();
+ }
+
+ // Test whether the feed text is displayed and contains the correct text
+ @Test
+ public void testFeedFragmentTextView() {
+ feedText.check(matches(isDisplayed()));
+ feedText.check(matches(withText("My Reviews")));
+ }
+
+ // Test that all the reviews from the followed users are displayed
+ // In this test, only user 2 is followed and they have 2 reviews
+ @Test
+ public void testItemCount() throws InterruptedException {
+ Thread.sleep(5000);
+ assertRecyclerViewItemCount(R.id.feed_posts, 2);
+ }
+
+ /**
+ * --------------Util functions--------------------
+ */
+
+ //Helper function that creates users and adds them to the database
+ private void createUsers() throws ExecutionException, InterruptedException, TimeoutException {
+ //Create new sample users
+ user1 = new User.UserBuilder("uniqueId1")
+ .setUsername("user_myreviews_test_1")
+ .setEmail("email_test_1")
+ .setRegisterDate("09/03/2023")
+ .setLocation(new Location(3.14, 3.14))
+ .build();
+ user2 = new User.UserBuilder("uniqueId2")
+ .setUsername("user_myreviews_test_2")
+ .setEmail("email_test_2")
+ .setRegisterDate("19/03/2023")
+ .setLocation(new Location(3.14, 3.14))
+ .build();
+ user3 = new User.UserBuilder("uniqueId3")
+ .setUsername("user_myreviews_test_3")
+ .setEmail("email_test_3")
+ .setRegisterDate("19/03/2023")
+ .setLocation(new Location(3.14, 3.14))
+ .build();
+ UserDatabase.addUser(user1).get(STANDARD_USER_TIMEOUT, TimeUnit.SECONDS);
+ UserDatabase.addUser(user2).get(STANDARD_USER_TIMEOUT, TimeUnit.SECONDS);
+ UserDatabase.addUser(user3).get(STANDARD_USER_TIMEOUT, TimeUnit.SECONDS);
+
+ }
+
+ //Helper function that creates reviews and adds them to the collections
+ private void createReviews() {
+ Media media1 = new Media(MediaType.MOVIE, "Harry Potter 1", "In the closet", "validUrl", 123);
+ Media media2 = new Media(MediaType.MOVIE, "Harry Potter 2", "In the WC", "validUrl", 1234);
+ Media media3 = new Media(MediaType.MOVIE, "Harry Potter 3", "In the prison", "validUrl", 12345);
+
+ Review review1 = new Review(user1.getUsername(), media1, 4, "Best movie in the world");
+ Review review2 = new Review(user1.getUsername(), media2, 5, "Pretty bad");
+ Review review3 = new Review(user1.getUsername(), media3, 6, "Really bad");
+
+ Map collection1Reviews = new HashMap<>();
+ collection1Reviews.put(review1.getMedia().getTitle(), review1);
+
+ Map collection2Reviews = new HashMap<>();
+ collection2Reviews.put(review2.getMedia().getTitle(), review2);
+
+ Map collection3Reviews = new HashMap<>();
+ collection3Reviews.put(review3.getMedia().getTitle(), review3);
+
+ collection1 = new Collection("The best", collection1Reviews);
+ collection2 = new Collection("The bad", collection2Reviews);
+ collection3 = new Collection("The worst", collection3Reviews);
+ }
+
+ //Helper function that adds the reviews to the database
+ private void addReviews() throws ExecutionException, InterruptedException, TimeoutException {
+ CollectionsDatabase.addCollection(user1.getUsername(), collection1);
+ CollectionsDatabase.addCollection(user1.getUsername(), collection2);
+ CollectionsDatabase.addCollection(user3.getUsername(), collection3);
+ Thread.sleep(1000);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/sdp/mediato/MainActivity.java b/app/src/main/java/com/github/sdp/mediato/MainActivity.java
index 3b7b5ce4..a5c21359 100644
--- a/app/src/main/java/com/github/sdp/mediato/MainActivity.java
+++ b/app/src/main/java/com/github/sdp/mediato/MainActivity.java
@@ -15,7 +15,6 @@
import com.github.sdp.mediato.cache.AppCache;
import com.github.sdp.mediato.databinding.ActivityMainBinding;
import com.github.sdp.mediato.ui.ExploreFragment;
-import com.github.sdp.mediato.model.Review;
import com.github.sdp.mediato.ui.FeedFragment;
import com.github.sdp.mediato.ui.MyProfileFragment;
import com.github.sdp.mediato.ui.ReadOnlyProfileFragment;
@@ -23,7 +22,6 @@
import com.github.sdp.mediato.ui.viewmodel.MyProfileViewModel;
import com.github.sdp.mediato.ui.viewmodel.ReadOnlyProfileViewModel;
import com.google.firebase.auth.FirebaseAuth;
-import com.google.gson.Gson;
/**
* The main activity of the app that displays a bottom navigation bar and manages the navigation
@@ -37,6 +35,7 @@ public class MainActivity extends AppCompatActivity implements FragmentSwitcher
SearchFragment searchFragment;
ExploreFragment exploreFragment;
FeedFragment feedFragment;
+ FeedFragment myReviewsFragment;
private MyProfileViewModel myProfileViewModel;
private ReadOnlyProfileViewModel readOnlyProfileViewModel;
AppCache globalCache;
@@ -78,8 +77,9 @@ private boolean navigateFragments(int itemId) {
replaceFragment(myProfileFragment);
} else if (itemId == R.id.explore) {
replaceFragment(exploreFragment);
+ } else if (itemId == R.id.my_reviews) {
+ replaceFragment(myReviewsFragment);
}
-
return true;
}
@@ -102,18 +102,29 @@ private void setDefaultFragment(String username) {
searchFragment = new SearchFragment();
exploreFragment = new ExploreFragment();
feedFragment = new FeedFragment();
+ myReviewsFragment = new FeedFragment();
Bundle args = new Bundle();
+ Bundle argsFeed = new Bundle();
+ Bundle argsMyReviews = new Bundle();
+
// Give the username as an argument to the profile page and switch to it
args.putString("username", username);
args.putString("general_search", "true");
args.putString("collection", "Recently watched");
+ argsFeed.putString("username", username);
+ argsMyReviews.putString("username", username);
+
+ argsFeed.putSerializable("feedType", FeedFragment.FeedType.FEED);
+ argsMyReviews.putSerializable("feedType", FeedFragment.FeedType.MY_REVIEWS);
+
searchFragment.setArguments(args);
myProfileFragment.setArguments(args);
exploreFragment.setArguments(args);
- feedFragment.setArguments(args);
+ feedFragment.setArguments(argsFeed);
+ myReviewsFragment.setArguments(argsMyReviews);
// Mark the profile item in the bottom bar as selected
binding.bottomNavigationView.setSelectedItemId(R.id.profile);
diff --git a/app/src/main/java/com/github/sdp/mediato/ui/FeedFragment.java b/app/src/main/java/com/github/sdp/mediato/ui/FeedFragment.java
index 34fc9c6e..9db95050 100644
--- a/app/src/main/java/com/github/sdp/mediato/ui/FeedFragment.java
+++ b/app/src/main/java/com/github/sdp/mediato/ui/FeedFragment.java
@@ -25,6 +25,7 @@ public class FeedFragment extends Fragment {
private FeedViewModel viewModel;
private FragmentFeedBinding binding;
private ReviewPostListAdapter adapter;
+ private FeedType feedType;
@Override
@@ -38,9 +39,12 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
USERNAME = getArguments().getString("username");
+ feedType = (FeedType) getArguments().getSerializable("feedType");
+
+ binding.textFeed.setText(feedType.toString());
viewModel = new ViewModelProvider(this).get(FeedViewModel.class);
- viewModel.setUsername(USERNAME);
+ viewModel.setData(USERNAME, feedType);
adapter = new ReviewPostListAdapter();
adapter.setUsername(USERNAME);
@@ -51,4 +55,20 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat
binding.feedPosts.setHasFixedSize(false);
viewModel.getPosts().observe(getViewLifecycleOwner(), adapter::submitList);
}
+
+ public enum FeedType {
+ MY_REVIEWS, FEED;
+
+ @Override
+ public String toString() {
+ switch (this) {
+ case MY_REVIEWS:
+ return "My Reviews";
+ case FEED:
+ return "Feed";
+ }
+ return "";
+ }
+ }
+
}
diff --git a/app/src/main/java/com/github/sdp/mediato/ui/viewmodel/FeedViewModel.java b/app/src/main/java/com/github/sdp/mediato/ui/viewmodel/FeedViewModel.java
index bfa6fc1f..57764039 100644
--- a/app/src/main/java/com/github/sdp/mediato/ui/viewmodel/FeedViewModel.java
+++ b/app/src/main/java/com/github/sdp/mediato/ui/viewmodel/FeedViewModel.java
@@ -11,6 +11,7 @@
import com.github.sdp.mediato.data.UserDatabase;
import com.github.sdp.mediato.model.User;
import com.github.sdp.mediato.model.post.ReviewPost;
+import com.github.sdp.mediato.ui.FeedFragment;
import java.util.ArrayList;
import java.util.List;
@@ -21,7 +22,6 @@ public class FeedViewModel extends AndroidViewModel {
Application application;
private final MutableLiveData> posts = new MutableLiveData<>(new ArrayList<>());
private String username;
-
public FeedViewModel (@NonNull Application application) {
super(application);
this.application = application;
@@ -31,9 +31,16 @@ public FeedViewModel (@NonNull Application application) {
* Sets the username of the user who is currently logged in and generates the list of posts
* @param username the username of the user who is currently logged in
*/
- public void setUsername(String username) {
+ public void setData(String username, FeedFragment.FeedType feedType) {
this.username = username;
- createFollowingsPosts();
+ switch (feedType) {
+ case MY_REVIEWS:
+ createMyPosts();
+ break;
+ case FEED:
+ createFollowingsPosts();
+ break;
+ }
}
/**
@@ -59,4 +66,13 @@ public void createFollowingsPosts() {
.thenAccept(posts::setValue);
}
+ /**
+ * Generates the list of posts from the current user
+ */
+ public void createMyPosts() {
+ UserDatabase.getUser(username)
+ .thenApply(user -> user.fetchReviewPosts())
+ .thenAccept(posts::setValue);
+ }
+
}
diff --git a/app/src/main/res/drawable/ic_my_reviews.xml b/app/src/main/res/drawable/ic_my_reviews.xml
new file mode 100644
index 00000000..ff022725
--- /dev/null
+++ b/app/src/main/res/drawable/ic_my_reviews.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/menu/bottom_menu.xml b/app/src/main/res/menu/bottom_menu.xml
index 59b5ac34..eab06c61 100644
--- a/app/src/main/res/menu/bottom_menu.xml
+++ b/app/src/main/res/menu/bottom_menu.xml
@@ -12,6 +12,10 @@
android:id="@+id/search"
android:title="Search"
android:icon="@drawable/ic_search"/>
+