Compare commits

...

96 Commits

Author SHA1 Message Date
Gilbert Kimutai
f561de2e72
Update README.md 2020-05-05 12:45:38 +03:00
Gilbert Kimutai
b6e5a32cd3 icon change on add to cart 2020-03-24 16:10:30 +03:00
Gilbert Kimutai
b941c425e8 Merge remote-tracking branch 'origin/master' 2020-03-15 13:04:07 +03:00
Gilbert Kimutai
250b805126 added offline cart repo 2020-03-15 13:03:52 +03:00
Gilbert Kimutai
7ffffd7e80 Added serialization annotation to attributes 2020-03-02 16:34:37 +03:00
Gilbert Kimutai
6d401b1f87
Added slack link 2020-01-08 06:11:36 +03:00
Gilbert Kimutai
00799f0830
Merge pull request #14 from gilokimu/cocart
Cocart Integration
2019-12-28 07:44:41 +03:00
Gilbert Kimutai
d528e38709 updated the cocart implementation 2019-12-17 05:15:48 +03:00
Gilbert Kimutai
e07d3236a3 added cocart api structure 2019-11-30 17:36:59 +03:00
Gilbert Kimutai
b7b8d020b7 update to androidx 2019-11-30 12:15:29 +03:00
Gilbert Kimutai
bf39bba675 Merge branch 'master' of https://github.com/gilokimu/WooDroid
 Conflicts:
	.idea/gradle.xml
2019-11-28 06:21:45 +03:00
Gilbert Kimutai
d0e88fa726 added working demo to test 2019-11-28 06:21:34 +03:00
gilo
0b3045ae81 added categories 2019-11-02 10:28:54 +03:00
Gilbert Kimutai
24c45491b6
Update README.md 2019-09-25 07:56:59 +03:00
Gilbert Kimutai
2cc68830e4 added working demo to test 2019-08-14 06:42:17 +03:00
Gilbert Kimutai
2f885897a0 added cart abstraction 2019-07-08 19:36:33 +03:00
Gilbert Kimutai
6591cf8f95 added cart abstraction 2019-07-08 06:19:41 +03:00
Gilbert Kimutai
47e5575417 updated fully to Kotlin 2019-06-08 12:27:15 +03:00
Gilbert Kimutai
7b13ab92c6
Merge pull request #8 from gilokimu/kotlin_refactor
Kotlin refactor
2019-06-08 12:13:38 +03:00
Gilbert Kimutai
f3deac9ea0 updated to kotlin 2019-06-08 12:12:54 +03:00
Gilbert Kimutai
51e651de76 started Kotlin refactor 2019-06-08 04:08:53 +03:00
Gilbert Kimutai
b1de98db52
Icon addition
Added icon on readme
2019-06-01 10:52:45 +03:00
Gilbert Kimutai
5bb5bd650e updated launcher icon 2019-06-01 10:42:39 +03:00
Gilbert Kimutai
33b5a96a69 migrated the package names 2019-06-01 10:37:22 +03:00
Gilbert Kimutai
8e49de29da
Merge pull request #7 from Aroniez/master
Java to kotlin conversion
2019-06-01 09:52:11 +03:00
Aaron Rono
38db311926 java to kotlin conversion 2019-05-31 16:31:56 +03:00
Gilbert Kimutai
fcaec04239 updated order detailed page 2019-05-21 05:54:21 +03:00
Gilbert Kimutai
31602df99e Added order detailed page 2019-05-21 05:21:28 +03:00
Gilbert Kimutai
1ec0747e26 complete order page 2019-04-25 06:15:39 +03:00
Gilbert Kimutai
ceda450bb8 WIP - Added my orders page 2019-04-23 06:21:32 +03:00
Gilbert Kimutai
3b08a0541c order billing and shipping address 2019-04-22 07:04:56 +03:00
Gilbert Kimutai
e8fc0899ca Add to cart function 2019-04-22 06:57:55 +03:00
Gilbert Kimutai
6b94ee730d Merge remote-tracking branch 'origin/master' 2019-04-17 05:04:22 +03:00
Gilbert Kimutai
b87f96d336 updated the callback classes 2019-04-17 04:58:55 +03:00
Gilbert Kimutai
95a8d53349
Updated the app version
updated to 0.2.0
2019-04-17 04:36:10 +03:00
Gilbert Kimutai
69277df89b Restructured the API classes 2019-04-17 04:27:02 +03:00
Gilbert Kimutai
58a8cd5f6a Added loading state on product page and empty state on cart page 2019-04-16 05:17:28 +03:00
Gilbert Kimutai
3e9ad9fa6a Support for anonymous users 2019-04-13 10:00:00 +03:00
Gilbert Kimutai
13a2ccac2c Further formatting of UI to fit longer images with white background 2019-04-08 04:28:33 +03:00
Gilbert Kimutai
48e747cce3 UI updates to supports liquor store example 2019-04-07 16:46:00 +03:00
Gilbert Kimutai
688433d9e6 added payments, settings and shipping methods into the api 2019-04-07 09:48:58 +03:00
Gilbert Kimutai
cf671d332e Added settings and webhooks api 2019-04-07 09:15:04 +03:00
Gilbert Kimutai
53b865824f Merge remote-tracking branch 'origin/master' 2019-04-05 05:28:24 +03:00
Gilbert Kimutai
9136c6c337 Added shipping address and payment checkout options on design 2019-04-05 05:28:04 +03:00
Gilbert Kimutai
17859f9c92
Added cart screenshot 2019-04-04 06:34:11 +03:00
Gilbert Kimutai
0bb4360564 Added a screenshot of the page 2019-04-04 06:32:44 +03:00
Gilbert Kimutai
25f090c49e Complete cart page 2019-04-04 06:30:51 +03:00
Gilbert Kimutai
a19c3e24e3 Adding a cart page 2019-04-03 06:52:33 +03:00
Gilbert Kimutai
6d3ee7f2c7 Added cart counter and add and remove from cart logic tied to counter 2019-04-02 06:59:51 +03:00
Gilbert Kimutai
d7be6e4831 Added cart icon on menu 2019-04-02 06:00:08 +03:00
Gilbert Kimutai
9dddd4713c Added firebase cart repo 2019-04-02 05:50:21 +03:00
Gilbert Kimutai
37e1147615 Complete customer edit functions 2019-04-01 05:49:16 +03:00
Gilbert Kimutai
b395c4e6e0 Added profile page 2019-04-01 05:17:00 +03:00
Gilbert Kimutai
6977c0fc85 update shipping address 2019-03-31 15:27:21 +03:00
Gilbert Kimutai
df9ae110d8 update billing address 2019-03-31 14:51:54 +03:00
Gilbert Kimutai
c5304e76d2 basic user details update 2019-03-31 13:07:23 +03:00
Gilbert Kimutai
7fe30becb1 UI design for customer pages 2019-03-31 10:36:21 +03:00
Gilbert Kimutai
5410926f5a Merge remote-tracking branch 'origin/master' 2019-03-31 08:09:59 +03:00
Gilbert Kimutai
8296ffc5ed UI design for customer pages 2019-03-31 08:09:47 +03:00
Gilbert Kimutai
fa59a544ec
Updated language 2019-03-30 06:50:30 +03:00
Gilbert Kimutai
5694e92dac
Updated Screenshots on Readme
Update screenshots
2019-03-30 06:49:27 +03:00
Gilbert Kimutai
0cc26c29cc Added screenshots 2019-03-30 06:38:53 +03:00
Gilbert Kimutai
7643a8e089 Added login and registration using firebase 2019-03-30 06:01:00 +03:00
Gilbert Kimutai
152397b6fa WIP - Added profile page view 2019-03-27 05:04:46 +03:00
Gilbert Kimutai
3ce22edb33 Redesign of the categories page 2019-03-26 05:32:08 +03:00
Gilbert Kimutai
0bc203c5db Add a review dialog and function 2019-03-25 06:32:24 +03:00
Gilbert Kimutai
53e6f95ab7 Composable UI approach with fragments on the product page 2019-03-24 07:50:59 +03:00
Gilbert Kimutai
3134e59f4c Added images on reviews section 2019-03-21 06:37:43 +03:00
Gilbert Kimutai
37e71535b7 Added product reviews section 2019-03-20 06:34:08 +03:00
Gilbert Kimutai
82c76bb970 Support for sending arrays in url for filters with arrays
Also able to get similar products in one call
2019-03-19 06:35:29 +03:00
Gilbert Kimutai
aa218fe992 Added similar product section on the product page 2019-03-18 05:51:48 +03:00
gilokimu
c161bc454a Viewpager added onto the products page for images 2019-03-14 05:48:50 +03:00
gilokimu
74362552b3 home page design 2019-03-12 06:24:17 +03:00
gilokimu
3272450dd7 home page design 2019-03-12 06:06:40 +03:00
gilokimu
9786252c78 Added home page and categories page on sample app 2019-03-06 05:53:47 +03:00
gilokimu
11ffd08276 WIP Add to cart struggling with cookies 2019-03-04 05:43:15 +03:00
gilokimu
ed0f31421f Add to cart function using cocart 2019-03-03 17:59:35 +03:00
Gilbert Kimutai
c5322be2b3 Added filter draw on sample app 2019-02-23 07:39:19 +03:00
Gilbert Kimutai
c3697b297f Changes on product layout 2019-02-22 06:16:29 +03:00
Gilbert Kimutai
db41825cc3 Updated readme 2019-02-21 18:32:14 +03:00
Gilbert Kimutai
0f244cbb15 Merge branch 'master' of https://github.com/gilokimu/WooDroid 2019-02-21 18:00:54 +03:00
Gilbert Kimutai
d23dde5d2a
Update README.md 2019-02-21 06:20:56 +03:00
Gilbert Kimutai
2548979f0e
Update README.md 2019-02-21 06:20:07 +03:00
Gilbert Kimutai
881870dadc Added settings api, enums for easier filtering 2019-02-21 06:07:49 +03:00
Gilbert Kimutai
9732f236ef Added search view and introduced filter icon 2019-02-20 06:51:33 +03:00
Gilbert Kimutai
e975393b5e Added reports API
Migrated to a MVVM architecture on sample app
2019-02-20 05:57:06 +03:00
Gilbert Kimutai
5b18bb626b Added filter classes 2019-02-19 20:03:29 +03:00
Gilbert Kimutai
256de109c3 Added Filters support for Products 2019-02-19 06:29:19 +03:00
Gilbert Kimutai
df5f1b0868 Merge remote-tracking branch 'origin/master' 2019-02-19 04:59:59 +03:00
Gilbert Kimutai
31002b6169 Modified AuthIntercepter to correctly authenticate requests with parameters that are not oauth 2019-02-19 04:59:29 +03:00
Gilbert Kimutai
4880090fb7
Update the example code to reflect current changes 2019-02-18 06:20:45 +03:00
Gilbert Kimutai
939afd1d9a Resorted to using Repo over service and exposed all the repos available 2019-02-18 06:16:27 +03:00
Gilbert Kimutai
b56ac5f17d OrderService and CustomerService are now available from API 2019-02-18 05:37:44 +03:00
Gilbert Kimutai
91c6ac52d4 Merge remote-tracking branch 'origin/master' 2019-02-18 05:26:32 +03:00
Gilbert Kimutai
5ca1540974 Added coupon use case for view, update and delete 2019-02-18 05:26:10 +03:00
Gilbert Kimutai
09d723b443
Added Gradle and maven dependencies 2019-02-17 13:13:03 +03:00
717 changed files with 19421 additions and 6499 deletions

View File

@ -1,17 +1,121 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<AndroidXmlCodeStyleSettings>
<option name="USE_CUSTOM_SETTINGS" value="true" />
</AndroidXmlCodeStyleSettings>
<JetCodeStyleSettings>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings>
<codeStyleSettings language="XML">
<indentOptions>
<option name="INDENT_SIZE" value="2" />
<option name="CONTINUATION_INDENT_SIZE" value="4" />
<option name="CONTINUATION_INDENT_SIZE" value="2" />
<option name="USE_TAB_CHARACTER" value="true" />
</indentOptions>
<arrangement>
<rules>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:android</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>xmlns:.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:id</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*:name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>name</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>style</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>^$</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
</AND>
</match>
<order>ANDROID_ATTRIBUTE_ORDER</order>
</rule>
</section>
<section>
<rule>
<match>
<AND>
<NAME>.*</NAME>
<XML_ATTRIBUTE />
<XML_NAMESPACE>.*</XML_NAMESPACE>
</AND>
</match>
<order>BY_NAME</order>
</rule>
</section>
</rules>
</arrangement>
</codeStyleSettings>
<codeStyleSettings language="kotlin">
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />

13
.idea/compiler.xml generated Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel>
<module name="app" target="1.8" />
<module name="cocart" target="1.7" />
<module name="core" target="1.7" />
<module name="firebasecart" target="1.8" />
<module name="offlinecart" target="1.8" />
<module name="woodroid" target="1.8" />
</bytecodeTargetLevel>
</component>
</project>

7
.idea/gradle.xml generated
View File

@ -1,14 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="delegatedBuild" value="false" />
<option name="testRunner" value="PLATFORM" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/cocart" />
<option value="$PROJECT_DIR$/core" />
<option value="$PROJECT_DIR$/firebasecart" />
<option value="$PROJECT_DIR$/offlinecart" />
<option value="$PROJECT_DIR$/woodroid" />
</set>
</option>

5
.idea/misc.xml generated
View File

@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeSettings">
<configurations>
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
</configurations>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>

2
.idea/vcs.xml generated
View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
<mapping directory="" vcs="Git" />
</component>
</project>

244
README.md
View File

