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 + + + + + + + +