diff --git a/app/build.gradle b/app/build.gradle
index 2329267..366a9f3 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,7 +8,7 @@ android {
compileSdkVersion 28
defaultConfig {
applicationId "me.gilo.wc"
- minSdkVersion 15
+ minSdkVersion 16
targetSdkVersion 28
versionCode 1
versionName "1.0"
@@ -54,6 +54,16 @@ dependencies {
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:design:28.0.0'
+ implementation 'com.google.firebase:firebase-database:16.0.4'
+ implementation 'com.google.firebase:firebase-auth:16.0.4'
+ implementation 'com.google.firebase:firebase-core:16.0.4'
+ implementation 'com.google.firebase:firebase-firestore:17.1.1'
+ implementation 'com.google.firebase:firebase-storage:16.0.4'
+ implementation 'com.firebaseui:firebase-ui-database:4.2.0'
+ implementation 'com.firebaseui:firebase-ui-firestore:4.2.0'
+ implementation 'com.firebaseui:firebase-ui-storage:4.2.0'
+ implementation 'com.google.firebase:firebase-messaging:17.1.0'
+
implementation 'io.github.inflationx:calligraphy3:3.0.0'
implementation 'io.github.inflationx:viewpump:1.0.0'
@@ -94,3 +104,7 @@ dependencies {
}
+
+
+apply plugin: 'com.google.gms.google-services'
+googleServices { disableVersionCheck = true }
\ No newline at end of file
diff --git a/app/google-services.json b/app/google-services.json
new file mode 100644
index 0000000..5c388b1
--- /dev/null
+++ b/app/google-services.json
@@ -0,0 +1,42 @@
+{
+ "project_info": {
+ "project_number": "159460744011",
+ "firebase_url": "https://api-project-159460744011.firebaseio.com",
+ "project_id": "api-project-159460744011",
+ "storage_bucket": "api-project-159460744011.appspot.com"
+ },
+ "client": [
+ {
+ "client_info": {
+ "mobilesdk_app_id": "1:159460744011:android:6480f4108da5caac",
+ "android_client_info": {
+ "package_name": "me.gilo.wc"
+ }
+ },
+ "oauth_client": [
+ {
+ "client_id": "159460744011-nbbmft1vofqfrkmt88fub6u8jumt4f7v.apps.googleusercontent.com",
+ "client_type": 3
+ }
+ ],
+ "api_key": [
+ {
+ "current_key": "AIzaSyCoViVbbgVc_-NOPwSwHIfutH6ZK8nbn-k"
+ }
+ ],
+ "services": {
+ "analytics_service": {
+ "status": 1
+ },
+ "appinvite_service": {
+ "status": 1,
+ "other_platform_oauth_client": []
+ },
+ "ads_service": {
+ "status": 2
+ }
+ }
+ }
+ ],
+ "configuration_version": "1"
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a31d86d..602c579 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -11,8 +11,13 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
- android:usesCleartextTraffic="true"
- android:theme="@style/AppTheme">
+ android:theme="@style/AppTheme"
+ android:usesCleartextTraffic="true">
+
+
+
+
+
+
+
+
+
{
+ private List orders;
+
+ public OrderAdapter(List orders) {
+ this.orders = orders;
+ }
+
+ @Override
+ public OrderViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return new OrderViewHolder(parent.getContext(), LayoutInflater.from(parent.getContext()).inflate(R.layout.single_order_item, parent, false));
+ }
+
+ @Override
+ public void onBindViewHolder(OrderViewHolder holder, int position) {
+ holder.renderView(orders.get(position));
+ }
+
+
+ @Override
+ public int getItemCount() {
+ return orders.size() == 0 ? 0 : orders.size();
+ }
+}
diff --git a/app/src/main/java/me/gilo/wc/adapter/viewholder/OrderViewHolder.kt b/app/src/main/java/me/gilo/wc/adapter/viewholder/OrderViewHolder.kt
new file mode 100644
index 0000000..493f7c7
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/adapter/viewholder/OrderViewHolder.kt
@@ -0,0 +1,24 @@
+package me.gilo.wc.adapter.viewholder
+
+import android.content.Context
+import android.content.Intent
+import android.support.v7.widget.RecyclerView
+import android.text.Html
+import android.view.View
+import android.widget.TextView
+import me.gilo.wc.R
+import me.gilo.wc.ui.product.ShopActivity
+import me.gilo.woodroid.models.Category
+import me.gilo.woodroid.models.Order
+
+class OrderViewHolder(val context: Context, itemView: View) :
+ RecyclerView.ViewHolder(itemView) {
+
+ fun renderView(order: Order) {
+ val tvTitle = itemView.findViewById(R.id.tvTitle)
+ tvTitle.text = order.orderNumber
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/gilo/wc/common/CompletionDocLiveData.java b/app/src/main/java/me/gilo/wc/common/CompletionDocLiveData.java
new file mode 100644
index 0000000..712b7a1
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/common/CompletionDocLiveData.java
@@ -0,0 +1,25 @@
+package me.gilo.wc.common;
+
+import android.arch.lifecycle.LiveData;
+import android.support.annotation.NonNull;
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.Task;
+import com.google.firebase.firestore.DocumentReference;
+
+
+public final class CompletionDocLiveData extends LiveData> implements OnCompleteListener {
+
+
+ public CompletionDocLiveData() {
+ setValue(new Resource<>(Status.LOADING));
+ }
+
+ @Override
+ public final void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ setValue(new Resource<>(true));
+ } else {
+ setValue(new Resource<>(task.getException()));
+ }
+ }
+}
diff --git a/app/src/main/java/me/gilo/wc/common/CompletionGenericLiveData.java b/app/src/main/java/me/gilo/wc/common/CompletionGenericLiveData.java
new file mode 100644
index 0000000..b88a466
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/common/CompletionGenericLiveData.java
@@ -0,0 +1,25 @@
+package me.gilo.wc.common;
+
+import android.arch.lifecycle.LiveData;
+import android.support.annotation.NonNull;
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.Task;
+
+
+public final class CompletionGenericLiveData extends LiveData> implements OnCompleteListener {
+
+
+ public CompletionGenericLiveData() {
+ setValue(new Resource<>(Status.LOADING));
+ }
+
+ @Override
+ public final void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ setValue(new Resource(task.getResult()));
+ } else {
+ setValue(new Resource<>(task.getException()));
+ }
+ }
+}
+
diff --git a/app/src/main/java/me/gilo/wc/common/CompletionLiveData.java b/app/src/main/java/me/gilo/wc/common/CompletionLiveData.java
new file mode 100644
index 0000000..bc7ea1b
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/common/CompletionLiveData.java
@@ -0,0 +1,24 @@
+package me.gilo.wc.common;
+
+import android.arch.lifecycle.LiveData;
+import android.support.annotation.NonNull;
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.Task;
+
+
+public final class CompletionLiveData extends LiveData> implements OnCompleteListener {
+
+
+ public CompletionLiveData() {
+ setValue(new Resource<>(Status.LOADING));
+ }
+
+ @Override
+ public final void onComplete(@NonNull Task task) {
+ if (task.isSuccessful()) {
+ setValue(new Resource<>(true));
+ } else {
+ setValue(new Resource<>(task.getException()));
+ }
+ }
+}
diff --git a/app/src/main/java/me/gilo/wc/common/DocumentLiveData.java b/app/src/main/java/me/gilo/wc/common/DocumentLiveData.java
new file mode 100644
index 0000000..9163d8b
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/common/DocumentLiveData.java
@@ -0,0 +1,41 @@
+package me.gilo.wc.common;
+
+import android.arch.lifecycle.LiveData;
+import com.google.firebase.firestore.*;
+
+
+public class DocumentLiveData extends LiveData>
+ implements EventListener {
+ private final Class type;
+ private ListenerRegistration registration;
+ private final DocumentReference ref;
+
+ public DocumentLiveData(DocumentReference ref, Class type) {
+ this.ref = ref;
+ this.type = type;
+ }
+
+ @Override
+ public void onEvent(DocumentSnapshot snapshot, FirebaseFirestoreException e) {
+ if (e != null) {
+ setValue(new Resource<>(e));
+ return;
+ }
+ setValue(new Resource<>(snapshot.toObject(type)));
+ }
+
+ @Override
+ protected void onActive() {
+ super.onActive();
+ registration = ref.addSnapshotListener(this);
+ }
+
+ @Override
+ protected void onInactive() {
+ super.onInactive();
+ if (registration != null) {
+ registration.remove();
+ registration = null;
+ }
+ }
+}
diff --git a/app/src/main/java/me/gilo/wc/di/ActivitiesModule.java b/app/src/main/java/me/gilo/wc/di/ActivitiesModule.java
index 4ddf8c7..adbb831 100644
--- a/app/src/main/java/me/gilo/wc/di/ActivitiesModule.java
+++ b/app/src/main/java/me/gilo/wc/di/ActivitiesModule.java
@@ -2,6 +2,8 @@ package me.gilo.wc.di;
import dagger.Module;
import dagger.android.ContributesAndroidInjector;
+import me.gilo.raison.ui.user.onboarding.SignInActivity;
+import me.gilo.raison.ui.user.onboarding.SignUpActivity;
import me.gilo.wc.MainActivity;
import me.gilo.wc.ui.home.HomeActivity;
import me.gilo.wc.ui.product.ProductActivity;
@@ -22,4 +24,10 @@ abstract class ActivitiesModule {
@ContributesAndroidInjector
abstract HomeActivity contributesHomeActivity();
+ @ContributesAndroidInjector
+ abstract SignInActivity contributesSignInActivity();
+
+ @ContributesAndroidInjector
+ abstract SignUpActivity contributesSignUpActivity();
+
}
diff --git a/app/src/main/java/me/gilo/wc/di/AppComponent.java b/app/src/main/java/me/gilo/wc/di/AppComponent.java
index 9ee95fe..dfe2104 100644
--- a/app/src/main/java/me/gilo/wc/di/AppComponent.java
+++ b/app/src/main/java/me/gilo/wc/di/AppComponent.java
@@ -14,6 +14,7 @@ import javax.inject.Singleton;
@Component(modules = {
AndroidSupportInjectionModule.class,
ViewModelModule.class,
+ FirebaseModule.class,
ActivitiesModule.class,
AppModule.class
})
diff --git a/app/src/main/java/me/gilo/wc/di/FirebaseModule.java b/app/src/main/java/me/gilo/wc/di/FirebaseModule.java
new file mode 100644
index 0000000..affa931
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/di/FirebaseModule.java
@@ -0,0 +1,46 @@
+package me.gilo.wc.di;
+
+import com.google.firebase.firestore.CollectionReference;
+import com.google.firebase.firestore.FirebaseFirestore;
+import com.google.firebase.storage.FirebaseStorage;
+import com.google.firebase.storage.StorageReference;
+import dagger.Module;
+import dagger.Provides;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+
+@Module
+class FirebaseModule {
+
+ @Singleton
+ @Provides
+ FirebaseFirestore providesFirestore() {
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+ return db;
+ }
+
+ @Singleton
+ @Provides
+ @Named("storage")
+ StorageReference providesStorage() {
+ return FirebaseStorage.getInstance().getReference();
+ }
+
+ @Singleton
+ @Provides
+ @Named("users")
+ CollectionReference providesUsers() {
+ return getFirestoreInstance().collection("users");
+ }
+
+ FirebaseFirestore getFirestoreInstance(){
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+
+ return db;
+ }
+
+
+
+}
diff --git a/app/src/main/java/me/gilo/wc/di/ViewModelModule.java b/app/src/main/java/me/gilo/wc/di/ViewModelModule.java
index c7ad6eb..4a7163a 100644
--- a/app/src/main/java/me/gilo/wc/di/ViewModelModule.java
+++ b/app/src/main/java/me/gilo/wc/di/ViewModelModule.java
@@ -2,19 +2,31 @@ package me.gilo.wc.di;
import android.arch.lifecycle.ViewModel;
import android.arch.lifecycle.ViewModelProvider;
+import com.google.firebase.firestore.CollectionReference;
import dagger.Binds;
import dagger.Module;
+import dagger.Provides;
import dagger.multibindings.IntoMap;
import me.gilo.wc.utils.ViewModelFactory;
import me.gilo.wc.viewmodels.CategoryViewModel;
import me.gilo.wc.viewmodels.ProductViewModel;
import me.gilo.wc.viewmodels.ReviewViewModel;
+import me.gilo.wc.viewmodels.UserViewModel;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
@SuppressWarnings("WeakerAccess")
@Module
public abstract class ViewModelModule {
+
+ @Binds
+ @IntoMap
+ @ViewModelKey(UserViewModel.class)
+ abstract ViewModel bindUserViewModel(UserViewModel viewModel);
+
@Binds
@IntoMap
@ViewModelKey(ProductViewModel.class)
@@ -29,8 +41,10 @@ public abstract class ViewModelModule {
@Binds
@IntoMap
@ViewModelKey(ReviewViewModel.class)
- abstract ViewModel bindRevuewViewModel(ReviewViewModel viewModel);
+ abstract ViewModel bindReviewViewModel(ReviewViewModel viewModel);
@Binds
abstract ViewModelProvider.Factory bindViewModelFactory(ViewModelFactory factory);
+
+
}
diff --git a/app/src/main/java/me/gilo/wc/models/Identifiable.java b/app/src/main/java/me/gilo/wc/models/Identifiable.java
new file mode 100644
index 0000000..7eeff74
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/models/Identifiable.java
@@ -0,0 +1,18 @@
+package me.gilo.wc.models;
+
+import com.google.firebase.firestore.Exclude;
+
+/**
+ * Represents an object that can be uniquely identified among other objects of the same type
+ * by using an UID.
+ *
+ * @param type of the unique key (UID) this object is uniquely identified by. The type needs
+ * a correct implementation of its equals() method or the behaviour of code using this
+ * interface will be undefined.
+ */
+public interface Identifiable {
+
+ @Exclude
+ TKey getEntityKey();
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/gilo/wc/models/Repository.java b/app/src/main/java/me/gilo/wc/models/Repository.java
new file mode 100644
index 0000000..3a450a8
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/models/Repository.java
@@ -0,0 +1,45 @@
+package me.gilo.wc.models;
+
+import com.google.android.gms.tasks.Task;
+
+/**
+ * Manages data access for POJOs that are uniquely identifiable by a key, such as POJOs implementing {@link Identifiable}.
+ */
+public interface Repository, TKey> {
+
+ /**
+ * Checks the repository for a given id and returns a boolean representing its existence.
+ * @param id the unique id of an entity.
+ * @return A {@link Task} for a boolean which is 'true' if the entity for the given id exists, 'false' otherwise.
+ */
+ Task exists(TKey id);
+
+ /**
+ * Queries the repository for an uniquely identified entity and returns it. If the entity does
+ * not exist in the repository, a new instance is returned.
+ * @param id the unique id of an entity.
+ * @return A {@link Task} for an entity implementing {@link Identifiable}.
+ */
+ Task get(TKey id);
+
+ /**
+ * Stores an entity in the repository so it is accessible via its unique id.
+ * @param entity the entity implementing {@link Identifiable} to be stored.
+ * @return An {@link Task} to be notified of failures.
+ */
+ Task create(TEntity entity);
+
+ /**
+ * Updates an entity in the repository
+ * @param entity the new entity to be stored.
+ * @return A {@link Task} to be notified of failures.
+ */
+ Task update(TEntity entity);
+
+ /**
+ * Deletes an entity from the repository.
+ * @param id uniquely identifying the entity.
+ * @return A {@link Task} to be notified of failures.
+ */
+ Task delete(TKey id);
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/gilo/wc/models/User.java b/app/src/main/java/me/gilo/wc/models/User.java
new file mode 100644
index 0000000..173bd79
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/models/User.java
@@ -0,0 +1,85 @@
+package me.gilo.wc.models;
+
+public class User{
+ String id;
+ private String middlename;
+ private String email;
+ private String dob;
+ private String gender;
+ private String surname;
+ private String firstname;
+ private String lastname;
+ private String password;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getMiddlename() {
+ return middlename;
+ }
+
+ public void setMiddlename(String middlename) {
+ this.middlename = middlename;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getDob() {
+ return dob;
+ }
+
+ public void setDob(String dob) {
+ this.dob = dob;
+ }
+
+ public String getGender() {
+ return gender;
+ }
+
+ public void setGender(String gender) {
+ this.gender = gender;
+ }
+
+ public String getSurname() {
+ return surname;
+ }
+
+ public void setSurname(String surname) {
+ this.surname = surname;
+ }
+
+ public String getFirstname() {
+ return firstname;
+ }
+
+ public void setFirstname(String firstname) {
+ this.firstname = firstname;
+ }
+
+ public String getLastname() {
+ return lastname;
+ }
+
+ public void setLastname(String lastname) {
+ this.lastname = lastname;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+}
diff --git a/app/src/main/java/me/gilo/wc/repo/FirebaseRepository.java b/app/src/main/java/me/gilo/wc/repo/FirebaseRepository.java
new file mode 100644
index 0000000..b99e7ec
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/repo/FirebaseRepository.java
@@ -0,0 +1,111 @@
+package me.gilo.wc.repo;
+
+import android.support.annotation.NonNull;
+import android.util.Log;
+import com.google.android.gms.tasks.Continuation;
+import com.google.android.gms.tasks.OnFailureListener;
+import com.google.android.gms.tasks.Task;
+import com.google.firebase.firestore.CollectionReference;
+import com.google.firebase.firestore.DocumentReference;
+import com.google.firebase.firestore.DocumentSnapshot;
+import com.google.firebase.firestore.FirebaseFirestore;
+import me.gilo.wc.models.Identifiable;
+import me.gilo.wc.models.Repository;
+
+
+/**
+ * Manages data access for Firebase
+ */
+public class FirebaseRepository> implements Repository {
+
+ private static final String TAG = "FirebaseRepository";
+
+ private final Class entityClass;
+
+ private final CollectionReference collectionReference;
+ private final String collectionName;
+
+
+ public FirebaseRepository(Class entityClass, String collectionName) {
+ this.collectionName = collectionName;
+ this.entityClass = entityClass;
+
+ FirebaseFirestore db = FirebaseFirestore.getInstance();
+ this.collectionReference = db.collection(this.collectionName);
+ }
+
+ @Override
+ public Task exists(final String documentName) {
+ DocumentReference documentReference = collectionReference.document(documentName);
+ Log.i(TAG, "Checking existence of '" + documentName + "' in '" + collectionName + "'.");
+
+ return documentReference.get().continueWith(new Continuation() {
+ @Override
+ public Boolean then(@NonNull Task task) {
+ Log.d(TAG,"Checking if '" + documentName + "' exists in '" + collectionName +"'.");
+ return task.getResult().exists();
+ }
+ });
+ }
+
+ @Override
+ public Task get(String id) {
+ final String documentName = id;
+ DocumentReference documentReference = collectionReference.document(documentName);
+ Log.i(TAG, "Getting '" + documentName + "' in '" + collectionName + "'.");
+
+ return documentReference.get().continueWith(new Continuation() {
+ @Override
+ public TEntity then(@NonNull Task task) throws Exception {
+ DocumentSnapshot documentSnapshot = task.getResult();
+ if (documentSnapshot.exists()) {
+ return documentSnapshot.toObject(entityClass);
+ } else {
+ Log.d(TAG, "Document '" + documentName + "' does not exist in '" + collectionName + "'.");
+ return entityClass.newInstance();
+ }
+ }
+ });
+ }
+
+ @Override
+ public Task create(TEntity entity) {
+ final String documentName = entity.getEntityKey();
+ DocumentReference documentReference = collectionReference.document(documentName);
+ Log.i(TAG, "Creating '" + documentName + "' in '" + collectionName + "'.");
+ return documentReference.set(entity).addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ Log.d(TAG, "There was an error creating '" + documentName + "' in '" + collectionName + "'!", e);
+ }
+ });
+ }
+
+ @Override
+ public Task update(TEntity entity) {
+ final String documentName = entity.getEntityKey();
+ DocumentReference documentReference = collectionReference.document(documentName);
+ Log.i(TAG, "Updating '" + documentName + "' in '" + collectionName + "'.");
+
+ return documentReference.set(entity).addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ Log.d(TAG, "There was an error updating '" + documentName + "' in '" + collectionName + "'.", e);
+ }
+ });
+ }
+
+ @Override
+ public Task delete(final String documentName) {
+ DocumentReference documentReference = collectionReference.document(documentName);
+ Log.i(TAG, "Deleting '" + documentName + "' in '" + collectionName + "'.");
+
+ return documentReference.delete().addOnFailureListener(new OnFailureListener() {
+ @Override
+ public void onFailure(@NonNull Exception e) {
+ Log.d(TAG, "There was an error deleting '" + documentName + "' in '" + collectionName + "'.", e);
+ }
+ });
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/me/gilo/wc/repo/FirebaseUserRepository.java b/app/src/main/java/me/gilo/wc/repo/FirebaseUserRepository.java
new file mode 100644
index 0000000..a676323
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/repo/FirebaseUserRepository.java
@@ -0,0 +1,85 @@
+package me.gilo.wc.repo;
+
+import com.google.android.gms.tasks.OnFailureListener;
+import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.firebase.auth.AuthResult;
+import com.google.firebase.auth.FirebaseAuth;
+import com.google.firebase.firestore.CollectionReference;
+import com.google.firebase.firestore.DocumentReference;
+import com.google.firebase.storage.StorageReference;
+import me.gilo.wc.common.CompletionGenericLiveData;
+import me.gilo.wc.common.CompletionLiveData;
+import me.gilo.wc.common.DocumentLiveData;
+import me.gilo.wc.models.User;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+public class FirebaseUserRepository extends FirebaseRepository {
+
+
+ private final CollectionReference users;
+ private final StorageReference storage;
+
+
+ @Inject
+ public FirebaseUserRepository(@Named("users") CollectionReference users, @Named("storage") StorageReference storage) {
+ super(User.class, "users");
+ this.users = users;
+ this.storage = storage;
+ }
+
+ public CompletionGenericLiveData login(String email, String password) {
+ final CompletionGenericLiveData completion = new CompletionGenericLiveData();
+
+ FirebaseAuth auth = FirebaseAuth.getInstance();
+ auth.signInWithEmailAndPassword(email, password).addOnCompleteListener(completion);
+
+ return completion;
+
+ }
+
+ public CompletionGenericLiveData signUp(String email, String password) {
+ final CompletionGenericLiveData completion = new CompletionGenericLiveData();
+
+ FirebaseAuth auth = FirebaseAuth.getInstance();
+ auth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(completion);
+
+
+
+ return completion;
+ }
+
+ public DocumentLiveData user(final String id) {
+ if (id == null) {
+ return null;
+ }
+ final DocumentReference userRef = users.document(id);
+ DocumentLiveData data = new DocumentLiveData<>(userRef, User.class);
+ userRef.addSnapshotListener(data);
+ return data;
+ }
+
+ public DocumentLiveData user() {
+ final DocumentReference userRef = users.document(FirebaseAuth.getInstance().getCurrentUser().getUid());
+ DocumentLiveData data = new DocumentLiveData<>(userRef, User.class);
+ userRef.addSnapshotListener(data);
+ return data;
+ }
+
+
+ public CompletionLiveData addUser(User user, OnSuccessListener successListener, OnFailureListener failureListener) {
+ final CompletionLiveData completion = new CompletionLiveData();
+ users.add(user).addOnSuccessListener(successListener).addOnFailureListener(failureListener).addOnCompleteListener(completion);
+
+ return completion;
+ }
+
+ public CompletionLiveData update(User user) {
+ final CompletionLiveData completion = new CompletionLiveData();
+ users.document(user.getId()).set(user).addOnCompleteListener(completion);
+ return completion;
+ }
+
+
+
+}
diff --git a/app/src/main/java/me/gilo/wc/repo/OrderRepository.java b/app/src/main/java/me/gilo/wc/repo/OrderRepository.java
index 5f284bd..c418009 100644
--- a/app/src/main/java/me/gilo/wc/repo/OrderRepository.java
+++ b/app/src/main/java/me/gilo/wc/repo/OrderRepository.java
@@ -4,8 +4,10 @@ package me.gilo.wc.repo;
import me.gilo.wc.common.WooLiveData;
import me.gilo.woodroid.Woocommerce;
import me.gilo.woodroid.models.Order;
+import me.gilo.woodroid.models.filters.OrderFilter;
import javax.inject.Inject;
+import java.util.List;
public class OrderRepository {
@@ -25,4 +27,53 @@ public class OrderRepository {
return callBack;
}
+ public WooLiveData create(Order order) {
+ final WooLiveData callBack = new WooLiveData();
+ woocommerce.OrderRepository().create(order).enqueue(callBack);
+ return callBack;
+ }
+
+
+ public WooLiveData order(int id) {
+ final WooLiveData callBack = new WooLiveData();
+ woocommerce.OrderRepository().order(id).enqueue(callBack);
+ return callBack;
+ }
+
+ public WooLiveData> orders() {
+ final WooLiveData> callBack = new WooLiveData();
+
+ woocommerce.OrderRepository().orders().enqueue(callBack);
+
+ return callBack;
+ }
+
+ public WooLiveData> orders(OrderFilter orderFilter) {
+ final WooLiveData> callBack = new WooLiveData();
+ woocommerce.OrderRepository().orders(orderFilter).enqueue(callBack);
+ return callBack;
+ }
+
+ public WooLiveData update(int id, Order order) {
+ final WooLiveData callBack = new WooLiveData();
+ woocommerce.OrderRepository().update(id, order).enqueue(callBack);
+
+ return callBack;
+ }
+
+ public WooLiveData delete(int id) {
+ final WooLiveData callBack = new WooLiveData();
+ woocommerce.OrderRepository().delete(id).enqueue(callBack);
+
+ return callBack;
+ }
+
+ public WooLiveData delete(int id, boolean force) {
+ final WooLiveData callBack = new WooLiveData();
+ woocommerce.OrderRepository().delete(id, force).enqueue(callBack);
+
+ return callBack;
+ }
+
+
}
diff --git a/app/src/main/java/me/gilo/wc/ui/onboarding/SignInActivity.kt b/app/src/main/java/me/gilo/wc/ui/onboarding/SignInActivity.kt
new file mode 100644
index 0000000..3d341f6
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/ui/onboarding/SignInActivity.kt
@@ -0,0 +1,125 @@
+package me.gilo.raison.ui.user.onboarding
+
+import android.arch.lifecycle.Observer
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v4.content.ContextCompat.startActivity
+import android.widget.Toast
+import io.github.inflationx.viewpump.ViewPumpContextWrapper
+import kotlinx.android.synthetic.main.content_sign_in.*
+import me.gilo.wc.R
+import me.gilo.wc.common.BaseActivity
+import me.gilo.wc.common.Status
+import me.gilo.wc.ui.home.HomeActivity
+import me.gilo.wc.ui.state.ProgressDialogFragment
+import me.gilo.wc.viewmodels.UserViewModel
+import org.json.JSONObject
+import java.util.regex.Matcher
+import java.util.regex.Pattern
+
+
+class SignInActivity : BaseActivity() {
+
+
+ lateinit var viewModel : UserViewModel
+ val TAG = this::getLocalClassName
+
+ private lateinit var progressDialog: ProgressDialogFragment
+ private val pattern = Pattern.compile(EMAIL_PATTERN)
+ private var matcher: Matcher? = null
+
+ override fun attachBaseContext(newBase: Context) {
+ super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_sign_in)
+
+
+ viewModel = getViewModel(UserViewModel::class.java)
+
+ title = "Sign In"
+
+ flSignIn.setOnClickListener{
+ login()
+ }
+
+ tvSignUp.setOnClickListener{startActivity(Intent(baseContext, SignUpActivity::class.java))}
+ }
+
+ private fun login() {
+ if (validates()) {
+ val email = etEmail.text.toString()
+ val password = etPassword.text.toString()
+
+ viewModel.login(email, password).observe(this, Observer {
+ response->
+ when (response!!.status()){
+ Status.LOADING ->{
+ showLoading("Performing log in", "This will only take a short while")
+ }
+
+ Status.SUCCESS ->{
+ stopShowingLoading()
+ startActivity(Intent(baseContext, HomeActivity::class.java))
+
+ }
+
+ Status.ERROR ->{
+ stopShowingLoading()
+ Toast.makeText(baseContext, "Something went wrong", Toast.LENGTH_LONG).show()
+ }
+
+ Status.EMPTY ->{
+ stopShowingLoading()
+ }
+
+ }
+ })
+
+
+
+ } else {
+ Toast.makeText(this, "Please correct the information entered", Toast.LENGTH_SHORT).show()
+ }
+ }
+
+ private fun validates(): Boolean {
+ var validation = true
+
+ tilEmail.isErrorEnabled = false
+ tilPassword.isErrorEnabled = false
+
+ val email = tilEmail.editText!!.text.toString()
+
+ if (email.isEmpty()) {
+ tilEmail.error = "This cannot be left blank!"
+ validation = false
+ }
+
+ return validation
+ }
+
+ private fun validateEmail(email: String): Boolean {
+ matcher = pattern.matcher(email)
+ return matcher!!.matches()
+ }
+
+ private fun showLoading(title: String, message: String) {
+ val manager = supportFragmentManager
+ progressDialog = ProgressDialogFragment.newInstance(title, message)
+ progressDialog.isCancelable = false
+ progressDialog.show(manager, "progress")
+ }
+
+ private fun stopShowingLoading() {
+ progressDialog.dismiss()
+ }
+
+ companion object {
+ private const val EMAIL_PATTERN = "^[a-zA-Z0-9#_~!$&'()*+,;=:.\"(),:;<>@\\[\\]\\\\]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*$"
+ }
+
+}
diff --git a/app/src/main/java/me/gilo/wc/ui/onboarding/SignUpActivity.kt b/app/src/main/java/me/gilo/wc/ui/onboarding/SignUpActivity.kt
new file mode 100644
index 0000000..cd73418
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/ui/onboarding/SignUpActivity.kt
@@ -0,0 +1,204 @@
+package me.gilo.raison.ui.user.onboarding
+
+import android.arch.lifecycle.Observer
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.support.v4.content.ContextCompat.startActivity
+import android.widget.Toast
+import io.github.inflationx.viewpump.ViewPumpContextWrapper
+import kotlinx.android.synthetic.main.content_sign_up.*
+import me.gilo.wc.R
+import me.gilo.wc.common.BaseActivity
+import me.gilo.wc.common.Status
+
+import me.gilo.wc.models.User
+import me.gilo.wc.ui.home.HomeActivity
+import me.gilo.wc.ui.state.ProgressDialogFragment
+import me.gilo.wc.viewmodels.UserViewModel
+import java.util.regex.Matcher
+import java.util.regex.Pattern
+
+class SignUpActivity : BaseActivity() {
+
+ lateinit var viewModel : UserViewModel
+ val TAG = this::getLocalClassName
+
+ private lateinit var progressDialog: ProgressDialogFragment
+ private val pattern = Pattern.compile(EMAIL_PATTERN)
+ private var matcher: Matcher? = null
+
+ override fun attachBaseContext(newBase: Context) {
+ super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_sign_up)
+
+ viewModel = getViewModel(UserViewModel::class.java)
+
+ title = "Sign Up"
+
+ flSignup.setOnClickListener{
+ signUp()
+ }
+
+ }
+
+ private fun signUp() {
+ if (validates()) {
+ val email = etEmail.text.toString()
+ val firstName = etFirstName.text.toString()
+ val lastName = etLastName.text.toString()
+ val password = etPassword.text.toString()
+
+ var user = User()
+ user.email = email
+ user.firstname = firstName
+ user.lastname = lastName
+
+ viewModel.signUp(email, password).observe(this, Observer {
+ response->
+ when (response!!.status()){
+ Status.LOADING ->{
+ showLoading("Uploading account details", "This will only take a short while")
+ }
+
+ Status.SUCCESS ->{
+ stopShowingLoading()
+ startActivity(Intent(baseContext, HomeActivity::class.java))
+ }
+
+ Status.ERROR ->{
+ stopShowingLoading()
+ Toast.makeText(baseContext, response.error().message.toString(), Toast.LENGTH_LONG).show()
+ }
+
+ Status.EMPTY ->{
+
+ }
+
+ }
+ })
+
+
+
+ } else {
+ Toast.makeText(this, "Please correct the information entered", Toast.LENGTH_SHORT).show()
+ }
+ }
+
+ private fun sendDetails() {
+ if (validates()) {
+ val email = etEmail.text.toString()
+ val firstName = etFirstName.text.toString()
+ val lastName = etLastName.text.toString()
+
+ var user = User()
+ user.email = email
+ user.firstname = firstName
+ user.lastname = lastName
+
+ viewModel.updateUser(user).observe(this, Observer {
+ response->
+ when (response!!.status()){
+ Status.LOADING ->{
+ showLoading("Uploading account details", "This will only take a short while")
+ }
+
+ Status.SUCCESS ->{
+ stopShowingLoading()
+ startActivity(Intent(baseContext, HomeActivity::class.java))
+ }
+
+ Status.ERROR ->{
+ stopShowingLoading()
+ Toast.makeText(baseContext, response.error().message.toString(), Toast.LENGTH_LONG).show()
+ }
+
+ Status.EMPTY ->{
+
+ }
+
+ }
+ })
+
+
+
+ } else {
+ Toast.makeText(this, "Please correct the information entered", Toast.LENGTH_SHORT).show()
+ }
+ }
+
+ private fun validates(): Boolean {
+ tilEmail.isErrorEnabled = false
+ tilFirstName.isErrorEnabled = false
+ tilLastName.isErrorEnabled = false
+ tilPassword.isErrorEnabled = false
+ tilPasswordVerify.isErrorEnabled = false
+
+ var validation = true
+
+ val email = tilEmail.editText!!.text.toString()
+ val firstName = etFirstName.text.toString()
+ val lastName = etLastName.text.toString()
+ val password = etPassword.text.toString()
+ val passwordVerify = etPasswordVerify.text.toString()
+
+
+
+ if (!validateEmail(email)) {
+ tilEmail.error = "Not a valid email address!"
+ validation = false
+ }
+
+ if (firstName.isEmpty()) {
+ tilFirstName.error = "Please fill this"
+ validation = false
+ }
+
+ if (lastName.isEmpty()) {
+ tilLastName.error = "Please fill this"
+ validation = false
+ }
+
+ if (password.isEmpty()) {
+ tilPassword.error = "Please fill this"
+ validation = false
+ }
+
+ if (passwordVerify.isEmpty()) {
+ tilPasswordVerify.error = "Please fill this"
+ validation = false
+ }
+
+ if (passwordVerify != password) {
+ tilPasswordVerify.error = "Passwords do not match"
+ validation = false
+ }
+
+ return validation
+ }
+
+ private fun validateEmail(email: String): Boolean {
+ matcher = pattern.matcher(email)
+ return matcher!!.matches()
+ }
+
+ private fun showLoading(title: String, message: String) {
+ val manager = supportFragmentManager
+ progressDialog = ProgressDialogFragment.newInstance(title, message)
+ progressDialog.isCancelable = false
+ progressDialog.show(manager, "progress")
+ }
+
+ private fun stopShowingLoading() {
+ progressDialog.dismiss()
+ }
+
+ companion object {
+ private const val EMAIL_PATTERN = "^[a-zA-Z0-9#_~!$&'()*+,;=:.\"(),:;<>@\\[\\]\\\\]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*$"
+ }
+
+}
diff --git a/app/src/main/java/me/gilo/wc/ui/order/MyOrdersActivity.kt b/app/src/main/java/me/gilo/wc/ui/order/MyOrdersActivity.kt
new file mode 100644
index 0000000..d710a9f
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/ui/order/MyOrdersActivity.kt
@@ -0,0 +1,19 @@
+package me.gilo.wc.ui.order
+
+import android.os.Bundle
+import android.support.design.widget.Snackbar
+import android.support.v7.app.AppCompatActivity
+import me.gilo.wc.R
+
+import kotlinx.android.synthetic.main.activity_my_orders.*
+
+class MyOrdersActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_my_orders)
+ setSupportActionBar(toolbar)
+
+ }
+
+}
diff --git a/app/src/main/java/me/gilo/wc/viewmodels/UserViewModel.java b/app/src/main/java/me/gilo/wc/viewmodels/UserViewModel.java
new file mode 100644
index 0000000..500cdbf
--- /dev/null
+++ b/app/src/main/java/me/gilo/wc/viewmodels/UserViewModel.java
@@ -0,0 +1,58 @@
+package me.gilo.wc.viewmodels;
+
+import android.arch.lifecycle.MutableLiveData;
+import android.arch.lifecycle.ViewModel;
+import com.google.android.gms.tasks.OnFailureListener;
+import com.google.android.gms.tasks.OnSuccessListener;
+import com.google.firebase.auth.AuthResult;
+import com.google.firebase.auth.FirebaseAuth;
+import me.gilo.wc.common.CompletionGenericLiveData;
+import me.gilo.wc.common.CompletionLiveData;
+import me.gilo.wc.common.DocumentLiveData;
+import me.gilo.wc.models.User;
+import me.gilo.wc.repo.FirebaseUserRepository;
+
+
+import javax.inject.Inject;
+
+
+public final class UserViewModel extends ViewModel {
+ private final MutableLiveData id = new MutableLiveData<>();
+ private final FirebaseUserRepository firebaseUserRepository;
+
+ @Inject
+ UserViewModel(FirebaseUserRepository firebaseUserRepository) {
+ this.firebaseUserRepository = firebaseUserRepository;
+ }
+
+ public CompletionGenericLiveData login(String username, String password) {
+ return firebaseUserRepository.login(username, password);
+ }
+
+ public CompletionGenericLiveData firebaseLogin(String email, String password) {
+ return firebaseUserRepository.login(email, password);
+ }
+
+ public CompletionGenericLiveData signUp(String email, String password) {
+ return firebaseUserRepository.signUp(email, password);
+ }
+
+ public CompletionLiveData addUser(User user, OnSuccessListener successListener, OnFailureListener failureListener) {
+ return firebaseUserRepository.addUser(user, successListener, failureListener);
+ }
+
+ public DocumentLiveData user(String user_id) {
+ return firebaseUserRepository.user(user_id);
+ }
+
+ public DocumentLiveData user() {
+ return firebaseUserRepository.user();
+ }
+
+ public CompletionLiveData updateUser(User user) {
+ user.setId(FirebaseAuth.getInstance().getCurrentUser().getUid());
+
+ return firebaseUserRepository.update(user);
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_my_orders.xml b/app/src/main/res/layout/activity_my_orders.xml
new file mode 100644
index 0000000..cb35af9
--- /dev/null
+++ b/app/src/main/res/layout/activity_my_orders.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_sign_in.xml b/app/src/main/res/layout/activity_sign_in.xml
new file mode 100644
index 0000000..3b7e70c
--- /dev/null
+++ b/app/src/main/res/layout/activity_sign_in.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_sign_up.xml b/app/src/main/res/layout/activity_sign_up.xml
new file mode 100644
index 0000000..41ae094
--- /dev/null
+++ b/app/src/main/res/layout/activity_sign_up.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_my_orders.xml b/app/src/main/res/layout/content_my_orders.xml
new file mode 100644
index 0000000..b358090
--- /dev/null
+++ b/app/src/main/res/layout/content_my_orders.xml
@@ -0,0 +1,12 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_sign_in.xml b/app/src/main/res/layout/content_sign_in.xml
new file mode 100644
index 0000000..9eebf7c
--- /dev/null
+++ b/app/src/main/res/layout/content_sign_in.xml
@@ -0,0 +1,183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/content_sign_up.xml b/app/src/main/res/layout/content_sign_up.xml
new file mode 100644
index 0000000..c849a96
--- /dev/null
+++ b/app/src/main/res/layout/content_sign_up.xml
@@ -0,0 +1,236 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/single_order_item.xml b/app/src/main/res/layout/single_order_item.xml
new file mode 100644
index 0000000..f8cfd94
--- /dev/null
+++ b/app/src/main/res/layout/single_order_item.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 2c62360..7eab091 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -31,5 +31,6 @@
CategoryActivity
HomeActivity
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry\'s standard dummy text ever since the 1500s
+ MyOrdersActivity
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 02247ab..b6507f6 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -11,6 +11,43 @@
- @style/SpinnerItemStyle
+
+
+
+
+
+
+
+