@ -1,23 +1,56 @@
<img src="https://github.com/gilokimu/woocommerce-android-sdk/raw/master/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png"/>
# Woocommerce Android SDK
This is an woocommerce api client for android
This is an android sdk for woocommerce
# Under construction, is not ready for use yet. :(
![alt text](https://github.com/gilokimu/woocommerce-android-sdk/raw/master/screens/screenshot-1549248597583.jpg "Woocommerce Android app")
<img src="https://github.com/gilokimu/woocommerce-android-sdk/raw/master/screens/screenshot-1553916911644.jpg" width="285"/> <img src="https://github.com/gilokimu/woocommerce-android-sdk/raw/master/screens/screenshot-1553916952806.jpg" width="285"/> <img src="https://github.com/gilokimu/woocommerce-android-sdk/raw/master/screens/screenshot-1553916959446.jpg" width="285"/> <img src="https://github.com/gilokimu/woocommerce-android-sdk/raw/master/screens/screenshot-1553916965766.jpg" width="285"/> <img src="https://github.com/gilokimu/woocommerce-android-sdk/raw/master/screens/screenshot-1553916980710.jpg" width="285"/> <img src="https://github.com/gilokimu/woocommerce-android-sdk/raw/master/screens/screenshot-1553916989454.jpg" width="285"/> <img src="https://github.com/gilokimu/woocommerce-android-sdk/raw/master/screens/screenshot-1553917011606.jpg" width="285"/>
<img src="https://github.com/gilokimu/woocommerce-android-sdk/raw/master/screens/screenshot-1554348601504.jpg" width="285"/>
Built-based on the documentation: http://woocommerce.github.io/woocommerce-rest-api-docs/#introduction
## Installation
Please note that files are still being moved around - the project should be stable before end Feb 2019
### Maven dependency:
Step 1. Add the JitPack repository to your build file
```xml
TODO
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
```
Step 2. Add the dependency
```xml
<dependency>
<groupId>com.github.gilokimu</groupId>
<artifactId>woodroid</artifactId>
<version>0.2.0</version>
</dependency>
```
### Gradle dependency:
```xml
TODO
Step 1. Add the JitPack repository to your build file
```gradle
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
```
Step 2. Add the dependency
```gradle
dependencies {
implementation 'com.github.gilokimu:woodroid:0.2.0'
}
```
## Getting started
@ -27,14 +60,24 @@ Generate API credentials (Consumer Key & Consumer Secret) following this instruc
Check out the WooCommerce API endpoints and data that can be manipulated in <https://woocommerce.github.io/woocommerce-rest-api-docs/>.
## Demo
I have left consumer key and secret within the app, for you to test the app without an installation of wordpress. To use my installation of wordpress, here are the credentials:
username: demo
password: demo2019
https://gilo.me/store/wp-admin
PS/ Do no harm
## Setup
Setup for the new WP REST API integration (WooCommerce 2.6 or later):
```kotlin
val woocommerce = Woocommerce.Builder()
val woocommerce = Woocommerce.Builder()
.setSiteUrl("http://example.com")
.setApiVersion("2")
.setApiVersion(Woocommerce.API_V2)
.setConsumerKey("ck_XXXXX")
.setConsumerSecret("cs_XXXX")
.build()
@ -44,55 +87,160 @@ Setup for the new WP REST API integration (WooCommerce 2.6 or later):
Getting products example
```kotlin
woocommerce.products.enqueue(object : Callback<ArrayList<Product>> {
override fun onResponse(call: Call<ArrayList<Product>>, response: Response<ArrayList<Product>>) {
val products = response.body()
for (product in products!!) {
tvText.append(product.title + "\n")
}
woocommerce.ProductRepository().products().enqueue(object : Callback<List<Product>> {
override fun onResponse(call: Call<List<Product>>, response: Response<List<Product>>) {
val productsResponse = response.body()
for (product in productsResponse!!) {
products.add(product)
}
override fun onFailure(call: Call<ArrayList<Product>>, t: Throwable) {
adapter.notifyDataSetChanged()
}
override fun onFailure(call: Call<List<Product>>, t: Throwable) {
}
})
```
## API Support Checklist
## Supported resources
The sdk currently supports :
1. Order Notes
2. Refunds
3. Attributes
4. Attribute Terms
5. Product Category
6. Shipping Class
7. Product Tags
8. Variations
9. Coupons
10. Customers
11. Orders
12. Products
13. Reports
Method | Create | Delete | Retrieve | Update | Batch
--------------------- | ------------- | ------------- | ------------- | ------------- | -------------
Coupons | N | N | N | N | N
Customers | N | N | N | N | N
Orders | N | N | N | N | N
Order notes | N | N | N | N | N
Refunds | N | N | N | N | N
Products | N | N | N | N | N
Product variations | N | N | N | N | N
Product attributes | N | N | N | N | N
Product attribute terms | N | N | N | N | N
Product categories | N | N | N | N | N
Product shipping classes | N | N | N | N | N
Product tags | N | N | N | N | N
Product reviews | N | N | N | N | N
Reports | N | N | N | N | N
Tax rates | N | N | N | N | N
Tax classes | N | N | N | N | N
Webhooks | N | N | N | N | N
Settings | N | N | N | N | N
Setting options | N | N | N | N | N
Payment gateways | N | N | N | N | N
Shipping zones | N | N | N | N | N
Shipping zone locations | N | N | N | N | N
Shipping zone methods | N | N | N | N | N
Shipping methods | N | N | N | N | N
### Coming soon
14. Settings
15. Payment gateway
## API Methods
The general resource method calls are
1. Create - Pass the object to create
2. List - a list of all items
3. View single method - retries a single item
4. Delete - deletes the resource
5. Filter - provides a list that meets a criteria
### Create Method
Create an instance of the resource then pass onto a .create() function on the resource repository
```kotlin
val coupon = Coupon()
coupon.code = code
coupon.description = description
woocommerce.CouponRepository().create(coupon).enqueue(object : Callback<Coupon> {
override fun onResponse(call: Call<Coupon>, response: Response<Coupon>) {
val couponResponse = response.body()
finish()
}
override fun onFailure(call: Call<Coupon>, t: Throwable) {
}
})
```
### List Method
```kotlin
woocommerce.CouponRepository().coupons().enqueue(object : Callback<List<Coupon>> {
override fun onResponse(call: Call<List<Coupon>>, response: Response<List<Coupon>>) {
val couponResponse = response.body()
for (coupon in couponResponse!!) {
coupons.add(coupon)
}
adapter.notifyDataSetChanged()
}
override fun onFailure(call: Call<List<Coupon>>, t: Throwable) {
}
})
```
### View single item
```kotlin
val couponId = intent.getIntExtra("couponId", 0)
woocommerce.CouponRepository().coupon(couponId).enqueue(object : Callback<Coupon> {
override fun onResponse(call: Call<Coupon>, response: Response<Coupon>) {
val coupon = response.body()!!
etCode.setText(coupon.code.toUpperCase())
etDescription.setText(coupon.description)
}
override fun onFailure(call: Call<Coupon>, t: Throwable) {
}
})
```
### Delete item
```kotlin
woocommerce.CouponRepository().delete(couponId).enqueue(object : Callback<Coupon> {
override fun onResponse(call: Call<Coupon>, response: Response<Coupon>) {
if (response.isSuccessful) {
val coupon = response.body()!!
finish()
}else{
Toast.makeText(this@CouponActivity, "" + response.code() + " : " + response.message(), Toast.LENGTH_SHORT).show()
}
}
override fun onFailure(call: Call<Coupon>, t: Throwable) {
stopShowingLoading()
}
})
```
### Filter item
```kotlin
val filter = CouponFilter()
filter.search = "FEB"
woocommerce.CouponRepository().coupons(filter).enqueue(object : Callback<List<Coupon>> {
override fun onResponse(call: Call<List<Coupon>>, response: Response<List<Coupon>>) {
val couponResponse = response.body()
for (coupon in couponResponse!!) {
coupons.add(coupon)
}
adapter.notifyDataSetChanged()
}
override fun onFailure(call: Call<List<Coupon>>, t: Throwable) {
}
})
```
### Sample app
The sample app implements an MVVM approach which would look slightly different from the above. The methods are the same though
## TODO
See the trello board for items and progress https://trello.com/b/Muw8vcBb/woocommerce-android-sdk
##Contribution
## Contribution
Contributions are highly welcomed, just create a PR
## Slack
You can also reach out through <a href="https://join.slack.com/t/woodroid/shared_invite/enQtODg1ODYzMDAzOTcxLTE4NDA0MTYyYjY5ZmVmNTU4OTEzYWQzZDcwN2Y1ZTZkMzk4ZDY0ZGU4NmZlMzQ1NjlhM2RlZDc4Mjc4ZjE2NzI">slack</a> in case of any issues with installation or feature request
## Love the Project?
You can donate to support the project futher.<a class="donate-with-crypto" href="https://commerce.coinbase.com/checkout/3efb7008-27b1-4c64-934b-791e5c1a6cda"> Donate with Crypto </a>

View File

@ -1,18 +1,18 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 28
compileSdkVersion 29
defaultConfig {
applicationId "me.gilo.wc"
minSdkVersion 15
targetSdkVersion 28
applicationId "me.gilo.woodroid.app"
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
@ -33,28 +33,181 @@ android {
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility = '1.8'
targetCompatibility = '1.8'
}
dataBinding {
enabled = true
}
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
}
defaultConfig {
vectorDrawables.useSupportLibrary = true
}
// To inline the bytecode built with JVM target 1.8 into
// bytecode that is being built with JVM target 1.6. (e.g. navArgs)
}
configurations.all {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
def requested = details.requested
if (requested.group == "com.android.support") {
if (!requested.name.startsWith("multidex")) {
details.useVersion "26.+"
}
}
}
all*.exclude group: 'com.google.guava', module: 'listenablefuture'
}
ext {
arch_version = '1.1.1'
firebase_version = '11.8.0'
support_lib_version = '28.0.0'
dagger_version = '2.14.1'
play_services = '15.0.1'
roomVersion = '1.1.1'
coroutinesVersion = "1.1.1"
}
kapt {
generateStubs = true
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
implementation 'androidx.paging:paging-runtime-ktx:2.1.0'
implementation 'com.google.android.gms:play-services-auth:17.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:design:28.0.0'
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
// Support Libs
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.vectordrawable:vectordrawable-animated:1.1.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'androidx.browser:browser:1.0.0'
implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.0.0'
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.viewpager2:viewpager2:1.0.0-rc01'
//firebase stuff
implementation 'com.google.firebase:firebase-database:19.2.0'
implementation 'com.google.firebase:firebase-auth:19.1.0'
implementation 'com.google.firebase:firebase-core:17.2.1'
implementation 'com.google.firebase:firebase-firestore:21.3.0'
implementation 'com.google.firebase:firebase-storage:19.1.0'
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:20.0.1'
implementation 'com.google.android.gms:play-services-maps:17.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
implementation 'io.github.inflationx:calligraphy3:3.0.0'
implementation 'io.github.inflationx:viewpump:1.0.0'
implementation 'io.github.inflationx:viewpump:2.0.3'
implementation 'org.greenrobot:eventbus:3.1.1'
implementation 'com.squareup.picasso:picasso:2.5.2'
implementation 'de.hdodenhof:circleimageview:2.1.0'
implementation 'com.romandanylyk:pageindicatorview:0.2.0@aar'
// Android architecture components
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0-rc02"
kapt "androidx.lifecycle:lifecycle-compiler:2.2.0-rc02"
implementation 'androidx.core:core-ktx:1.1.0'
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0-rc02"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-rc02"
// Room components
implementation "androidx.room:room-runtime:2.2.1"
kapt "androidx.room:room-compiler:2.2.1"
androidTestImplementation "androidx.room:room-testing:2.2.1"
// Dagger.
implementation "com.google.dagger:dagger:2.15"
implementation "com.google.dagger:dagger-android:2.15"
implementation "com.google.dagger:dagger-android-support:2.15"
kapt "com.google.dagger:dagger-android-processor:2.15"
kapt "com.google.dagger:dagger-compiler:2.15"
// Third-party libraries
implementation 'net.danlew:android.joda:2.9.9.4'
implementation 'com.readystatesoftware.systembartint:systembartint:1.0.3'
implementation 'com.akexorcist:googledirectionlibrary:1.0.5'
//noinspection GradleDynamicVersion
implementation 'com.google.maps.android:android-maps-utils:0.5+'
implementation 'com.github.aarsy.googlemapsanimations:googlemapsanimations:1.0.5'
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.jakewharton.retrofit:retrofit1-okhttp3-client:1.1.0'
implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'io.reactivex:rxjava:1.3.0'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.room:room-runtime:2.2.2'
kapt 'androidx.room:room-compiler:2.2.2'
implementation 'org.greenrobot:eventbus:3.1.1'
implementation "com.hootsuite.android:nachos:1.1.1"
implementation 'me.relex:circleindicator:1.2.2@aar'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation project(path: ':woodroid')
implementation project(path: ':firebasecart')
implementation project(path: ':core')
implementation project(path: ':cocart')
implementation project(path: ':offlinecart')
debugImplementation 'im.dino:dbinspector:3.4.1@aar'
implementation 'org.fabiomsr:moneytextview:1.1.0'
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
}
apply plugin: 'com.google.gms.google-services'
googleServices { disableVersionCheck = true }

42
app/google-services.json Normal file
View File

@ -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.woodroid.app"
}
},
"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"
}

View File

@ -1,4 +1,4 @@
package me.gilo.wc
package me.gilo.woodroid
import android.support.test.InstrumentationRegistry
import android.support.test.runner.AndroidJUnit4

View File

@ -1,38 +1,137 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="me.gilo.wc">
xmlns:tools="http://schemas.android.com/tools"
package="me.gilo.woodroid.app">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name=".WcApp"
android:name="me.gilo.woodroid.app.WcApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true"
tools:ignore="GoogleAppIndexingWarning">
<activity
android:name=".ui.coupon.AddCouponActivity"
android:label="@string/title_activity_add_coupon"
android:name="me.gilo.woodroid.app.ui.order.OrderActivity"
android:label="@string/title_activity_order"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name=".ui.MenuActivity"
android:label="@string/title_activity_menu"
android:name="me.gilo.woodroid.app.ui.onboarding.AnonymousSignInActivity"
android:label="@string/title_activity_anonymous_sign_in"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name=".ui.coupon.CouponActivity"
android:name="me.gilo.woodroid.app.ui.checkout.CheckoutActivity"
android:label="@string/title_activity_checkout"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name="me.gilo.woodroid.app.ui.product.CartActivity"
android:label="@string/title_activity_cart"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name="me.gilo.woodroid.app.ui.customer.ProfileActivity"
android:label="@string/title_activity_profile"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name="me.gilo.woodroid.app.ui.customer.ShippingAddressActivity"
android:label="@string/title_activity_shipping_address"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name="me.gilo.woodroid.app.ui.customer.BillingAddressActivity"
android:label="@string/title_activity_billing_address"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name="me.gilo.woodroid.app.ui.customer.BasicCustomerDetailsActivity"
android:label="@string/title_activity_basic_customer_details"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name="me.gilo.woodroid.app.ui.onboarding.UserDetailsActivity"
android:label="@string/title_activity_user_details"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name="me.gilo.woodroid.app.ui.order.MyOrdersActivity"
android:label="@string/title_activity_my_orders"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name="me.gilo.woodroid.app.ui.home.HomeActivity"
android:label="@string/title_activity_home"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name=".ui.category.CategoryActivity"
android:label="@string/title_activity_category"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name="me.gilo.raison.ui.user.onboarding.SignUpActivity"
android:label="@string/title_activity_category"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name="me.gilo.raison.ui.user.onboarding.SignInActivity"
android:label="@string/title_activity_category"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name=".ui.product.NavigatioDrawerActivity"
android:label="@string/title_activity_navigatio_drawer"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name="me.gilo.woodroid.app.ui.product.ProductActivity"
android:label="@string/title_activity_product"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name="me.gilo.woodroid.app.ui.product.ProductSearchActivity"
android:label="@string/title_activity_product_search"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.SEARCH"/>
</intent-filter>
</activity>
<activity
android:name="me.gilo.woodroid.app.ui.coupon.CouponActivity"
android:label="@string/title_activity_coupon"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name=".ui.ShopActivity"
android:label="@string/title_activity_shop"
android:name="me.gilo.woodroid.app.ui.coupon.CouponsActivity"
android:label="@string/title_activity_coupons"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity android:name=".MainActivity">
<activity
android:name="me.gilo.woodroid.app.ui.coupon.AddCouponActivity"
android:label="@string/title_activity_add_coupon"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name="me.gilo.woodroid.app.ui.MenuActivity"
android:label="@string/title_activity_menu"
android:theme="@style/AppTheme.NoActionBar">
</activity>
<activity
android:name="me.gilo.woodroid.app.ui.product.ShopActivity"
android:label="@string/title_activity_shop"
android:theme="@style/AppTheme.NoActionBar">
<meta-data
android:name="android.app.searchable"
android:resource="@xml/searchable"/>
</activity>
<activity android:name="me.gilo.woodroid.app.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>

View File

@ -1,56 +0,0 @@
package me.gilo.wc
import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*
import me.gilo.wc.ui.MenuActivity
import me.gilo.woodroid.Woocommerce
import me.gilo.woodroid.models.Coupon
import me.gilo.woodroid.models.Product
import java.util.ArrayList
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class MainActivity : AppCompatActivity() {
val TAG = "MainActivity";
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
startActivity(Intent(baseContext, MenuActivity::class.java));
finish()
}
// private fun coupons() {
// val woocommerce = Woocommerce.Builder()
// .setSiteUrl("http://157.230.131.179")
// .setApiVersion("2")
// .setConsumerKey("ck_26c61abd7eeff238d87dc56585bf26cb2d1a1ec3")
// .setConsumerSecret("cs_062e8e3a7ae0ce08fdebc0c39f8f834d5e87598e")
// .build()
//
// tvText.append("\n")
// tvText.append("\n")
// tvText.append("Products")
// tvText.append("\n")
// tvText.append("\n")
//
// woocommerce.Coupon().coupons().enqueue(object : Callback<List<Coupon>> {
// override fun onResponse(call: Call<List<Coupon>>, response: Response<List<Coupon>>) {
// val coupons = response.body()
// for (coupon in coupons!!) {
// tvText.append(coupon.description + "\n")
// }
// }
//
// override fun onFailure(call: Call<List<Coupon>>, t: Throwable) {
//
// }
// })
// }
}

View File

@ -1,24 +0,0 @@
package me.gilo.wc;
import android.app.Application;
import io.github.inflationx.calligraphy3.CalligraphyConfig;
import io.github.inflationx.calligraphy3.CalligraphyInterceptor;
import io.github.inflationx.viewpump.ViewPump;
public class WcApp extends Application {
@Override
public void onCreate() {
super.onCreate();
ViewPump.init(ViewPump.builder()
.addInterceptor(new CalligraphyInterceptor(
new CalligraphyConfig.Builder()
.setDefaultFontPath("fonts/GT-America-Regular.otf")
.setFontAttrId(R.attr.fontPath)
.build()))
.build());
}
}

View File

@ -1,34 +0,0 @@
package me.gilo.wc.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import me.gilo.wc.R;
import me.gilo.wc.adapter.viewholder.CouponViewHolder;
import me.gilo.woodroid.models.Coupon;
import java.util.List;
public class CouponAdapter extends RecyclerView.Adapter<CouponViewHolder> {
private List<Coupon> coupons;
public CouponAdapter(List<Coupon> coupons) {
this.coupons = coupons;
}
@Override
public CouponViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new CouponViewHolder(parent.getContext(), LayoutInflater.from(parent.getContext()).inflate(R.layout.single_coupon_item, parent, false));
}
@Override
public void onBindViewHolder(CouponViewHolder holder, int position) {
holder.renderView(coupons.get(position));
}
@Override
public int getItemCount() {
return coupons.size() == 0 ? 0 : coupons.size();
}
}

View File

@ -1,36 +0,0 @@
package me.gilo.wc.adapter;
import android.app.Activity;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import me.gilo.wc.R;
import me.gilo.wc.adapter.viewholder.MenuViewHolder;
import java.util.HashMap;
import java.util.List;
public class MenuAdapter extends RecyclerView.Adapter<MenuViewHolder> {
private List<String> titles;
public MenuAdapter( List<String> titles) {
this.titles = titles;
}
@Override
public MenuViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new MenuViewHolder(parent.getContext(), LayoutInflater.from(parent.getContext()).inflate(R.layout.single_menu_item, parent, false));
}
@Override
public void onBindViewHolder(MenuViewHolder holder, int position) {
holder.renderView(titles.get(position));
}
@Override
public int getItemCount() {
return titles.size() == 0 ? 0 : titles.size();
}
}

View File

@ -1,35 +0,0 @@
package me.gilo.wc.adapter;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import me.gilo.wc.R;
import me.gilo.wc.adapter.viewholder.MenuViewHolder;
import me.gilo.wc.adapter.viewholder.ProductViewHolder;
import me.gilo.woodroid.models.Product;
import java.util.List;
public class ProductAdapter extends RecyclerView.Adapter<ProductViewHolder> {
private List<Product> products;
public ProductAdapter(List<Product> products) {
this.products = products;
}
@Override
public ProductViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ProductViewHolder(parent.getContext(), LayoutInflater.from(parent.getContext()).inflate(R.layout.single_product_item, parent, false));
}
@Override
public void onBindViewHolder(ProductViewHolder holder, int position) {
holder.renderView(products.get(position));
}
@Override
public int getItemCount() {
return products.size() == 0 ? 0 : products.size();
}
}

View File

@ -1,32 +0,0 @@
package me.gilo.wc.adapter.viewholder
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.text.Html
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import com.squareup.picasso.Picasso
import me.gilo.wc.R
import me.gilo.woodroid.models.Product
class ProductViewHolder(val context: Context, itemView: View) :
RecyclerView.ViewHolder(itemView) {
fun renderView(product: Product) {
val ivImage = itemView.findViewById<ImageView>(R.id.ivImage)
val tvTitle = itemView.findViewById<TextView>(R.id.tvTitle)
val tvDescription = itemView.findViewById<TextView>(R.id.tvDescription)
val tvCallToAction = itemView.findViewById<TextView>(R.id.tvCallToAction)
tvTitle.text = product.name
tvDescription.text = Html.fromHtml(product.description)
tvCallToAction.text = Html.fromHtml(product.price_html)
if (product.images != null && product.images.isNotEmpty()){
Picasso.with(context).load(product.images[0].src).into(ivImage)
}
}
}

View File

@ -1,68 +0,0 @@
package me.gilo.wc.ui
import android.os.Bundle
import android.support.v7.widget.GridLayoutManager
import kotlinx.android.synthetic.main.activity_shop.*
import kotlinx.android.synthetic.main.content_shop.*
import me.gilo.wc.R
import me.gilo.wc.adapter.ProductAdapter
import me.gilo.woodroid.Woocommerce
import me.gilo.woodroid.models.Product
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.util.*
class ShopActivity : BaseActivity() {
lateinit var adapter : ProductAdapter
lateinit var products: ArrayList<Product>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_shop)
setSupportActionBar(toolbar)
title = "Shop"
val layoutManager = GridLayoutManager(baseContext, 2)
rvShop.layoutManager = layoutManager
rvShop.isNestedScrollingEnabled = false
products = ArrayList<Product>()
adapter = ProductAdapter(products)
rvShop.adapter = adapter
products()
}
//Not best practise, but works for purposes of demo
private fun products() {
val woocommerce = Woocommerce.Builder()
.setSiteUrl("http://157.230.131.179")
.setApiVersion(Woocommerce.API_V2)
.setConsumerKey("ck_26c61abd7eeff238d87dc56585bf26cb2d1a1ec3")
.setConsumerSecret("cs_062e8e3a7ae0ce08fdebc0c39f8f834d5e87598e")
.build()
woocommerce.products.enqueue(object : Callback<List<Product>> {
override fun onResponse(call: Call<List<Product>>, response: Response<List<Product>>) {
val productsResponse = response.body()
for (product in productsResponse!!) {
products.add(product)
}
adapter.notifyDataSetChanged()
}
override fun onFailure(call: Call<List<Product>>, t: Throwable) {
}
})
}
}

