Added product reviews section

This commit is contained in:
Gilbert Kimutai 2019-03-20 06:34:08 +03:00
parent 82c76bb970
commit 37e71535b7
15 changed files with 402 additions and 21 deletions

View File

@ -12,6 +12,7 @@ android {
targetSdkVersion 28 targetSdkVersion 28
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
multiDexEnabled true
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {
@ -87,5 +88,7 @@ dependencies {
implementation 'me.relex:circleindicator:1.2.2@aar' implementation 'me.relex:circleindicator:1.2.2@aar'
implementation 'net.danlew:android.joda:2.9.9.4'
} }

View File

@ -4,6 +4,7 @@ import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.support.v7.app.AppCompatActivity import android.support.v7.app.AppCompatActivity
import me.gilo.wc.ui.home.HomeActivity import me.gilo.wc.ui.home.HomeActivity
import me.gilo.wc.ui.product.ProductActivity
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
@ -15,10 +16,10 @@ class MainActivity : AppCompatActivity() {
startActivity(Intent(baseContext, HomeActivity::class.java)) startActivity(Intent(baseContext, HomeActivity::class.java))
// val intent = Intent(baseContext, ProductActivity::class.java) val intent = Intent(baseContext, ProductActivity::class.java)
// intent.putExtra("productId", 63) intent.putExtra("productId", 63)
//
// startActivity(intent) startActivity(intent)
finish() finish()

View File

@ -0,0 +1,36 @@
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.ProductReviewViewHolder;
import me.gilo.wc.adapter.viewholder.ProductViewHolder;
import me.gilo.woodroid.models.Product;
import me.gilo.woodroid.models.ProductReview;
import java.util.List;
public class ProductReviewAdapter extends RecyclerView.Adapter<ProductReviewViewHolder> {
private List<ProductReview> reviews;
public ProductReviewAdapter(List<ProductReview> reviews) {
this.reviews = reviews;
}
@Override
public ProductReviewViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new ProductReviewViewHolder(parent.getContext(), LayoutInflater.from(parent.getContext()).inflate(R.layout.single_product_review, parent, false));
}
@Override
public void onBindViewHolder(ProductReviewViewHolder holder, int position) {
holder.renderView(reviews.get(position));
}
@Override
public int getItemCount() {
return reviews.size() == 0 ? 0 : reviews.size();
}
}

View File

@ -0,0 +1,34 @@
package me.gilo.wc.adapter.viewholder
import android.content.Context
import android.content.Intent
import android.support.v7.widget.RecyclerView
import android.text.Html
import android.view.View
import android.widget.RatingBar
import android.widget.TextView
import me.gilo.wc.R
import me.gilo.wc.ui.product.ShopActivity
import me.gilo.wc.utils.DateUtils
import me.gilo.woodroid.models.Category
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)
tvName.text = review.reviewer
tvMessage.text = Html.fromHtml(review.review)
rbRating.rating = review.rating.toFloat()
tvDate.text = DateUtils.getDateString_shortAndSmart(review.date_created)
}
}

View File

