diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index e88b280..cca6d01 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -57,6 +57,22 @@
+
+
+
+ GETTERS_AND_SETTERS
+ KEEP
+
+
+ OVERRIDDEN_METHODS
+ BY_NAME
+
+
+ DEPENDENT_METHODS
+ BREADTH_FIRST
+
+
+
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..a1757ae
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index cfe743e..f156e9a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -3,12 +3,15 @@ apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 28
+ dataBinding {
+ enabled = true
+ }
defaultConfig {
applicationId "ch.beerpro"
minSdkVersion 21
targetSdkVersion 28
- versionCode 7
- versionName "Alpha 7"
+ versionCode 8
+ versionName "Alpha 8"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true
}
@@ -26,12 +29,12 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
- implementation 'androidx.appcompat:appcompat:1.0.0-beta01'
+ implementation 'androidx.appcompat:appcompat:1.0.0-rc01'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha1'
implementation 'com.google.firebase:firebase-core:16.0.1'
implementation 'com.firebaseui:firebase-ui-auth:4.1.0'
implementation 'com.google.firebase:firebase-storage:16.0.1'
- implementation 'com.google.android.material:material:1.0.0-beta01'
+ implementation 'com.google.android.material:material:1.0.0-rc01'
implementation 'com.google.firebase:firebase-firestore:17.0.4'
implementation 'com.firebaseui:firebase-ui-firestore:4.0.0'
@@ -40,13 +43,16 @@ dependencies {
annotationProcessor 'com.github.bumptech.glide:compiler:4.7.1'
implementation 'androidx.legacy:legacy-support-v4:1.0.0-beta01'
- implementation 'androidx.recyclerview:recyclerview:1.0.0-beta01'
+ implementation 'androidx.recyclerview:recyclerview:1.0.0-rc01'
implementation 'com.github.yalantis:ucrop:2.2.2-native'
implementation 'com.github.tajchert:nammu:1.2.0'
implementation 'com.github.jkwiecien:EasyImage:2.1.0'
+
// lombok
- //compileOnly "org.projectlombok:lombok:1.18.2"
- //annotationProcessor "org.projectlombok:lombok:1.18.2"
+ // before upgrading, check if this has been resolved:
+ // https://github.com/mplushnikov/lombok-intellij-plugin/issues/496
+ compileOnly "org.projectlombok:lombok:1.16.20"
+ annotationProcessor "org.projectlombok:lombok:1.16.20"
// ButterKnife
implementation 'com.jakewharton:butterknife:9.0.0-SNAPSHOT'
@@ -54,10 +60,12 @@ dependencies {
implementation 'net.danlew:android.joda:2.9.9.4'
+ implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.7'
+
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.0-alpha4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4'
- implementation 'com.android.support:design:28.0.0-beta01'
+ implementation 'com.android.support:design:28.0.0-rc01'
}
apply plugin: 'com.google.gms.google-services'
diff --git a/app/release/app.aab b/app/release/app.aab
new file mode 100644
index 0000000..2c3f8fb
Binary files /dev/null and b/app/release/app.aab differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index aef4473..348ebf1 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -15,7 +15,7 @@
android:theme="@style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
@@ -24,30 +24,49 @@
-
+
+ android:value=".presentation.search.SearchActivity" />
+ android:value=".presentation.details.DetailsActivity" />
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/ch/beerpro/MyApplication.java b/app/src/main/java/ch/beerpro/MyApplication.java
index 291c361..f4e6bfc 100644
--- a/app/src/main/java/ch/beerpro/MyApplication.java
+++ b/app/src/main/java/ch/beerpro/MyApplication.java
@@ -1,12 +1,16 @@
package ch.beerpro;
import android.app.Application;
+import com.google.firebase.firestore.FirebaseFirestore;
import net.danlew.android.joda.JodaTimeAndroid;
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
+
+ FirebaseFirestore.setLoggingEnabled(true);
+
JodaTimeAndroid.init(this);
}
}
\ No newline at end of file
diff --git a/app/src/main/java/ch/beerpro/helpers/FirestoreQueryLiveData.java b/app/src/main/java/ch/beerpro/domain/helpers/FirestoreQueryLiveData.java
similarity index 81%
rename from app/src/main/java/ch/beerpro/helpers/FirestoreQueryLiveData.java
rename to app/src/main/java/ch/beerpro/domain/helpers/FirestoreQueryLiveData.java
index d8a0808..0023587 100644
--- a/app/src/main/java/ch/beerpro/helpers/FirestoreQueryLiveData.java
+++ b/app/src/main/java/ch/beerpro/domain/helpers/FirestoreQueryLiveData.java
@@ -1,19 +1,12 @@
-package ch.beerpro.helpers;
+package ch.beerpro.domain.helpers;
import android.os.Handler;
-import android.util.Log;
-import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
-import ch.beerpro.models.Beer;
-import ch.beerpro.models.Entity;
-import com.firebase.ui.common.ChangeEventType;
-import com.firebase.ui.firestore.ChangeEventListener;
-import com.firebase.ui.firestore.FirestoreArray;
-import com.firebase.ui.firestore.ObservableSnapshotArray;
+import ch.beerpro.domain.models.Entity;
+import ch.beerpro.presentation.helpers.EntityClassSnapshotParser;
import com.google.firebase.firestore.*;
import javax.annotation.Nullable;
-import java.util.List;
public class FirestoreQueryLiveData extends LiveData implements EventListener {
diff --git a/app/src/main/java/ch/beerpro/helpers/FirestoreQueryLiveDataArray.java b/app/src/main/java/ch/beerpro/domain/helpers/FirestoreQueryLiveDataArray.java
similarity index 93%
rename from app/src/main/java/ch/beerpro/helpers/FirestoreQueryLiveDataArray.java
rename to app/src/main/java/ch/beerpro/domain/helpers/FirestoreQueryLiveDataArray.java
index 4ba8d54..70c1391 100644
--- a/app/src/main/java/ch/beerpro/helpers/FirestoreQueryLiveDataArray.java
+++ b/app/src/main/java/ch/beerpro/domain/helpers/FirestoreQueryLiveDataArray.java
@@ -1,10 +1,11 @@
-package ch.beerpro.helpers;
+package ch.beerpro.domain.helpers;
import android.os.Handler;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
-import ch.beerpro.models.Entity;
+import ch.beerpro.domain.models.Entity;
+import ch.beerpro.presentation.helpers.EntityClassSnapshotParser;
import com.firebase.ui.common.ChangeEventType;
import com.firebase.ui.firestore.ChangeEventListener;
import com.firebase.ui.firestore.FirestoreArray;
diff --git a/app/src/main/java/ch/beerpro/domain/helpers/LiveDataExtensions.java b/app/src/main/java/ch/beerpro/domain/helpers/LiveDataExtensions.java
new file mode 100644
index 0000000..9c1f355
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/domain/helpers/LiveDataExtensions.java
@@ -0,0 +1,93 @@
+package ch.beerpro.domain.helpers;
+
+import android.util.Pair;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MediatorLiveData;
+import org.apache.commons.lang3.tuple.Triple;
+
+public class LiveDataExtensions {
+
+ public static LiveData> zip(LiveData as, LiveData bs) {
+ return new MediatorLiveData>() {
+
+ A lastA = null;
+ B lastB = null;
+
+ {
+ {
+ addSource(as, (A a) -> {
+ lastA = a;
+ update();
+ });
+ addSource(bs, (B b) -> {
+ lastB = b;
+ update();
+ });
+ }
+ }
+
+ private void update() {
+ this.setValue(new Pair<>(lastA, lastB));
+ }
+ };
+ }
+
+ public static LiveData> combineLatest(LiveData as, LiveData bs) {
+ return new MediatorLiveData>() {
+
+ A lastA = null;
+ B lastB = null;
+
+ {
+ {
+ addSource(as, (A a) -> {
+ lastA = a;
+ update();
+ });
+ addSource(bs, (B b) -> {
+ lastB = b;
+ update();
+ });
+ }
+ }
+
+ private void update() {
+ if (lastA != null && lastB != null) {
+ this.setValue(new Pair<>(lastA, lastB));
+ }
+ }
+ };
+ }
+
+ public static LiveData> combineLatest(LiveData as, LiveData bs, LiveData cs) {
+ return new MediatorLiveData>() {
+
+ A lastA = null;
+ B lastB = null;
+ C lastC = null;
+
+ {
+ {
+ addSource(as, (A a) -> {
+ lastA = a;
+ update();
+ });
+ addSource(bs, (B b) -> {
+ lastB = b;
+ update();
+ });
+ addSource(cs, (C c) -> {
+ lastC = c;
+ update();
+ });
+ }
+ }
+
+ private void update() {
+ if (lastA != null && lastB != null && lastC != null) {
+ this.setValue(Triple.of(lastA, lastB, lastC));
+ }
+ }
+ };
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/domain/models/Beer.java b/app/src/main/java/ch/beerpro/domain/models/Beer.java
new file mode 100644
index 0000000..d37ef79
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/domain/models/Beer.java
@@ -0,0 +1,27 @@
+package ch.beerpro.domain.models;
+
+import com.google.firebase.firestore.Exclude;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Beer implements Entity, Serializable {
+
+ public static final String COLLECTION = "beers";
+ public static final String FIELD_NAME = "name";
+
+ @Exclude
+ private String id;
+ private String manufacturer;
+ private String name;
+ private String category;
+ private String photo;
+ private float avgRating;
+ private int numRatings;
+
+}
diff --git a/app/src/main/java/ch/beerpro/domain/models/Entity.java b/app/src/main/java/ch/beerpro/domain/models/Entity.java
new file mode 100644
index 0000000..60f3416
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/domain/models/Entity.java
@@ -0,0 +1,19 @@
+package ch.beerpro.domain.models;
+
+import java.util.HashMap;
+import java.util.List;
+
+public interface Entity {
+
+ String getId();
+
+ void setId(String id);
+
+ static HashMap entitiesById(List entries) {
+ HashMap byId = new HashMap<>();
+ for (T entry : entries) {
+ byId.put(entry.getId(), entry);
+ }
+ return byId;
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/models/Like.java b/app/src/main/java/ch/beerpro/domain/models/Like.java
similarity index 98%
rename from app/src/main/java/ch/beerpro/models/Like.java
rename to app/src/main/java/ch/beerpro/domain/models/Like.java
index 2bf7016..5163a0f 100644
--- a/app/src/main/java/ch/beerpro/models/Like.java
+++ b/app/src/main/java/ch/beerpro/domain/models/Like.java
@@ -1,4 +1,4 @@
-package ch.beerpro.models;
+package ch.beerpro.domain.models;
import com.google.firebase.firestore.Exclude;
diff --git a/app/src/main/java/ch/beerpro/domain/models/Rating.java b/app/src/main/java/ch/beerpro/domain/models/Rating.java
new file mode 100644
index 0000000..f5c237a
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/domain/models/Rating.java
@@ -0,0 +1,38 @@
+package ch.beerpro.domain.models;
+
+import com.google.firebase.firestore.Exclude;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.*;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Rating implements Entity {
+ public static final String COLLECTION = "ratings";
+ public static final String FIELD_BEER_ID = "beerId";
+ public static final String FIELD_USER_ID = "userId";
+ public static final String FIELD_LIKES = "likes";
+ public static final String FIELD_CREATION_DATE = "creationDate";
+
+ @Exclude
+ private String id;
+ private String beerId;
+ private String beerName;
+ private String userId;
+ private String userName;
+ private String userPhoto;
+ private String photo;
+ private float rating;
+ private String comment;
+
+ /**
+ * We use a Map instead of an Array to be able to query it.
+ *
+ * @see
+ */
+ private Map likes;
+ private Date creationDate;
+}
diff --git a/app/src/main/java/ch/beerpro/domain/models/User.java b/app/src/main/java/ch/beerpro/domain/models/User.java
new file mode 100644
index 0000000..7736d0d
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/domain/models/User.java
@@ -0,0 +1,19 @@
+package ch.beerpro.domain.models;
+
+import com.google.firebase.firestore.Exclude;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+public class User implements Entity {
+ public static final String COLLECTION = "users";
+ public static final String FIELD_ID = "id";
+ public static final String FIELD_NAME = "name";
+ public static final String FIELD_PHOTO = "photo";
+
+ @Exclude
+ private String id;
+ private String name;
+ private String photo;
+}
diff --git a/app/src/main/java/ch/beerpro/domain/models/Wish.java b/app/src/main/java/ch/beerpro/domain/models/Wish.java
new file mode 100644
index 0000000..922e4ba
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/domain/models/Wish.java
@@ -0,0 +1,39 @@
+package ch.beerpro.domain.models;
+
+import com.google.firebase.firestore.Exclude;
+import com.google.firebase.firestore.IgnoreExtraProperties;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
+
+import java.util.Date;
+
+@IgnoreExtraProperties
+@Data
+@NoArgsConstructor
+@RequiredArgsConstructor
+public class Wish implements Entity {
+
+ public static final String COLLECTION = "wishes";
+ public static final String FIELD_ID = "id";
+ public static final String FIELD_USER_ID = "userId";
+ public static final String FIELD_BEER_ID = "beerId";
+ public static final String FIELD_ADDED_AT = "addedAt";
+
+ /**
+ * The id is formed by `$userId_$beerId` to make queries easier.
+ */
+ @Exclude
+ private String id;
+ @NonNull
+ private String userId;
+ @NonNull
+ private String beerId;
+ @NonNull
+ private Date addedAt;
+
+ public static String generateId(String userId, String beerId) {
+ return String.format("%s_%s", userId, beerId);
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/domain/repositories/BeersRepository.java b/app/src/main/java/ch/beerpro/domain/repositories/BeersRepository.java
new file mode 100644
index 0000000..f4a9f19
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/domain/repositories/BeersRepository.java
@@ -0,0 +1,19 @@
+package ch.beerpro.domain.repositories;
+
+import androidx.lifecycle.LiveData;
+import ch.beerpro.domain.helpers.FirestoreQueryLiveDataArray;
+import ch.beerpro.domain.models.Beer;
+import com.google.firebase.firestore.FirebaseFirestore;
+
+import java.util.List;
+
+public class BeersRepository {
+
+ private final FirestoreQueryLiveDataArray allBeers =
+ new FirestoreQueryLiveDataArray<>(FirebaseFirestore.getInstance().collection(Beer.COLLECTION), Beer.class);
+
+
+ public LiveData> getAllBeers() {
+ return allBeers;
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/domain/repositories/LikesRepository.java b/app/src/main/java/ch/beerpro/domain/repositories/LikesRepository.java
new file mode 100644
index 0000000..4948786
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/domain/repositories/LikesRepository.java
@@ -0,0 +1,37 @@
+package ch.beerpro.domain.repositories;
+
+import ch.beerpro.presentation.helpers.EntityClassSnapshotParser;
+import ch.beerpro.domain.models.Rating;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.auth.FirebaseUser;
+import com.google.firebase.firestore.DocumentReference;
+import com.google.firebase.firestore.FirebaseFirestore;
+import com.google.firebase.firestore.Transaction;
+
+import java.util.Map;
+
+public class LikesRepository {
+
+ private final static EntityClassSnapshotParser parser = new EntityClassSnapshotParser<>(Rating.class);
+
+
+ public void toggleLike(Rating rating) {
+
+ FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+ final DocumentReference ratingRef = db.collection(Rating.COLLECTION).document(rating.getId());
+
+ db.runTransaction((Transaction.Function) transaction -> {
+ Rating currentRating = parser.parseSnapshot(transaction.get(ratingRef));
+ Map likes = currentRating.getLikes();
+ String currentUserUid = currentUser.getUid();
+ if (likes.containsKey(currentUserUid)) {
+ likes.remove(currentUserUid);
+ } else {
+ likes.put(currentUserUid, true);
+ }
+ transaction.update(ratingRef, Rating.FIELD_LIKES, likes);
+ return null;
+ });
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/domain/repositories/RatingsRepository.java b/app/src/main/java/ch/beerpro/domain/repositories/RatingsRepository.java
new file mode 100644
index 0000000..841cc46
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/domain/repositories/RatingsRepository.java
@@ -0,0 +1,32 @@
+package ch.beerpro.domain.repositories;
+
+import androidx.lifecycle.LiveData;
+import ch.beerpro.domain.helpers.FirestoreQueryLiveDataArray;
+import ch.beerpro.domain.models.Rating;
+import com.google.firebase.firestore.FirebaseFirestore;
+import com.google.firebase.firestore.Query;
+
+import java.util.List;
+
+public class RatingsRepository {
+
+ private final FirestoreQueryLiveDataArray allRatings = new FirestoreQueryLiveDataArray<>(
+ FirebaseFirestore.getInstance().collection(Rating.COLLECTION)
+ .orderBy(Rating.FIELD_CREATION_DATE, Query.Direction.DESCENDING), Rating.class);
+
+ public static LiveData> getRatingsByUser(String userId) {
+ return new FirestoreQueryLiveDataArray<>(FirebaseFirestore.getInstance().collection(Rating.COLLECTION)
+ .orderBy(Rating.FIELD_CREATION_DATE, Query.Direction.DESCENDING)
+ .whereEqualTo(Rating.FIELD_USER_ID, userId), Rating.class);
+ }
+
+ public static LiveData> getRatingsByBeer(String beerId) {
+ return new FirestoreQueryLiveDataArray<>(FirebaseFirestore.getInstance().collection(Rating.COLLECTION)
+ .orderBy(Rating.FIELD_CREATION_DATE, Query.Direction.DESCENDING)
+ .whereEqualTo(Rating.FIELD_BEER_ID, beerId), Rating.class);
+ }
+
+ public LiveData> getAllRatings() {
+ return allRatings;
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/domain/repositories/WishesRepository.java b/app/src/main/java/ch/beerpro/domain/repositories/WishesRepository.java
new file mode 100644
index 0000000..9c2cf32
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/domain/repositories/WishesRepository.java
@@ -0,0 +1,52 @@
+package ch.beerpro.domain.repositories;
+
+import android.util.Pair;
+import androidx.lifecycle.LiveData;
+import ch.beerpro.domain.helpers.FirestoreQueryLiveData;
+import ch.beerpro.domain.helpers.FirestoreQueryLiveDataArray;
+import ch.beerpro.domain.models.Beer;
+import ch.beerpro.domain.models.Wish;
+import com.google.android.gms.tasks.Task;
+import com.google.firebase.firestore.DocumentReference;
+import com.google.firebase.firestore.FirebaseFirestore;
+import com.google.firebase.firestore.Query;
+
+import java.util.Date;
+import java.util.List;
+
+public class WishesRepository {
+
+
+ public static LiveData> getWishesByUser(String userId) {
+ return new FirestoreQueryLiveDataArray<>(FirebaseFirestore.getInstance().collection(Wish.COLLECTION)
+ .orderBy(Wish.FIELD_ADDED_AT, Query.Direction.DESCENDING).whereEqualTo(Wish.FIELD_USER_ID, userId),
+ Wish.class);
+ }
+
+ public static LiveData getUserWishListFor(Pair input) {
+ String userId = input.first;
+ Beer beer = input.second;
+ DocumentReference document = FirebaseFirestore.getInstance().collection(Wish.COLLECTION)
+ .document(Wish.generateId(userId, beer.getId()));
+ return new FirestoreQueryLiveData<>(document, Wish.class);
+ }
+
+ public Task toggleUserWishlistItem(String userId, String itemId) {
+
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+
+ String wishId = Wish.generateId(userId, itemId);
+
+ DocumentReference wishEntryQuery = db.collection(Wish.COLLECTION).document(wishId);
+
+ return wishEntryQuery.get().continueWithTask(task -> {
+ if (task.isSuccessful() && task.getResult().exists()) {
+ return wishEntryQuery.delete();
+ } else if (task.isSuccessful()) {
+ return wishEntryQuery.set(new Wish(userId, itemId, new Date()));
+ } else {
+ throw task.getException();
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/helpers/LiveDataExtensions.java b/app/src/main/java/ch/beerpro/helpers/LiveDataExtensions.java
deleted file mode 100644
index 3c424c2..0000000
--- a/app/src/main/java/ch/beerpro/helpers/LiveDataExtensions.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package ch.beerpro.helpers;
-
-import android.util.Pair;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MediatorLiveData;
-
-public class LiveDataExtensions {
-
- public static LiveData> combineLatest(LiveData as, LiveData bs) {
- return new MediatorLiveData>() {
-
- A lastA = null;
- B lastB = null;
-
- {
- {
- addSource(as, (A a) -> {
- lastA = a;
- update();
- });
- addSource(bs, (B b) -> {
- lastB = b;
- update();
- });
- }
- }
-
- private void update() {
- this.setValue(new Pair<>(lastA, lastB));
- }
- };
- }
-}
diff --git a/app/src/main/java/ch/beerpro/home/HomeScreenProfileFragment.java b/app/src/main/java/ch/beerpro/home/HomeScreenProfileFragment.java
deleted file mode 100644
index cd527dc..0000000
--- a/app/src/main/java/ch/beerpro/home/HomeScreenProfileFragment.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package ch.beerpro.home;
-
-import android.net.Uri;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import ch.beerpro.R;
-import com.bumptech.glide.Glide;
-import com.bumptech.glide.request.RequestOptions;
-import com.google.firebase.auth.FirebaseAuth;
-import com.google.firebase.auth.FirebaseUser;
-
-import androidx.fragment.app.Fragment;
-
-public class HomeScreenProfileFragment extends Fragment {
-
- private static final String TAG = "ProfileFragment";
-
- public HomeScreenProfileFragment() {
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- setHasOptionsMenu(true);
- View rootView = inflater.inflate(R.layout.fragment_profile_screen, container, false);
- ImageView userProfileImageView = rootView.findViewById(R.id.userProfileImageView);
- TextView userProfileNameText = rootView.findViewById(R.id.userProfileNameText);
-
- FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
-
- if (user != null) {
- // Name, email address, and profile photo Url
- String name = user.getDisplayName();
- userProfileNameText.setText(name);
- Uri photoUrl = user.getPhotoUrl();
- Glide.with(this).load(photoUrl).apply(new RequestOptions().circleCrop()).into(userProfileImageView);
-
- }
-
- return rootView;
- }
-
-}
diff --git a/app/src/main/java/ch/beerpro/home/HomeScreenViewModel.java b/app/src/main/java/ch/beerpro/home/HomeScreenViewModel.java
deleted file mode 100644
index 62e93a6..0000000
--- a/app/src/main/java/ch/beerpro/home/HomeScreenViewModel.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package ch.beerpro.home;
-
-import android.util.Log;
-import androidx.arch.core.util.Function;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.Transformations;
-import androidx.lifecycle.ViewModel;
-import ch.beerpro.helpers.EntityClassSnapshotParser;
-import ch.beerpro.helpers.FirestoreQueryLiveDataArray;
-import ch.beerpro.models.Beer;
-import ch.beerpro.models.Like;
-import ch.beerpro.models.Rating;
-import com.google.firebase.auth.FirebaseAuth;
-import com.google.firebase.auth.FirebaseUser;
-import com.google.firebase.firestore.*;
-
-import java.util.*;
-
-public class HomeScreenViewModel extends ViewModel {
-
- private static final String TAG = "SearchViewModel";
- private final FirestoreQueryLiveDataArray allBeers = new FirestoreQueryLiveDataArray<>(
- FirebaseFirestore.getInstance().collection(Beer.COLLECTION).orderBy(Beer.FIELD_NAME), Beer.class);
- private final FirestoreQueryLiveDataArray allRatings = new FirestoreQueryLiveDataArray<>(
- FirebaseFirestore.getInstance().collection(Rating.COLLECTION)
- .orderBy(Rating.FIELD_CREATION_DATE, Query.Direction.DESCENDING), Rating.class);
- private final LiveData> beerCategories;
- private final LiveData> beerManufacturers;
- private EntityClassSnapshotParser parser = new EntityClassSnapshotParser<>(Rating.class);
-
- public HomeScreenViewModel() {
- beerCategories = Transformations.map(allBeers, projectBeersToCagetories());
- beerManufacturers = Transformations.map(allBeers, projectBeersToManufacturers());
- }
-
- public FirestoreQueryLiveDataArray getAllRatings() {
- return allRatings;
- }
-
- private Function, List> projectBeersToCagetories() {
- return (List beers) -> {
- Set filtered = new HashSet<>();
- for (Beer beer : beers) {
- filtered.add(beer.getCategory());
-
- }
- String[] strings = filtered.toArray(new String[0]);
- return Arrays.asList(strings).subList(0, 8);
- };
- }
-
-
- private Function, List> projectBeersToManufacturers() {
- return (List beers) -> {
- Set filtered = new HashSet<>();
- for (Beer beer : beers) {
- filtered.add(beer.getManufacturer());
-
- }
- String[] strings = filtered.toArray(new String[0]);
- Arrays.sort(strings);
- return Arrays.asList(strings);
- };
- }
-
-
- public LiveData> getBeerCategories() {
- return beerCategories;
- }
-
- public LiveData> getBeerManufacturers() {
- return beerManufacturers;
- }
-
- public void toggleLike(Rating rating) {
-
- FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
- FirebaseFirestore db = FirebaseFirestore.getInstance();
- final DocumentReference ratingRef = db.collection(Rating.COLLECTION).document(rating.getId());
-
- db.runTransaction((Transaction.Function) transaction -> {
- Rating currentRating = parser.parseSnapshot(transaction.get(ratingRef));
- Map likes = currentRating.getLikes();
- String currentUserUid = currentUser.getUid();
- if (likes.containsKey(currentUserUid)) {
- likes.remove(currentUserUid);
- } else {
- likes.put(currentUserUid, true);
- }
- transaction.update(ratingRef, Rating.FIELD_LIKES, likes);
- return null;
- });
- }
-
- public FirebaseUser getCurrentUser() {
- return FirebaseAuth.getInstance().getCurrentUser();
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/ch/beerpro/models/Beer.java b/app/src/main/java/ch/beerpro/models/Beer.java
deleted file mode 100644
index 2504acc..0000000
--- a/app/src/main/java/ch/beerpro/models/Beer.java
+++ /dev/null
@@ -1,111 +0,0 @@
-package ch.beerpro.models;
-
-import com.google.firebase.firestore.Exclude;
-
-import java.io.Serializable;
-import java.util.Objects;
-
-//@Data
-//@NoArgsConstructor
-public class Beer implements Entity, Serializable {
-
- public static final String COLLECTION = "beers";
- public static final String FIELD_NAME = "name";
-
- @Exclude
- private String id;
- private String manufacturer;
- private String name;
- private String category;
- private String photo;
- private float avgRating;
- private int numRatings;
-
- public Beer() {
- }
-
- public Beer(String id, String manufacturer, String name, String category, String photo, float avgRating,
- int numRatings) {
- this.id = id;
- this.manufacturer = manufacturer;
- this.name = name;
- this.category = category;
- this.photo = photo;
- this.avgRating = avgRating;
- this.numRatings = numRatings;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o)
- return true;
- if (o == null || getClass() != o.getClass())
- return false;
- Beer beer = (Beer) o;
- return avgRating == beer.avgRating && numRatings == beer.numRatings && Objects.equals(id, beer.id) &&
- Objects.equals(manufacturer, beer.manufacturer) && Objects.equals(name, beer.name) &&
- Objects.equals(category, beer.category) && Objects.equals(photo, beer.photo);
- }
-
- @Override
- public int hashCode() {
-
- return Objects.hash(id, manufacturer, name, category, photo, avgRating, numRatings);
- }
-
- public String getId() {
- return id;
- }
-
- public void setId(String id) {
- this.id = id;
- }
-
- public String getManufacturer() {
- return manufacturer;
- }
-
- public void setManufacturer(String manufacturer) {
- this.manufacturer = manufacturer;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getCategory() {
- return category;
- }
-
- public void setCategory(String category) {
- this.category = category;
- }
-
- public String getPhoto() {
- return photo;
- }
-
- public void setPhoto(String photo) {
- this.photo = photo;
- }
-
- public float getAvgRating() {
- return avgRating;
- }
-
- public void setAvgRating(float avgRating) {
- this.avgRating = avgRating;
- }
-
- public int getNumRatings() {
- return numRatings;
- }
-
- public void setNumRatings(int numRatings) {
- this.numRatings = numRatings;
- }
-}
diff --git a/app/src/main/java/ch/beerpro/models/Entity.java b/app/src/main/java/ch/beerpro/models/Entity.java
deleted file mode 100644
index 94f368d..0000000
--- a/app/src/main/java/ch/beerpro/models/Entity.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package ch.beerpro.models;
-
-public interface Entity {
-
- String getId();
-
- void setId(String id);
-}
diff --git a/app/src/main/java/ch/beerpro/models/Rating.java b/app/src/main/java/ch/beerpro/models/Rating.java
deleted file mode 100644
index a249ed9..0000000
--- a/app/src/main/java/ch/beerpro/models/Rating.java
+++ /dev/null
@@ -1,163 +0,0 @@
-package ch.beerpro.models;
-
-import com.google.firebase.firestore.Exclude;
-
-import java.util.*;
-
-public class Rating implements Entity {
- public static final String COLLECTION = "ratings";
- public static final String FIELD_BEER_ID = "beerId";
- public static final String FIELD_LIKES = "likes";
- public static final String FIELD_CREATION_DATE = "creationDate";
-
- @Exclude
- private String id;
- private String beerId;
- private String beerName;
- private String userId;
- private String userName;
- private String userPhoto;
- private String photo;
- private float rating;
- private String comment;
- private Map likes;
- private Date creationDate;
-
- public Rating(String beerId, String beerName, String userId, String userName, String userPhoto, String photo,
- float rating, String comment, Date creationDate) {
- this.beerId = beerId;
- this.beerName = beerName;
- this.userId = userId;
- this.userName = userName;
- this.userPhoto = userPhoto;
- this.photo = photo;
- this.rating = rating;
- this.comment = comment;
- this.likes = new HashMap<>();
- this.creationDate = creationDate;
- }
-
- public Rating() {
-
- }
-
- @Override
- public String toString() {
- return "Rating{" + "id='" + id + '\'' + ", beerId='" + beerId + '\'' + ", beerName='" + beerName + '\'' +
- ", userId='" + userId + '\'' + ", userName='" + userName + '\'' + ", userPhoto='" + userPhoto + '\'' +
- ", photo='" + photo + '\'' + ", rating=" + rating + ", comment='" + comment + '\'' + ", likes=" +
- likes + ", creationDate=" + creationDate + '}';
- }
-
- public String getBeerName() {
- return beerName;
- }
-
- public void setBeerName(String beerName) {
- this.beerName = beerName;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o)
- return true;
- if (o == null || getClass() != o.getClass())
- return false;
- Rating rating1 = (Rating) o;
- return Float.compare(rating1.rating, rating) == 0 && Objects.equals(id, rating1.id) &&
- Objects.equals(beerId, rating1.beerId) && Objects.equals(beerName, rating1.beerName) &&
- Objects.equals(userId, rating1.userId) && Objects.equals(userName, rating1.userName) &&
- Objects.equals(userPhoto, rating1.userPhoto) && Objects.equals(photo, rating1.photo) &&
- Objects.equals(comment, rating1.comment) && Objects.equals(likes, rating1.likes) &&
- Objects.equals(creationDate, rating1.creationDate);
- }
-
- @Override
- public int hashCode() {
-
- return Objects
- .hash(id, beerId, beerName, userId, userName, userPhoto, photo, rating, comment, likes, creationDate);
- }
-
- public Date getCreationDate() {
- return creationDate;
- }
-
- public void setCreationDate(Date creationDate) {
- this.creationDate = creationDate;
- }
-
- public Map getLikes() {
- return likes;
- }
-
- public void setLikes(Map likes) {
- this.likes = likes;
- }
-
- public String getBeerId() {
- return beerId;
- }
-
- public void setBeerId(String beerId) {
- this.beerId = beerId;
- }
-
- public String getUserId() {
- return userId;
- }
-
- public void setUserId(String userId) {
- this.userId = userId;
- }
-
- public String getPhoto() {
- return photo;
- }
-
- public void setPhoto(String photo) {
- this.photo = photo;
- }
-
- public float getRating() {
- return rating;
- }
-
- public void setRating(float rating) {
- this.rating = rating;
- }
-
- public String getComment() {
- return comment;
- }
-
- public void setComment(String comment) {
- this.comment = comment;
- }
-
- @Override
- public String getId() {
- return id;
- }
-
- @Override
- public void setId(String id) {
- this.id = id;
- }
-
- public String getUserName() {
- return userName;
- }
-
- public void setUserName(String userName) {
- this.userName = userName;
- }
-
- public String getUserPhoto() {
- return userPhoto;
- }
-
- public void setUserPhoto(String userPhoto) {
- this.userPhoto = userPhoto;
- }
-}
diff --git a/app/src/main/java/ch/beerpro/models/User.java b/app/src/main/java/ch/beerpro/models/User.java
deleted file mode 100644
index a052f58..0000000
--- a/app/src/main/java/ch/beerpro/models/User.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package ch.beerpro.models;
-
-import com.google.firebase.firestore.Exclude;
-
-import java.util.Date;
-import java.util.Objects;
-
-public class User implements Entity {
- public static final String COLLECTION = "users";
- public static final String FIELD_ID = "id";
-
- @Exclude
- private String id;
- private String name;
- private String photo;
-
- public User() {
- }
-
- public User(String id, String name, String photo) {
- this.id = id;
- this.name = name;
- this.photo = photo;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o)
- return true;
- if (o == null || getClass() != o.getClass())
- return false;
- User user = (User) o;
- return Objects.equals(id, user.id) && Objects.equals(photo, user.photo) && Objects.equals(name, user.name);
- }
-
- @Override
- public int hashCode() {
-
- return Objects.hash(id, photo, name);
- }
-
- @Override
- public String getId() {
- return id;
- }
-
- @Override
- public void setId(String id) {
- this.id = id;
- }
-
- public String getPhoto() {
- return photo;
- }
-
- public void setPhoto(String photo) {
- this.photo = photo;
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
-}
diff --git a/app/src/main/java/ch/beerpro/rating/RatingActivity.java b/app/src/main/java/ch/beerpro/presentation/createrating/CreateRatingActivity.java
similarity index 93%
rename from app/src/main/java/ch/beerpro/rating/RatingActivity.java
rename to app/src/main/java/ch/beerpro/presentation/createrating/CreateRatingActivity.java
index 6a40fe7..f714da7 100644
--- a/app/src/main/java/ch/beerpro/rating/RatingActivity.java
+++ b/app/src/main/java/ch/beerpro/presentation/createrating/CreateRatingActivity.java
@@ -1,4 +1,4 @@
-package ch.beerpro.rating;
+package ch.beerpro.presentation.createrating;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -18,7 +18,7 @@
import butterknife.BindView;
import butterknife.ButterKnife;
import ch.beerpro.R;
-import ch.beerpro.models.Beer;
+import ch.beerpro.domain.models.Beer;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.firebase.auth.FirebaseAuth;
@@ -33,11 +33,11 @@
import java.util.List;
import java.util.UUID;
-public class RatingActivity extends AppCompatActivity {
+public class CreateRatingActivity extends AppCompatActivity {
public static final String ITEM = "item";
public static final String RATING = "rating";
- private static final String TAG = "RatingActivity";
+ private static final String TAG = "CreateRatingActivity";
@BindView(R.id.toolbar)
Toolbar toolbar;
@@ -56,7 +56,7 @@ public class RatingActivity extends AppCompatActivity {
@BindView(R.id.photoExplanation)
TextView photoExplanation;
- private RatingViewModel model;
+ private CreateRatingViewModel model;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -72,7 +72,7 @@ protected void onCreate(Bundle savedInstanceState) {
Beer item = (Beer) getIntent().getExtras().getSerializable(ITEM);
float rating = getIntent().getExtras().getFloat(RATING);
- model = ViewModelProviders.of(this).get(RatingViewModel.class);
+ model = ViewModelProviders.of(this).get(CreateRatingViewModel.class);
model.setItem(item);
addRatingBar.setRating(rating);
@@ -94,7 +94,7 @@ public void permissionRefused() {
EasyImage.configuration(this).setImagesFolderName("BeerPro");
photo.setOnClickListener(view -> {
- EasyImage.openChooserWithDocuments(RatingActivity.this, "", 0);
+ EasyImage.openChooserWithDocuments(CreateRatingActivity.this, "", 0);
});
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
@@ -129,7 +129,7 @@ public void onImagePickerError(Exception e, EasyImage.ImageSource source, int ty
@Override
public void onImagesPicked(List imageFiles, EasyImage.ImageSource source, int type) {
- Log.i("RatingActivity", imageFiles.toString());
+ Log.i("CreateRatingActivity", imageFiles.toString());
UCrop.Options options = new UCrop.Options() {
{
@@ -147,14 +147,14 @@ public void onImagesPicked(List imageFiles, EasyImage.ImageSource source,
UCrop.of(Uri.fromFile(imageFiles.get(0)),
Uri.fromFile(new File(getCacheDir(), "image_" + UUID.randomUUID().toString())))
.withAspectRatio(1, 1).withMaxResultSize(1024, 1024).withOptions(options)
- .start(RatingActivity.this);
+ .start(CreateRatingActivity.this);
}
@Override
public void onCanceled(EasyImage.ImageSource source, int type) {
//Cancel handling, you might wanna remove taken photo if it was canceled
if (source == EasyImage.ImageSource.CAMERA_IMAGE) {
- File photoFile = EasyImage.lastlyTakenButCanceledPhoto(RatingActivity.this);
+ File photoFile = EasyImage.lastlyTakenButCanceledPhoto(CreateRatingActivity.this);
if (photoFile != null)
photoFile.delete();
}
diff --git a/app/src/main/java/ch/beerpro/rating/RatingViewModel.java b/app/src/main/java/ch/beerpro/presentation/createrating/CreateRatingViewModel.java
similarity index 85%
rename from app/src/main/java/ch/beerpro/rating/RatingViewModel.java
rename to app/src/main/java/ch/beerpro/presentation/createrating/CreateRatingViewModel.java
index f603ecd..fe0b8ec 100644
--- a/app/src/main/java/ch/beerpro/rating/RatingViewModel.java
+++ b/app/src/main/java/ch/beerpro/presentation/createrating/CreateRatingViewModel.java
@@ -1,11 +1,11 @@
-package ch.beerpro.rating;
+package ch.beerpro.presentation.createrating;
import android.util.Log;
-import ch.beerpro.helpers.EntityClassSnapshotParser;
-import ch.beerpro.models.Rating;
+import ch.beerpro.presentation.helpers.EntityClassSnapshotParser;
+import ch.beerpro.domain.models.Rating;
import android.net.Uri;
import androidx.lifecycle.ViewModel;
-import ch.beerpro.models.Beer;
+import ch.beerpro.domain.models.Beer;
import com.google.android.gms.tasks.*;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
@@ -13,11 +13,12 @@
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
+import java.util.Collections;
import java.util.Date;
-public class RatingViewModel extends ViewModel {
+public class CreateRatingViewModel extends ViewModel {
- private static final String TAG = "RatingViewModel";
+ private static final String TAG = "CreateRatingViewModel";
private EntityClassSnapshotParser parser = new EntityClassSnapshotParser<>(Rating.class);
private Beer item;
@@ -56,8 +57,8 @@ public Task saveRating(Beer item, float rating, String comment, Uri loca
throw task.getException();
}
- Rating newRating = new Rating(item.getId(), item.getName(), user.getUid(), user.getDisplayName(),
- user.getPhotoUrl().toString(), photoUrl, rating, comment, new Date());
+ Rating newRating = new Rating(null, item.getId(), item.getName(), user.getUid(), user.getDisplayName(),
+ user.getPhotoUrl().toString(), photoUrl, rating, comment, Collections.emptyMap(), new Date());
Log.i(TAG, "Adding new rating: " + newRating.toString());
return FirebaseFirestore.getInstance().collection("ratings").add(newRating);
diff --git a/app/src/main/java/ch/beerpro/single/BottomSheetFragment.java b/app/src/main/java/ch/beerpro/presentation/details/BottomSheetFragment.java
similarity index 95%
rename from app/src/main/java/ch/beerpro/single/BottomSheetFragment.java
rename to app/src/main/java/ch/beerpro/presentation/details/BottomSheetFragment.java
index 9143c1a..461074d 100644
--- a/app/src/main/java/ch/beerpro/single/BottomSheetFragment.java
+++ b/app/src/main/java/ch/beerpro/presentation/details/BottomSheetFragment.java
@@ -1,4 +1,4 @@
-package ch.beerpro.single;
+package ch.beerpro.presentation.details;
import android.os.Bundle;
import android.view.LayoutInflater;
diff --git a/app/src/main/java/ch/beerpro/single/SingleBeerActivity.java b/app/src/main/java/ch/beerpro/presentation/details/DetailsActivity.java
similarity index 68%
rename from app/src/main/java/ch/beerpro/single/SingleBeerActivity.java
rename to app/src/main/java/ch/beerpro/presentation/details/DetailsActivity.java
index d5e39f1..4b30f91 100644
--- a/app/src/main/java/ch/beerpro/single/SingleBeerActivity.java
+++ b/app/src/main/java/ch/beerpro/presentation/details/DetailsActivity.java
@@ -1,18 +1,12 @@
-package ch.beerpro.single;
+package ch.beerpro.presentation.details;
import android.app.ActivityOptions;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
-import android.util.Log;
import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.ImageView;
-import android.widget.RatingBar;
-import android.widget.TextView;
+import android.widget.*;
import androidx.core.widget.NestedScrollView;
-import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
@@ -21,13 +15,12 @@
import butterknife.ButterKnife;
import butterknife.OnClick;
import ch.beerpro.R;
-import ch.beerpro.models.Beer;
-import ch.beerpro.models.Rating;
-import ch.beerpro.rating.RatingActivity;
+import ch.beerpro.domain.models.Beer;
+import ch.beerpro.domain.models.Rating;
+import ch.beerpro.domain.models.Wish;
+import ch.beerpro.presentation.createrating.CreateRatingActivity;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
-import com.google.android.material.appbar.AppBarLayout;
-import com.google.android.material.appbar.CollapsingToolbarLayout;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.bottomsheet.BottomSheetDialog;
@@ -35,10 +28,12 @@
import java.util.ArrayList;
import java.util.List;
-public class SingleBeerActivity extends AppCompatActivity implements OnRatingLikedListener {
+import static ch.beerpro.presentation.helpers.DrawableHelpers.setDrawableTint;
+
+public class DetailsActivity extends AppCompatActivity implements OnRatingLikedListener {
public static final String ITEM_ID = "item_id";
- private static final String TAG = "SingleBeerActivity";
+ private static final String TAG = "DetailsActivity";
@BindView(R.id.toolbar)
Toolbar toolbar;
@@ -60,6 +55,9 @@ public class SingleBeerActivity extends AppCompatActivity implements OnRatingLik
@BindView(R.id.name)
TextView name;
+ @BindView(R.id.wishlist)
+ ToggleButton wishlist;
+
@BindView(R.id.manufacturer)
TextView manufacturer;
@@ -74,7 +72,7 @@ public class SingleBeerActivity extends AppCompatActivity implements OnRatingLik
private RatingsRecyclerViewAdapter adapter;
- private SingleBeerViewModel model;
+ private DetailsViewModel model;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -84,12 +82,13 @@ protected void onCreate(Bundle savedInstanceState) {
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
+ getWindow().getDecorView()
+ .setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
toolbar.setTitleTextColor(Color.alpha(0));
String beerId = getIntent().getExtras().getString(ITEM_ID);
- model = ViewModelProviders.of(this).get(SingleBeerViewModel.class);
+ model = ViewModelProviders.of(this).get(DetailsViewModel.class);
model.setBeerId(beerId);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
@@ -100,15 +99,28 @@ protected void onCreate(Bundle savedInstanceState) {
model.getBeer().observe(this, this::updateBeer);
model.getRatings().observe(this, this::updateRatings);
+ model.getWish().observe(this, this::updateWishlist);
recyclerView.setAdapter(adapter);
addRatingBar.setOnRatingBarChangeListener(this::addNewRating);
}
+ private void updateWishlist(Wish wish) {
+ if (wish != null) {
+ int color = getResources().getColor(R.color.colorPrimary);
+ setDrawableTint(wishlist, color);
+ wishlist.setChecked(true);
+ } else {
+ int color = getResources().getColor(android.R.color.darker_gray);
+ setDrawableTint(wishlist, color);
+ wishlist.setChecked(false);
+ }
+ }
+
private void addNewRating(RatingBar ratingBar, float v, boolean b) {
- Intent intent = new Intent(this, RatingActivity.class);
- intent.putExtra(RatingActivity.ITEM, model.getBeer().getValue());
- intent.putExtra(RatingActivity.RATING, v);
+ Intent intent = new Intent(this, CreateRatingActivity.class);
+ intent.putExtra(CreateRatingActivity.ITEM, model.getBeer().getValue());
+ intent.putExtra(CreateRatingActivity.RATING, v);
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, addRatingBar, "rating");
startActivity(intent, options.toBundle());
}
@@ -146,15 +158,14 @@ public void onRatingLikedListener(Rating rating) {
model.toggleLike(rating);
}
-
- private void setWindowFlag(final int bits, boolean on) {
- Window win = getWindow();
- WindowManager.LayoutParams winParams = win.getAttributes();
- if (on) {
- winParams.flags |= bits;
- } else {
- winParams.flags &= ~bits;
+ @OnClick(R.id.wishlist)
+ public void onWishClickedListener(View view) {
+ model.toggleItemInWishlist(model.getBeer().getValue().getId());
+ /*
+ * We won't get an update from firestore when the wish is removed, so we need to reset the UI state ourselves.
+ * */
+ if (!wishlist.isChecked()) {
+ updateWishlist(null);
}
- win.setAttributes(winParams);
}
}
diff --git a/app/src/main/java/ch/beerpro/presentation/details/DetailsViewModel.java b/app/src/main/java/ch/beerpro/presentation/details/DetailsViewModel.java
new file mode 100644
index 0000000..60d1413
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/details/DetailsViewModel.java
@@ -0,0 +1,75 @@
+package ch.beerpro.presentation.details;
+
+import androidx.lifecycle.*;
+import ch.beerpro.domain.models.*;
+import ch.beerpro.presentation.helpers.EntityClassSnapshotParser;
+import ch.beerpro.domain.helpers.FirestoreQueryLiveData;
+import ch.beerpro.domain.models.Beer;
+import ch.beerpro.domain.repositories.LikesRepository;
+import ch.beerpro.domain.repositories.RatingsRepository;
+import ch.beerpro.domain.repositories.WishesRepository;
+import com.google.android.gms.tasks.Task;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.auth.FirebaseUser;
+import com.google.firebase.firestore.DocumentReference;
+import com.google.firebase.firestore.FirebaseFirestore;
+
+import java.util.*;
+
+import static androidx.lifecycle.Transformations.switchMap;
+import static ch.beerpro.domain.helpers.LiveDataExtensions.combineLatest;
+
+public class DetailsViewModel extends ViewModel {
+
+ private static final EntityClassSnapshotParser parser = new EntityClassSnapshotParser<>(Rating.class);
+ private final MutableLiveData beerId = new MutableLiveData<>();
+ private final LiveData beer = switchMap(beerId, beerId -> {
+ DocumentReference document = FirebaseFirestore.getInstance().collection(Beer.COLLECTION).document(beerId);
+ return new FirestoreQueryLiveData<>(document, Beer.class);
+ });
+ private final LiveData> ratings = switchMap(beerId, RatingsRepository::getRatingsByBeer);
+
+
+ private final MutableLiveData currentUserId = new MutableLiveData<>();
+ private final LiveData wish =
+ switchMap(combineLatest(currentUserId, getBeer()), WishesRepository::getUserWishListFor);
+ private final LikesRepository likesRepository;
+ private final WishesRepository wishesRepository;
+
+ public DetailsViewModel() {
+ // TODO We should really be injecting these!
+ likesRepository = new LikesRepository();
+ wishesRepository = new WishesRepository();
+
+ currentUserId.setValue(getCurrentUser().getUid());
+ }
+
+
+ public LiveData getWish() {
+ return wish;
+ }
+
+ public LiveData> getRatings() {
+ return ratings;
+ }
+
+ public LiveData getBeer() {
+ return beer;
+ }
+
+ public void setBeerId(String beerId) {
+ this.beerId.setValue(beerId);
+ }
+
+ public FirebaseUser getCurrentUser() {
+ return FirebaseAuth.getInstance().getCurrentUser();
+ }
+
+ public void toggleLike(Rating rating) {
+ likesRepository.toggleLike(rating);
+ }
+
+ public Task toggleItemInWishlist(String itemId) {
+ return wishesRepository.toggleUserWishlistItem(getCurrentUser().getUid(), itemId);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ch/beerpro/presentation/details/OnRatingLikedListener.java b/app/src/main/java/ch/beerpro/presentation/details/OnRatingLikedListener.java
new file mode 100644
index 0000000..b7856a0
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/details/OnRatingLikedListener.java
@@ -0,0 +1,7 @@
+package ch.beerpro.presentation.details;
+
+import ch.beerpro.domain.models.Rating;
+
+interface OnRatingLikedListener {
+ void onRatingLikedListener(Rating rating);
+}
diff --git a/app/src/main/java/ch/beerpro/single/RatingsRecyclerViewAdapter.java b/app/src/main/java/ch/beerpro/presentation/details/RatingsRecyclerViewAdapter.java
similarity index 96%
rename from app/src/main/java/ch/beerpro/single/RatingsRecyclerViewAdapter.java
rename to app/src/main/java/ch/beerpro/presentation/details/RatingsRecyclerViewAdapter.java
index 5e51b32..22de2b2 100644
--- a/app/src/main/java/ch/beerpro/single/RatingsRecyclerViewAdapter.java
+++ b/app/src/main/java/ch/beerpro/presentation/details/RatingsRecyclerViewAdapter.java
@@ -1,7 +1,7 @@
-package ch.beerpro.single;
+package ch.beerpro.presentation.details;
import ch.beerpro.R;
-import ch.beerpro.models.Rating;
+import ch.beerpro.domain.models.Rating;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -13,7 +13,7 @@
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.ButterKnife;
-import ch.beerpro.helpers.EntityDiffItemCallback;
+import ch.beerpro.presentation.helpers.EntityDiffItemCallback;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.firebase.auth.FirebaseUser;
diff --git a/app/src/main/java/ch/beerpro/helpers/BackgroundImageProvider.java b/app/src/main/java/ch/beerpro/presentation/helpers/BackgroundImageProvider.java
similarity index 95%
rename from app/src/main/java/ch/beerpro/helpers/BackgroundImageProvider.java
rename to app/src/main/java/ch/beerpro/presentation/helpers/BackgroundImageProvider.java
index 6f1f982..ea4a8ee 100644
--- a/app/src/main/java/ch/beerpro/helpers/BackgroundImageProvider.java
+++ b/app/src/main/java/ch/beerpro/presentation/helpers/BackgroundImageProvider.java
@@ -1,4 +1,4 @@
-package ch.beerpro.helpers;
+package ch.beerpro.presentation.helpers;
import android.content.Context;
import android.graphics.drawable.Drawable;
diff --git a/app/src/main/java/ch/beerpro/presentation/helpers/DrawableHelpers.java b/app/src/main/java/ch/beerpro/presentation/helpers/DrawableHelpers.java
new file mode 100644
index 0000000..1002f50
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/helpers/DrawableHelpers.java
@@ -0,0 +1,17 @@
+package ch.beerpro.presentation.helpers;
+
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.widget.Button;
+
+public class DrawableHelpers {
+
+
+ public static void setDrawableTint(Button button, int color) {
+ for (Drawable drawable : button.getCompoundDrawables()) {
+ if (drawable != null) {
+ drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/helpers/EntityClassSnapshotParser.java b/app/src/main/java/ch/beerpro/presentation/helpers/EntityClassSnapshotParser.java
similarity index 86%
rename from app/src/main/java/ch/beerpro/helpers/EntityClassSnapshotParser.java
rename to app/src/main/java/ch/beerpro/presentation/helpers/EntityClassSnapshotParser.java
index 9be411b..a6013c0 100644
--- a/app/src/main/java/ch/beerpro/helpers/EntityClassSnapshotParser.java
+++ b/app/src/main/java/ch/beerpro/presentation/helpers/EntityClassSnapshotParser.java
@@ -1,7 +1,7 @@
-package ch.beerpro.helpers;
+package ch.beerpro.presentation.helpers;
import androidx.annotation.NonNull;
-import ch.beerpro.models.Entity;
+import ch.beerpro.domain.models.Entity;
import com.firebase.ui.firestore.ClassSnapshotParser;
import com.google.firebase.firestore.DocumentSnapshot;
diff --git a/app/src/main/java/ch/beerpro/helpers/EntityDiffItemCallback.java b/app/src/main/java/ch/beerpro/presentation/helpers/EntityDiffItemCallback.java
similarity index 82%
rename from app/src/main/java/ch/beerpro/helpers/EntityDiffItemCallback.java
rename to app/src/main/java/ch/beerpro/presentation/helpers/EntityDiffItemCallback.java
index 4750b08..ca69d2f 100644
--- a/app/src/main/java/ch/beerpro/helpers/EntityDiffItemCallback.java
+++ b/app/src/main/java/ch/beerpro/presentation/helpers/EntityDiffItemCallback.java
@@ -1,9 +1,8 @@
-package ch.beerpro.helpers;
+package ch.beerpro.presentation.helpers;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
-import ch.beerpro.models.Beer;
-import ch.beerpro.models.Entity;
+import ch.beerpro.domain.models.Entity;
public class EntityDiffItemCallback extends DiffUtil.ItemCallback {
@Override
diff --git a/app/src/main/java/ch/beerpro/presentation/helpers/EntityPairDiffItemCallback.java b/app/src/main/java/ch/beerpro/presentation/helpers/EntityPairDiffItemCallback.java
new file mode 100644
index 0000000..ca29cb0
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/helpers/EntityPairDiffItemCallback.java
@@ -0,0 +1,18 @@
+package ch.beerpro.presentation.helpers;
+
+import android.util.Pair;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.DiffUtil;
+import ch.beerpro.domain.models.Entity;
+
+public class EntityPairDiffItemCallback extends DiffUtil.ItemCallback> {
+ @Override
+ public boolean areItemsTheSame(@NonNull Pair oldE, @NonNull Pair newE) {
+ return oldE.first.getId().equals(newE.first.getId());
+ }
+
+ @Override
+ public boolean areContentsTheSame(@NonNull Pair oldE, @NonNull Pair newE) {
+ return oldE.equals(newE);
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/helpers/GridSpacingItemDecoration.java b/app/src/main/java/ch/beerpro/presentation/helpers/GridSpacingItemDecoration.java
similarity index 98%
rename from app/src/main/java/ch/beerpro/helpers/GridSpacingItemDecoration.java
rename to app/src/main/java/ch/beerpro/presentation/helpers/GridSpacingItemDecoration.java
index 552ef71..2637c40 100644
--- a/app/src/main/java/ch/beerpro/helpers/GridSpacingItemDecoration.java
+++ b/app/src/main/java/ch/beerpro/presentation/helpers/GridSpacingItemDecoration.java
@@ -1,4 +1,4 @@
-package ch.beerpro.helpers;
+package ch.beerpro.presentation.helpers;
import android.graphics.Rect;
import android.view.View;
diff --git a/app/src/main/java/ch/beerpro/helpers/StringItemCallback.java b/app/src/main/java/ch/beerpro/presentation/helpers/StringDiffItemCallback.java
similarity index 75%
rename from app/src/main/java/ch/beerpro/helpers/StringItemCallback.java
rename to app/src/main/java/ch/beerpro/presentation/helpers/StringDiffItemCallback.java
index 45595d9..afdff2d 100644
--- a/app/src/main/java/ch/beerpro/helpers/StringItemCallback.java
+++ b/app/src/main/java/ch/beerpro/presentation/helpers/StringDiffItemCallback.java
@@ -1,9 +1,9 @@
-package ch.beerpro.helpers;
+package ch.beerpro.presentation.helpers;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DiffUtil;
-public class StringItemCallback extends DiffUtil.ItemCallback {
+public class StringDiffItemCallback extends DiffUtil.ItemCallback {
@Override
public boolean areItemsTheSame(@NonNull String oldE, @NonNull String newE) {
return oldE.equals(newE);
diff --git a/app/src/main/java/ch/beerpro/ToolbarScrollingBehaviour.java b/app/src/main/java/ch/beerpro/presentation/helpers/ToolbarScrollingBehaviour.java
similarity index 97%
rename from app/src/main/java/ch/beerpro/ToolbarScrollingBehaviour.java
rename to app/src/main/java/ch/beerpro/presentation/helpers/ToolbarScrollingBehaviour.java
index 7fde013..bfdda76 100644
--- a/app/src/main/java/ch/beerpro/ToolbarScrollingBehaviour.java
+++ b/app/src/main/java/ch/beerpro/presentation/helpers/ToolbarScrollingBehaviour.java
@@ -1,4 +1,4 @@
-package ch.beerpro;
+package ch.beerpro.presentation.helpers;
import android.content.Context;
import android.content.res.Resources;
@@ -12,6 +12,7 @@
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.graphics.ColorUtils;
import androidx.core.view.ViewCompat;
+import ch.beerpro.R;
public class ToolbarScrollingBehaviour extends CoordinatorLayout.Behavior {
diff --git a/app/src/main/java/ch/beerpro/helpers/ViewPagerAdapter.java b/app/src/main/java/ch/beerpro/presentation/helpers/ViewPagerAdapter.java
similarity index 96%
rename from app/src/main/java/ch/beerpro/helpers/ViewPagerAdapter.java
rename to app/src/main/java/ch/beerpro/presentation/helpers/ViewPagerAdapter.java
index af5427c..e0f1e6e 100644
--- a/app/src/main/java/ch/beerpro/helpers/ViewPagerAdapter.java
+++ b/app/src/main/java/ch/beerpro/presentation/helpers/ViewPagerAdapter.java
@@ -1,4 +1,4 @@
-package ch.beerpro.helpers;
+package ch.beerpro.presentation.helpers;
import java.util.ArrayList;
import java.util.List;
diff --git a/app/src/main/java/ch/beerpro/home/BeerCategoriesFragment.java b/app/src/main/java/ch/beerpro/presentation/home/BeerCategoriesFragment.java
similarity index 95%
rename from app/src/main/java/ch/beerpro/home/BeerCategoriesFragment.java
rename to app/src/main/java/ch/beerpro/presentation/home/BeerCategoriesFragment.java
index 0b589d8..5635cd0 100644
--- a/app/src/main/java/ch/beerpro/home/BeerCategoriesFragment.java
+++ b/app/src/main/java/ch/beerpro/presentation/home/BeerCategoriesFragment.java
@@ -1,4 +1,4 @@
-package ch.beerpro.home;
+package ch.beerpro.presentation.home;
import android.content.Context;
import android.os.Bundle;
@@ -13,7 +13,7 @@
import butterknife.BindView;
import butterknife.ButterKnife;
import ch.beerpro.R;
-import ch.beerpro.helpers.GridSpacingItemDecoration;
+import ch.beerpro.presentation.helpers.GridSpacingItemDecoration;
public class BeerCategoriesFragment extends Fragment {
diff --git a/app/src/main/java/ch/beerpro/home/BeerCategoriesRecyclerViewAdapter.java b/app/src/main/java/ch/beerpro/presentation/home/BeerCategoriesRecyclerViewAdapter.java
similarity index 90%
rename from app/src/main/java/ch/beerpro/home/BeerCategoriesRecyclerViewAdapter.java
rename to app/src/main/java/ch/beerpro/presentation/home/BeerCategoriesRecyclerViewAdapter.java
index 1a9f938..a6b36ea 100644
--- a/app/src/main/java/ch/beerpro/home/BeerCategoriesRecyclerViewAdapter.java
+++ b/app/src/main/java/ch/beerpro/presentation/home/BeerCategoriesRecyclerViewAdapter.java
@@ -1,4 +1,4 @@
-package ch.beerpro.home;
+package ch.beerpro.presentation.home;
import android.content.Context;
import android.view.LayoutInflater;
@@ -12,8 +12,8 @@
import butterknife.BindView;
import butterknife.ButterKnife;
import ch.beerpro.R;
-import ch.beerpro.helpers.BackgroundImageProvider;
-import ch.beerpro.helpers.StringItemCallback;
+import ch.beerpro.presentation.helpers.BackgroundImageProvider;
+import ch.beerpro.presentation.helpers.StringDiffItemCallback;
public class BeerCategoriesRecyclerViewAdapter
@@ -22,7 +22,7 @@ public class BeerCategoriesRecyclerViewAdapter
private final BeerCategoriesFragment.OnItemSelectedListener listener;
public BeerCategoriesRecyclerViewAdapter(BeerCategoriesFragment.OnItemSelectedListener listener) {
- super(new StringItemCallback());
+ super(new StringDiffItemCallback());
this.listener = listener;
}
diff --git a/app/src/main/java/ch/beerpro/home/BeerManufacturersFragment.java b/app/src/main/java/ch/beerpro/presentation/home/BeerManufacturersFragment.java
similarity index 95%
rename from app/src/main/java/ch/beerpro/home/BeerManufacturersFragment.java
rename to app/src/main/java/ch/beerpro/presentation/home/BeerManufacturersFragment.java
index 0ed7c68..827a34d 100644
--- a/app/src/main/java/ch/beerpro/home/BeerManufacturersFragment.java
+++ b/app/src/main/java/ch/beerpro/presentation/home/BeerManufacturersFragment.java
@@ -1,4 +1,4 @@
-package ch.beerpro.home;
+package ch.beerpro.presentation.home;
import android.content.Context;
import android.os.Bundle;
@@ -13,7 +13,7 @@
import butterknife.BindView;
import butterknife.ButterKnife;
import ch.beerpro.R;
-import ch.beerpro.helpers.GridSpacingItemDecoration;
+import ch.beerpro.presentation.helpers.GridSpacingItemDecoration;
public class BeerManufacturersFragment extends Fragment {
diff --git a/app/src/main/java/ch/beerpro/home/BeerManufacturersRecyclerViewAdapter.java b/app/src/main/java/ch/beerpro/presentation/home/BeerManufacturersRecyclerViewAdapter.java
similarity index 90%
rename from app/src/main/java/ch/beerpro/home/BeerManufacturersRecyclerViewAdapter.java
rename to app/src/main/java/ch/beerpro/presentation/home/BeerManufacturersRecyclerViewAdapter.java
index 7a81c69..db6e82e 100644
--- a/app/src/main/java/ch/beerpro/home/BeerManufacturersRecyclerViewAdapter.java
+++ b/app/src/main/java/ch/beerpro/presentation/home/BeerManufacturersRecyclerViewAdapter.java
@@ -1,4 +1,4 @@
-package ch.beerpro.home;
+package ch.beerpro.presentation.home;
import android.content.Context;
import android.view.LayoutInflater;
@@ -12,8 +12,8 @@
import butterknife.BindView;
import butterknife.ButterKnife;
import ch.beerpro.R;
-import ch.beerpro.helpers.BackgroundImageProvider;
-import ch.beerpro.helpers.StringItemCallback;
+import ch.beerpro.presentation.helpers.BackgroundImageProvider;
+import ch.beerpro.presentation.helpers.StringDiffItemCallback;
public class BeerManufacturersRecyclerViewAdapter
@@ -22,7 +22,7 @@ public class BeerManufacturersRecyclerViewAdapter
private final BeerManufacturersFragment.OnItemSelectedListener listener;
public BeerManufacturersRecyclerViewAdapter(BeerManufacturersFragment.OnItemSelectedListener listener) {
- super(new StringItemCallback());
+ super(new StringDiffItemCallback());
this.listener = listener;
}
diff --git a/app/src/main/java/ch/beerpro/presentation/home/FeedRecyclerViewAdapter.java b/app/src/main/java/ch/beerpro/presentation/home/FeedRecyclerViewAdapter.java
new file mode 100644
index 0000000..c77c5cd
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/home/FeedRecyclerViewAdapter.java
@@ -0,0 +1,147 @@
+package ch.beerpro.presentation.home;
+
+import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.RatingBar;
+import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.DiffUtil;
+import androidx.recyclerview.widget.ListAdapter;
+import androidx.recyclerview.widget.RecyclerView;
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import ch.beerpro.R;
+import ch.beerpro.presentation.helpers.EntityPairDiffItemCallback;
+import ch.beerpro.domain.models.Rating;
+import ch.beerpro.domain.models.Wish;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
+import com.google.firebase.auth.FirebaseUser;
+
+import java.text.DateFormat;
+
+import static ch.beerpro.presentation.helpers.DrawableHelpers.setDrawableTint;
+
+
+public class FeedRecyclerViewAdapter extends ListAdapter, FeedRecyclerViewAdapter.ViewHolder> {
+
+ private static final String TAG = "FeedRecyclerViewAdapter";
+
+ private static final DiffUtil.ItemCallback> DIFF_CALLBACK = new EntityPairDiffItemCallback<>();
+
+ private final OnFeedItemInteractionListener listener;
+ private final FirebaseUser user;
+
+ public FeedRecyclerViewAdapter(OnFeedItemInteractionListener listener, FirebaseUser user) {
+ super(DIFF_CALLBACK);
+ this.listener = listener;
+ this.user = user;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
+ View view = layoutInflater.inflate(R.layout.fragment_feed_ratings_entry, parent, false);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
+ Pair item = getItem(position);
+ holder.bind(item.first, item.second, listener);
+ }
+
+ class ViewHolder extends RecyclerView.ViewHolder {
+
+ @BindView(R.id.comment)
+ TextView comment;
+
+ @BindView(R.id.beerName)
+ TextView beerName;
+
+ @BindView(R.id.avatar)
+ ImageView avatar;
+
+ @BindView(R.id.ratingBar)
+ RatingBar ratingBar;
+
+ @BindView(R.id.authorName)
+ TextView authorName;
+
+ @BindView(R.id.date)
+ TextView date;
+
+ @BindView(R.id.numLikes)
+ TextView numLikes;
+
+ @BindView(R.id.details)
+ Button details;
+
+ @BindView(R.id.wishlist)
+ Button wishlist;
+
+ @BindView(R.id.like)
+ Button like;
+
+ @BindView(R.id.photo)
+ ImageView photo;
+
+ ViewHolder(View view) {
+ super(view);
+ ButterKnife.bind(this, itemView);
+ }
+
+ void bind(Rating item, Wish wish, OnFeedItemInteractionListener listener) {
+ // TODO This code is almost the same in MyRatingsRecyclerViewAdapter.. could be simplified
+ // with databinding!
+ beerName.setText(item.getBeerName());
+ comment.setText(item.getComment());
+
+ ratingBar.setNumStars(5);
+ ratingBar.setRating(item.getRating());
+ String formattedDate =
+ DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.SHORT).format(item.getCreationDate());
+ date.setText(formattedDate);
+
+ if (item.getPhoto() != null) {
+ // Take a look at https://bumptech.github.io/glide/int/recyclerview.html
+ Glide.with(itemView).load(item.getPhoto()).into(photo);
+ } else {
+ Glide.with(itemView).clear(photo);
+ photo.setVisibility(View.GONE);
+ }
+
+ authorName.setText(item.getUserName());
+ Glide.with(itemView).load(item.getUserPhoto()).apply(new RequestOptions().circleCrop()).into(avatar);
+
+ numLikes.setText(itemView.getResources().getString(R.string.fmt_num_ratings, item.getLikes().size()));
+
+ if (item.getLikes().containsKey(user.getUid())) {
+ int color = itemView.getResources().getColor(R.color.colorPrimary);
+ setDrawableTint(like, color);
+ } else {
+ int color = itemView.getResources().getColor(android.R.color.darker_gray);
+ setDrawableTint(like, color);
+ }
+
+ if (wish != null) {
+ int color = itemView.getResources().getColor(R.color.colorPrimary);
+ setDrawableTint(wishlist, color);
+ } else {
+ int color = itemView.getResources().getColor(android.R.color.darker_gray);
+ setDrawableTint(wishlist, color);
+ }
+
+ if (listener != null) {
+ like.setOnClickListener(v -> listener.onRatingLikedListener(item));
+ details.setOnClickListener(v -> listener.onMoreClickedListener(item));
+ wishlist.setOnClickListener(v -> listener.onWishClickedListener(item));
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/home/HomeScreenActivity.java b/app/src/main/java/ch/beerpro/presentation/home/HomeScreenActivity.java
similarity index 96%
rename from app/src/main/java/ch/beerpro/home/HomeScreenActivity.java
rename to app/src/main/java/ch/beerpro/presentation/home/HomeScreenActivity.java
index 92007af..d3b6f83 100644
--- a/app/src/main/java/ch/beerpro/home/HomeScreenActivity.java
+++ b/app/src/main/java/ch/beerpro/presentation/home/HomeScreenActivity.java
@@ -1,11 +1,11 @@
-package ch.beerpro.home;
+package ch.beerpro.presentation.home;
import android.content.Intent;
import android.os.Bundle;
import ch.beerpro.R;
-import ch.beerpro.SplashScreenActivity;
-import ch.beerpro.helpers.ViewPagerAdapter;
+import ch.beerpro.presentation.splash.SplashScreenActivity;
+import ch.beerpro.presentation.helpers.ViewPagerAdapter;
import com.firebase.ui.auth.AuthUI;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
diff --git a/app/src/main/java/ch/beerpro/home/HomeScreenFeedFragment.java b/app/src/main/java/ch/beerpro/presentation/home/HomeScreenFeedFragment.java
similarity index 64%
rename from app/src/main/java/ch/beerpro/home/HomeScreenFeedFragment.java
rename to app/src/main/java/ch/beerpro/presentation/home/HomeScreenFeedFragment.java
index 50ee82b..67f0ec1 100644
--- a/app/src/main/java/ch/beerpro/home/HomeScreenFeedFragment.java
+++ b/app/src/main/java/ch/beerpro/presentation/home/HomeScreenFeedFragment.java
@@ -1,6 +1,8 @@
-package ch.beerpro.home;
+package ch.beerpro.presentation.home;
+import android.content.Intent;
import android.os.Bundle;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -13,16 +15,18 @@
import butterknife.BindView;
import butterknife.ButterKnife;
import ch.beerpro.R;
-import ch.beerpro.models.Rating;
-import ch.beerpro.single.OnRatingLikedListener;
+import ch.beerpro.presentation.details.DetailsActivity;
+import ch.beerpro.domain.models.Rating;
+import ch.beerpro.domain.models.Wish;
import androidx.fragment.app.Fragment;
+import lombok.val;
import java.util.ArrayList;
import java.util.List;
public class HomeScreenFeedFragment extends Fragment
- implements OnRatingLikedListener, SwipeRefreshLayout.OnRefreshListener {
+ implements OnFeedItemInteractionListener, SwipeRefreshLayout.OnRefreshListener {
private static final String TAG = "FeedFragment";
@@ -45,9 +49,9 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
ButterKnife.bind(this, rootView);
model = ViewModelProviders.of(this).get(HomeScreenViewModel.class);
- model.getAllRatings().observe(this, this::updateRatings);
+ model.getAllRatingsWithWishes().observe(this, this::updateRatings);
- LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
+ val layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
adapter = new FeedRecyclerViewAdapter(this, model.getCurrentUser());
@@ -60,8 +64,10 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa
return rootView;
}
- private void updateRatings(List ratings) {
- adapter.submitList(new ArrayList<>(ratings));
+ private void updateRatings(List> ratings) {
+ if (ratings != null) {
+ adapter.submitList(new ArrayList<>(ratings));
+ }
}
@Override
@@ -69,9 +75,21 @@ public void onRatingLikedListener(Rating rating) {
model.toggleLike(rating);
}
+ @Override
+ public void onMoreClickedListener(Rating rating) {
+ Intent intent = new Intent(getActivity(), DetailsActivity.class);
+ intent.putExtra(DetailsActivity.ITEM_ID, rating.getBeerId());
+ startActivity(intent);
+ }
+
+ @Override
+ public void onWishClickedListener(Rating item) {
+ model.toggleItemInWishlist(item.getBeerId());
+ }
+
@Override
public void onRefresh() {
- updateRatings(model.getAllRatings().getValue());
+ updateRatings(model.getAllRatingsWithWishes().getValue());
swipeRefreshLayout.setRefreshing(false);
adapter.notifyDataSetChanged();
}
diff --git a/app/src/main/java/ch/beerpro/presentation/home/HomeScreenProfileFragment.java b/app/src/main/java/ch/beerpro/presentation/home/HomeScreenProfileFragment.java
new file mode 100644
index 0000000..b2380ac
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/home/HomeScreenProfileFragment.java
@@ -0,0 +1,104 @@
+package ch.beerpro.presentation.home;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+import androidx.fragment.app.Fragment;
+import androidx.lifecycle.ViewModelProviders;
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnClick;
+import ch.beerpro.R;
+import ch.beerpro.domain.models.Rating;
+import ch.beerpro.domain.models.Wish;
+import ch.beerpro.presentation.myratings.MyRatingsActivity;
+import ch.beerpro.presentation.wishlist.WishlistActivity;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.auth.FirebaseUser;
+
+import java.util.List;
+
+public class HomeScreenProfileFragment extends Fragment {
+
+ private static final String TAG = "ProfileFragment";
+
+ @BindView(R.id.userProfileImageView)
+ ImageView userProfileImageView;
+
+ @BindView(R.id.userProfileNameText)
+ TextView userProfileNameText;
+
+ @BindView(R.id.myBeersCount)
+ TextView myBeersCount;
+
+ @BindView(R.id.myFridgeCount)
+ TextView myFridgeCount;
+
+ @BindView(R.id.myRatingsCount)
+ TextView myRatingsCount;
+
+ @BindView(R.id.myWishlistCount)
+ TextView myWishlistCount;
+
+ private HomeScreenViewModel model;
+
+ public HomeScreenProfileFragment() {
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ setHasOptionsMenu(true);
+ View rootView = inflater.inflate(R.layout.fragment_profile_screen, container, false);
+ ButterKnife.bind(this, rootView);
+
+ model = ViewModelProviders.of(this).get(HomeScreenViewModel.class);
+ model.getMyWishlist().observe(this, this::updateWishlistCount);
+ model.getMyRatings().observe(this, this::updateRatingsCount);
+ model.getMyBeersUniqueCount().observe(this, this::updateMyBeersCount);
+
+ FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
+
+ if (user != null) {
+ // Name, email address, and profile photo Url
+ String name = user.getDisplayName();
+ userProfileNameText.setText(name);
+ Uri photoUrl = user.getPhotoUrl();
+ Glide.with(this).load(photoUrl).apply(new RequestOptions().circleCrop()).into(userProfileImageView);
+ }
+
+ return rootView;
+ }
+
+ private void updateMyBeersCount(int size) {
+ myBeersCount.setText(String.valueOf(size));
+ }
+
+ @OnClick(R.id.myRatings)
+ public void handleMyRatingsClick(View view) {
+ Intent intent = new Intent(getActivity(), MyRatingsActivity.class);
+ startActivity(intent);
+ }
+
+
+ @OnClick(R.id.myWishlist)
+ public void handleMyWishlistClick(View view) {
+ Intent intent = new Intent(getActivity(), WishlistActivity.class);
+ startActivity(intent);
+ }
+
+ private void updateRatingsCount(List ratings) {
+ myRatingsCount.setText(String.valueOf(ratings.size()));
+ }
+
+ private void updateWishlistCount(List wishes) {
+ myWishlistCount.setText(String.valueOf(wishes.size()));
+ }
+
+}
diff --git a/app/src/main/java/ch/beerpro/home/HomeScreenSearchFragment.java b/app/src/main/java/ch/beerpro/presentation/home/HomeScreenSearchFragment.java
similarity index 90%
rename from app/src/main/java/ch/beerpro/home/HomeScreenSearchFragment.java
rename to app/src/main/java/ch/beerpro/presentation/home/HomeScreenSearchFragment.java
index ca0aec3..5946d85 100644
--- a/app/src/main/java/ch/beerpro/home/HomeScreenSearchFragment.java
+++ b/app/src/main/java/ch/beerpro/presentation/home/HomeScreenSearchFragment.java
@@ -1,4 +1,4 @@
-package ch.beerpro.home;
+package ch.beerpro.presentation.home;
import android.app.ActivityOptions;
import androidx.fragment.app.Fragment;
@@ -8,14 +8,13 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import androidx.viewpager.widget.ViewPager;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import ch.beerpro.R;
-import ch.beerpro.helpers.ViewPagerAdapter;
-import ch.beerpro.search.SearchActivity;
+import ch.beerpro.presentation.helpers.ViewPagerAdapter;
+import ch.beerpro.presentation.search.SearchActivity;
import com.google.android.material.tabs.TabLayout;
public class HomeScreenSearchFragment extends Fragment {
diff --git a/app/src/main/java/ch/beerpro/presentation/home/HomeScreenViewModel.java b/app/src/main/java/ch/beerpro/presentation/home/HomeScreenViewModel.java
new file mode 100644
index 0000000..5d6c975
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/home/HomeScreenViewModel.java
@@ -0,0 +1,164 @@
+package ch.beerpro.presentation.home;
+
+import android.util.Pair;
+import androidx.arch.core.util.Function;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+import ch.beerpro.domain.helpers.FirestoreQueryLiveDataArray;
+import ch.beerpro.domain.models.Beer;
+import ch.beerpro.domain.models.Entity;
+import ch.beerpro.domain.models.Rating;
+import ch.beerpro.domain.models.Wish;
+import ch.beerpro.domain.repositories.LikesRepository;
+import ch.beerpro.domain.repositories.RatingsRepository;
+import ch.beerpro.domain.repositories.WishesRepository;
+import ch.beerpro.presentation.helpers.EntityClassSnapshotParser;
+import ch.beerpro.presentation.models.MyBeerFromRating;
+import ch.beerpro.presentation.models.MyBeerFromWishlist;
+import ch.beerpro.presentation.models.MyBeerItem;
+import com.google.android.gms.tasks.Task;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.auth.FirebaseUser;
+import com.google.firebase.firestore.FirebaseFirestore;
+
+import java.util.*;
+
+import static androidx.lifecycle.Transformations.map;
+import static androidx.lifecycle.Transformations.switchMap;
+import static ch.beerpro.domain.helpers.LiveDataExtensions.combineLatest;
+
+public class HomeScreenViewModel extends ViewModel {
+
+ private static final String TAG = "HomeScreenViewModel";
+
+ private final static EntityClassSnapshotParser parser = new EntityClassSnapshotParser<>(Beer.class);
+
+
+ private final static Function, List> mapBeersToCategories = (List beers) -> {
+ Set filtered = new HashSet<>();
+ for (Beer beer : beers) {
+ filtered.add(beer.getCategory());
+ }
+ String[] strings = filtered.toArray(new String[0]);
+ return Arrays.asList(strings).subList(0, 8);
+ };
+ private final static Function, List> mapBeersToManufacturers = (List beers) -> {
+ Set filtered = new HashSet<>();
+ for (Beer beer : beers) {
+ filtered.add(beer.getManufacturer());
+ }
+ String[] strings = filtered.toArray(new String[0]);
+ Arrays.sort(strings);
+ return Arrays.asList(strings);
+ };
+
+ private final LikesRepository likesRepository;
+ private final LiveData> allBeers = new FirestoreQueryLiveDataArray<>(
+ FirebaseFirestore.getInstance().collection(Beer.COLLECTION).orderBy(Beer.FIELD_NAME), Beer.class);
+
+
+ private final LiveData> beerCategories;
+
+ private final LiveData> beerManufacturers;
+
+ private final LiveData> myWishlist;
+
+ private final MutableLiveData currentUserId = new MutableLiveData<>();
+ private final WishesRepository wishesRepository;
+ private final RatingsRepository ratingsRepository;
+ private final LiveData> myRatings;
+ private final LiveData> myBeers;
+ private final LiveData myBeersUniqueCount;
+
+ public HomeScreenViewModel() {
+ // TODO We should really be injecting these!
+ likesRepository = new LikesRepository();
+ wishesRepository = new WishesRepository();
+ ratingsRepository = new RatingsRepository();
+
+ beerCategories = map(allBeers, mapBeersToCategories);
+ beerManufacturers = map(allBeers, mapBeersToManufacturers);
+ myWishlist = switchMap(currentUserId, WishesRepository::getWishesByUser);
+ myRatings = switchMap(currentUserId, RatingsRepository::getRatingsByUser);
+
+ myBeers = map(combineLatest(myWishlist, myRatings, map(allBeers, Entity::entitiesById)), input -> {
+ List wishlist = input.getLeft();
+ List ratings = input.getMiddle();
+ HashMap beers = input.getRight();
+
+ ArrayList result = new ArrayList<>();
+ for (Wish wish : wishlist) {
+ result.add(new MyBeerFromWishlist(wish, beers.get(wish.getBeerId())));
+ }
+ for (Rating rating : ratings) {
+ result.add(new MyBeerFromRating(rating, beers.get(rating.getBeerId())));
+ }
+ return result;
+ });
+
+ myBeersUniqueCount = map(myBeers, beers -> {
+ Set ids = new HashSet<>();
+ for (MyBeerItem beer : beers) {
+ ids.add(beer.getBeerId());
+ }
+ return ids.size();
+ });
+
+ currentUserId.setValue(getCurrentUser().getUid());
+ }
+
+ FirebaseUser getCurrentUser() {
+ return FirebaseAuth.getInstance().getCurrentUser();
+ }
+
+ public LiveData> getMyBeers() {
+ return myBeers;
+ }
+
+ public LiveData> getMyRatings() {
+ return myRatings;
+ }
+
+ public LiveData>> getAllRatingsWithWishes() {
+ return map(combineLatest(getAllRatings(), map(getMyWishlist(), Entity::entitiesById)), input -> {
+ List ratings = input.first;
+ HashMap wishesByItem = input.second;
+
+ ArrayList> result = new ArrayList<>();
+ for (Rating rating : ratings) {
+ Wish wish = wishesByItem.get(rating.getBeerId());
+ result.add(Pair.create(rating, wish));
+ }
+ return result;
+ });
+ }
+
+ public LiveData> getAllRatings() {
+ return ratingsRepository.getAllRatings();
+ }
+
+ public LiveData> getMyWishlist() {
+ return myWishlist;
+ }
+
+ public LiveData> getBeerCategories() {
+ return beerCategories;
+ }
+
+ public LiveData> getBeerManufacturers() {
+ return beerManufacturers;
+ }
+
+ public void toggleLike(Rating rating) {
+ likesRepository.toggleLike(rating);
+ }
+
+ public Task toggleItemInWishlist(String itemId) {
+ return wishesRepository.toggleUserWishlistItem(getCurrentUser().getUid(), itemId);
+ }
+
+ public LiveData getMyBeersUniqueCount() {
+ return myBeersUniqueCount;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ch/beerpro/presentation/home/OnFeedItemInteractionListener.java b/app/src/main/java/ch/beerpro/presentation/home/OnFeedItemInteractionListener.java
new file mode 100644
index 0000000..911d255
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/home/OnFeedItemInteractionListener.java
@@ -0,0 +1,11 @@
+package ch.beerpro.presentation.home;
+
+import ch.beerpro.domain.models.Rating;
+
+public interface OnFeedItemInteractionListener {
+ void onRatingLikedListener(Rating rating);
+
+ void onMoreClickedListener(Rating rating);
+
+ void onWishClickedListener(Rating item);
+}
diff --git a/app/src/main/java/ch/beerpro/presentation/models/MyBeerFromRating.java b/app/src/main/java/ch/beerpro/presentation/models/MyBeerFromRating.java
new file mode 100644
index 0000000..b81ea2f
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/models/MyBeerFromRating.java
@@ -0,0 +1,17 @@
+package ch.beerpro.presentation.models;
+
+import ch.beerpro.domain.models.Beer;
+import ch.beerpro.domain.models.Rating;
+
+public class MyBeerFromRating implements MyBeerItem {
+ private Rating rating;
+
+ public MyBeerFromRating(Rating rating, Beer beer) {
+ this.rating = rating;
+ }
+
+ @Override
+ public String getBeerId() {
+ return rating.getBeerId();
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/presentation/models/MyBeerFromWishlist.java b/app/src/main/java/ch/beerpro/presentation/models/MyBeerFromWishlist.java
new file mode 100644
index 0000000..40072c8
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/models/MyBeerFromWishlist.java
@@ -0,0 +1,17 @@
+package ch.beerpro.presentation.models;
+
+import ch.beerpro.domain.models.Beer;
+import ch.beerpro.domain.models.Wish;
+
+public class MyBeerFromWishlist implements MyBeerItem {
+ private Wish wish;
+
+ public MyBeerFromWishlist(Wish wish, Beer beer) {
+ this.wish = wish;
+ }
+
+ @Override
+ public String getBeerId() {
+ return wish.getBeerId();
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/presentation/models/MyBeerItem.java b/app/src/main/java/ch/beerpro/presentation/models/MyBeerItem.java
new file mode 100644
index 0000000..712a8ed
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/models/MyBeerItem.java
@@ -0,0 +1,5 @@
+package ch.beerpro.presentation.models;
+
+public interface MyBeerItem {
+ String getBeerId();
+}
diff --git a/app/src/main/java/ch/beerpro/presentation/myratings/MyRatingsActivity.java b/app/src/main/java/ch/beerpro/presentation/myratings/MyRatingsActivity.java
new file mode 100644
index 0000000..88125e4
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/myratings/MyRatingsActivity.java
@@ -0,0 +1,81 @@
+package ch.beerpro.presentation.myratings;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Pair;
+import android.view.MenuItem;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+import androidx.lifecycle.ViewModelProviders;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import ch.beerpro.R;
+import ch.beerpro.domain.models.Rating;
+import ch.beerpro.domain.models.Wish;
+import ch.beerpro.presentation.details.DetailsActivity;
+import lombok.val;
+
+import java.util.List;
+
+public class MyRatingsActivity extends AppCompatActivity implements OnMyRatingItemInteractionListener {
+
+ @BindView(R.id.toolbar)
+ Toolbar toolbar;
+
+ @BindView(R.id.recyclerView)
+ RecyclerView recyclerView;
+ private MyRatingsViewModel model;
+ private MyRatingsRecyclerViewAdapter adapter;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_my_ratings);
+ ButterKnife.bind(this);
+ setSupportActionBar(toolbar);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setTitle(getString(R.string.title_activity_myratings));
+
+
+ model = ViewModelProviders.of(this).get(MyRatingsViewModel.class);
+ model.getMyRatingsWithWishes().observe(this, this::updateMyRatings);
+
+ val layoutManager = new LinearLayoutManager(this);
+ recyclerView.setLayoutManager(layoutManager);
+
+ adapter = new MyRatingsRecyclerViewAdapter(this, model.getCurrentUser());
+
+ recyclerView.setAdapter(adapter);
+
+ }
+
+ private void updateMyRatings(List> entries) {
+ adapter.submitList(entries);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ finish();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+
+ @Override
+ public void onMoreClickedListener(Rating item) {
+ Intent intent = new Intent(this, DetailsActivity.class);
+ intent.putExtra(DetailsActivity.ITEM_ID, item.getBeerId());
+ startActivity(intent);
+ }
+
+ @Override
+ public void onWishClickedListener(Rating item) {
+ model.toggleItemInWishlist(item.getBeerId());
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/home/FeedRecyclerViewAdapter.java b/app/src/main/java/ch/beerpro/presentation/myratings/MyRatingsRecyclerViewAdapter.java
similarity index 62%
rename from app/src/main/java/ch/beerpro/home/FeedRecyclerViewAdapter.java
rename to app/src/main/java/ch/beerpro/presentation/myratings/MyRatingsRecyclerViewAdapter.java
index ad2562e..7dc7f78 100644
--- a/app/src/main/java/ch/beerpro/home/FeedRecyclerViewAdapter.java
+++ b/app/src/main/java/ch/beerpro/presentation/myratings/MyRatingsRecyclerViewAdapter.java
@@ -1,39 +1,43 @@
-package ch.beerpro.home;
+package ch.beerpro.presentation.myratings;
-import android.net.Uri;
-import android.util.Log;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.Button;
import android.widget.ImageView;
import android.widget.RatingBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.DiffUtil;
import androidx.recyclerview.widget.ListAdapter;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.ButterKnife;
import ch.beerpro.R;
-import ch.beerpro.helpers.EntityDiffItemCallback;
-import ch.beerpro.models.Rating;
-import ch.beerpro.single.OnRatingLikedListener;
+import ch.beerpro.presentation.helpers.EntityPairDiffItemCallback;
+import ch.beerpro.domain.models.*;
+import ch.beerpro.domain.models.Wish;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.google.firebase.auth.FirebaseUser;
import java.text.DateFormat;
+import static ch.beerpro.presentation.helpers.DrawableHelpers.setDrawableTint;
-public class FeedRecyclerViewAdapter extends ListAdapter {
- private static final String TAG = "FeedRecyclerViewAdapter";
+public class MyRatingsRecyclerViewAdapter
+ extends ListAdapter, MyRatingsRecyclerViewAdapter.ViewHolder> {
- private static final EntityDiffItemCallback DIFF_CALLBACK = new EntityDiffItemCallback<>();
+ private static final String TAG = "WishlistRecyclerViewAda";
- private final OnRatingLikedListener listener;
- private final FirebaseUser user;
+ private static final DiffUtil.ItemCallback> DIFF_CALLBACK = new EntityPairDiffItemCallback<>();
- public FeedRecyclerViewAdapter(OnRatingLikedListener listener, FirebaseUser user) {
+ private final OnMyRatingItemInteractionListener listener;
+ private FirebaseUser user;
+
+ public MyRatingsRecyclerViewAdapter(OnMyRatingItemInteractionListener listener, FirebaseUser user) {
super(DIFF_CALLBACK);
this.listener = listener;
this.user = user;
@@ -49,7 +53,8 @@ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
@Override
public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
- holder.bind(getItem(position), listener);
+ Pair entry = getItem(position);
+ holder.bind(entry.first, entry.second, listener);
}
class ViewHolder extends RecyclerView.ViewHolder {
@@ -75,8 +80,14 @@ class ViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.numLikes)
TextView numLikes;
+ @BindView(R.id.details)
+ Button details;
+
+ @BindView(R.id.wishlist)
+ Button wishlist;
+
@BindView(R.id.like)
- ImageView like;
+ Button like;
@BindView(R.id.photo)
ImageView photo;
@@ -86,8 +97,7 @@ class ViewHolder extends RecyclerView.ViewHolder {
ButterKnife.bind(this, itemView);
}
- void bind(Rating item, OnRatingLikedListener listener) {
- Log.i(TAG, item.toString());
+ void bind(Rating item, Wish wish, OnMyRatingItemInteractionListener listener) {
beerName.setText(item.getBeerName());
comment.setText(item.getComment());
@@ -109,17 +119,22 @@ void bind(Rating item, OnRatingLikedListener listener) {
Glide.with(itemView).load(item.getUserPhoto()).apply(new RequestOptions().circleCrop()).into(avatar);
numLikes.setText(itemView.getResources().getString(R.string.fmt_num_ratings, item.getLikes().size()));
- if (item.getLikes().containsKey(user.getUid())) {
- like.setColorFilter(itemView.getResources().getColor(R.color.colorPrimary));
+
+ // don't need it here
+ like.setVisibility(View.GONE);
+
+ if (wish != null) {
+ int color = itemView.getResources().getColor(R.color.colorPrimary);
+ setDrawableTint(wishlist, color);
} else {
- like.setColorFilter(itemView.getResources().getColor(android.R.color.darker_gray));
+ int color = itemView.getResources().getColor(android.R.color.darker_gray);
+ setDrawableTint(wishlist, color);
}
+
if (listener != null) {
- like.setOnClickListener(v -> listener.onRatingLikedListener(item));
+ details.setOnClickListener(v -> listener.onMoreClickedListener(item));
+ wishlist.setOnClickListener(v -> listener.onWishClickedListener(item));
}
}
-
-
-
}
}
diff --git a/app/src/main/java/ch/beerpro/presentation/myratings/MyRatingsViewModel.java b/app/src/main/java/ch/beerpro/presentation/myratings/MyRatingsViewModel.java
new file mode 100644
index 0000000..206c126
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/myratings/MyRatingsViewModel.java
@@ -0,0 +1,76 @@
+package ch.beerpro.presentation.myratings;
+
+import android.util.Pair;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.Transformations;
+import androidx.lifecycle.ViewModel;
+import ch.beerpro.domain.helpers.LiveDataExtensions;
+import ch.beerpro.domain.models.Rating;
+import ch.beerpro.domain.models.Wish;
+import ch.beerpro.domain.repositories.RatingsRepository;
+import ch.beerpro.domain.repositories.WishesRepository;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.auth.FirebaseUser;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+import static androidx.lifecycle.Transformations.map;
+import static ch.beerpro.domain.helpers.LiveDataExtensions.combineLatest;
+
+public class MyRatingsViewModel extends ViewModel {
+
+ private static final String TAG = "MyRatingsViewModel";
+
+ private final MutableLiveData currentUserId = new MutableLiveData<>();
+ private final LiveData> myRatings;
+ private final LiveData> myWishlist;
+ private final WishesRepository wishesRepository;
+
+ public MyRatingsViewModel() {
+ wishesRepository = new WishesRepository();
+ myWishlist = Transformations.switchMap(currentUserId, WishesRepository::getWishesByUser);
+ myRatings = Transformations.switchMap(currentUserId, RatingsRepository::getRatingsByUser);
+
+ currentUserId.setValue(getCurrentUser().getUid());
+ }
+
+ FirebaseUser getCurrentUser() {
+ return FirebaseAuth.getInstance().getCurrentUser();
+ }
+
+ public LiveData>> getMyRatingsWithWishes() {
+ return map(combineLatest(getMyRatings(), getMyWishlist()), input -> {
+ List ratings = input.first;
+
+ // Optimization: also do this in a transformation
+ List wishes = input.second == null ? Collections.emptyList() : input.second;
+ HashMap wishesByItem = new HashMap<>();
+ for (Wish wish : wishes) {
+ wishesByItem.put(wish.getBeerId(), wish);
+ }
+
+ ArrayList> result = new ArrayList<>();
+ for (Rating rating : ratings) {
+ Wish wish = wishesByItem.get(rating.getBeerId());
+ result.add(Pair.create(rating, wish));
+ }
+ return result;
+ });
+ }
+
+ public LiveData> getMyRatings() {
+ return myRatings;
+ }
+
+ public LiveData> getMyWishlist() {
+ return myWishlist;
+ }
+
+ public void toggleItemInWishlist(String beerId) {
+ wishesRepository.toggleUserWishlistItem(getCurrentUser().getUid(), beerId);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/ch/beerpro/presentation/myratings/OnMyRatingItemInteractionListener.java b/app/src/main/java/ch/beerpro/presentation/myratings/OnMyRatingItemInteractionListener.java
new file mode 100644
index 0000000..c21a78a
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/myratings/OnMyRatingItemInteractionListener.java
@@ -0,0 +1,10 @@
+package ch.beerpro.presentation.myratings;
+
+import ch.beerpro.domain.models.Rating;
+
+public interface OnMyRatingItemInteractionListener {
+
+ void onMoreClickedListener(Rating item);
+
+ void onWishClickedListener(Rating item);
+}
diff --git a/app/src/main/java/ch/beerpro/search/MyBeersFragment.java b/app/src/main/java/ch/beerpro/presentation/search/MyBeersFragment.java
similarity index 94%
rename from app/src/main/java/ch/beerpro/search/MyBeersFragment.java
rename to app/src/main/java/ch/beerpro/presentation/search/MyBeersFragment.java
index b0c5366..3e1d1a2 100644
--- a/app/src/main/java/ch/beerpro/search/MyBeersFragment.java
+++ b/app/src/main/java/ch/beerpro/presentation/search/MyBeersFragment.java
@@ -1,4 +1,4 @@
-package ch.beerpro.search;
+package ch.beerpro.presentation.search;
import android.content.Context;
import android.os.Bundle;
@@ -12,8 +12,8 @@
import butterknife.BindView;
import butterknife.ButterKnife;
import ch.beerpro.R;
-import ch.beerpro.models.Beer;
-import ch.beerpro.search.adapters.MyBeersRecyclerViewAdapter;
+import ch.beerpro.domain.models.Beer;
+import ch.beerpro.presentation.search.adapters.MyBeersRecyclerViewAdapter;
import java.util.ArrayList;
import java.util.List;
diff --git a/app/src/main/java/ch/beerpro/search/SearchActivity.java b/app/src/main/java/ch/beerpro/presentation/search/SearchActivity.java
similarity index 86%
rename from app/src/main/java/ch/beerpro/search/SearchActivity.java
rename to app/src/main/java/ch/beerpro/presentation/search/SearchActivity.java
index de4c4d6..92e3bf8 100644
--- a/app/src/main/java/ch/beerpro/search/SearchActivity.java
+++ b/app/src/main/java/ch/beerpro/presentation/search/SearchActivity.java
@@ -1,4 +1,4 @@
-package ch.beerpro.search;
+package ch.beerpro.presentation.search;
import android.app.ActivityOptions;
import android.content.Context;
@@ -11,15 +11,14 @@
import androidx.lifecycle.ViewModelProviders;
import androidx.viewpager.widget.ViewPager;
import ch.beerpro.R;
-import ch.beerpro.single.SingleBeerActivity;
-import ch.beerpro.models.Beer;
+import ch.beerpro.presentation.details.DetailsActivity;
+import ch.beerpro.domain.models.Beer;
import android.os.Bundle;
-import ch.beerpro.search.adapters.ViewPagerAdapter;
+import ch.beerpro.presentation.search.adapters.ViewPagerAdapter;
import com.google.android.material.tabs.TabLayout;
import com.google.common.base.Strings;
-import com.google.firebase.firestore.FirebaseFirestore;
public class SearchActivity extends AppCompatActivity
implements SearchResultFragment.OnItemSelectedListener, SearchSuggestionsFragment.OnItemSelectedListener,
@@ -58,8 +57,8 @@ protected void onCreate(Bundle savedInstanceState) {
@Override
public void onSearchResultListItemSelected(View animationSource, Beer item) {
- Intent intent = new Intent(this, SingleBeerActivity.class);
- intent.putExtra(SingleBeerActivity.ITEM_ID, item.getId());
+ Intent intent = new Intent(this, DetailsActivity.class);
+ intent.putExtra(DetailsActivity.ITEM_ID, item.getId());
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, animationSource, "image");
startActivity(intent, options.toBundle());
}
@@ -74,8 +73,8 @@ public void onSearchSuggestionListItemSelected(String text) {
@Override
public void onMyBeersListItemSelected(View animationSource, Beer item) {
- Intent intent = new Intent(this, SingleBeerActivity.class);
- intent.putExtra(SingleBeerActivity.ITEM_ID, item.getId());
+ Intent intent = new Intent(this, DetailsActivity.class);
+ intent.putExtra(DetailsActivity.ITEM_ID, item.getId());
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, animationSource, "image");
startActivity(intent, options.toBundle());
}
diff --git a/app/src/main/java/ch/beerpro/search/SearchResultFragment.java b/app/src/main/java/ch/beerpro/presentation/search/SearchResultFragment.java
similarity index 94%
rename from app/src/main/java/ch/beerpro/search/SearchResultFragment.java
rename to app/src/main/java/ch/beerpro/presentation/search/SearchResultFragment.java
index d24e9cc..92d6257 100644
--- a/app/src/main/java/ch/beerpro/search/SearchResultFragment.java
+++ b/app/src/main/java/ch/beerpro/presentation/search/SearchResultFragment.java
@@ -1,4 +1,4 @@
-package ch.beerpro.search;
+package ch.beerpro.presentation.search;
import android.content.Context;
import android.os.Bundle;
@@ -15,8 +15,8 @@
import butterknife.BindView;
import butterknife.ButterKnife;
import ch.beerpro.R;
-import ch.beerpro.models.Beer;
-import ch.beerpro.search.adapters.SearchResultRecyclerViewAdapter;
+import ch.beerpro.domain.models.Beer;
+import ch.beerpro.presentation.search.adapters.SearchResultRecyclerViewAdapter;
import java.util.ArrayList;
import java.util.List;
diff --git a/app/src/main/java/ch/beerpro/search/SearchSuggestionsFragment.java b/app/src/main/java/ch/beerpro/presentation/search/SearchSuggestionsFragment.java
similarity index 93%
rename from app/src/main/java/ch/beerpro/search/SearchSuggestionsFragment.java
rename to app/src/main/java/ch/beerpro/presentation/search/SearchSuggestionsFragment.java
index 9ca6738..74a239a 100644
--- a/app/src/main/java/ch/beerpro/search/SearchSuggestionsFragment.java
+++ b/app/src/main/java/ch/beerpro/presentation/search/SearchSuggestionsFragment.java
@@ -1,4 +1,4 @@
-package ch.beerpro.search;
+package ch.beerpro.presentation.search;
import android.content.Context;
import android.os.Bundle;
@@ -10,7 +10,7 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import ch.beerpro.R;
-import ch.beerpro.search.adapters.SearchSuggestionsRecyclerViewAdapter;
+import ch.beerpro.presentation.search.adapters.SearchSuggestionsRecyclerViewAdapter;
import java.util.Arrays;
diff --git a/app/src/main/java/ch/beerpro/search/SearchViewModel.java b/app/src/main/java/ch/beerpro/presentation/search/SearchViewModel.java
similarity index 85%
rename from app/src/main/java/ch/beerpro/search/SearchViewModel.java
rename to app/src/main/java/ch/beerpro/presentation/search/SearchViewModel.java
index 7fbe764..9298d8b 100644
--- a/app/src/main/java/ch/beerpro/search/SearchViewModel.java
+++ b/app/src/main/java/ch/beerpro/presentation/search/SearchViewModel.java
@@ -1,11 +1,11 @@
-package ch.beerpro.search;
+package ch.beerpro.presentation.search;
import android.util.Pair;
import androidx.arch.core.util.Function;
import androidx.lifecycle.*;
-import ch.beerpro.models.Beer;
-import ch.beerpro.helpers.FirestoreQueryLiveDataArray;
-import ch.beerpro.helpers.LiveDataExtensions;
+import ch.beerpro.domain.models.Beer;
+import ch.beerpro.domain.helpers.FirestoreQueryLiveDataArray;
+import ch.beerpro.domain.helpers.LiveDataExtensions;
import com.google.common.base.Strings;
import com.google.firebase.firestore.FirebaseFirestore;
@@ -24,7 +24,7 @@ public class SearchViewModel extends ViewModel {
private final LiveData> filteredBeers;
public SearchViewModel() {
- filteredBeers = Transformations.map(LiveDataExtensions.combineLatest(searchTerm, allBeers), filterBeers());
+ filteredBeers = Transformations.map(LiveDataExtensions.zip(searchTerm, allBeers), filterBeers());
}
private Function>, List> filterBeers() {
diff --git a/app/src/main/java/ch/beerpro/search/adapters/MyBeersRecyclerViewAdapter.java b/app/src/main/java/ch/beerpro/presentation/search/adapters/MyBeersRecyclerViewAdapter.java
similarity index 92%
rename from app/src/main/java/ch/beerpro/search/adapters/MyBeersRecyclerViewAdapter.java
rename to app/src/main/java/ch/beerpro/presentation/search/adapters/MyBeersRecyclerViewAdapter.java
index 0156e74..c9352ec 100644
--- a/app/src/main/java/ch/beerpro/search/adapters/MyBeersRecyclerViewAdapter.java
+++ b/app/src/main/java/ch/beerpro/presentation/search/adapters/MyBeersRecyclerViewAdapter.java
@@ -1,4 +1,4 @@
-package ch.beerpro.search.adapters;
+package ch.beerpro.presentation.search.adapters;
import android.view.LayoutInflater;
import android.view.View;
@@ -12,9 +12,9 @@
import butterknife.BindView;
import butterknife.ButterKnife;
import ch.beerpro.R;
-import ch.beerpro.models.Beer;
-import ch.beerpro.search.MyBeersFragment.OnItemSelectedListener;
-import ch.beerpro.helpers.EntityDiffItemCallback;
+import ch.beerpro.domain.models.Beer;
+import ch.beerpro.presentation.search.MyBeersFragment.OnItemSelectedListener;
+import ch.beerpro.presentation.helpers.EntityDiffItemCallback;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
diff --git a/app/src/main/java/ch/beerpro/search/adapters/SearchResultRecyclerViewAdapter.java b/app/src/main/java/ch/beerpro/presentation/search/adapters/SearchResultRecyclerViewAdapter.java
similarity index 90%
rename from app/src/main/java/ch/beerpro/search/adapters/SearchResultRecyclerViewAdapter.java
rename to app/src/main/java/ch/beerpro/presentation/search/adapters/SearchResultRecyclerViewAdapter.java
index 04a54fa..36503d3 100644
--- a/app/src/main/java/ch/beerpro/search/adapters/SearchResultRecyclerViewAdapter.java
+++ b/app/src/main/java/ch/beerpro/presentation/search/adapters/SearchResultRecyclerViewAdapter.java
@@ -1,4 +1,4 @@
-package ch.beerpro.search.adapters;
+package ch.beerpro.presentation.search.adapters;
import android.view.LayoutInflater;
import android.view.View;
@@ -12,16 +12,16 @@
import butterknife.BindView;
import butterknife.ButterKnife;
import ch.beerpro.R;
-import ch.beerpro.models.Beer;
-import ch.beerpro.search.SearchResultFragment.OnItemSelectedListener;
-import ch.beerpro.helpers.EntityDiffItemCallback;
+import ch.beerpro.domain.models.Beer;
+import ch.beerpro.presentation.search.SearchResultFragment.OnItemSelectedListener;
+import ch.beerpro.presentation.helpers.EntityDiffItemCallback;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
public class SearchResultRecyclerViewAdapter extends ListAdapter {
- private static final EntityDiffItemCallback DIFF_CALLBACK = new EntityDiffItemCallback();
+ private static final EntityDiffItemCallback DIFF_CALLBACK = new EntityDiffItemCallback<>();
private final OnItemSelectedListener listener;
diff --git a/app/src/main/java/ch/beerpro/search/adapters/SearchSuggestionsRecyclerViewAdapter.java b/app/src/main/java/ch/beerpro/presentation/search/adapters/SearchSuggestionsRecyclerViewAdapter.java
similarity index 96%
rename from app/src/main/java/ch/beerpro/search/adapters/SearchSuggestionsRecyclerViewAdapter.java
rename to app/src/main/java/ch/beerpro/presentation/search/adapters/SearchSuggestionsRecyclerViewAdapter.java
index 9c68338..7069b6e 100644
--- a/app/src/main/java/ch/beerpro/search/adapters/SearchSuggestionsRecyclerViewAdapter.java
+++ b/app/src/main/java/ch/beerpro/presentation/search/adapters/SearchSuggestionsRecyclerViewAdapter.java
@@ -1,4 +1,4 @@
-package ch.beerpro.search.adapters;
+package ch.beerpro.presentation.search.adapters;
import android.view.LayoutInflater;
import android.view.View;
@@ -9,7 +9,7 @@
import butterknife.BindView;
import butterknife.ButterKnife;
import ch.beerpro.R;
-import ch.beerpro.search.SearchSuggestionsFragment.OnItemSelectedListener;
+import ch.beerpro.presentation.search.SearchSuggestionsFragment.OnItemSelectedListener;
import java.util.List;
diff --git a/app/src/main/java/ch/beerpro/search/adapters/ViewPagerAdapter.java b/app/src/main/java/ch/beerpro/presentation/search/adapters/ViewPagerAdapter.java
similarity index 84%
rename from app/src/main/java/ch/beerpro/search/adapters/ViewPagerAdapter.java
rename to app/src/main/java/ch/beerpro/presentation/search/adapters/ViewPagerAdapter.java
index ae6357d..c13ba61 100644
--- a/app/src/main/java/ch/beerpro/search/adapters/ViewPagerAdapter.java
+++ b/app/src/main/java/ch/beerpro/presentation/search/adapters/ViewPagerAdapter.java
@@ -1,19 +1,13 @@
-package ch.beerpro.search.adapters;
+package ch.beerpro.presentation.search.adapters;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentPagerAdapter;
import androidx.fragment.app.FragmentStatePagerAdapter;
-import ch.beerpro.search.MyBeersFragment;
-import ch.beerpro.search.SearchResultFragment;
-import ch.beerpro.search.SearchSuggestionsFragment;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static androidx.viewpager.widget.PagerAdapter.POSITION_NONE;
+import ch.beerpro.presentation.search.MyBeersFragment;
+import ch.beerpro.presentation.search.SearchResultFragment;
+import ch.beerpro.presentation.search.SearchSuggestionsFragment;
public class ViewPagerAdapter extends FragmentStatePagerAdapter {
diff --git a/app/src/main/java/ch/beerpro/SplashScreenActivity.java b/app/src/main/java/ch/beerpro/presentation/splash/SplashScreenActivity.java
similarity index 85%
rename from app/src/main/java/ch/beerpro/SplashScreenActivity.java
rename to app/src/main/java/ch/beerpro/presentation/splash/SplashScreenActivity.java
index b2ec7fc..4cdbf4a 100644
--- a/app/src/main/java/ch/beerpro/SplashScreenActivity.java
+++ b/app/src/main/java/ch/beerpro/presentation/splash/SplashScreenActivity.java
@@ -1,14 +1,14 @@
-package ch.beerpro;
+package ch.beerpro.presentation.splash;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
-import android.os.Handler;
import android.util.Log;
-import ch.beerpro.home.HomeScreenActivity;
-import ch.beerpro.models.User;
+import ch.beerpro.R;
+import ch.beerpro.presentation.home.HomeScreenActivity;
+import ch.beerpro.domain.models.User;
import com.firebase.ui.auth.AuthUI;
import com.firebase.ui.auth.IdpResponse;
import com.google.firebase.auth.FirebaseAuth;
@@ -51,9 +51,11 @@ protected void onStart() {
}
private void redirectToHomeScreenActivity(FirebaseUser currentUser) {
- // We save all logged in users so we can query them later on.
- User user = new User(null, currentUser.getDisplayName(), currentUser.getPhotoUrl().toString());
- FirebaseFirestore.getInstance().collection(User.COLLECTION).document(currentUser.getUid()).set(user);
+ String uid = currentUser.getUid();
+ String displayName = currentUser.getDisplayName();
+ String photoUrl = currentUser.getPhotoUrl().toString();
+ FirebaseFirestore.getInstance().collection(User.COLLECTION).document(uid)
+ .update(User.FIELD_NAME, displayName, User.FIELD_PHOTO, photoUrl);
startActivity(new Intent(this, HomeScreenActivity.class));
finish();
diff --git a/app/src/main/java/ch/beerpro/presentation/wishlist/OnWishlistItemInteractionListener.java b/app/src/main/java/ch/beerpro/presentation/wishlist/OnWishlistItemInteractionListener.java
new file mode 100644
index 0000000..84df154
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/wishlist/OnWishlistItemInteractionListener.java
@@ -0,0 +1,11 @@
+package ch.beerpro.presentation.wishlist;
+
+import android.widget.ImageView;
+import ch.beerpro.domain.models.Beer;
+
+public interface OnWishlistItemInteractionListener {
+
+ void onMoreClickedListener(ImageView photo, Beer beer);
+
+ void onWishClickedListener(Beer beer);
+}
diff --git a/app/src/main/java/ch/beerpro/presentation/wishlist/WishlistActivity.java b/app/src/main/java/ch/beerpro/presentation/wishlist/WishlistActivity.java
new file mode 100644
index 0000000..68d4518
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/wishlist/WishlistActivity.java
@@ -0,0 +1,84 @@
+package ch.beerpro.presentation.wishlist;
+
+import android.app.ActivityOptions;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Pair;
+import android.view.MenuItem;
+import android.widget.ImageView;
+import androidx.lifecycle.ViewModelProviders;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import ch.beerpro.domain.models.Beer;
+import ch.beerpro.domain.models.Wish;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+import ch.beerpro.R;
+import ch.beerpro.presentation.details.DetailsActivity;
+import lombok.val;
+
+import java.util.List;
+
+public class WishlistActivity extends AppCompatActivity implements OnWishlistItemInteractionListener {
+
+ @BindView(R.id.toolbar)
+ Toolbar toolbar;
+
+ @BindView(R.id.recyclerView)
+ RecyclerView recyclerView;
+ private WishlistViewModel model;
+ private WishlistRecyclerViewAdapter adapter;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_wishlist);
+ ButterKnife.bind(this);
+ setSupportActionBar(toolbar);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setTitle(getString(R.string.title_activity_wishlist));
+
+
+ model = ViewModelProviders.of(this).get(WishlistViewModel.class);
+ model.getMyWishlistWithBeers().observe(this, this::updateWishlist);
+
+ val layoutManager = new LinearLayoutManager(this);
+ recyclerView.setLayoutManager(layoutManager);
+
+ adapter = new WishlistRecyclerViewAdapter(this);
+
+ recyclerView.setAdapter(adapter);
+
+ }
+
+ private void updateWishlist(List> pairs) {
+ adapter.submitList(pairs);
+ }
+
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ finish();
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ @Override
+ public void onMoreClickedListener(ImageView animationSource, Beer beer) {
+ Intent intent = new Intent(this, DetailsActivity.class);
+ intent.putExtra(DetailsActivity.ITEM_ID, beer.getId());
+ ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(this, animationSource, "image");
+ startActivity(intent, options.toBundle());
+ }
+
+ @Override
+ public void onWishClickedListener(Beer beer) {
+ model.toggleItemInWishlist(beer.getId());
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/presentation/wishlist/WishlistRecyclerViewAdapter.java b/app/src/main/java/ch/beerpro/presentation/wishlist/WishlistRecyclerViewAdapter.java
new file mode 100644
index 0000000..2b32926
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/wishlist/WishlistRecyclerViewAdapter.java
@@ -0,0 +1,104 @@
+package ch.beerpro.presentation.wishlist;
+
+import android.util.Pair;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.RatingBar;
+import android.widget.TextView;
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.DiffUtil;
+import androidx.recyclerview.widget.ListAdapter;
+import androidx.recyclerview.widget.RecyclerView;
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import ch.beerpro.R;
+import ch.beerpro.presentation.helpers.EntityPairDiffItemCallback;
+import ch.beerpro.domain.models.Beer;
+import ch.beerpro.domain.models.Wish;
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.request.RequestOptions;
+
+import java.text.DateFormat;
+
+
+public class WishlistRecyclerViewAdapter extends ListAdapter, WishlistRecyclerViewAdapter.ViewHolder> {
+
+ private static final String TAG = "WishlistRecyclerViewAda";
+
+ private static final DiffUtil.ItemCallback> DIFF_CALLBACK = new EntityPairDiffItemCallback<>();
+
+ private final OnWishlistItemInteractionListener listener;
+
+ public WishlistRecyclerViewAdapter(OnWishlistItemInteractionListener listener) {
+ super(DIFF_CALLBACK);
+ this.listener = listener;
+ }
+
+ @NonNull
+ @Override
+ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ LayoutInflater layoutInflater = LayoutInflater.from(parent.getContext());
+ View view = layoutInflater.inflate(R.layout.wishlist_entry, parent, false);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
+ Pair item = getItem(position);
+ holder.bind(item.first, item.second, listener);
+ }
+
+ class ViewHolder extends RecyclerView.ViewHolder {
+
+ @BindView(R.id.name)
+ TextView name;
+
+ @BindView(R.id.manufacturer)
+ TextView manufacturer;
+
+ @BindView(R.id.category)
+ TextView category;
+
+ @BindView(R.id.photo)
+ ImageView photo;
+
+ @BindView(R.id.ratingBar)
+ RatingBar ratingBar;
+
+ @BindView(R.id.numRatings)
+ TextView numRatings;
+
+ @BindView(R.id.addedAt)
+ TextView addedAt;
+
+ @BindView(R.id.remove)
+ Button remove;
+
+ ViewHolder(View view) {
+ super(view);
+ ButterKnife.bind(this, itemView);
+ }
+
+ void bind(Wish wish, Beer item, OnWishlistItemInteractionListener listener) {
+ name.setText(item.getName());
+ manufacturer.setText(item.getManufacturer());
+ category.setText(item.getCategory());
+ name.setText(item.getName());
+ Glide.with(itemView).load(item.getPhoto()).apply(new RequestOptions().override(240, 240).centerInside())
+ .into(photo);
+ ratingBar.setNumStars(5);
+ ratingBar.setRating(item.getAvgRating());
+ numRatings.setText(itemView.getResources().getString(R.string.fmt_num_ratings, item.getNumRatings()));
+ itemView.setOnClickListener(v -> listener.onMoreClickedListener(photo, item));
+
+ String formattedDate =
+ DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.SHORT).format(wish.getAddedAt());
+ addedAt.setText(formattedDate);
+ remove.setOnClickListener(v -> listener.onWishClickedListener(item));
+ }
+
+ }
+}
diff --git a/app/src/main/java/ch/beerpro/presentation/wishlist/WishlistViewModel.java b/app/src/main/java/ch/beerpro/presentation/wishlist/WishlistViewModel.java
new file mode 100644
index 0000000..21f7aa1
--- /dev/null
+++ b/app/src/main/java/ch/beerpro/presentation/wishlist/WishlistViewModel.java
@@ -0,0 +1,69 @@
+package ch.beerpro.presentation.wishlist;
+
+import android.util.Pair;
+import androidx.lifecycle.LiveData;
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+import ch.beerpro.domain.models.Beer;
+import ch.beerpro.domain.models.Entity;
+import ch.beerpro.domain.models.Wish;
+import ch.beerpro.domain.repositories.BeersRepository;
+import ch.beerpro.domain.repositories.WishesRepository;
+import com.google.android.gms.tasks.Task;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.auth.FirebaseUser;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import static androidx.lifecycle.Transformations.map;
+import static androidx.lifecycle.Transformations.switchMap;
+import static ch.beerpro.domain.helpers.LiveDataExtensions.combineLatest;
+
+public class WishlistViewModel extends ViewModel {
+
+ private static final String TAG = "WishlistViewModel";
+
+ private final LiveData> myWishlist;
+
+ private final MutableLiveData currentUserId = new MutableLiveData<>();
+ private final WishesRepository wishesRepository;
+ private final BeersRepository beersRepository;
+
+ public WishlistViewModel() {
+ wishesRepository = new WishesRepository();
+ beersRepository = new BeersRepository();
+
+ myWishlist = switchMap(currentUserId, WishesRepository::getWishesByUser);
+
+ currentUserId.setValue(getCurrentUser().getUid());
+ }
+
+ FirebaseUser getCurrentUser() {
+ return FirebaseAuth.getInstance().getCurrentUser();
+ }
+
+ public LiveData>> getMyWishlistWithBeers() {
+ return map(combineLatest(getMyWishlist(), map(beersRepository.getAllBeers(), Entity::entitiesById)), input -> {
+ List wishes = input.first;
+ HashMap beersById = input.second;
+
+ ArrayList> result = new ArrayList<>();
+ for (Wish wish : wishes) {
+ Beer beer = beersById.get(wish.getBeerId());
+ result.add(Pair.create(wish, beer));
+ }
+ return result;
+ });
+ }
+
+ public LiveData> getMyWishlist() {
+ return myWishlist;
+ }
+
+ public Task toggleItemInWishlist(String itemId) {
+ return wishesRepository.toggleUserWishlistItem(getCurrentUser().getUid(), itemId);
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/ch/beerpro/single/OnRatingLikedListener.java b/app/src/main/java/ch/beerpro/single/OnRatingLikedListener.java
deleted file mode 100644
index 6d38786..0000000
--- a/app/src/main/java/ch/beerpro/single/OnRatingLikedListener.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package ch.beerpro.single;
-
-import ch.beerpro.models.Rating;
-
-public interface OnRatingLikedListener {
- void onRatingLikedListener(Rating rating);
-}
diff --git a/app/src/main/java/ch/beerpro/single/SingleBeerViewModel.java b/app/src/main/java/ch/beerpro/single/SingleBeerViewModel.java
deleted file mode 100644
index 86cf093..0000000
--- a/app/src/main/java/ch/beerpro/single/SingleBeerViewModel.java
+++ /dev/null
@@ -1,74 +0,0 @@
-package ch.beerpro.single;
-
-import androidx.annotation.NonNull;
-import androidx.lifecycle.*;
-import ch.beerpro.models.*;
-import ch.beerpro.helpers.EntityClassSnapshotParser;
-import ch.beerpro.helpers.FirestoreQueryLiveData;
-import ch.beerpro.helpers.FirestoreQueryLiveDataArray;
-import ch.beerpro.models.Beer;
-import com.google.firebase.auth.FirebaseAuth;
-import com.google.firebase.auth.FirebaseUser;
-import com.google.firebase.firestore.DocumentReference;
-import com.google.firebase.firestore.FirebaseFirestore;
-import com.google.firebase.firestore.Query;
-import com.google.firebase.firestore.Transaction;
-
-import java.util.List;
-import java.util.Map;
-
-import static androidx.lifecycle.Transformations.switchMap;
-
-public class SingleBeerViewModel extends ViewModel {
-
- private static final EntityClassSnapshotParser parser = new EntityClassSnapshotParser<>(Rating.class);
- private final MutableLiveData beerId = new MutableLiveData<>();
- private final LiveData beer = switchMap(beerId, beerId -> {
- DocumentReference document = FirebaseFirestore.getInstance().collection(Beer.COLLECTION).document(beerId);
- return new FirestoreQueryLiveData<>(document, Beer.class);
- });
- private final LiveData> ratings = switchMap(beerId, beerId -> new FirestoreQueryLiveDataArray<>(
- FirebaseFirestore.getInstance().collection(Rating.COLLECTION)
- .orderBy(Rating.FIELD_CREATION_DATE, Query.Direction.DESCENDING)
- .whereEqualTo(Rating.FIELD_BEER_ID, beerId), Rating.class));
-
-
- public LiveData> getRatings() {
- return ratings;
- }
-
- public LiveData getBeer() {
- return beer;
- }
-
- public void setBeerId(String beerId) {
- this.beerId.setValue(beerId);
- }
-
- public FirebaseUser getCurrentUser() {
- return FirebaseAuth.getInstance().getCurrentUser();
- }
-
- public void toggleLike(Rating rating) {
-
- // TODO remove duplication with HomeScreenViewModel
-
- FirebaseUser currentUser = FirebaseAuth.getInstance().getCurrentUser();
- FirebaseFirestore db = FirebaseFirestore.getInstance();
- final DocumentReference ratingRef = db.collection(Rating.COLLECTION).document(rating.getId());
-
- db.runTransaction((Transaction.Function) transaction -> {
- Rating currentRating = parser.parseSnapshot(transaction.get(ratingRef));
- Map likes = currentRating.getLikes();
- String currentUserUid = currentUser.getUid();
- if (likes.containsKey(currentUserUid)) {
- likes.remove(currentUserUid);
- } else {
- likes.put(currentUserUid, true);
- }
- transaction.update(ratingRef, Rating.FIELD_LIKES, likes);
- return null;
- });
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_home_screen.xml b/app/src/main/res/layout/activity_home_screen.xml
index e9010c2..be07ec9 100644
--- a/app/src/main/res/layout/activity_home_screen.xml
+++ b/app/src/main/res/layout/activity_home_screen.xml
@@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".home.HomeScreenActivity">
+ tools:context=".presentation.home.HomeScreenActivity">
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_rating.xml b/app/src/main/res/layout/activity_rating.xml
index 165cf0f..c7f8a59 100644
--- a/app/src/main/res/layout/activity_rating.xml
+++ b/app/src/main/res/layout/activity_rating.xml
@@ -5,7 +5,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
- tools:context=".rating.RatingActivity">
+ tools:context=".presentation.createrating.CreateRatingActivity">
+ tools:context=".presentation.details.DetailsActivity">
+ tools:context=".presentation.search.SearchActivity">
+ tools:context=".presentation.details.DetailsActivity">
-
@@ -301,7 +302,7 @@
android:layout_height="wrap_content"
android:elevation="4dp"
android:orientation="vertical"
- app:layout_behavior="ch.beerpro.ToolbarScrollingBehaviour">
+ app:layout_behavior="ch.beerpro.presentation.helpers.ToolbarScrollingBehaviour">
+ tools:context=".presentation.splash.SplashScreenActivity">
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_beer_listentry_base.xml b/app/src/main/res/layout/content_beer_listentry_base.xml
new file mode 100644
index 0000000..b33dc11
--- /dev/null
+++ b/app/src/main/res/layout/content_beer_listentry_base.xml
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_beer_categories.xml b/app/src/main/res/layout/fragment_beer_categories.xml
index 81e6f5a..4389053 100644
--- a/app/src/main/res/layout/fragment_beer_categories.xml
+++ b/app/src/main/res/layout/fragment_beer_categories.xml
@@ -5,6 +5,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/fragment_beer_categories_card"
- tools:context=".home.BeerCategoriesFragment">
+ tools:context=".presentation.home.BeerCategoriesFragment">
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_beer_manufacturers.xml b/app/src/main/res/layout/fragment_beer_manufacturers.xml
index 2470146..3b917df 100644
--- a/app/src/main/res/layout/fragment_beer_manufacturers.xml
+++ b/app/src/main/res/layout/fragment_beer_manufacturers.xml
@@ -5,6 +5,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:listitem="@layout/fragment_beer_manufacturers_card"
- tools:context=".home.BeerManufacturersFragment">
+ tools:context=".presentation.home.BeerManufacturersFragment">
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_feed_ratings_entry.xml b/app/src/main/res/layout/fragment_feed_ratings_entry.xml
index ef41a0f..bf04b7e 100644
--- a/app/src/main/res/layout/fragment_feed_ratings_entry.xml
+++ b/app/src/main/res/layout/fragment_feed_ratings_entry.xml
@@ -11,6 +11,16 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
+
+
-
-
+
+
+ app:layout_constraintBaseline_toBaselineOf="@+id/authorName"
+ app:layout_constraintEnd_toEndOf="parent" />
-
+
-
+ app:layout_constraintTop_toBottomOf="@+id/avatar">
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_feed_screen.xml b/app/src/main/res/layout/fragment_feed_screen.xml
index 450cd2b..7e9567a 100644
--- a/app/src/main/res/layout/fragment_feed_screen.xml
+++ b/app/src/main/res/layout/fragment_feed_screen.xml
@@ -6,7 +6,7 @@
android:layout_height="match_parent"
android:background="@android:color/white"
android:id="@+id/swipeRefreshLayout"
- tools:context=".home.HomeScreenSearchFragment">
+ tools:context=".presentation.home.HomeScreenSearchFragment">
+ tools:context=".presentation.home.HomeScreenSearchFragment">
-
@@ -52,6 +52,7 @@
-
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_search_screen.xml b/app/src/main/res/layout/fragment_search_screen.xml
index 512d4cd..6258cbb 100644
--- a/app/src/main/res/layout/fragment_search_screen.xml
+++ b/app/src/main/res/layout/fragment_search_screen.xml
@@ -4,7 +4,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tools:context=".home.HomeScreenSearchFragment">
+ tools:context=".presentation.home.HomeScreenSearchFragment">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/app/src/main/res/layout/fragment_searchresult_list.xml b/app/src/main/res/layout/fragment_searchresult_list.xml
index 6ade821..fbe28d1 100644
--- a/app/src/main/res/layout/fragment_searchresult_list.xml
+++ b/app/src/main/res/layout/fragment_searchresult_list.xml
@@ -8,7 +8,7 @@
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:animateLayoutChanges="true"
- tools:context=".search.SearchResultFragment">
+ tools:context=".presentation.search.SearchResultFragment">
diff --git a/app/src/main/res/layout/wishlist_entry.xml b/app/src/main/res/layout/wishlist_entry.xml
new file mode 100644
index 0000000..289f833
--- /dev/null
+++ b/app/src/main/res/layout/wishlist_entry.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/menu/menu_home_screen.xml b/app/src/main/res/menu/menu_home_screen.xml
index cb3df8a..12ac377 100644
--- a/app/src/main/res/menu/menu_home_screen.xml
+++ b/app/src/main/res/menu/menu_home_screen.xml
@@ -1,7 +1,7 @@
Abmelden
TODO
- (%d)
+ Gefällt %d
%.1f
%d Beurteilungen
SingleBeerActivity
@@ -99,4 +99,6 @@
"when a user tries to pick up one of cards.\n\n"
Unexpected error
+ Wunschliste
+ Meine Bewertungen