View File

@ -0,0 +1,16 @@
package me.gilo.woodroid.app;
public class Config {
public static String CURRENCY_SYMBOL = "Ksh.";
public static String siteUrl = "https://gilo.me/store"; //sometimes you need to append /index.php at the end
public static String consumerKey = "ck_4ff858c97e1ed097cc24cb95593b2bcc45e835d5";
public static String consumerSecret = "cs_24865d302c443dec4a1391e5d2a438ba46e95cb6";
//sorry guys :( someday I am gonna add live and debug to have this stored somewhere
//for now commenting will do
// public static String siteUrl = "http://192.168.100.61/shop/index.php";
// public static String consumerKey = "ck_da34628a4a69128001876492b842be4cd3c76bf8";
// public static String consumerSecret = "cs_c3c70248288a60bc21a0cddc81acdc018df1632d";
}

View File

@ -0,0 +1,28 @@
package me.gilo.woodroid.app
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import android.util.Log
import com.google.firebase.auth.FirebaseAuth
import me.gilo.raison.ui.user.onboarding.SignInActivity
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.ui.home.HomeActivity
import me.gilo.woodroid.app.ui.onboarding.AnonymousSignInActivity
import me.gilo.woodroid.app.ui.order.MyOrdersActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (FirebaseAuth.getInstance().currentUser != null) {
startActivity(Intent(baseContext, HomeActivity::class.java))
} else {
startActivity(Intent(baseContext, AnonymousSignInActivity::class.java))
}
finish()
}
}

View File

@ -0,0 +1,35 @@
package me.gilo.woodroid.app
import dagger.android.AndroidInjector
import dagger.android.DaggerApplication
import io.github.inflationx.calligraphy3.CalligraphyConfig
import io.github.inflationx.calligraphy3.CalligraphyInterceptor
import io.github.inflationx.viewpump.ViewPump
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.di.DaggerAppComponent
class WcApp : DaggerApplication() {
override fun onCreate() {
super.onCreate()
ViewPump.init(
ViewPump.builder()
.addInterceptor(
CalligraphyInterceptor(
CalligraphyConfig.Builder()
.setDefaultFontPath("fonts/GT-America-Regular.otf")
.setFontAttrId(R.attr.fontPath)
.build()
)
)
.build()
)
}
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerAppComponent.create()
}
}

View File

@ -0,0 +1,27 @@
package me.gilo.woodroid.app.adapter
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.viewholder.CartViewHolder
import me.gilo.woodroid.app.models.CartLineItem
class CartAdapter(private val cartLineItems: List<CartLineItem>) : RecyclerView.Adapter<CartViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CartViewHolder {
return CartViewHolder(
parent.context,
LayoutInflater.from(parent.context).inflate(R.layout.single_cart_item, parent, false)
)
}
override fun onBindViewHolder(holder: CartViewHolder, position: Int) {
holder.renderView(cartLineItems[position])
}
override fun getItemCount(): Int {
return if (cartLineItems.isEmpty()) 0 else cartLineItems.size
}
}

View File

@ -0,0 +1,27 @@
package me.gilo.woodroid.app.adapter
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.viewholder.CategoryViewHolder
import me.gilo.woodroid.models.Category
class CategoryAdapter(private val categories: List<Category>) : RecyclerView.Adapter<CategoryViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CategoryViewHolder {
return CategoryViewHolder(
parent.context,
LayoutInflater.from(parent.context).inflate(R.layout.single_category_item, parent, false)
)
}
override fun onBindViewHolder(holder: CategoryViewHolder, position: Int) {
holder.renderView(categories[position])
}
override fun getItemCount(): Int {
return if (categories.isEmpty()) 0 else categories.size
}
}

View File

@ -0,0 +1,27 @@
package me.gilo.woodroid.app.adapter
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.viewholder.CouponViewHolder
import me.gilo.woodroid.models.Coupon
class CouponAdapter(private val coupons: List<Coupon>) : RecyclerView.Adapter<CouponViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CouponViewHolder {
return CouponViewHolder(
parent.context,
LayoutInflater.from(parent.context).inflate(R.layout.single_coupon_item, parent, false)
)
}
override fun onBindViewHolder(holder: CouponViewHolder, position: Int) {
holder.renderView(coupons[position])
}
override fun getItemCount(): Int {
return if (coupons.size == 0) 0 else coupons.size
}
}

View File

@ -0,0 +1,27 @@
package me.gilo.woodroid.app.adapter
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.viewholder.ProductViewHolder
import me.gilo.woodroid.models.Product
class HomeProductAdapter(private val products: List<Product>) : RecyclerView.Adapter<ProductViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
return ProductViewHolder(
parent.context,
LayoutInflater.from(parent.context).inflate(R.layout.single_home_product_item, parent, false)
)
}
override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
holder.renderView(products[position])
}
override fun getItemCount(): Int {
return if (products.isEmpty()) 0 else products.size
}
}

View File

@ -0,0 +1,46 @@
package me.gilo.woodroid.app.adapter
import android.content.Context
import androidx.viewpager.widget.PagerAdapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import com.squareup.picasso.Picasso
import me.gilo.woodroid.app.R
import me.gilo.woodroid.models.Image
class ImagePagerAdapter(val context: Context, private val images: List<Image>) : PagerAdapter() {
override fun instantiateItem(collection: ViewGroup, position: Int): View {
val inflater = LayoutInflater.from(context)
val layout = inflater.inflate(R.layout.single_product_image, collection, false)
val ivImage = layout.findViewById<ImageView>(R.id.ivImage)
val image = images[position]
Picasso
.with(context)
.load(image.src)
.into(ivImage)
collection.addView(layout)
return layout
}
override fun destroyItem(container: ViewGroup, position: Int, view: Any) {
container.removeView(view as View)
}
override fun getCount(): Int {
return this.images.size
}
override fun isViewFromObject(view: View, obj: Any): Boolean {
return view == obj
}
}

View File

@ -0,0 +1,27 @@
package me.gilo.woodroid.app.adapter
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.viewholder.ProductViewHolder
import me.gilo.woodroid.models.Product
class ListAdapter(private val products: List<Product>) : RecyclerView.Adapter<ProductViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
return ProductViewHolder(
parent.context,
LayoutInflater.from(parent.context).inflate(R.layout.single_product_item, parent, false)
)
}
override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
holder.renderView(products[position])
}
override fun getItemCount(): Int {
return if (products.isEmpty()) 0 else products.size
}
}

View File

@ -0,0 +1,26 @@
package me.gilo.woodroid.app.adapter
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.viewholder.MenuViewHolder
class MenuAdapter(private val titles: List<String>) : RecyclerView.Adapter<MenuViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MenuViewHolder {
return MenuViewHolder(
parent.context,
LayoutInflater.from(parent.context).inflate(R.layout.single_menu_item, parent, false)
)
}
override fun onBindViewHolder(holder: MenuViewHolder, position: Int) {
holder.renderView(titles[position])
}
override fun getItemCount(): Int {
return if (titles.isEmpty()) 0 else titles.size
}
}

View File

@ -0,0 +1,27 @@
package me.gilo.woodroid.app.adapter
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.viewholder.OrderViewHolder
import me.gilo.woodroid.models.Order
class OrderAdapter(private val orders: List<Order>) : RecyclerView.Adapter<OrderViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): OrderViewHolder {
return OrderViewHolder(
parent.context,
LayoutInflater.from(parent.context).inflate(R.layout.single_order_item, parent, false)
)
}
override fun onBindViewHolder(holder: OrderViewHolder, position: Int) {
holder.renderView(orders[position])
}
override fun getItemCount(): Int {
return if (orders.isEmpty()) 0 else orders.size
}
}

View File

@ -0,0 +1,27 @@
package me.gilo.woodroid.app.adapter
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.viewholder.ProductViewHolder
import me.gilo.woodroid.models.Product
class ProductAdapter(private val products: List<Product>) : RecyclerView.Adapter<ProductViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
return ProductViewHolder(
parent.context,
LayoutInflater.from(parent.context).inflate(R.layout.single_product_item, parent, false)
)
}
override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
holder.renderView(products[position])
}
override fun getItemCount(): Int {
return if (products.isEmpty()) 0 else products.size
}
}

View File

@ -0,0 +1,27 @@
package me.gilo.woodroid.app.adapter
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.viewholder.ProductReviewViewHolder
import me.gilo.woodroid.models.ProductReview
class ProductReviewAdapter(private val reviews: List<ProductReview>) : RecyclerView.Adapter<ProductReviewViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductReviewViewHolder {
return ProductReviewViewHolder(
parent.context,
LayoutInflater.from(parent.context).inflate(R.layout.single_product_review, parent, false)
)
}
override fun onBindViewHolder(holder: ProductReviewViewHolder, position: Int) {
holder.renderView(reviews[position])
}
override fun getItemCount(): Int {
return if (reviews.isEmpty()) 0 else reviews.size
}
}

View File

@ -0,0 +1,75 @@
package me.gilo.woodroid.app.adapter.viewholder
import android.content.Context
import android.content.Intent
import androidx.recyclerview.widget.RecyclerView
import android.text.Html
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import com.squareup.picasso.Picasso
import android.text.SpannableString
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.events.AddQuantityEvent
import me.gilo.woodroid.app.events.LessQuantityEvent
import me.gilo.woodroid.app.models.CartLineItem
import me.gilo.woodroid.app.ui.product.ProductActivity
import org.greenrobot.eventbus.EventBus
class CartViewHolder(val context: Context, itemView: View) :
RecyclerView.ViewHolder(itemView) {
fun renderView(cartLineItem: CartLineItem) {
val ivImage = itemView.findViewById<ImageView>(R.id.ivImage)
val tvTitle = itemView.findViewById<TextView>(R.id.tvTitle)
val tvDescription = itemView.findViewById<TextView>(R.id.tvDescription)
val tvPrice = itemView.findViewById<TextView>(R.id.tvPrice)
val tvAdd = itemView.findViewById<TextView>(R.id.tvAdd)
val tvQty = itemView.findViewById<TextView>(R.id.tvQty)
val tvLess = itemView.findViewById<TextView>(R.id.tvReduce)
tvQty.text = "" + cartLineItem.quantity
var product = cartLineItem.product
tvTitle.text = cartLineItem.name
tvDescription.text = Html.fromHtml(product.description)
if (product.images != null && product.images.isNotEmpty()){
Picasso.with(context).load(product.images[0].src).into(ivImage)
}
tvTitle.text = product.name
val regularPrice = product.regular_price
val salePrice = product.sale_price
if (product.isOn_sale) {
tvPrice.text = SpannableString("Ksh$salePrice")
}else{
tvPrice.text = SpannableString("Ksh$regularPrice")
}
itemView.setOnClickListener{
val intent = Intent(context, ProductActivity::class.java)
intent.putExtra("productId", cartLineItem.productId)
context.startActivity(intent)
}
tvAdd.setOnClickListener{
EventBus.getDefault().post(AddQuantityEvent(cartLineItem))
}
tvLess.setOnClickListener{
EventBus.getDefault().post(LessQuantityEvent(cartLineItem))
}
}
}

View File

@ -0,0 +1,30 @@
package me.gilo.woodroid.app.adapter.viewholder
import android.content.Context
import android.content.Intent
import androidx.recyclerview.widget.RecyclerView
import android.view.View
import android.widget.TextView
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.ui.product.ShopActivity
import me.gilo.woodroid.models.Category
class CategoryViewHolder(val context: Context, itemView: View) :
RecyclerView.ViewHolder(itemView) {
fun renderView(category: Category) {
val tvTitle = itemView.findViewById<TextView>(R.id.tvTitle)
tvTitle.text = category.name
itemView.setOnClickListener{
val intent = Intent(context, ShopActivity::class.java)
intent.putExtra("categoryId",category.id)
intent.putExtra("name",category.name)
context.startActivity(intent)
}
}
}

View File

@ -1,11 +1,13 @@
package me.gilo.wc.adapter.viewholder
package me.gilo.woodroid.app.adapter.viewholder
import android.content.Context
import android.support.v7.widget.RecyclerView
import android.content.Intent
import androidx.recyclerview.widget.RecyclerView
import android.text.Html
import android.view.View
import android.widget.TextView
import me.gilo.wc.R
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.ui.coupon.CouponActivity
import me.gilo.woodroid.models.Coupon
class CouponViewHolder(val context: Context, itemView: View) :
@ -15,8 +17,15 @@ class CouponViewHolder(val context: Context, itemView: View) :
val tvTitle = itemView.findViewById<TextView>(R.id.tvTitle)
val tvDescription = itemView.findViewById<TextView>(R.id.tvDescription)
tvTitle.text = coupon.code.toUpperCase()
tvTitle.text = coupon.code?.toUpperCase()
tvDescription.text = Html.fromHtml(coupon.description)
itemView.setOnClickListener{
val intent = Intent(context, CouponActivity::class.java)
intent.putExtra("couponId", coupon.id)
context.startActivity(intent)
}
}

View File

@ -1,13 +1,13 @@
package me.gilo.wc.adapter.viewholder;
package me.gilo.woodroid.app.adapter.viewholder;
import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView;
import android.view.View;
import android.widget.TextView;
import me.gilo.wc.R;
import me.gilo.wc.ui.coupon.CouponActivity;
import me.gilo.wc.ui.ShopActivity;
import me.gilo.woodroid.app.R;
import me.gilo.woodroid.app.ui.coupon.CouponsActivity;
import me.gilo.woodroid.app.ui.product.ShopActivity;
public class MenuViewHolder extends RecyclerView.ViewHolder {
@ -37,7 +37,7 @@ public class MenuViewHolder extends RecyclerView.ViewHolder {
context.startActivity(intent);
break;
case "Coupons":
intent = new Intent(context, CouponActivity.class);
intent = new Intent(context, CouponsActivity.class);
context.startActivity(intent);
break;
}

View File

@ -0,0 +1,51 @@
package me.gilo.woodroid.app.adapter.viewholder
import android.content.Context
import android.content.Intent
import androidx.recyclerview.widget.RecyclerView
import android.text.SpannableString
import android.view.View
import android.widget.TextView
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.ui.order.OrderActivity
import me.gilo.woodroid.app.utils.DateUtils
import me.gilo.woodroid.models.Order
class OrderViewHolder(val context: Context, itemView: View) :
RecyclerView.ViewHolder(itemView) {
fun renderView(order: Order) {
val tvTitle = itemView.findViewById<TextView>(R.id.tvTitle)
val tvDescription = itemView.findViewById<TextView>(R.id.tvDescription)
val tvPrice = itemView.findViewById<TextView>(R.id.tvPrice)
val tvStatus = itemView.findViewById<TextView>(R.id.tvStatus)
val tvDate = itemView.findViewById<TextView>(R.id.tvDate)
tvTitle.text = "#" + order.orderNumber
tvStatus.text = order.status
tvDate.text = DateUtils.getDateString_shortAndSmart(order.dateCreated)
tvPrice.text = SpannableString("Ksh${order.total}")
var description = ""
for (lineItem in order.lineItems){
description += lineItem.name + "(" + lineItem.quantity + "), "
}
tvDescription.text = description
itemView.setOnClickListener{
var intent = Intent(context, OrderActivity::class.java)
intent.putExtra("orderId", order.id)
context.startActivity(intent)
}
}
}

View File

@ -0,0 +1,38 @@
package me.gilo.woodroid.app.adapter.viewholder
import android.content.Context
import androidx.recyclerview.widget.RecyclerView
import android.text.Html
import android.view.View
import android.widget.ImageView
import android.widget.RatingBar
import android.widget.TextView
import com.squareup.picasso.Picasso
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.utils.DateUtils
import me.gilo.woodroid.models.ProductReview
class ProductReviewViewHolder(val context: Context, itemView: View) :
RecyclerView.ViewHolder(itemView) {
fun renderView(review: ProductReview) {
val tvName = itemView.findViewById<TextView>(R.id.tvName)
val tvDate = itemView.findViewById<TextView>(R.id.tvDate)
val rbRating = itemView.findViewById<RatingBar>(R.id.rbRating)
val tvMessage = itemView.findViewById<TextView>(R.id.tvMessage)
val ivImage = itemView.findViewById<ImageView>(R.id.ivImage)
tvName.text = review.reviewer
tvMessage.text = Html.fromHtml(review.review)
rbRating.rating = review.rating.toFloat()
tvDate.text = DateUtils.getDateString_shortAndSmart(review.date_created)
if (review.reviewer_avatar_urls["96"]!!.isNotEmpty()){
Picasso.with(context).load(review.reviewer_avatar_urls["96"]).into(ivImage)
}
}
}

View File

@ -0,0 +1,57 @@
package me.gilo.woodroid.app.adapter.viewholder
import android.content.Context
import android.content.Intent
import androidx.recyclerview.widget.RecyclerView
import android.text.Html
import android.view.View
import android.widget.ImageView
import android.widget.TextView
import com.squareup.picasso.Picasso
import android.text.SpannableString
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.ui.product.ProductActivity
import me.gilo.woodroid.models.Product
class ProductViewHolder(val context: Context, itemView: View) :
RecyclerView.ViewHolder(itemView) {
fun renderView(product: Product) {
val ivImage = itemView.findViewById<ImageView>(R.id.ivImage)
val tvTitle = itemView.findViewById<TextView>(R.id.tvTitle)
val tvDescription = itemView.findViewById<TextView>(R.id.tvDescription)
val tvCallToAction = itemView.findViewById<TextView>(R.id.tvCallToAction)
val tvOnSale = itemView.findViewById<TextView>(R.id.tvOnSale)
tvTitle.text = product.name
tvDescription.text = Html.fromHtml(product.description)
if (product.images != null && product.images.isNotEmpty()){
Picasso.with(context).load(product.images[0].src).into(ivImage)
}
val regularPrice = product.regular_price
val salePrice = product.sale_price
val price = SpannableString("$$regularPrice $$salePrice")
if (product.isOn_sale) {
tvCallToAction.text = Html.fromHtml(product.price_html)
tvOnSale.visibility = View.VISIBLE
}else{
tvCallToAction.text = Html.fromHtml(product.price_html)
tvOnSale.visibility = View.GONE
}
itemView.setOnClickListener{
val intent = Intent(context, ProductActivity::class.java)
intent.putExtra("productId", product.id)
context.startActivity(intent)
}
}
}

View File

@ -0,0 +1,32 @@
package me.gilo.woodroid.app.common;
import android.annotation.SuppressLint;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelProviders;
import android.content.Context;
import dagger.android.support.DaggerAppCompatActivity;
import io.github.inflationx.viewpump.ViewPumpContextWrapper;
import javax.inject.Inject;
/**
* This Activity is to be inherited by any activity to initiate the injection.
*/
@SuppressLint("Registered")
public class BaseActivity extends DaggerAppCompatActivity {
@Inject
public ViewModelProvider.Factory viewModelFactory;
public <T extends ViewModel> T getViewModel(final Class<T> cls) {
return ViewModelProviders.of(this, viewModelFactory).get(cls);
}
public void attachBaseContext(Context newBase) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase));
}
}