@ -4,7 +4,9 @@ package me.gilo.wc.repo;
import me.gilo.wc.common.WooLiveData; import me.gilo.wc.common.WooLiveData;
import me.gilo.woodroid.Woocommerce; import me.gilo.woodroid.Woocommerce;
import me.gilo.woodroid.models.Product; 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.ProductFilter;
import me.gilo.woodroid.models.filters.ProductReviewFilter;
import javax.inject.Inject; import javax.inject.Inject;
import java.util.List; import java.util.List;
@ -41,6 +43,19 @@ public class ProductRepository {
} }
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) { public WooLiveData<List<Product>> search(String term) {
final WooLiveData<List<Product>> callBack = new WooLiveData(); final WooLiveData<List<Product>> callBack = new WooLiveData();

View File

@ -10,11 +10,13 @@ import kotlinx.android.synthetic.main.content_product.*
import me.gilo.wc.R import me.gilo.wc.R
import me.gilo.wc.adapter.HomeProductAdapter import me.gilo.wc.adapter.HomeProductAdapter
import me.gilo.wc.adapter.ImagePagerAdapter import me.gilo.wc.adapter.ImagePagerAdapter
import me.gilo.wc.adapter.ProductReviewAdapter
import me.gilo.wc.common.BaseActivity import me.gilo.wc.common.BaseActivity
import me.gilo.wc.common.Status import me.gilo.wc.common.Status
import me.gilo.wc.ui.state.ProgressDialogFragment import me.gilo.wc.ui.state.ProgressDialogFragment
import me.gilo.wc.viewmodels.ProductViewModel import me.gilo.wc.viewmodels.ProductViewModel
import me.gilo.woodroid.models.Product 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.ProductFilter
import java.util.ArrayList import java.util.ArrayList
@ -38,6 +40,7 @@ class ProductActivity : BaseActivity() {
if (productId != 0){ if (productId != 0){
product(productId) product(productId)
reviews(productId)
} }
@ -63,10 +66,6 @@ class ProductActivity : BaseActivity() {
val filter = ProductFilter() val filter = ProductFilter()
filter.include = product.related_ids.toIntArray() filter.include = product.related_ids.toIntArray()
for (id in product.related_ids){
Log.d("Related ids", "" + id)
}
viewModel.products(filter).observe(this, android.arch.lifecycle.Observer { response -> viewModel.products(filter).observe(this, android.arch.lifecycle.Observer { response ->
when (response!!.status()) { when (response!!.status()) {
Status.LOADING -> { Status.LOADING -> {
@ -149,6 +148,50 @@ class ProductActivity : BaseActivity() {
} }
private fun reviews(productId : Int) {
val layoutManager = LinearLayoutManager(baseContext, 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, android.arch.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 -> {
}
}
})
}
private fun setUpPage(product: Product) { private fun setUpPage(product: Product) {
tvTitle.text = product.name tvTitle.text = product.name
tvDescription.text = Html.fromHtml(product.description) tvDescription.text = Html.fromHtml(product.description)

View File

@ -0,0 +1,87 @@
package me.gilo.wc.utils;
import org.joda.time.DateMidnight;
import org.joda.time.DateTime;
import org.joda.time.Days;
import java.text.SimpleDateFormat;
import java.util.Date;
public class DateUtils {
static SimpleDateFormat dateFormat = new SimpleDateFormat("EEE hh:mma MMM d, yyyy");
static SimpleDateFormat longagoDateFormat = new SimpleDateFormat("dd/MM/yyyy");
static SimpleDateFormat weekdayFormat = new SimpleDateFormat("EEE");
static SimpleDateFormat hourMinuteFormat = new SimpleDateFormat("hh:mm a");
private static boolean isToday (DateTime dateTime) {
DateMidnight today = new DateMidnight();
return today.equals(dateTime.toDateMidnight());
}
private static boolean isYesterday (DateTime dateTime) {
DateMidnight yesterday = (new DateMidnight()).minusDays(1);
return yesterday.equals(dateTime.toDateMidnight());
}
private static String getDayString(Date date) {
String s;
if (isToday(new DateTime(date)))
s = "Today";
else if (isYesterday(new DateTime(date)))
s = "Yesterday";
else
s = weekdayFormat.format(date);
return s;
}
public static String getDateString_shortAndSmart(Date date) {
String s;
DateTime nowDT = new DateTime();
DateTime dateDT = new DateTime(date);
int days = Days.daysBetween(dateDT, nowDT).getDays();
if (isToday(new DateTime(date)))
s = getHourMinuteString(date);
else if (days < 7)
s = getDayString(date);
else
s = getDateString(date);
return s;
}
public static String getDateStatus(Date date) {
String s;
if (date == null)
return "Null";
DateTime nowDT = new DateTime();
DateTime dateDT = new DateTime(date);
int days = Days.daysBetween(dateDT, nowDT).getDays();
if (isToday(new DateTime(date)))
s = getHourMinuteString(date);
else if (days < 7)
s = getDayString(date) + "at " + getHourMinuteString(date);
else
s = getDateString(date);
return "Last online " + s;
}
private static String getDateString(Date date) {
return longagoDateFormat.format(date);
}
private static String getHourMinuteString(Date date) {
String s = hourMinuteFormat.format(date);
return s;
}
}

View File

@ -8,6 +8,7 @@ import me.gilo.wc.repo.OrderRepository;
import me.gilo.wc.repo.ProductRepository; import me.gilo.wc.repo.ProductRepository;
import me.gilo.woodroid.models.LineItem; import me.gilo.woodroid.models.LineItem;
import me.gilo.woodroid.models.Product; 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.ProductFilter;
import javax.inject.Inject; import javax.inject.Inject;
@ -50,6 +51,11 @@ public final class ProductViewModel extends ViewModel {
return productRepository.product(productId); return productRepository.product(productId);
} }
public WooLiveData<List<ProductReview>> reviews(int productId) {
return productRepository.reviews(productId);
}
public WooLiveData<List<Product>> search(String term) { public WooLiveData<List<Product>> search(String term) {
return productRepository.search(term); return productRepository.search(term);
} }

View File

@ -21,6 +21,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="320dp" android:layout_height="320dp"
android:layout_marginBottom="16dp" android:layout_marginBottom="16dp"
android:layout_marginTop="16dp"
> >
@ -109,7 +110,7 @@
<TextView <TextView
fontPath="@string/font_medium" fontPath="@string/font_medium"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="30dp" android:layout_height="wrap_content"
android:gravity="left" android:gravity="left"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
@ -122,7 +123,27 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/rvShop" android:id="@+id/rvShop"
></android.support.v7.widget.RecyclerView>
<TextView
fontPath="@string/font_medium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp" android:layout_marginTop="16dp"
android:layout_marginRight="16dp"
android:text="Reviews"
android:textColor="@color/text_black_2"
android:textSize="20sp"/>
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/rvReviews"
android:background="@drawable/rect_white"
android:layout_margin="16dp"
></android.support.v7.widget.RecyclerView> ></android.support.v7.widget.RecyclerView>
</LinearLayout> </LinearLayout>

View File

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="16dp"
android:background="#ffffff"
tools:ignore="MissingPrefix">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="#ffffff"
tools:ignore="MissingPrefix">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_weight="1"
android:layout_marginRight="8dp"
>
<TextView
android:id="@+id/tvName"
fontPath="@string/font_medium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:maxLines="1"
android:text="Gilbert Kimutai"
android:textColor="@color/text_black_4"
android:textSize="16sp"/>
<android.support.v7.widget.AppCompatRatingBar
android:id="@+id/rbRating"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:numStars="5"
android:rating="4"
android:layout_marginTop="4dp"
style="?android:attr/ratingBarStyleSmall"
/>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="right"
>
<TextView
android:id="@+id/tvDate"
fontPath="@string/font_regular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:text="Jan 7, 2018"
android:maxLines="2"
android:lineSpacingMultiplier="1.2"
android:textColor="@color/text_black_5"
android:textSize="14sp"/>
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/tvMessage"
fontPath="@string/font_regular"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="left"
android:text="@string/lorem"
android:maxLines="4"
android:layout_marginTop="8dp"
android:lineSpacingMultiplier="1.2"
android:textColor="@color/text_black_5"
android:textSize="16sp"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="16dp"
android:background="@color/bg"
/>
</LinearLayout>

View File

@ -27,6 +27,8 @@ public class Woocommerce {
final OrderRepository orderRepository; final OrderRepository orderRepository;
final ProductRepository productRepository; final ProductRepository productRepository;
final ReviewRepository reviewRepository;
final ReportsRepository reportsRepository; final ReportsRepository reportsRepository;
final CartRepository cartRepository; final CartRepository cartRepository;
@ -75,6 +77,8 @@ public class Woocommerce {
cartRepository = new CartRepository(cartBaseUrl, consumerKey, consumerSecret); cartRepository = new CartRepository(cartBaseUrl, consumerKey, consumerSecret);
reviewRepository = new ReviewRepository(baseUrl, consumerKey, consumerSecret);
} }
@ -162,6 +166,10 @@ public class Woocommerce {
return productRepository; return productRepository;
} }
public ReviewRepository ReviewRepository() {
return reviewRepository;
}
public ReportsRepository ReportsRepository() { public ReportsRepository ReportsRepository() {
return reportsRepository; return reportsRepository;
} }

View File

@ -3,6 +3,7 @@ package me.gilo.woodroid.data.api;
import me.gilo.woodroid.data.callbacks.ReviewsData; import me.gilo.woodroid.data.callbacks.ReviewsData;
import me.gilo.woodroid.models.Coupon; import me.gilo.woodroid.models.Coupon;
import me.gilo.woodroid.models.Product;
import me.gilo.woodroid.models.ProductReview; import me.gilo.woodroid.models.ProductReview;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.http.*; import retrofit2.http.*;

View File

@ -2,16 +2,21 @@ package me.gilo.woodroid.models;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
import java.util.Map;
public class ProductReview implements Serializable{ public class ProductReview implements Serializable{
private int id; private int id;
private Date date_created; private Date date_created;
private Date date_created_gmt; private Date date_created_gmt;
int product_id;
String reviewer;
String reviewer_email;
Map<String, String> reviewer_avatar_urls;
private String review; private String review;
private int rating; private int rating;
private String name;
private String email;
private boolean verified; private boolean verified;
public int getId() { public int getId() {
@ -54,20 +59,36 @@ public class ProductReview implements Serializable{
this.rating = rating; this.rating = rating;
} }
public String getName() { public int getProduct_id() {
return name; return product_id;
} }
public void setName(String name) { public void setProduct_id(int product_id) {
this.name = name; this.product_id = product_id;
} }
public String getEmail() { public String getReviewer() {
return email; return reviewer;
} }
public void setEmail(String email) { public void setReviewer(String reviewer) {
this.email = email; this.reviewer = reviewer;
}
public String getReviewer_email() {
return reviewer_email;
}
public void setReviewer_email(String reviewer_email) {
this.reviewer_email = reviewer_email;
}
public Map<String, String> getReviewer_avatar_urls() {
return reviewer_avatar_urls;
}
public void setReviewer_avatar_urls(Map<String, String> reviewer_avatar_urls) {
this.reviewer_avatar_urls = reviewer_avatar_urls;
} }
public boolean isVerified() { public boolean isVerified() {

View File

@ -1,6 +1,5 @@
package me.gilo.woodroid.models.filters; package me.gilo.woodroid.models.filters;
import android.util.Log;
import me.gilo.woodroid.utils.Converter; import me.gilo.woodroid.utils.Converter;
import java.util.*; import java.util.*;

View File

@ -1,5 +1,7 @@
package me.gilo.woodroid.repo; package me.gilo.woodroid.repo;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import me.gilo.woodroid.data.auth.AuthIntercepter; import me.gilo.woodroid.data.auth.AuthIntercepter;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor; import okhttp3.logging.HttpLoggingInterceptor;
@ -17,6 +19,11 @@ public class WooRepository {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(); HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY); loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
Gson gson = new GsonBuilder()
.setDateFormat("yyyy-MM-dd'T'HH:mm:ss")
.create();
OkHttpClient client = new OkHttpClient.Builder() OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(new AuthIntercepter(consumerKey, consumerSecret)) .addInterceptor(new AuthIntercepter(consumerKey, consumerSecret))
.addInterceptor(loggingInterceptor) .addInterceptor(loggingInterceptor)
@ -27,7 +34,7 @@ public class WooRepository {
retrofit = new Retrofit.Builder() retrofit = new Retrofit.Builder()
.baseUrl(baseUrl) .baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create(gson))
.client(client) .client(client)
.build(); .build();
} }