View File

@ -0,0 +1,25 @@
package me.gilo.woodroid.app.common;
import androidx.lifecycle.LiveData;
import androidx.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<Resource<Boolean>> implements OnCompleteListener<DocumentReference> {
public CompletionDocLiveData() {
setValue(new Resource<>(Status.LOADING));
}
@Override
public final void onComplete(@NonNull Task<DocumentReference> task) {
if (task.isSuccessful()) {
setValue(new Resource<>(true));
} else {
setValue(new Resource<>(task.getException()));
}
}
}

View File

@ -0,0 +1,21 @@
package me.gilo.woodroid.app.common
import androidx.lifecycle.LiveData
import com.google.android.gms.tasks.OnCompleteListener
import com.google.android.gms.tasks.Task
class CompletionGenericLiveData<T> : LiveData<Resource<T>>(), OnCompleteListener<T> {
init {
value = Resource(Status.LOADING)
}
override fun onComplete(task: Task<T>) {
if (task.isSuccessful) {
setValue(Resource(task.result!!))
} else {
setValue(Resource(task.exception!!))
}
}
}

View File

@ -0,0 +1,24 @@
package me.gilo.woodroid.app.common;
import androidx.lifecycle.LiveData;
import androidx.annotation.NonNull;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
public final class CompletionLiveData extends LiveData<Resource<Boolean>> implements OnCompleteListener<Void> {
public CompletionLiveData() {
setValue(new Resource<>(Status.LOADING));
}
@Override
public final void onComplete(@NonNull Task<Void> task) {
if (task.isSuccessful()) {
setValue(new Resource<>(true));
} else {
setValue(new Resource<>(task.getException()));
}
}
}

View File

@ -0,0 +1,41 @@
package me.gilo.woodroid.app.common;
import androidx.lifecycle.LiveData;
import com.google.firebase.firestore.*;
public class DocumentLiveData<T> extends LiveData<Resource<T>>
implements EventListener<DocumentSnapshot> {
private final Class<T> type;
private ListenerRegistration registration;
private final DocumentReference ref;
public DocumentLiveData(DocumentReference ref, Class<T> 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;
}
}
}

View File

@ -1,4 +1,4 @@
package me.gilo.woodroid.callback;
package me.gilo.woodroid.app.common;
public class NetworkException extends Exception{

View File

@ -0,0 +1,12 @@
package me.gilo.woodroid.app.common;
import androidx.recyclerview.widget.RecyclerView;
/**
* Created by amrro <amr.elghobary@gmail.com> on 9/15/17.
* General interface callback for handling clicks inside {@link RecyclerView}
*/
public interface OnItemClickedListener<T> {
void onClicked(T item);
}

View File

@ -0,0 +1,64 @@
package me.gilo.woodroid.app.common;
import androidx.lifecycle.LiveData;
import androidx.annotation.NonNull;
import com.google.firebase.firestore.*;
import me.gilo.woodroid.app.models.Model;
import java.util.ArrayList;
import java.util.List;
public final class QueryLiveData<T extends Model>
extends LiveData<Resource<List<T>>> implements EventListener<QuerySnapshot> {
private final Query query;
private final Class<T> type;
private ListenerRegistration registration;
public QueryLiveData(Query query, Class<T> type) {
this.query = query;
this.type = type;
setValue(new Resource<>(Status.LOADING));
}
@Override
public void onEvent(QuerySnapshot snapshots, FirebaseFirestoreException e) {
if (e != null) {
setValue(new Resource<>(e));
return;
}
setValue(new Resource<>(documentToList(snapshots)));
}
@Override
protected void onActive() {
super.onActive();
registration = query.addSnapshotListener(this);
}
@Override
protected void onInactive() {
super.onInactive();
if (registration != null) {
registration.remove();
registration = null;
}
}
@NonNull
private List<T> documentToList(QuerySnapshot snapshots) {
final List<T> retList = new ArrayList<>();
if (snapshots.isEmpty()) {
return retList;
}
for (DocumentSnapshot document : snapshots.getDocuments()) {
retList.add(document.toObject(type).withId(document.getId()));
}
return retList;
}
}

View File

@ -1,8 +1,7 @@
package me.gilo.woodroid.callback;
package me.gilo.woodroid.app.common;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.util.List;

View File

@ -1,4 +1,4 @@
package me.gilo.woodroid.callback;
package me.gilo.woodroid.app.common;
public enum Status {
EMPTY,

View File

@ -1,15 +1,15 @@
package me.gilo.woodroid.callback;
package me.gilo.woodroid.app.common;
import android.arch.lifecycle.LiveData;
import androidx.lifecycle.LiveData;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import java.io.IOException;
public class CallBackLiveData<T> extends LiveData<Resource<T>> implements Callback<T> {
public class WooLiveData<T> extends LiveData<Resource<T>> implements Callback<T> {
public CallBackLiveData() {
public WooLiveData() {
setValue(new Resource<>(Status.LOADING));
}

View File

@ -0,0 +1,65 @@
package me.gilo.woodroid.app.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.woodroid.app.MainActivity
import me.gilo.woodroid.app.ui.customer.BasicCustomerDetailsActivity
import me.gilo.woodroid.app.ui.customer.BillingAddressActivity
import me.gilo.woodroid.app.ui.customer.ProfileActivity
import me.gilo.woodroid.app.ui.customer.ShippingAddressActivity
import me.gilo.woodroid.app.ui.home.HomeActivity
import me.gilo.woodroid.app.ui.onboarding.AnonymousSignInActivity
import me.gilo.woodroid.app.ui.order.MyOrdersActivity
import me.gilo.woodroid.app.ui.order.OrderActivity
import me.gilo.woodroid.app.ui.product.CartActivity
import me.gilo.woodroid.app.ui.product.ProductActivity
import me.gilo.woodroid.app.ui.product.ShopActivity
@Module
internal abstract class ActivitiesModule {
@ContributesAndroidInjector
internal abstract fun contributesMainActivity(): MainActivity
@ContributesAndroidInjector
internal abstract fun contributesShopActivity(): ShopActivity
@ContributesAndroidInjector
internal abstract fun contributesProductActivity(): ProductActivity
@ContributesAndroidInjector
internal abstract fun contributesHomeActivity(): HomeActivity
@ContributesAndroidInjector
internal abstract fun contributesSignInActivity(): SignInActivity
@ContributesAndroidInjector
internal abstract fun contributesSignUpActivity(): SignUpActivity
@ContributesAndroidInjector
internal abstract fun contributesBasicCustomerDetailsActivity(): BasicCustomerDetailsActivity
@ContributesAndroidInjector
internal abstract fun contributesBillingAddressActivity(): BillingAddressActivity
@ContributesAndroidInjector
internal abstract fun contributesShippingAddressActivity(): ShippingAddressActivity
@ContributesAndroidInjector
internal abstract fun contributesCartActivity(): CartActivity
@ContributesAndroidInjector
internal abstract fun contributesProfileActivity(): ProfileActivity
@ContributesAndroidInjector
internal abstract fun contributesAnonymousSignInActivity(): AnonymousSignInActivity
@ContributesAndroidInjector
internal abstract fun contributesMyOrdersActivity(): MyOrdersActivity
@ContributesAndroidInjector
internal abstract fun contributesOrderActivity(): OrderActivity
}

View File

@ -0,0 +1,19 @@
package me.gilo.woodroid.app.di
import dagger.Component
import dagger.android.AndroidInjector
import dagger.android.DaggerApplication
import dagger.android.support.AndroidSupportInjectionModule
import me.gilo.woodroid.app.WcApp
import javax.inject.Singleton
@Singleton
@Component(modules = [AndroidSupportInjectionModule::class, ViewModelModule::class, FirebaseModule::class, ActivitiesModule::class, AppModule::class])
internal interface AppComponent : AndroidInjector<DaggerApplication> {
fun inject(app: WcApp)
}

View File

@ -0,0 +1,46 @@
package me.gilo.woodroid.app.di
import dagger.Module
import dagger.Provides
import me.gilo.woodroid.app.Config
import me.gilo.woodroid.app.WcApp
import me.gilo.woodroid.Woocommerce
import me.gilo.woodroid.offlinecart.repo.RoomCartRepository
import javax.inject.Singleton
@Module
class AppModule {
internal var app: WcApp? = null
internal fun AppModule(application: WcApp) {
app = application
}
@Provides
@Singleton
internal fun providesApplication(): WcApp {
return app!!
}
@Provides
@Singleton
internal fun providesWoocommerce(): Woocommerce {
return Woocommerce.Builder()
.setSiteUrl(Config.siteUrl)
.setApiVersion(Woocommerce.API_V3)
.setConsumerKey(Config.consumerKey)
.setConsumerSecret(Config.consumerSecret)
.build()
}
@Provides
@Singleton
internal fun providesRoomCartRepository(): RoomCartRepository = RoomCartRepository(app!!.baseContext)
}

View File

@ -0,0 +1,41 @@
package me.gilo.woodroid.app.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
internal class FirebaseModule {
private val firestoreInstance: FirebaseFirestore
get() = FirebaseFirestore.getInstance()
@Singleton
@Provides
fun providesFirestore(): FirebaseFirestore {
return FirebaseFirestore.getInstance()
}
@Singleton
@Provides
@Named("storage")
fun providesStorage(): StorageReference {
return FirebaseStorage.getInstance().reference
}
@Singleton
@Provides
@Named("users")
fun providesUsers(): CollectionReference {
return firestoreInstance.collection("users")
}
}

View File

@ -0,0 +1,14 @@
package me.gilo.woodroid.app.di;
import androidx.lifecycle.ViewModel;
import dagger.MapKey;
import java.lang.annotation.*;
@Documented
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@MapKey
@interface ViewModelKey {
Class<? extends ViewModel> value();
}

View File

@ -0,0 +1,55 @@
package me.gilo.woodroid.app.di
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoMap
import me.gilo.woodroid.app.utils.ViewModelFactory
import me.gilo.woodroid.app.viewmodels.*
@Module
abstract class ViewModelModule {
@Binds
@IntoMap
@ViewModelKey(UserViewModel::class)
internal abstract fun bindUserViewModel(viewModel: UserViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(ProductViewModel::class)
internal abstract fun bindProductViewModel(viewModel: ProductViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(CategoryViewModel::class)
internal abstract fun bindCategoryViewModel(viewModel: CategoryViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(CustomerViewModel::class)
internal abstract fun bindCustomerViewModel(viewModel: CustomerViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(CartViewModel::class)
internal abstract fun bindCartViewModel(viewModel: CartViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(OrderViewModel::class)
internal abstract fun bindOrderViewModel(viewModel: OrderViewModel): ViewModel
@Binds
@IntoMap
@ViewModelKey(ReviewViewModel::class)
internal abstract fun bindReviewViewModel(viewModel: ReviewViewModel): ViewModel
@Binds
internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
}

View File

@ -0,0 +1,20 @@
package me.gilo.woodroid.app.events;
import me.gilo.woodroid.app.models.CartLineItem;
public class AddQuantityEvent {
CartLineItem cartLineItem;
public AddQuantityEvent(CartLineItem cartLineItem) {
this.cartLineItem = cartLineItem;
}
public CartLineItem getCartLineItem() {
return cartLineItem;
}
public void setCartLineItem(CartLineItem cartLineItem) {
this.cartLineItem = cartLineItem;
}
}

View File

@ -0,0 +1,20 @@
package me.gilo.woodroid.app.events;
import me.gilo.woodroid.app.models.CartLineItem;
public class LessQuantityEvent {
CartLineItem cartLineItem;
public LessQuantityEvent(CartLineItem cartLineItem) {
this.cartLineItem = cartLineItem;
}
public CartLineItem getCartLineItem() {
return cartLineItem;
}
public void setCartLineItem(CartLineItem cartLineItem) {
this.cartLineItem = cartLineItem;
}
}

View File

@ -1,10 +1,14 @@
package me.gilo.woodroid.data.callbacks;
package me.gilo.woodroid.app.events;
import me.gilo.woodroid.models.Product;
public class ProductData {
private Product product;
public class ProductEvent {
Product product;
public ProductEvent(Product product) {
this.product = product;
}
public Product getProduct() {
return product;

View File

@ -0,0 +1,20 @@
package me.gilo.woodroid.app.events;
import me.gilo.woodroid.models.ProductReview;
public class ReviewEvent {
ProductReview review;
public ReviewEvent(ProductReview review) {
this.review = review;
}
public ProductReview getReview() {
return review;
}
public void setReview(ProductReview review) {
this.review = review;
}
}

View File

@ -0,0 +1,72 @@
package me.gilo.woodroid.app.models;
import me.gilo.woodroid.models.Product;
public class CartLineItem extends Model{
public float price;
public int quantity;
public int productId;
Product product;
String name;
String imageUrl;
String priceString;
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public int getProductId() {
return productId;
}
public void setProductId(int productId) {
this.productId = productId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public String getPriceString() {
return priceString;
}
public void setPriceString(String priceString) {
this.priceString = priceString;
}
public void setProduct(Product product) {
this.product = product;
}
public Product getProduct() {
return product;
}
}

View File

@ -0,0 +1,18 @@
package me.gilo.woodroid.app.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 <TKey> 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<TKey> {
@Exclude
TKey getEntityKey();
}

View File

@ -0,0 +1,37 @@
package me.gilo.woodroid.app.models;
import androidx.annotation.NonNull;
import com.google.firebase.firestore.IgnoreExtraProperties;
import com.google.firebase.firestore.ServerTimestamp;
import java.io.Serializable;
import java.util.Date;
/**
* A Base Model to be extended by other models to add ids.
*/
@IgnoreExtraProperties
public class Model implements Serializable {
public String id;
@ServerTimestamp
private Date date_created = null;
public <T extends Model> T withId(@NonNull final String id) {
this.id = id;
return (T) this;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}

View File

@ -0,0 +1,45 @@
package me.gilo.woodroid.app.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<TEntity extends Identifiable<TKey>, 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<Boolean> 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<TEntity> 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<Void> 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<Void> 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<Void> delete(TKey id);
}

View File

@ -0,0 +1,85 @@
package me.gilo.woodroid.app.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;
}
}

View File

@ -0,0 +1,77 @@
package me.gilo.woodroid.app.repo
import android.content.Context
import com.google.android.gms.tasks.Task
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.CollectionReference
import com.google.firebase.firestore.DocumentReference
import com.google.firebase.firestore.FirebaseFirestore
import me.gilo.woodroid.app.common.CompletionGenericLiveData
import me.gilo.woodroid.app.common.QueryLiveData
import me.gilo.woodroid.app.common.WooLiveData
import me.gilo.woodroid.app.models.CartLineItem
import me.gilo.woodroid.Woocommerce
import me.gilo.woodroid.core.cart.Cart
import me.gilo.woodroid.core.cart.CartItem
import me.gilo.woodroid.models.Product
import me.gilo.woodroid.offlinecart.repo.RoomCartRepository
import javax.inject.Inject
open class CartRepository @Inject
constructor() {
@Inject
lateinit var woocommerce: Woocommerce
private val cart: CollectionReference = FirebaseFirestore.getInstance()
.collection("users")
.document(FirebaseAuth.getInstance().currentUser?.uid ?: "0")
.collection("cart")
fun cart(): QueryLiveData<CartLineItem> {
return QueryLiveData(cart, CartLineItem::class.java)
}
fun deleteItem(cartLineItem: CartLineItem): CompletionGenericLiveData<Void> {
val completion = CompletionGenericLiveData<Void>()
cart.document(cartLineItem.getId()).delete().addOnCompleteListener(completion)
return completion
}
fun setQuantity(cartLineItem: CartLineItem, quantity: Int): CompletionGenericLiveData<Void> {
val completion = CompletionGenericLiveData<Void>()
cartLineItem.setQuantity(quantity)
cart.document(cartLineItem.getId()).set(cartLineItem).addOnCompleteListener(completion)
return completion
}
fun deleteItems(): CompletionGenericLiveData<Void> {
val completion = CompletionGenericLiveData<Void>()
deleteCartItems().addOnCompleteListener(completion)
return completion
}
private fun deleteCartItems(): Task<Void> {
return cart.firestore.runTransaction {
cart.get().addOnCompleteListener { task ->
if (task.isSuccessful) {
for (document in task.result!!) {
cart.document(document.id).delete()
}
} else {
}
}
null
}
}
}

View File

@ -0,0 +1,69 @@
package me.gilo.woodroid.app.repo
import me.gilo.woodroid.app.common.WooLiveData
import me.gilo.woodroid.Woocommerce
import me.gilo.woodroid.models.Category
import me.gilo.woodroid.models.filters.ProductCategoryFilter
import javax.inject.Inject
class CategoryRepository @Inject
constructor() {
@Inject
lateinit var woocommerce: Woocommerce
fun create(category: Category): WooLiveData<Category> {
val callBack = WooLiveData<Category>()
woocommerce.CategoryRepository().create(category).enqueue(callBack)
return callBack
}
fun category(id: Int): WooLiveData<Category> {
val callBack = WooLiveData<Category>()
woocommerce.CategoryRepository().category(id).enqueue(callBack)
return callBack
}
fun categories(): WooLiveData<List<Category>> {
val callBack = WooLiveData<List<Category>>()
woocommerce.CategoryRepository().categories().enqueue(callBack)
return callBack
}
fun categories(productCategoryFilter: ProductCategoryFilter): WooLiveData<List<Category>> {
val callBack = WooLiveData<List<Category>>()
woocommerce.CategoryRepository().categories(productCategoryFilter).enqueue(callBack)
return callBack
}
fun update(id: Int, category: Category): WooLiveData<Category> {
val callBack = WooLiveData<Category>()
woocommerce.CategoryRepository().update(id, category).enqueue(callBack)
return callBack
}
fun delete(id: Int): WooLiveData<Category> {
val callBack = WooLiveData<Category>()
woocommerce.CategoryRepository().delete(id).enqueue(callBack)
return callBack
}
fun delete(id: Int, force: Boolean): WooLiveData<Category> {
val callBack = WooLiveData<Category>()
woocommerce.CategoryRepository().delete(id, force).enqueue(callBack)
return callBack
}
}

View File

@ -0,0 +1,76 @@
package me.gilo.woodroid.app.repo
import com.google.firebase.auth.FirebaseAuth
import me.gilo.woodroid.app.common.WooLiveData
import me.gilo.woodroid.Woocommerce
import me.gilo.woodroid.models.Customer
import me.gilo.woodroid.models.filters.CustomerFilter
import javax.inject.Inject
class CustomerRepository @Inject
constructor() {
@Inject
lateinit var woocommerce: Woocommerce
fun create(customer: Customer): WooLiveData<Customer> {
val callBack = WooLiveData<Customer>()
woocommerce.CustomerRepository().create(customer).enqueue(callBack)
return callBack
}
fun currentCustomer(): WooLiveData<List<Customer>> {
val callBack = WooLiveData<List<Customer>>()
val customerFilter = CustomerFilter()
customerFilter.setEmail(FirebaseAuth.getInstance().currentUser!!.email!!)
woocommerce.CustomerRepository().customers(customerFilter).enqueue(callBack)
return callBack
}
fun customer(id: Int): WooLiveData<Customer> {
val callBack = WooLiveData<Customer>()
woocommerce.CustomerRepository().customer(id).enqueue(callBack)
return callBack
}
fun customers(): WooLiveData<List<Customer>> {
val callBack = WooLiveData<List<Customer>>()
woocommerce.CustomerRepository().customers().enqueue(callBack)
return callBack
}
fun customers(customerFilter: CustomerFilter): WooLiveData<List<Customer>> {
val callBack = WooLiveData<List<Customer>>()
woocommerce.CustomerRepository().customers(customerFilter).enqueue(callBack)
return callBack
}
fun update(id: Int, customer: Customer): WooLiveData<Customer> {
val callBack = WooLiveData<Customer>()
woocommerce.CustomerRepository().update(id, customer).enqueue(callBack)
return callBack
}
fun delete(id: Int): WooLiveData<Customer> {
val callBack = WooLiveData<Customer>()
woocommerce.CustomerRepository().delete(id).enqueue(callBack)
return callBack
}
fun delete(id: Int, force: Boolean): WooLiveData<Customer> {
val callBack = WooLiveData<Customer>()
woocommerce.CustomerRepository().delete(id, force).enqueue(callBack)
return callBack
}
}

View File

@ -0,0 +1,98 @@
package me.gilo.woodroid.app.repo
import android.util.Log
import com.google.android.gms.tasks.Task
import com.google.firebase.firestore.CollectionReference
import com.google.firebase.firestore.FirebaseFirestore
import me.gilo.woodroid.app.models.Identifiable
import me.gilo.woodroid.app.models.Repository
/**
* Manages data access for Firebase
*/
open class FirebaseRepository<TEntity : Identifiable<String>>(
private val entityClass: Class<TEntity>,
private val collectionName: String
) : Repository<TEntity, String> {
private val collectionReference: CollectionReference
init {
val db = FirebaseFirestore.getInstance()
this.collectionReference = db.collection(this.collectionName)
}
override fun exists(documentName: String): Task<Boolean> {
val documentReference = collectionReference.document(documentName)
Log.i(TAG, "Checking existence of '$documentName' in '$collectionName'.")
return documentReference.get().continueWith { task ->
Log.d(TAG, "Checking if '$documentName' exists in '$collectionName'.")
task.result!!.exists()
}
}
override fun get(id: String): Task<TEntity> {
val documentReference = collectionReference.document(id)
Log.i(TAG, "Getting '$id' in '$collectionName'.")
return documentReference.get().continueWith { task ->
val documentSnapshot = task.result
if (documentSnapshot!!.exists()) {
documentSnapshot.toObject(entityClass)
} else {
Log.d(TAG, "Document '$id' does not exist in '$collectionName'.")
entityClass.newInstance()
}
}
}
override fun create(entity: TEntity): Task<Void> {
val documentName = entity.entityKey
val documentReference = collectionReference.document(documentName)
Log.i(TAG, "Creating '$documentName' in '$collectionName'.")
return documentReference.set(entity).addOnFailureListener { e ->
Log.d(
TAG,
"There was an error creating '$documentName' in '$collectionName'!",
e
)
}
}
override fun update(entity: TEntity): Task<Void> {
val documentName = entity.entityKey
val documentReference = collectionReference.document(documentName)
Log.i(TAG, "Updating '$documentName' in '$collectionName'.")
return documentReference.set(entity).addOnFailureListener { e ->
Log.d(
TAG,
"There was an error updating '$documentName' in '$collectionName'.",
e
)
}
}
override fun delete(documentName: String): Task<Void> {
val documentReference = collectionReference.document(documentName)
Log.i(TAG, "Deleting '$documentName' in '$collectionName'.")
return documentReference.delete().addOnFailureListener { e ->
Log.d(
TAG,
"There was an error deleting '$documentName' in '$collectionName'.",
e
)
}
}
companion object {
private val TAG = "FirebaseRepository"
}
}

View File

@ -0,0 +1,101 @@
package me.gilo.woodroid.app.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.woodroid.app.common.CompletionGenericLiveData;
import me.gilo.woodroid.app.common.CompletionLiveData;
import me.gilo.woodroid.app.common.DocumentLiveData;
import me.gilo.woodroid.app.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<AuthResult> login(String email, String password) {
final CompletionGenericLiveData<AuthResult> completion = new CompletionGenericLiveData();
FirebaseAuth auth = FirebaseAuth.getInstance();
auth.signInWithEmailAndPassword(email, password).addOnCompleteListener(completion);
return completion;
}
public void logout() {
FirebaseAuth auth = FirebaseAuth.getInstance();
auth.signOut();
}
public CompletionGenericLiveData<AuthResult> anonymousSignIn() {
final CompletionGenericLiveData<AuthResult> completion = new CompletionGenericLiveData();
FirebaseAuth auth = FirebaseAuth.getInstance();
auth.signInAnonymously().addOnCompleteListener(completion);
return completion;
}
public CompletionGenericLiveData<AuthResult> signUp(String email, String password) {
final CompletionGenericLiveData<AuthResult> completion = new CompletionGenericLiveData();
FirebaseAuth auth = FirebaseAuth.getInstance();
auth.createUserWithEmailAndPassword(email, password).addOnCompleteListener(completion);
return completion;
}
public DocumentLiveData<User> user(final String id) {
if (id == null) {
return null;
}
final DocumentReference userRef = users.document(id);
DocumentLiveData<User> data = new DocumentLiveData<>(userRef, User.class);
userRef.addSnapshotListener(data);
return data;
}
public DocumentLiveData<User> user() {
final DocumentReference userRef = users.document(FirebaseAuth.getInstance().getCurrentUser().getUid());
DocumentLiveData<User> 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;
}
}

View File

@ -0,0 +1,79 @@
package me.gilo.woodroid.app.repo;
import me.gilo.woodroid.app.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 {
@Inject
Woocommerce woocommerce;
@Inject
public OrderRepository() {
}
public WooLiveData<Order> addToCart(int productId) {
final WooLiveData<Order> callBack = new WooLiveData();
woocommerce.OrderRepository().addToCart(productId, null).enqueue(callBack);
return callBack;
}
public WooLiveData<Order> create(Order order) {
final WooLiveData<Order> callBack = new WooLiveData();
woocommerce.OrderRepository().create(order).enqueue(callBack);
return callBack;
}
public WooLiveData<Order> order(int id) {
final WooLiveData<Order> callBack = new WooLiveData();
woocommerce.OrderRepository().order(id).enqueue(callBack);
return callBack;
}
public WooLiveData<List<Order>> orders() {
final WooLiveData<List<Order>> callBack = new WooLiveData();
woocommerce.OrderRepository().orders().enqueue(callBack);
return callBack;
}
public WooLiveData<List<Order>> orders(OrderFilter orderFilter) {
final WooLiveData<List<Order>> callBack = new WooLiveData();
woocommerce.OrderRepository().orders(orderFilter).enqueue(callBack);
return callBack;
}
public WooLiveData<Order> update(int id, Order order) {
final WooLiveData<Order> callBack = new WooLiveData();
woocommerce.OrderRepository().update(id, order).enqueue(callBack);
return callBack;
}
public WooLiveData<Order> delete(int id) {
final WooLiveData<Order> callBack = new WooLiveData();
woocommerce.OrderRepository().delete(id).enqueue(callBack);
return callBack;
}
public WooLiveData<Order> delete(int id, boolean force) {
final WooLiveData<Order> callBack = new WooLiveData();
woocommerce.OrderRepository().delete(id, force).enqueue(callBack);
return callBack;
}
}

View File

@ -0,0 +1,67 @@
package me.gilo.woodroid.app.repo;
import me.gilo.woodroid.app.common.WooLiveData;
import me.gilo.woodroid.Woocommerce;
import me.gilo.woodroid.models.Product;
import me.gilo.woodroid.models.ProductReview;
import me.gilo.woodroid.models.filters.ProductFilter;
import me.gilo.woodroid.models.filters.ProductReviewFilter;
import javax.inject.Inject;
import java.util.List;
public class ProductRepository {
@Inject
Woocommerce woocommerce;
@Inject
public ProductRepository() {
}
public WooLiveData<List<Product>> products() {
final WooLiveData<List<Product>> callBack = new WooLiveData();
woocommerce.ProductRepository().products().enqueue(callBack);
return callBack;
}
public WooLiveData<List<Product>> products(ProductFilter productFilter) {
final WooLiveData<List<Product>> callBack = new WooLiveData();
woocommerce.ProductRepository().products(productFilter).enqueue(callBack);
return callBack;
}
public WooLiveData<Product> product(int productId) {
final WooLiveData<Product> callBack = new WooLiveData();
woocommerce.ProductRepository().product(productId).enqueue(callBack);
return callBack;
}
public WooLiveData<List<ProductReview>> reviews(int productId) {
final WooLiveData<List<ProductReview>> callBack = new WooLiveData();
ProductReviewFilter filter = new ProductReviewFilter();
int[] products = {productId};
filter.setProduct(products);
woocommerce.ReviewRepository().reviews(filter).enqueue(callBack);
return callBack;
}
public WooLiveData<List<Product>> search(String term) {
final WooLiveData<List<Product>> callBack = new WooLiveData();
woocommerce.ProductRepository().search(term).enqueue(callBack);
return callBack;
}
}

View File

@ -0,0 +1,41 @@
package me.gilo.woodroid.app.repo;
import me.gilo.woodroid.app.common.WooLiveData;
import me.gilo.woodroid.Woocommerce;
import me.gilo.woodroid.models.ProductReview;
import me.gilo.woodroid.models.filters.ProductReviewFilter;
import javax.inject.Inject;
import java.util.List;
public class ReviewRepository {
@Inject
Woocommerce woocommerce;
@Inject
public ReviewRepository() {
}
public WooLiveData<List<ProductReview>> reviews(int productId) {
final WooLiveData<List<ProductReview>> callBack = new WooLiveData();
ProductReviewFilter filter = new ProductReviewFilter();
int[] products = {productId};
filter.setProduct(products);
woocommerce.ReviewRepository().reviews(filter).enqueue(callBack);
return callBack;
}
public WooLiveData<ProductReview> create(ProductReview review) {
final WooLiveData<ProductReview> callBack = new WooLiveData();
woocommerce.ReviewRepository().create(review).enqueue(callBack);
return callBack;
}
}

View File

@ -1,14 +1,24 @@
package me.gilo.wc.ui
package me.gilo.woodroid.app.ui
import android.content.Context
import android.support.v7.app.AppCompatActivity
import androidx.appcompat.app.AppCompatActivity
import io.github.inflationx.viewpump.ViewPumpContextWrapper
import me.gilo.wc.ui.state.ProgressDialogFragment
import me.gilo.woodroid.app.Config
import me.gilo.woodroid.app.ui.state.ProgressDialogFragment
import me.gilo.woodroid.Woocommerce
open class BaseActivity : AppCompatActivity() {
private lateinit var progressDialog : ProgressDialogFragment
val woocommerce = Woocommerce.Builder()
.setSiteUrl(Config.siteUrl)
.setApiVersion(Woocommerce.API_V3)
.setConsumerKey(Config.consumerKey)
.setConsumerSecret(Config.consumerSecret)
.build()
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
}
@ -20,6 +30,10 @@ open class BaseActivity : AppCompatActivity() {
progressDialog.show(manager, "progress")
}
fun showLoading() {
showLoading("This will only take a sec", "Loading")
}
fun stopShowingLoading() {
progressDialog.dismiss()
}

View File

@ -1,16 +1,12 @@
package me.gilo.wc.ui
package me.gilo.woodroid.app.ui
import android.app.Activity
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import me.gilo.wc.R
import androidx.recyclerview.widget.LinearLayoutManager
import me.gilo.woodroid.app.R
import kotlinx.android.synthetic.main.activity_menu.*
import kotlinx.android.synthetic.main.content_menu.*
import me.gilo.wc.adapter.MenuAdapter
import me.gilo.woodroid.app.adapter.MenuAdapter
import java.util.ArrayList
class MenuActivity : BaseActivity() {
@ -22,7 +18,11 @@ class MenuActivity : BaseActivity() {
title = "Menu"
val layoutManager = LinearLayoutManager(baseContext, LinearLayoutManager.VERTICAL, false)
val layoutManager = LinearLayoutManager(
baseContext,
LinearLayoutManager.VERTICAL,
false
)
rvMenu.layoutManager = layoutManager
rvMenu.isNestedScrollingEnabled = false

View File

@ -0,0 +1,129 @@
package me.gilo.woodroid.app.ui
import androidx.lifecycle.ViewModel
import android.content.Context
import android.content.Intent
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.FrameLayout
import android.widget.TextView
import android.widget.Toast
import com.google.firebase.auth.FirebaseAuth
import io.github.inflationx.viewpump.ViewPumpContextWrapper
import me.gilo.raison.ui.user.onboarding.SignInActivity
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.common.BaseActivity
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.ui.product.CartActivity
import me.gilo.woodroid.app.ui.state.ProgressDialogFragment
import me.gilo.woodroid.app.viewmodels.CartViewModel
abstract class WooDroidActivity<T : ViewModel> : BaseActivity() {
abstract var viewModel : T
private lateinit var progressDialog: ProgressDialogFragment
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
}
override fun onResume() {
super.onResume()
if(FirebaseAuth.getInstance().currentUser == null){
startActivity(Intent(baseContext, SignInActivity::class.java))
finish()
}
//cart()
}
fun showLoading() {
showLoading("Please wait", "This will only take a second")
}
fun showLoading(title: String, message: String) {
val manager = supportFragmentManager
progressDialog = ProgressDialogFragment.newInstance(title, message)
progressDialog.isCancelable = false
progressDialog.show(manager, "progress")
}
fun stopShowingLoading() {
progressDialog.dismiss()
}
fun toast(text : String){
Toast.makeText(baseContext, text, Toast.LENGTH_LONG).show()
}
var tvCartCounter : TextView? = null
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.product, menu)
val item = menu.findItem(R.id.menu_cart)
val rootView = item.actionView as FrameLayout
tvCartCounter = rootView.findViewById<TextView>(R.id.tvCart_counter)
rootView.setOnClickListener{startActivity(Intent(baseContext, CartActivity::class.java))}
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_cart -> {
true
}
else -> super.onOptionsItemSelected(item)
}
}
open fun cart() {
var viewModel = getViewModel(CartViewModel::class.java)
viewModel.cart().observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
}
Status.SUCCESS -> {
for (cartItem in response.data()){
}
if ( response.data().size == 0 && tvCartCounter != null){
tvCartCounter?.visibility = View.GONE
}else{
tvCartCounter?.visibility = View.VISIBLE
tvCartCounter?.text = response.data().size.toString()
}
}
Status.ERROR -> {
}
Status.EMPTY -> {
if ( response.data().size == 0 && tvCartCounter != null){
tvCartCounter?.visibility = View.GONE
}else{
tvCartCounter?.visibility = View.VISIBLE
tvCartCounter?.text = response.data().size.toString()
}
}
}
})
}
}

View File

@ -0,0 +1,18 @@
package me.gilo.woodroid.app.ui.checkout
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import me.gilo.woodroid.app.R
import kotlinx.android.synthetic.main.activity_checkout.*
class CheckoutActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_checkout)
setSupportActionBar(toolbar)
}
}

View File

@ -1,11 +1,10 @@
package me.gilo.wc.ui.coupon
package me.gilo.woodroid.app.ui.coupon
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_add_coupon.*
import kotlinx.android.synthetic.main.content_add_coupon.*
import me.gilo.wc.R
import me.gilo.wc.ui.BaseActivity
import me.gilo.woodroid.Woocommerce
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.ui.BaseActivity
import me.gilo.woodroid.models.Coupon
import retrofit2.Call
import retrofit2.Callback
@ -13,13 +12,20 @@ import retrofit2.Response
class AddCouponActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_coupon)
setSupportActionBar(toolbar)
title = "Add Coupon"
bCreate.setOnClickListener { submit() }
}
private fun submit() {
@ -36,14 +42,7 @@ class AddCouponActivity : BaseActivity() {
private fun createCoupon(coupon: Coupon) {
showLoading("Loading", "This won't take long")
val woocommerce = Woocommerce.Builder()
.setSiteUrl("http://157.230.131.179")
.setApiVersion(Woocommerce.API_V2)
.setConsumerKey("ck_26c61abd7eeff238d87dc56585bf26cb2d1a1ec3")
.setConsumerSecret("cs_062e8e3a7ae0ce08fdebc0c39f8f834d5e87598e")
.build()
woocommerce.Coupon().create(coupon).enqueue(object : Callback<Coupon> {
woocommerce.CouponRepository().create(coupon).enqueue(object : Callback<Coupon> {
override fun onResponse(call: Call<Coupon>, response: Response<Coupon>) {
val couponResponse = response.body()
stopShowingLoading()

View File

@ -0,0 +1,112 @@
package me.gilo.woodroid.app.ui.coupon
import android.os.Bundle
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_coupon.*
import kotlinx.android.synthetic.main.content_coupon.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.ui.BaseActivity
import me.gilo.woodroid.models.Coupon
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
class CouponActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_coupon)
setSupportActionBar(toolbar)
title = "Coupon"
val couponId = intent.getIntExtra("couponId", 0)
if (couponId != 0){
getCoupon(couponId)
bDelete.setOnClickListener{delete(couponId)}
bUpdate.setOnClickListener{
val coupon = Coupon()
coupon.id = couponId
coupon.code = etCode.text.toString()
coupon.description = etDescription.text.toString()
update(coupon)
}
}else{
Toast.makeText(baseContext, "You did not pass coupon id", Toast.LENGTH_LONG).show()
}
}
private fun getCoupon(couponId: Int) {
showLoading()
woocommerce.CouponRepository().coupon(couponId).enqueue(object : Callback<Coupon> {
override fun onResponse(call: Call<Coupon>, response: Response<Coupon>) {
val coupon = response.body()!!
etCode.setText(coupon.code?.toUpperCase())
etDescription.setText(coupon.description)
stopShowingLoading()
}
override fun onFailure(call: Call<Coupon>, t: Throwable) {
stopShowingLoading()
}
})
}
private fun delete(couponId: Int) {
showLoading()
woocommerce.CouponRepository().delete(couponId).enqueue(object : Callback<Coupon> {
override fun onResponse(call: Call<Coupon>, response: Response<Coupon>) {
if (response.isSuccessful) {
val coupon = response.body()!!
etCode.setText(coupon.code?.toUpperCase())
etDescription.setText(coupon.description)
finish()
}else{
Toast.makeText(this@CouponActivity, "" + response.code() + " : " + response.message(), Toast.LENGTH_SHORT).show()
}
stopShowingLoading()
}
override fun onFailure(call: Call<Coupon>, t: Throwable) {
stopShowingLoading()
}
})
}
private fun update(coupon: Coupon) {
showLoading()
woocommerce.CouponRepository().update(coupon.id, coupon).enqueue(object : Callback<Coupon> {
override fun onResponse(call: Call<Coupon>, response: Response<Coupon>) {
val coupon = response.body()!!
etCode.setText(coupon.code?.toUpperCase())
etDescription.setText(coupon.description)
stopShowingLoading()
finish()
}
override fun onFailure(call: Call<Coupon>, t: Throwable) {
stopShowingLoading()
}
})
}
}

View File

@ -1,21 +1,21 @@
package me.gilo.wc.ui.coupon
package me.gilo.woodroid.app.ui.coupon
import android.content.Intent
import android.os.Bundle
import android.support.v7.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_coupon.*
import kotlinx.android.synthetic.main.content_coupon.*
import me.gilo.wc.R
import me.gilo.wc.adapter.CouponAdapter
import me.gilo.wc.ui.BaseActivity
import me.gilo.woodroid.Woocommerce
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_coupons.*
import kotlinx.android.synthetic.main.content_coupons.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.CouponAdapter
import me.gilo.woodroid.app.ui.BaseActivity
import me.gilo.woodroid.models.Coupon
import me.gilo.woodroid.models.filters.CouponFilter
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.util.*
class CouponActivity : BaseActivity() {
class CouponsActivity : BaseActivity() {
lateinit var adapter : CouponAdapter
@ -23,12 +23,16 @@ class CouponActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_coupon)
setContentView(R.layout.activity_coupons)
setSupportActionBar(toolbar)
title = "Coupon"
title = "Coupons"
val layoutManager = LinearLayoutManager(baseContext, LinearLayoutManager.VERTICAL, false)
val layoutManager = LinearLayoutManager(
baseContext,
LinearLayoutManager.VERTICAL,
false
)
rvCoupons.layoutManager = layoutManager
rvCoupons.isNestedScrollingEnabled = false
@ -47,14 +51,10 @@ class CouponActivity : BaseActivity() {
//Not best practise, but works for purposes of demo
private fun coupons() {
val woocommerce = Woocommerce.Builder()
.setSiteUrl("http://157.230.131.179")
.setApiVersion(Woocommerce.API_V2)
.setConsumerKey("ck_26c61abd7eeff238d87dc56585bf26cb2d1a1ec3")
.setConsumerSecret("cs_062e8e3a7ae0ce08fdebc0c39f8f834d5e87598e")
.build()
val filter = CouponFilter()
filter.setSearch("FEB")
woocommerce.Coupon().coupons().enqueue(object : Callback<List<Coupon>> {
woocommerce.CouponRepository().coupons(filter).enqueue(object : Callback<List<Coupon>> {
override fun onResponse(call: Call<List<Coupon>>, response: Response<List<Coupon>>) {
val couponResponse = response.body()
for (coupon in couponResponse!!) {

View File

@ -0,0 +1,212 @@
package me.gilo.woodroid.app.ui.customer
import androidx.lifecycle.Observer
import android.content.Context
import android.os.Bundle
import android.widget.Toast
import io.github.inflationx.viewpump.ViewPumpContextWrapper
import kotlinx.android.synthetic.main.customer_basic_details.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.ui.WooDroidActivity
import me.gilo.woodroid.app.viewmodels.CustomerViewModel
import me.gilo.woodroid.models.Customer
import java.util.regex.Matcher
import java.util.regex.Pattern
class BasicCustomerDetailsActivity : WooDroidActivity<CustomerViewModel>() {
override lateinit var viewModel: CustomerViewModel
private val pattern = Pattern.compile(EMAIL_PATTERN)
private var matcher: Matcher? = null
lateinit var customer: Customer
var newCustomer = false
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_basic_customer_details)
viewModel = getViewModel(CustomerViewModel::class.java)
title = "Basic Details"
customer()
flSave.setOnClickListener {
if (newCustomer) {
create()
} else {
save()
}
}
}
private fun customer() {
viewModel.currentCustomer().observe(this, Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
showLoading("Retrieve customer details", "This will only take a short while")
}
Status.SUCCESS -> {
stopShowingLoading()
customer = response.data()[0]
etEmail.setText(customer.email)
etFirstName.setText(customer.firstName)
etLastName.setText(customer.lastName)
etUsername.setText(customer.username)
newCustomer = false
}
Status.ERROR -> {
stopShowingLoading()
Toast.makeText(baseContext, response.error().message.toString(), Toast.LENGTH_LONG).show()
}
Status.EMPTY -> {
stopShowingLoading()
newCustomer = true
}
}
})
}
private fun save() {
if (validates()) {
val email = etEmail.text.toString()
val firstName = etFirstName.text.toString()
val lastName = etLastName.text.toString()
val username = etUsername.text.toString()
customer.email = email
customer.firstName = firstName
customer.lastName = lastName
customer.username = username
viewModel.update(customer.id, customer).observe(this, Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
showLoading("Uploading account details", "This will only take a short while")
}
Status.SUCCESS -> {
stopShowingLoading()
finish()
}
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 create() {
if (validates()) {
val email = etEmail.text.toString()
val firstName = etFirstName.text.toString()
val lastName = etLastName.text.toString()
val username = etUsername.text.toString()
var customer = Customer()
customer.email = email
customer.firstName = firstName
customer.lastName = lastName
customer.username = username
viewModel.create(customer).observe(this, Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
showLoading("Uploading account details", "This will only take a short while")
}
Status.SUCCESS -> {
stopShowingLoading()
finish()
}
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
tilUsername.isErrorEnabled = false
var validation = true
val email = tilEmail.editText!!.text.toString()
val firstName = etFirstName.text.toString()
val lastName = etLastName.text.toString()
val username = etUsername.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
}
return validation
}
private fun validateEmail(email: String): Boolean {
matcher = pattern.matcher(email)
return matcher!!.matches()
}
companion object {
private const val EMAIL_PATTERN =
"^[a-zA-Z0-9#_~!$&'()*+,;=:.\"(),:;<>@\\[\\]\\\\]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*$"
}
}

View File

@ -0,0 +1,200 @@
package me.gilo.woodroid.app.ui.customer
import androidx.lifecycle.Observer
import android.content.Context
import android.os.Bundle
import android.widget.Toast
import com.google.firebase.auth.FirebaseAuth
import io.github.inflationx.viewpump.ViewPumpContextWrapper
import kotlinx.android.synthetic.main.customer_billing_address.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.ui.WooDroidActivity
import me.gilo.woodroid.app.viewmodels.CustomerViewModel
import me.gilo.woodroid.models.BillingAddress
import me.gilo.woodroid.models.Customer
class BillingAddressActivity : WooDroidActivity<CustomerViewModel>() {
override lateinit var viewModel : CustomerViewModel
lateinit var customer : Customer
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_billing_address)
viewModel = getViewModel(CustomerViewModel::class.java)
title = "Billing Address"
customer()
}
private fun customer() {
viewModel.currentCustomer().observe(this, Observer {
response->
when (response!!.status()){
Status.LOADING ->{
showLoading("Retrieve customer details", "This will only take a short while")
}
Status.SUCCESS ->{
stopShowingLoading()
customer = response.data()[0]
if (customer.billingAddress != null) {
etFirstName.setText(customer.billingAddress.firstName)
etLastName.setText(customer.billingAddress.firstName)
etCompany.setText(customer.billingAddress.company)
etStreetAddress.setText(customer.billingAddress.address1)
etStreetAddress2.setText(customer.billingAddress.address2)
etCity.setText(customer.billingAddress.city)
etState.setText(customer.billingAddress.state)
etZipcode.setText(customer.billingAddress.postcode)
etCountry.setText(customer.billingAddress.country)
etPhone.setText(customer.billingAddress.phone)
}else{
etFirstName.setText(customer.firstName)
etLastName.setText(customer.firstName)
}
}
Status.ERROR ->{
stopShowingLoading()
Toast.makeText(baseContext, response.error().message.toString(), Toast.LENGTH_LONG).show()
}
Status.EMPTY ->{
stopShowingLoading()
}
}
})
flSave.setOnClickListener{save()}
}
private fun save() {
if (validates()) {
val firstName = etFirstName.text.toString()
val lastName = etLastName.text.toString()
val company = etCompany.text.toString()
val streetAddress = etStreetAddress.text.toString()
val streetAddress2 = etStreetAddress2.text.toString()
val city = etCity.text.toString()
val state = etState.text.toString()
val zipcode = etZipcode.text.toString()
val country = etCountry.text.toString()
val phone = etPhone.text.toString()
customer.billingAddress = BillingAddress()
customer.billingAddress.firstName = firstName
customer.billingAddress.lastName = lastName
customer.billingAddress.company = company
customer.billingAddress.address1 = streetAddress
customer.billingAddress.address2 = streetAddress2
customer.billingAddress.city = city
customer.billingAddress.state = state
customer.billingAddress.postcode = zipcode
customer.billingAddress.country = country
customer.billingAddress.phone = phone
customer.billingAddress.email = FirebaseAuth.getInstance().currentUser!!.email!!
viewModel.update(customer.id, customer).observe(this, Observer {
response->
when (response!!.status()){
Status.LOADING ->{
showLoading("Uploading account details", "This will only take a short while")
}
Status.SUCCESS ->{
stopShowingLoading()
finish()
}
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 {
tilFirstName.isErrorEnabled = false
tilLastName.isErrorEnabled = false
tilStreetAddress.isErrorEnabled = false
tilCity.isErrorEnabled = false
tilZipcode.isErrorEnabled = false
tilCountry.isErrorEnabled = false
tilPhone.isErrorEnabled = false
var validation = true
val firstName = etFirstName.text.toString()
val lastName = etLastName.text.toString()
val streetAddress = etStreetAddress.text.toString()
val city = etCity.text.toString()
val zipcode = etZipcode.text.toString()
val country = etCountry.text.toString()
val phone = etPhone.text.toString()
if (firstName.isEmpty()) {
tilFirstName.error = "Please fill this"
validation = false
}
if (lastName.isEmpty()) {
tilLastName.error = "Please fill this"
validation = false
}
if (streetAddress.isEmpty()) {
tilStreetAddress.error = "Please fill this"
validation = false
}
if (city.isEmpty()) {
tilCity.error = "Please fill this"
validation = false
}
if (zipcode.isEmpty()) {
tilZipcode.error = "Please fill this"
validation = false
}
if (country.isEmpty()) {
tilCountry.error = "Please fill this"
validation = false
}
if (phone.isEmpty()) {
tilPhone.error = "Please fill this"
validation = false
}
return validation
}
}

View File

@ -0,0 +1,82 @@
package me.gilo.woodroid.app.ui.customer
import androidx.lifecycle.Observer
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import io.github.inflationx.viewpump.ViewPumpContextWrapper
import kotlinx.android.synthetic.main.activity_profile.*
import kotlinx.android.synthetic.main.content_profile.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.ui.WooDroidActivity
import me.gilo.woodroid.app.viewmodels.CustomerViewModel
class ProfileActivity : WooDroidActivity<CustomerViewModel>() {
override lateinit var viewModel : CustomerViewModel
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_profile)
setSupportActionBar(toolbar)
title = "Profile"
tvBasicDetailsEdit.setOnClickListener{startActivity(Intent(baseContext, BasicCustomerDetailsActivity::class.java))}
tvBillingAddressEdit.setOnClickListener{startActivity(Intent(baseContext, BillingAddressActivity::class.java))}
tvShippingAddressEdit.setOnClickListener{startActivity(Intent(baseContext, ShippingAddressActivity::class.java))}
}
override fun onResume() {
super.onResume()
viewModel = getViewModel(CustomerViewModel::class.java)
customer()
}
private fun customer() {
viewModel.currentCustomer().observe(this, Observer {
response->
when (response!!.status()){
Status.LOADING ->{
showLoading("Retrieve customer details", "This will only take a short while")
}
Status.SUCCESS ->{
stopShowingLoading()
var customer = response.data()[0]
tvBasicDetailsName.text = customer.firstName + " " + customer.lastName
tvEmail.text = "Email : " + customer.email
tvUsername.text = "Username : " + customer.username
tvShippingAddress.text = customer.shippingAddress.toString()
tvBillingAddress.text = customer.billingAddress.toString()
}
Status.ERROR ->{
stopShowingLoading()
Toast.makeText(baseContext, response.error().message.toString(), Toast.LENGTH_LONG).show()
}
Status.EMPTY ->{
stopShowingLoading()
}
}
})
}
}

View File

@ -0,0 +1,186 @@
package me.gilo.woodroid.app.ui.customer
import androidx.lifecycle.Observer
import android.content.Context
import android.os.Bundle
import android.widget.Toast
import io.github.inflationx.viewpump.ViewPumpContextWrapper
import kotlinx.android.synthetic.main.customer_shipping_address.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.ui.WooDroidActivity
import me.gilo.woodroid.app.viewmodels.CustomerViewModel
import me.gilo.woodroid.models.Customer
import me.gilo.woodroid.models.ShippingAddress
class ShippingAddressActivity : WooDroidActivity<CustomerViewModel>() {
override lateinit var viewModel : CustomerViewModel
lateinit var customer : Customer
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_shipping_address)
viewModel = getViewModel(CustomerViewModel::class.java)
title = "Billing Address"
customer()
}
private fun customer() {
viewModel.currentCustomer().observe(this, Observer {
response->
when (response!!.status()){
Status.LOADING ->{
showLoading("Retrieve customer details", "This will only take a short while")
}
Status.SUCCESS ->{
stopShowingLoading()
customer = response.data()[0]
if (customer.shippingAddress != null) {
etFirstName.setText(customer.shippingAddress.firstName)
etLastName.setText(customer.shippingAddress.firstName)
etCompany.setText(customer.shippingAddress.company)
etStreetAddress.setText(customer.shippingAddress.address1)
etStreetAddress2.setText(customer.shippingAddress.address2)
etCity.setText(customer.shippingAddress.city)
etState.setText(customer.shippingAddress.state)
etZipcode.setText(customer.shippingAddress.postcode)
etCountry.setText(customer.shippingAddress.country)
}else{
etFirstName.setText(customer.firstName)
etLastName.setText(customer.firstName)
}
}
Status.ERROR ->{
stopShowingLoading()
Toast.makeText(baseContext, response.error().message.toString(), Toast.LENGTH_LONG).show()
}
Status.EMPTY ->{
stopShowingLoading()
}
}
})
flSave.setOnClickListener{save()}
}
private fun save() {
if (validates()) {
val firstName = etFirstName.text.toString()
val lastName = etLastName.text.toString()
val company = etCompany.text.toString()
val streetAddress = etStreetAddress.text.toString()
val streetAddress2 = etStreetAddress2.text.toString()
val city = etCity.text.toString()
val state = etState.text.toString()
val zipcode = etZipcode.text.toString()
val country = etCountry.text.toString()
customer.shippingAddress = ShippingAddress()
customer.shippingAddress.firstName = firstName
customer.shippingAddress.lastName = lastName
customer.shippingAddress.company = company
customer.shippingAddress.address1 = streetAddress
customer.shippingAddress.address2 = streetAddress2
customer.shippingAddress.city = city
customer.shippingAddress.state = state
customer.shippingAddress.postcode = zipcode
customer.shippingAddress.country = country
viewModel.update(customer.id, customer).observe(this, Observer {
response->
when (response!!.status()){
Status.LOADING ->{
showLoading("Uploading account details", "This will only take a short while")
}
Status.SUCCESS ->{
stopShowingLoading()
finish()
}
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 {
tilFirstName.isErrorEnabled = false
tilLastName.isErrorEnabled = false
tilStreetAddress.isErrorEnabled = false
tilCity.isErrorEnabled = false
tilZipcode.isErrorEnabled = false
tilCountry.isErrorEnabled = false
var validation = true
val firstName = etFirstName.text.toString()
val lastName = etLastName.text.toString()
val streetAddress = etStreetAddress.text.toString()
val city = etCity.text.toString()
val zipcode = etZipcode.text.toString()
val country = etCountry.text.toString()
if (firstName.isEmpty()) {
tilFirstName.error = "Please fill this"
validation = false
}
if (lastName.isEmpty()) {
tilLastName.error = "Please fill this"
validation = false
}
if (streetAddress.isEmpty()) {
tilStreetAddress.error = "Please fill this"
validation = false
}
if (city.isEmpty()) {
tilCity.error = "Please fill this"
validation = false
}
if (zipcode.isEmpty()) {
tilZipcode.error = "Please fill this"
validation = false
}
if (country.isEmpty()) {
tilCountry.error = "Please fill this"
validation = false
}
return validation
}
}

View File

@ -0,0 +1,115 @@
package me.gilo.woodroid.app.ui.home
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.fragment_category.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.CategoryAdapter
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.viewmodels.CategoryViewModel
import me.gilo.woodroid.models.Category
import me.gilo.woodroid.models.filters.ProductCategoryFilter
import java.util.*
class CategoryFragment : Fragment() {
lateinit var viewModel: CategoryViewModel
val TAG = "CategoryFragment"
lateinit var adapter: CategoryAdapter
lateinit var categories: ArrayList<Category>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_category, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = (activity as HomeActivity).getViewModel(CategoryViewModel::class.java)
val layoutManager = LinearLayoutManager(
activity,
LinearLayoutManager.VERTICAL,
false
)
rvCategory.layoutManager = layoutManager
rvCategory.isNestedScrollingEnabled = false
categories = ArrayList()
adapter = CategoryAdapter(categories)
rvCategory.adapter = adapter
categories()
}
private fun categories() {
val filter = ProductCategoryFilter()
filter.setPer_page(50)
viewModel.categories(filter).observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
}
Status.SUCCESS -> {
categories.clear()
val categoriesResponse = response.data()
for (category in categoriesResponse) {
if (category.name != "Uncategorized") {
categories.add(category)
}
}
adapter.notifyDataSetChanged()
}
Status.ERROR -> {
}
Status.EMPTY -> {
}
}
})
}
companion object {
@JvmStatic
fun newInstance() =
CategoryFragment().apply {
arguments = Bundle().apply {
}
}
}
}

View File

@ -0,0 +1,50 @@
package me.gilo.woodroid.app.ui.home
import android.os.Bundle
import com.google.android.material.bottomnavigation.BottomNavigationView
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.activity_home.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.ui.WooDroidActivity
import me.gilo.woodroid.app.viewmodels.CartViewModel
class HomeActivity : WooDroidActivity<CartViewModel>() {
override lateinit var viewModel: CartViewModel
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
var selectedFragment: Fragment? = HomeFragment.newInstance()
when (item.itemId) {
R.id.navigation_home -> {
selectedFragment = HomeFragment.newInstance()
}
R.id.navigation_deals -> {
selectedFragment = CategoryFragment.newInstance()
}
R.id.navigation_account -> {
selectedFragment = ProfileFragment.newInstance()
}
}
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.container, selectedFragment!!)
transaction.commit()
true
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
setSupportActionBar(toolbar)
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.container, HomeFragment.newInstance())
transaction.commit()
}
}

View File

@ -0,0 +1,174 @@
package me.gilo.woodroid.app.ui.home
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.fragment_home.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.HomeProductAdapter
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.viewmodels.ProductViewModel
import me.gilo.woodroid.models.Product
import me.gilo.woodroid.models.filters.ProductFilter
import java.util.*
class HomeFragment : Fragment() {
lateinit var viewModel: ProductViewModel
val TAG = "HomeFragment"
lateinit var adapter: HomeProductAdapter
private lateinit var products: ArrayList<Product>
lateinit var hoodieAdapter: HomeProductAdapter
private lateinit var hoodieProducts: ArrayList<Product>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = (activity as HomeActivity).getViewModel(ProductViewModel::class.java)
setUpProducts()
setUpHoodies()
Picasso
.with(activity)
.load("http://157.230.131.179/wp-content/uploads/2019/01/T_6_front.jpg")
.into(ivIntro)
}
private fun setUpProducts() {
val layoutManager = LinearLayoutManager(
activity,
LinearLayoutManager.HORIZONTAL,
false
)
rvShop.layoutManager = layoutManager
rvShop.isNestedScrollingEnabled = false
products = ArrayList()
adapter = HomeProductAdapter(products)
rvShop.adapter = adapter
products()
}
private fun setUpHoodies() {
val layoutManager = LinearLayoutManager(
activity,
LinearLayoutManager.HORIZONTAL,
false
)
rvHoodies.layoutManager = layoutManager
rvHoodies.isNestedScrollingEnabled = false
hoodieProducts = ArrayList()
hoodieAdapter = HomeProductAdapter(hoodieProducts)
rvHoodies.adapter = hoodieAdapter
val filter = ProductFilter()
filter.category = 21
products(filter)
}
companion object {
@JvmStatic
fun newInstance() =
HomeFragment().apply {
arguments = Bundle().apply {
}
}
}
private fun products() {
viewModel.products().observe(viewLifecycleOwner, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
}
Status.SUCCESS -> {
products.clear()
val productsResponse = response.data()
for (product in productsResponse) {
products.add(product)
}
adapter.notifyDataSetChanged()
}
Status.ERROR -> {
}
Status.EMPTY -> {
}
}
})
}
private fun products(filter: ProductFilter) {
viewModel.products(filter).observe(viewLifecycleOwner, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
}
Status.SUCCESS -> {
hoodieProducts.clear()
val productsResponse = response.data()
for (product in productsResponse) {
hoodieProducts.add(product)
}
hoodieAdapter.notifyDataSetChanged()
}
Status.ERROR -> {
}
Status.EMPTY -> {
}
}
})
}
}

View File

@ -0,0 +1,73 @@
package me.gilo.woodroid.app.ui.home
import android.content.Intent
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.google.firebase.auth.FirebaseAuth
import kotlinx.android.synthetic.main.fragment_profile.*
import me.gilo.raison.ui.user.onboarding.SignUpActivity
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.ui.customer.ProfileActivity
import me.gilo.woodroid.app.ui.order.MyOrdersActivity
import me.gilo.woodroid.app.viewmodels.UserViewModel
class ProfileFragment : Fragment() {
lateinit var viewModel: UserViewModel
val TAG = "ProfileFragment"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
}
}
override fun onCreateView(inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?): View {
return inflater.inflate(R.layout.fragment_profile, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = (activity as HomeActivity).getViewModel(UserViewModel::class.java)
llMyProfile.setOnClickListener{
if (FirebaseAuth.getInstance().currentUser != null) {
startActivity(Intent(activity, ProfileActivity::class.java))
}else{
startActivity(Intent(activity, SignUpActivity::class.java))
}
}
llLogout.setOnClickListener{
viewModel.logout()
startActivity(Intent(activity, SignUpActivity::class.java))
}
llMyOrders.setOnClickListener{
startActivity(Intent(activity, MyOrdersActivity::class.java))
}
}
companion object {
@JvmStatic
fun newInstance() =
ProfileFragment().apply {
arguments = Bundle().apply {
}
}
}
}

View File

@ -0,0 +1,59 @@
package me.gilo.woodroid.app.ui.onboarding
import androidx.lifecycle.Observer
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import io.github.inflationx.viewpump.ViewPumpContextWrapper
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.ui.WooDroidActivity
import me.gilo.woodroid.app.ui.home.HomeActivity
import me.gilo.woodroid.app.viewmodels.UserViewModel
class AnonymousSignInActivity : WooDroidActivity<UserViewModel>() {
override lateinit var viewModel: UserViewModel
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_anonymous_sign_in)
viewModel = getViewModel(UserViewModel::class.java)
anonymousSignIn()
}
private fun anonymousSignIn() {
viewModel.anonymousSignIn().observe(this, Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
showLoading("Setting you up with an account", "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()
}
}
})
}
}

View File

@ -0,0 +1,111 @@
package me.gilo.raison.ui.user.onboarding
import androidx.lifecycle.Observer
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import io.github.inflationx.viewpump.ViewPumpContextWrapper
import kotlinx.android.synthetic.main.content_sign_in.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.ui.WooDroidActivity
import me.gilo.woodroid.app.ui.home.HomeActivity
import me.gilo.woodroid.app.ui.state.ProgressDialogFragment
import me.gilo.woodroid.app.viewmodels.UserViewModel
import java.util.regex.Matcher
import java.util.regex.Pattern
class SignInActivity : WooDroidActivity<UserViewModel>() {
override lateinit var viewModel : UserViewModel
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()
}
companion object {
private const val EMAIL_PATTERN = "^[a-zA-Z0-9#_~!$&'()*+,;=:.\"(),:;<>@\\[\\]\\\\]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*$"
}
}

View File

@ -0,0 +1,192 @@
package me.gilo.raison.ui.user.onboarding
import androidx.lifecycle.Observer
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import io.github.inflationx.viewpump.ViewPumpContextWrapper
import kotlinx.android.synthetic.main.content_sign_up.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.models.User
import me.gilo.woodroid.app.ui.WooDroidActivity
import me.gilo.woodroid.app.ui.home.HomeActivity
import me.gilo.woodroid.app.ui.state.ProgressDialogFragment
import me.gilo.woodroid.app.viewmodels.UserViewModel
import java.util.regex.Matcher
import java.util.regex.Pattern
class SignUpActivity : WooDroidActivity<UserViewModel>() {
override 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()
}
companion object {
private const val EMAIL_PATTERN = "^[a-zA-Z0-9#_~!$&'()*+,;=:.\"(),:;<>@\\[\\]\\\\]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*$"
}
}

View File

@ -0,0 +1,23 @@
package me.gilo.woodroid.app.ui.onboarding
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.snackbar.Snackbar
import me.gilo.woodroid.app.R
import kotlinx.android.synthetic.main.activity_user_details.*
class UserDetailsActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_user_details)
setSupportActionBar(toolbar)
fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
}
}

View File

@ -0,0 +1,98 @@
package me.gilo.woodroid.app.ui.order
import android.content.Intent
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import android.view.View
import kotlinx.android.synthetic.main.activity_my_orders.*
import kotlinx.android.synthetic.main.content_my_orders.*
import kotlinx.android.synthetic.main.state_empty.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.OrderAdapter
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.ui.WooDroidActivity
import me.gilo.woodroid.app.ui.home.HomeActivity
import me.gilo.woodroid.app.viewmodels.OrderViewModel
import me.gilo.woodroid.models.Order
class MyOrdersActivity : WooDroidActivity<OrderViewModel>() {
override lateinit var viewModel: OrderViewModel
var orders: ArrayList<Order> = ArrayList()
lateinit var adapter: OrderAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_my_orders)
setSupportActionBar(toolbar)
viewModel = getViewModel(OrderViewModel::class.java)
title = "My Orders"
val layoutManager = LinearLayoutManager(
baseContext,
LinearLayoutManager.VERTICAL,
false
)
rvOrders.layoutManager = layoutManager
rvOrders.isNestedScrollingEnabled = false
orders = ArrayList()
adapter = OrderAdapter(orders)
rvOrders.adapter = adapter
orders()
llEmptyState_layout.visibility = View.GONE
}
private fun showEmpty(title : String, description : String) {
tvEmptyState_title.text = title
tvEmptyState_description.text = description
llEmptyState_layout.visibility = View.VISIBLE
bEmptyState_action.setOnClickListener{
startActivity(Intent(baseContext, HomeActivity::class.java))
}
}
private fun orders() {
viewModel.orders().observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
showLoading()
}
Status.SUCCESS -> {
orders.clear()
stopShowingLoading()
for (order in response.data()) {
orders.add(order)
}
adapter.notifyDataSetChanged()
}
Status.ERROR -> {
stopShowingLoading()
}
Status.EMPTY -> {
stopShowingLoading()
showEmpty("No orders", "Seems like you haven't ordered anything yet!")
}
}
})
}
}

View File

@ -0,0 +1,169 @@
package me.gilo.woodroid.app.ui.order
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.synthetic.main.activity_order.*
import kotlinx.android.synthetic.main.content_order.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.CartAdapter
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.models.CartLineItem
import me.gilo.woodroid.app.ui.WooDroidActivity
import me.gilo.woodroid.app.viewmodels.OrderViewModel
import me.gilo.woodroid.models.Order
import me.gilo.woodroid.models.filters.ProductFilter
class OrderActivity : WooDroidActivity<OrderViewModel>() {
override lateinit var viewModel: OrderViewModel
var orders: ArrayList<Order> = ArrayList()
var cartItems: ArrayList<CartLineItem> = ArrayList()
lateinit var adapter: CartAdapter
var orderId = 0
lateinit var order : Order
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_order)
setSupportActionBar(toolbar)
viewModel = getViewModel(OrderViewModel::class.java)
title = "Orders"
orderId = intent.getIntExtra("orderId", 0)
val layoutManager = LinearLayoutManager(
baseContext,
LinearLayoutManager.VERTICAL,
false
)
rvCart.layoutManager = layoutManager
rvCart.isNestedScrollingEnabled = false
cartItems = ArrayList()
adapter = CartAdapter(cartItems)
rvCart.adapter = adapter
if(orderId != 0){
order(orderId)
}
}
private fun order(orderId : Int) {
viewModel.order(orderId).observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
showLoading()
}
Status.SUCCESS -> {
stopShowingLoading()
order = response.data()
var productIds = ArrayList<Int>()
for(orderLineItem in order.lineItems){
var cartLineItem = CartLineItem()
cartLineItem.name = orderLineItem.name
cartLineItem.price = orderLineItem.price.toFloat()
cartLineItem.quantity= orderLineItem.quantity
cartLineItem.productId = orderLineItem.productId
cartItems.add(cartLineItem)
productIds.add(orderLineItem.productId)
}
products(productIds.toIntArray())
}
Status.ERROR -> {
stopShowingLoading()
}
Status.EMPTY -> {
stopShowingLoading()
}
}
})
}
private fun products(productIds : IntArray) {
var filter = ProductFilter()
filter.setInclude(productIds)
viewModel.products(filter).observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
showLoading()
}
Status.SUCCESS -> {
stopShowingLoading()
var products = response.data()
var tempCartItems = ArrayList(cartItems)
cartItems.clear()
for (cartItem in tempCartItems){
var product = products.find { product -> product.id == cartItem.productId }
cartItem.product = product
cartItems.add(cartItem)
}
adapter.notifyDataSetChanged()
setUpPage()
}
Status.ERROR -> {
stopShowingLoading()
}
Status.EMPTY -> {
stopShowingLoading()
}
}
})
}
private fun setUpPage() {
var itemCount = cartItems.size
var total = 0
for (cartitem in cartItems){
var price = if (cartitem.product.isOn_sale) {
cartitem.product.sale_price.replace(",","").toInt()
}else{
cartitem.product.regular_price.replace(",","").toInt()
}
var qty = cartitem.quantity
total += price * qty
}
if (itemCount == 1){
tvTotalItemCountTitle.text = "Item ($itemCount)"
}else{
tvTotalItemCountTitle.text = "Items ($itemCount)"
}
tvTotalItemCost.text = "Ksh$total"
tvTotal.text = "Ksh$total"
}
}

View File

@ -0,0 +1,300 @@
package me.gilo.woodroid.app.ui.product
import androidx.lifecycle.Observer
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import android.view.View
import android.widget.Toast
import io.github.inflationx.viewpump.ViewPumpContextWrapper
import kotlinx.android.synthetic.main.activity_cart.*
import kotlinx.android.synthetic.main.content_cart.*
import kotlinx.android.synthetic.main.state_empty.*
import me.gilo.raison.ui.user.onboarding.SignUpActivity
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.CartAdapter
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.events.AddQuantityEvent
import me.gilo.woodroid.app.events.LessQuantityEvent
import me.gilo.woodroid.app.models.CartLineItem
import me.gilo.woodroid.app.ui.WooDroidActivity
import me.gilo.woodroid.app.viewmodels.CartViewModel
import me.gilo.woodroid.models.Customer
import me.gilo.woodroid.models.LineItem
import me.gilo.woodroid.models.Order
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
class CartActivity : WooDroidActivity<CartViewModel>() {
override lateinit var viewModel: CartViewModel
var cartItems: ArrayList<CartLineItem> = ArrayList()
lateinit var adapter: CartAdapter
lateinit var customer: Customer
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_cart)
setSupportActionBar(toolbar)
viewModel = getViewModel(CartViewModel::class.java)
title = "Cart"
val layoutManager = LinearLayoutManager(
baseContext,
LinearLayoutManager.VERTICAL,
false
)
rvCart.layoutManager = layoutManager
rvCart.isNestedScrollingEnabled = false
cartItems = ArrayList()
adapter = CartAdapter(cartItems)
rvCart.adapter = adapter
cart()
customer()
llEmptyState_layout.visibility = View.GONE
}
override fun cart() {
viewModel.cart().observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
showLoading()
}
Status.SUCCESS -> {
cartItems.clear()
stopShowingLoading()
for (cartItem in response.data()) {
cartItems.add(cartItem)
}
adapter.notifyDataSetChanged()
setUpPage()
}
Status.ERROR -> {
stopShowingLoading()
}
Status.EMPTY -> {
stopShowingLoading()
llEmptyState_layout.visibility = View.VISIBLE
}
}
})
}
private fun createOrder(order : Order) {
viewModel.createOrder(order).observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
showLoading()
}
Status.SUCCESS -> {
finish()
}
Status.ERROR -> {
stopShowingLoading()
toast("Something went wrong!")
}
Status.EMPTY -> {
stopShowingLoading()
}
}
})
}
private fun setUpPage() {
var itemCount = cartItems.size
var total = 0
for (cartitem in cartItems){
var price = if (cartitem.product.isOn_sale) {
cartitem.product.sale_price.replace(",","").toInt()
}else{
cartitem.product.regular_price.replace(",","").toInt()
}
var qty = cartitem.quantity
total += price * qty
}
if (itemCount == 1){
tvTotalItemCountTitle.text = "Item ($itemCount)"
}else{
tvTotalItemCountTitle.text = "Items ($itemCount)"
}
tvTotalItemCost.text = "Ksh$total"
tvTotal.text = "Ksh$total"
flSave.setOnClickListener{
prepOrder()
}
}
private fun prepOrder() {
var order = Order()
var lineitems = ArrayList<LineItem>()
for (cartitem in cartItems){
var lineItem = LineItem()
lineItem.price = cartitem.getPrice().toString()
lineItem.productId = cartitem.productId
lineItem.quantity = cartitem.quantity
lineitems.add(lineItem)
}
order.lineItems = lineitems
order.billingAddress = customer.billingAddress
order.shippingAddress = customer.shippingAddress
order.customer = customer
createOrder(order)
}
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
}
override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: AddQuantityEvent) {
var cartLineItem = event.cartLineItem
var quantity = cartLineItem.quantity + 1
updateCart(cartLineItem, quantity)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: LessQuantityEvent) {
var cartLineItem = event.cartLineItem
var quantity = cartLineItem.quantity - 1
if (quantity == 0) {
delete(cartLineItem)
} else {
updateCart(cartLineItem, quantity)
}
}
private fun updateCart(cartLineItem: CartLineItem, quantity: Int) {
viewModel.setQuantity(cartLineItem, quantity).observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
}
Status.SUCCESS -> {
}
Status.ERROR -> {
}
Status.EMPTY -> {
}
}
})
}
private fun delete(cartLineItem: CartLineItem) {
viewModel.deleteItem(cartLineItem).observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
}
Status.SUCCESS -> {
}
Status.ERROR -> {
}
Status.EMPTY -> {
}
}
})
}
private fun customer() {
viewModel.currentCustomer().observe(this, Observer {
response->
when (response!!.status()){
Status.LOADING ->{
}
Status.SUCCESS ->{
customer = response.data()[0]
}
Status.ERROR ->{
Toast.makeText(baseContext, response.error().message.toString(), Toast.LENGTH_LONG).show()
}
Status.EMPTY ->{
startActivity(Intent(baseContext, SignUpActivity::class.java))
finish()
}
}
})
}
}

View File

@ -0,0 +1,256 @@
package me.gilo.woodroid.app.ui.product
import android.content.Intent
import android.content.res.ColorStateList
import android.os.Bundle
import android.text.Html
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.FrameLayout
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.lifecycle.Observer
import kotlinx.android.synthetic.main.activity_product.*
import kotlinx.android.synthetic.main.content_product.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.ImagePagerAdapter
import me.gilo.woodroid.app.common.BaseActivity
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.events.ProductEvent
import me.gilo.woodroid.app.models.CartLineItem
import me.gilo.woodroid.app.ui.state.ProgressDialogFragment
import me.gilo.woodroid.app.utils.AppUtils
import me.gilo.woodroid.app.viewmodels.ProductViewModel
import me.gilo.woodroid.core.cart.CartItem
import me.gilo.woodroid.models.Product
import me.gilo.woodroid.offlinecart.repo.RoomCartRepository
import org.greenrobot.eventbus.EventBus
class ProductActivity : BaseActivity() {
var productInCart = false;
lateinit var currentCartItem : CartLineItem
lateinit var viewModel: ProductViewModel
val TAG = this::getLocalClassName.toString()
var related_ids : IntArray = intArrayOf()
var cartItems : ArrayList<CartLineItem> = ArrayList()
var productId = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_product)
setSupportActionBar(toolbar)
viewModel = getViewModel(ProductViewModel::class.java)
title = "Product"
productId = intent.getIntExtra("productId", 0)
if (productId != 0){
product(productId)
checkIfExistsInCart(productId)
}
cart()
}
private fun checkIfExistsInCart(productId: Int) {
RoomCartRepository(baseContext).exists(productId).observe(this, Observer {productExists ->
if (productExists) {
fab.backgroundTintList = ColorStateList.valueOf(resources.getColor(R.color.carnation_red))
fab.setImageDrawable(ContextCompat.getDrawable(baseContext, R.drawable.baseline_remove_shopping_cart_24))
}else{
fab.backgroundTintList = ColorStateList.valueOf(resources.getColor(R.color.colorPrimary))
fab.setImageDrawable(ContextCompat.getDrawable(baseContext, R.drawable.baseline_add_shopping_cart_24))
}
productInCart = productExists
})
}
private fun addToCart(product: Product) {
RoomCartRepository(baseContext).addToCart(
CartItem(
productId = product.id,
productImage = product.getFeatureImage(),
quantity = 1,
productPrice = product.price
)
)
}
private fun removeFromCart(cartLineItem: CartLineItem) {
}
private fun product(productId : Int) {
viewModel.product(productId).observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
flLoading.visibility = View.VISIBLE
}
Status.SUCCESS -> {
val product = response.data()
setUpPage(product)
//similarProducts(product)
flLoading.visibility = View.GONE
EventBus.getDefault().post(ProductEvent(product))
}
Status.ERROR -> {
flLoading.visibility = View.GONE
}
Status.EMPTY -> {
}
}
})
}
private fun cart() {
viewModel.cart().observe(this, Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
}
Status.SUCCESS -> {
cartItems.clear()
productInCart = false
for (cartItem in response.data()){
cartItems.add(cartItem)
if(cartItem.productId == productId){
productInCart = true
currentCartItem = cartItem
}
}
if (cartItems.size == 0 && tvCartCounter != null){
tvCartCounter?.visibility = View.GONE
}else{
tvCartCounter?.visibility = View.VISIBLE
tvCartCounter?.text = cartItems.size.toString()
}
}
Status.ERROR -> {
}
Status.EMPTY -> {
productInCart = false
cartItems.clear()
if (cartItems.size == 0 && tvCartCounter != null){
tvCartCounter?.visibility = View.GONE
}else{
tvCartCounter?.visibility = View.VISIBLE
tvCartCounter?.text = cartItems.size.toString()
}
}
}
})
}
private fun setUpPage(product: Product) {
tvTitle.text = product.name
tvDescription.text = Html.fromHtml(product.description)
if (product.images != null && product.images.isNotEmpty()){
vpImages.offscreenPageLimit = product.images.size
vpImages.adapter = ImagePagerAdapter(baseContext, product.images)
indicator.setViewPager(vpImages)
}
if (product.isOn_sale) {
tvCallToAction.text = Html.fromHtml(product.price_html)
tvOnSale.visibility = View.VISIBLE
}else{
tvCallToAction.text = Html.fromHtml(product.price_html).trim()
tvOnSale.visibility = View.GONE
}
fab.setOnClickListener{
if (productInCart){
removeFromCart(currentCartItem)
}else {
addToCart(product)
}
}
}
fun toast(text : String){
Toast.makeText(baseContext, text, Toast.LENGTH_LONG).show()
}
private lateinit var progressDialog: ProgressDialogFragment
fun showLoading(title: String, message: String) {
val manager = supportFragmentManager
progressDialog = ProgressDialogFragment.newInstance(title, message)
progressDialog.isCancelable = false
progressDialog.show(manager, "progress")
}
fun showLoading() {
showLoading("This will only take a sec", "Loading")
}
fun stopShowingLoading() {
progressDialog.dismiss()
}
var tvCartCounter : TextView? = null
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.product, menu)
val item = menu.findItem(R.id.menu_cart)
val rootView = item.actionView as FrameLayout
tvCartCounter = rootView.findViewById<TextView>(R.id.tvCart_counter)
rootView.setOnClickListener{startActivity(Intent(baseContext, CartActivity::class.java))}
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_cart -> {
true
}
else -> super.onOptionsItemSelected(item)
}
}
}

View File

@ -0,0 +1,137 @@
package me.gilo.woodroid.app.ui.product
import android.app.SearchManager
import android.content.Context
import android.content.Intent
import android.os.Bundle
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.recyclerview.widget.GridLayoutManager
import android.widget.Toast
import io.github.inflationx.viewpump.ViewPumpContextWrapper
import me.gilo.woodroid.app.R
import kotlinx.android.synthetic.main.activity_product_search.*
import kotlinx.android.synthetic.main.content_shop.*
import me.gilo.woodroid.app.adapter.ProductAdapter
import me.gilo.woodroid.app.common.BaseActivity
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.ui.state.ProgressDialogFragment
import me.gilo.woodroid.app.viewmodels.ProductViewModel
import me.gilo.woodroid.models.Product
import org.json.JSONObject
import java.util.ArrayList
class ProductSearchActivity : BaseActivity() {
lateinit var adapter: ProductAdapter
lateinit var products: ArrayList<Product>
lateinit var toggle: ActionBarDrawerToggle
lateinit var viewModel: ProductViewModel
val TAG = this::getLocalClassName
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_product_search)
setSupportActionBar(toolbar)
viewModel = getViewModel(ProductViewModel::class.java)
title = "Search"
val layoutManager =
GridLayoutManager(baseContext, 2)
rvShop.layoutManager = layoutManager
rvShop.isNestedScrollingEnabled = false
products = ArrayList()
adapter = ProductAdapter(products)
rvShop.adapter = adapter
handleIntent(intent)
}
override fun onNewIntent(intent: Intent) {
handleIntent(intent)
}
private fun handleIntent(intent: Intent) {
if (Intent.ACTION_SEARCH == intent.action) {
val query = intent.getStringExtra(SearchManager.QUERY)
search(query)
}
}
private fun search(query : String) {
viewModel.search(query).observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
showLoading("Performing search", "This will only take a short while")
}
Status.SUCCESS -> {
stopShowingLoading()
val productsResponse = response.data()
for (product in productsResponse) {
products.add(product)
}
adapter.notifyDataSetChanged()
}
Status.ERROR -> {
stopShowingLoading()
var message: String
var loginError = JSONObject(response.error().message)
if (loginError.has("status_message")) {
message = loginError.getString("status_message")
} else {
message = response.error().message.toString()
}
Toast.makeText(baseContext, message, Toast.LENGTH_LONG).show()
}
Status.EMPTY -> {
stopShowingLoading()
}
}
})
}
private lateinit var progressDialog: ProgressDialogFragment
fun showLoading(title: String, message: String) {
val manager = supportFragmentManager
progressDialog = ProgressDialogFragment.newInstance(title, message)
progressDialog.isCancelable = false
progressDialog.show(manager, "progress")
}
fun showLoading() {
showLoading("This will only take a sec", "Loading")
}
fun stopShowingLoading() {
progressDialog.dismiss()
}
}

View File

@ -0,0 +1,255 @@
package me.gilo.woodroid.app.ui.product
import android.content.Context
import android.os.Bundle
import androidx.core.view.GravityCompat
import androidx.recyclerview.widget.GridLayoutManager
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import io.github.inflationx.viewpump.ViewPumpContextWrapper
import kotlinx.android.synthetic.main.activity_shop.*
import kotlinx.android.synthetic.main.content_shop.*
import kotlinx.android.synthetic.main.drawer_filter.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.ProductAdapter
import me.gilo.woodroid.app.common.BaseActivity
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.ui.state.ProgressDialogFragment
import me.gilo.woodroid.app.utils.AppUtils
import me.gilo.woodroid.app.viewmodels.ProductViewModel
import me.gilo.woodroid.models.Product
import me.gilo.woodroid.models.filters.ProductFilter
import java.util.*
class ShopActivity : BaseActivity() {
lateinit var adapter: ProductAdapter
var products : ArrayList<Product> = ArrayList()
private lateinit var viewModel: ProductViewModel
val TAG = this::getLocalClassName
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_shop)
setSupportActionBar(toolbar)
viewModel = getViewModel(ProductViewModel::class.java)
title = "Shop"
setUpPage()
cart()
bFilter.setOnClickListener{filter()}
if(intent.hasExtra("categoryId")){
val filter = ProductFilter()
filter.category = intent.getIntExtra("categoryId", 0)
products(filter)
title = intent.getStringExtra("name")
}else{
products()
}
}
private fun setUpPage() {
val layoutManager =
GridLayoutManager(baseContext, 2)
rvShop.layoutManager = layoutManager
rvShop.isNestedScrollingEnabled = false
products = ArrayList()
adapter = ProductAdapter(products)
rvShop.adapter = adapter
}
private fun filter() {
val filter = ProductFilter()
if (etSearch.text.toString().isNotEmpty()){
filter.setSearch(etSearch.text.toString())
}
if (etMinPrice.text.toString().isNotEmpty()){
filter.min_price = etMinPrice.text.toString()
}
if (etMaxPrice.text.toString().isNotEmpty()){
filter.max_price = etMaxPrice.text.toString()
}
if (cbFeatured.isChecked){
filter.isFeatured = true
}
if (cbOnSale.isChecked){
filter.isOn_sale = true
}
toggleDrawer()
products(filter)
}
private fun products(filter: ProductFilter) {
viewModel.products(filter).observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
}
Status.SUCCESS -> {
products.clear()
val productsResponse = response.data()
for (product in productsResponse) {
products.add(product)
}
adapter.notifyDataSetChanged()
}
Status.ERROR -> {
}
Status.EMPTY -> {
}
}
})
}
private fun cart() {
val cartKey = AppUtils(baseContext).cartSession
}
private fun search(query : String) {
viewModel.search(query).observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
}
Status.SUCCESS -> {
products.clear()
val productsResponse = response.data()
for (product in productsResponse) {
products.add(product)
}
adapter.notifyDataSetChanged()
}
Status.ERROR -> {
}
Status.EMPTY -> {
}
}
})
}
private fun products() {
viewModel.products().observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
}
Status.SUCCESS -> {
products.clear()
val productsResponse = response.data()
for (product in productsResponse) {
products.add(product)
}
adapter.notifyDataSetChanged()
}
Status.ERROR -> {
}
Status.EMPTY -> {
}
}
})
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.products, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.action_filter -> {
toggleDrawer()
true
}
R.id.action_search -> {
toggleDrawer()
true
}
else -> super.onOptionsItemSelected(item)
}
}
private fun toast(text: String) {
Toast.makeText(baseContext, text, Toast.LENGTH_LONG).show()
}
private fun toggleDrawer() {
if (drawer_layout.isDrawerOpen(GravityCompat.END)) {
drawer_layout.closeDrawer(GravityCompat.END)
} else {
drawer_layout.openDrawer(GravityCompat.END)
}
}
private lateinit var progressDialog: ProgressDialogFragment
fun showLoading(title: String, message: String) {
val manager = supportFragmentManager
progressDialog = ProgressDialogFragment.newInstance(title, message)
progressDialog.isCancelable = false
progressDialog.show(manager, "progress")
}
fun showLoading() {
showLoading("This will only take a sec", "Loading")
}
fun stopShowingLoading() {
progressDialog.dismiss()
}
}

View File

@ -0,0 +1,78 @@
package me.gilo.woodroid.app.ui.product.section
import android.os.Bundle
import androidx.fragment.app.DialogFragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.section_add_a_review.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.events.ReviewEvent
import me.gilo.woodroid.models.ProductReview
import org.greenrobot.eventbus.EventBus
class AddAReviewDialogFragment : DialogFragment() {
var productId = 0
private val ARG_PRODUCT_ID = "productId"
init {
val args = Bundle()
args.putInt(ARG_PRODUCT_ID, productId)
arguments = args
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.section_add_a_review, container)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
productId = arguments!!.getInt(ARG_PRODUCT_ID)
llSave.setOnClickListener{save()}
}
private fun save() {
var productReview = ProductReview()
var review = etReview.text.toString()
var rating = rbRating.rating
var email = etEmail.text.toString()
var name = etName.text.toString()
productReview.product_id = productId
productReview.rating = rating.toInt()
productReview.review = review
productReview.reviewer = name
productReview.reviewer_email = email
productReview.isVerified = true
EventBus.getDefault().post(ReviewEvent(productReview))
dismiss()
}
companion object {
fun newInstance(productId : Int): AddAReviewDialogFragment {
val fragment = AddAReviewDialogFragment()
val args = Bundle()
args.putInt("productId", productId)
fragment.arguments = args
return fragment
}
}
}

View File

@ -0,0 +1,169 @@
package me.gilo.woodroid.app.ui.product.section
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.section_product_reviews.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.ProductReviewAdapter
import me.gilo.woodroid.app.common.BaseActivity
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.events.ReviewEvent
import me.gilo.woodroid.app.ui.product.ProductActivity
import me.gilo.woodroid.app.viewmodels.ReviewViewModel
import me.gilo.woodroid.models.ProductReview
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.*
class ProductReviewsFragment : Fragment() {
lateinit var viewModel: ReviewViewModel
val TAG = "ProductReviewsFragment"
var productId = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.section_product_reviews, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = (activity as BaseActivity).getViewModel(ReviewViewModel::class.java)
productId = (activity as ProductActivity).intent.getIntExtra("productId", 0)
reviews(productId)
tvAddAReview.setOnClickListener{addAReviewDialog()}
}
private fun reviews(productId : Int) {
val layoutManager = LinearLayoutManager(
activity,
LinearLayoutManager.VERTICAL,
false
)
rvReviews.layoutManager = layoutManager
rvReviews.isNestedScrollingEnabled = false
var reviews = ArrayList<ProductReview>()
var productReviewAdapter = ProductReviewAdapter(reviews)
rvReviews.adapter = productReviewAdapter
viewModel.reviews(productId).observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
}
Status.SUCCESS -> {
reviews.clear()
val reviewsResponse = response.data()
for (review in reviewsResponse) {
reviews.add(review)
}
productReviewAdapter.notifyDataSetChanged()
}
Status.ERROR -> {
Log.d("Error", response.error().message)
}
Status.EMPTY -> {
}
}
})
}
companion object {
@JvmStatic
fun newInstance() =
ProductReviewsFragment().apply {
arguments = Bundle().apply {
}
}
}
lateinit var addAReviewFragment: AddAReviewDialogFragment
private fun addAReviewDialog() {
val manager = childFragmentManager
addAReviewFragment =
AddAReviewDialogFragment.newInstance(productId)
addAReviewFragment.isCancelable = true
addAReviewFragment.show(manager, "add Review")
}
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
}
override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: ReviewEvent) {
save(event.review)
}
private fun save(review: ProductReview) {
viewModel.create(review).observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
}
Status.SUCCESS -> {
val reviewsResponse = response.data()
reviews(productId)
}
Status.ERROR -> {
Log.d("Error", response.error().message)
}
Status.EMPTY -> {
}
}
})
}
}

View File

@ -0,0 +1,132 @@
package me.gilo.woodroid.app.ui.product.section
import android.os.Bundle
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.LinearLayoutManager
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.section_related_products.*
import me.gilo.woodroid.app.R
import me.gilo.woodroid.app.adapter.HomeProductAdapter
import me.gilo.woodroid.app.common.BaseActivity
import me.gilo.woodroid.app.common.Status
import me.gilo.woodroid.app.events.ProductEvent
import me.gilo.woodroid.app.viewmodels.ProductViewModel
import me.gilo.woodroid.models.Product
import me.gilo.woodroid.models.filters.ProductFilter
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.util.*
class RelatedProductsFragment : Fragment() {
lateinit var viewModel: ProductViewModel
val TAG = "RelatedProductFragment"
lateinit var adapter: HomeProductAdapter
private lateinit var products: ArrayList<Product>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
}
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.section_related_products, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel = (activity as BaseActivity).getViewModel(ProductViewModel::class.java)
//similarProducts()
}
private fun similarProducts(product: Product) {
val layoutManager = LinearLayoutManager(
activity,
LinearLayoutManager.HORIZONTAL,
false
)
rvShop.layoutManager = layoutManager
rvShop.isNestedScrollingEnabled = false
products = ArrayList()
adapter = HomeProductAdapter(products)
rvShop.adapter = adapter
val filter = ProductFilter()
filter.setInclude(product.related_ids.toIntArray())
viewModel.products(filter).observe(this, androidx.lifecycle.Observer { response ->
when (response!!.status()) {
Status.LOADING -> {
}
Status.SUCCESS -> {
products.clear()
val productsResponse = response.data()
for (product in productsResponse) {
products.add(product)
}
adapter.notifyDataSetChanged()
}
Status.ERROR -> {
}
Status.EMPTY -> {
}
}
})
}
override fun onStart() {
super.onStart()
EventBus.getDefault().register(this)
}
override fun onStop() {
super.onStop()
EventBus.getDefault().unregister(this)
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onMessageEvent(event: ProductEvent) {
similarProducts(event.product)
}
companion object {
@JvmStatic
fun newInstance() =
RelatedProductsFragment().apply {
arguments = Bundle().apply {
}
}
}
}

View File

@ -1,12 +1,12 @@
package me.gilo.wc.ui.state;
package me.gilo.woodroid.app.ui.state;
import android.os.Bundle;
import android.support.v4.app.DialogFragment;
import androidx.fragment.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import me.gilo.wc.R;
import me.gilo.woodroid.app.R;
public class ProgressDialogFragment extends DialogFragment {

Some files were not shown because too many files have changed in this diff Show More