Friday, May 25, 2018

Android Create RatingBar Review Like Google Play Store + Firebase

RatingBar review can make our product or apps become more better then before. From the reviews that given by users we able to know what problem of our product or apps.

This article will show you how to create ratingbar review that looks like rating on Google play store. As you know the user interface of review on Google Play store is great and full color.

To achieve rating look like Google Play Store, you have to know the formula of count rating view (especially for create rating that shown with color)

For create the icon of rating (icon star), you can use several library, but in this article I use library Zhanghai Material RatingBar.



Oh, In this article I also use Firebase Firestore as database to store the data of product and the reviews of product.

Create project in Firebase 


Open Firebase Console and create new project. You also can use the existing project in Firebase. After that download the google-services.json then place it on directory app in your project.

Here I created data of product in Firebase Firestore manually :

The sample product the created manually


The data above will displayed on mobile android, and then from android we will send the review of this product.

Create Android Studio Project


After the sample data in Firebase has created, now we crate the android application to display the sample data and send review that data.

Gradle Configuration


In this project, I use some libraries that support the application, you can see at the following gradle :

build.gradle (Project:RatingGooglePlayStore)

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.2'
//add this line
classpath 'com.google.gms:google-services:3.3.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
view raw build.gradle hosted with ❤ by GitHub
build.gradle (Module:app)

apply plugin: 'com.android.application'
android {
compileSdkVersion 27
defaultConfig {
applicationId "com.putuguna.ratinggoogleplaystore"
minSdkVersion 15
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
targetCompatibility 1.8
sourceCompatibility 1.8
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
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 "com.android.support:cardview-v7:27.1.1"
implementation "com.jakewharton:butterknife:8.8.1"
implementation 'com.android.support:support-v4:27.1.1'
annotationProcessor "com.jakewharton:butterknife-compiler:8.8.1"
implementation "com.android.support:recyclerview-v7:27.1.1"
implementation 'me.zhanghai.android.materialratingbar:library:1.0.2'
implementation 'com.google.firebase:firebase-core:15.0.2'
implementation "com.google.firebase:firebase-firestore:15.0.0"
implementation 'com.google.code.gson:gson:2.8.1'
}
apply plugin: 'com.google.gms.google-services'
view raw build.gradle hosted with ❤ by GitHub
Create Page Product


The first page that will appears is page Product (MainActivity). In this page, the data that created manually in Firebase will displayed.

Recommended : Take image from gallery or camera using EasyImage Library

First, we create the model (object) that will handle the data from Firebase Firestore, here it is

ProductModel.java

package com.putuguna.ratinggoogleplaystore.reviews;
public class ProductModel {
private String idProduct;
private int totalVoters;
private double totalRating;
private int star1;
private int star2;
private int star3;
private int star4;
private int star5;
private String productName;
public ProductModel(int totalVoters, double totalRating, int star1, int star2, int star3, int star4, int star5, String productName) {
this.totalVoters = totalVoters;
this.totalRating = totalRating;
this.star1 = star1;
this.star2 = star2;
this.star3 = star3;
this.star4 = star4;
this.star5 = star5;
this.productName = productName;
}
public ProductModel() {
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getIdProduct() {
return idProduct;
}
public void setIdProduct(String idProduct) {
this.idProduct = idProduct;
}
public int getTotalVoters() {
return totalVoters;
}
public void setTotalVoters(int totalVoters) {
this.totalVoters = totalVoters;
}
public double getTotalRating() {
return totalRating;
}
public void setTotalRating(double totalRating) {
this.totalRating = totalRating;
}
public int getStar1() {
return star1;
}
public void setStar1(int star1) {
this.star1 = star1;
}
public int getStar2() {
return star2;
}
public void setStar2(int star2) {
this.star2 = star2;
}
public int getStar3() {
return star3;
}
public void setStar3(int star3) {
this.star3 = star3;
}
public int getStar4() {
return star4;
}
public void setStar4(int star4) {
this.star4 = star4;
}
public int getStar5() {
return star5;
}
public void setStar5(int star5) {
this.star5 = star5;
}
}
After that, create Adapter that handle the list of product (even the sample product that create is one, but we still create adapter to handle much data)

item_product.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:id="@+id/cv_item"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:orientation="vertical">
<TextView
android:id="@+id/tv_product_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:textSize="18sp"
android:textStyle="bold"
tools:text="Product Name"/>
<me.zhanghai.android.materialratingbar.MaterialRatingBar
android:id="@+id/total_star_rating"
style="@style/Widget.MaterialRatingBar.RatingBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginBottom="@dimen/margin_value_5dp"
android:layout_marginTop="@dimen/margin_value_5dp"
android:isIndicator="true"
android:maxHeight="20dp"
android:minHeight="20dp"
android:numStars="5"
android:stepSize="0.25"
app:mrb_progressBackgroundTint="@color/colorPrimary"
app:mrb_progressTint="@color/colorPrimary"
app:mrb_secondaryProgressTint="@color/colorPrimary" />
</LinearLayout>
</android.support.v7.widget.CardView>
</LinearLayout>
ProductAdapter.java

package com.putuguna.ratinggoogleplaystore.product;
import android.support.annotation.NonNull;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.google.gson.Gson;
import com.putuguna.ratinggoogleplaystore.R;
import com.putuguna.ratinggoogleplaystore.reviews.ProductModel;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import me.zhanghai.android.materialratingbar.MaterialRatingBar;
public class ProductAdapter extends RecyclerView.Adapter<ProductAdapter.ProductHolder> {
public interface OnClickListenerAdapter {
void onItemClicked(String product);
}
private OnClickListenerAdapter onClickListenerAdapter;
private List<ProductModel> listProductModel;
public ProductAdapter(List<ProductModel> listProductModel) {
this.listProductModel = listProductModel;
}
@NonNull
@Override
public ProductHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_product, parent, false);
return new ProductHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ProductHolder holder, int position) {
ProductModel model = listProductModel.get(position);
holder.totalStarRating.setRating(Float.parseFloat(String.valueOf(model.getTotalRating())));
holder.tvProductName.setText(model.getProductName());
holder.cvItem.setOnClickListener(v -> {
if (onClickListenerAdapter != null) {
onClickListenerAdapter.onItemClicked(new Gson().toJson(model));
}
});
}
@Override
public int getItemCount() {
return listProductModel.size();
}
public void setOnClickListenerAdapter(OnClickListenerAdapter onClickListenerAdapter) {
this.onClickListenerAdapter = onClickListenerAdapter;
}
public class ProductHolder extends RecyclerView.ViewHolder {
@BindView(R.id.tv_product_name)
TextView tvProductName;
@BindView(R.id.total_star_rating)
MaterialRatingBar totalStarRating;
@BindView(R.id.cv_item)
CardView cvItem;
public ProductHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
Now get the data of product from Firebase Firestore and then display it on Recyclerview by using the following code :

MainActivity.java

package com.putuguna.ratinggoogleplaystore.product;
import android.app.ProgressDialog;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.widget.Toast;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.DocumentReference;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.QuerySnapshot;
import com.putuguna.ratinggoogleplaystore.R;
import com.putuguna.ratinggoogleplaystore.reviews.ProductModel;
import com.putuguna.ratinggoogleplaystore.reviews.ReviewActivity;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
public class MainActivity extends AppCompatActivity implements ProductAdapter.OnClickListenerAdapter {
@BindView(R.id.rv_product)
RecyclerView rvProduct;
private ProductAdapter adapter;
private FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();
ProgressDialog progressDialog ;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
initView();
getProduct();
}
private void initView(){
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("Load data product ...");
progressDialog.show();
}
private void getProduct(){
CollectionReference collectionReference = firebaseFirestore.collection("product");
collectionReference.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
progressDialog.dismiss();
if(!queryDocumentSnapshots.isEmpty()){
List<ProductModel> list = new ArrayList<>();
for(DocumentSnapshot document : queryDocumentSnapshots){
ProductModel productModel = document.toObject(ProductModel.class);
list.add(productModel);
}
initListProduct(list);
}else{
Toast.makeText(MainActivity.this, "Product is empty", Toast.LENGTH_SHORT).show();
}
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Toast.makeText(MainActivity.this, "Failed : "+e.getMessage(), Toast.LENGTH_SHORT).show();
progressDialog.dismiss();
}
});
}
private void initListProduct(List<ProductModel> productModelList){
adapter = new ProductAdapter(productModelList);
rvProduct.setLayoutManager(new LinearLayoutManager(this));
adapter.setOnClickListenerAdapter(this);
rvProduct.setAdapter(adapter);
}
@Override
protected void onResume() {
super.onResume();
getProduct();
}
@Override
public void onItemClicked(String product) {
ReviewActivity.start(this, product);
}
}
If you follow all the steps above, you will get result look like the following image :

The data that I created manually in firebase has displayed on mobile

Create Page Review


After the product has displayed, now we create page review that display the rating, insert review and displaying review.

ReviewModel.java

This class use to handle data of review data got from Firebase Firestore, here is the code

package com.putuguna.ratinggoogleplaystore.reviews;
import java.util.Date;
public class ReviewModel {
private String name;
private String review;
private Date timeStamp;
private double totalStarGiven;
public ReviewModel(String name, String review, Date timeStamp, double totalStarGiven) {
this.name = name;
this.review = review;
this.timeStamp = timeStamp;
this.totalStarGiven = totalStarGiven;
}
public ReviewModel() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getReview() {
return review;
}
public void setReview(String review) {
this.review = review;
}
public Date getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(Date timeStamp) {
this.timeStamp = timeStamp;
}
public double getTotalStarGiven() {
return totalStarGiven;
}
public void setTotalStarGiven(double totalStarGiven) {
this.totalStarGiven = totalStarGiven;
}
}
Now create the adapter of list review :

item_review.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_value_10dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_nama_pasien"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="@dimen/margin_value_10dp"
android:layout_marginRight="@dimen/margin_value_10dp"
android:textStyle="bold"
tools:text="Nama Pasien" />
<me.zhanghai.android.materialratingbar.MaterialRatingBar
android:id="@+id/total_star_rating"
style="@style/Widget.MaterialRatingBar.RatingBar"
android:layout_width="wrap_content"
android:layout_height="15dp"
android:layout_gravity="center"
android:layout_marginBottom="@dimen/margin_value_5dp"
android:layout_marginTop="@dimen/margin_value_5dp"
android:isIndicator="true"
android:maxHeight="20dp"
android:minHeight="20dp"
android:numStars="5"
android:stepSize="0.25"
app:mrb_progressBackgroundTint="@color/colorPrimary"
app:mrb_progressTint="@color/colorPrimary"
app:mrb_secondaryProgressTint="@color/colorPrimary" />
</LinearLayout>
<TextView
android:id="@+id/tv_tgl_rating"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_value_10dp"
android:textSize="10sp"
android:textStyle="bold"
tools:text="12:23:34"/>
<TextView
android:id="@+id/tv_desc_review"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/margin_value_10dp"
tools:text="Lambat!!! apa yang saya minta selalu saya dapatkan dan tidak pernah buruk pelayanannya, Good Job ya" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="@dimen/margin_value_10dp"
android:layout_marginRight="@dimen/margin_value_10dp"
android:layout_marginTop="@dimen/margin_value_10dp"
android:background="@android:color/darker_gray" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
view raw item_review.xml hosted with ❤ by GitHub
ReviewAdapter.java

package com.putuguna.ratinggoogleplaystore.reviews;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.putuguna.ratinggoogleplaystore.R;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import me.zhanghai.android.materialratingbar.MaterialRatingBar;
public class ReviewAdapter extends RecyclerView.Adapter<ReviewAdapter.ReviewViewHolder> {
private List<ReviewModel> listReview;
public ReviewAdapter(List<ReviewModel> listReview) {
this.listReview = listReview;
}
@NonNull
@Override
public ReviewViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_review, parent, false);
return new ReviewViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ReviewViewHolder holder, int position) {
ReviewModel model = listReview.get(position);
holder.totalStarRating.setRating(Float.parseFloat(String.valueOf(model.getTotalStarGiven())));
holder.tvDescReview.setText(model.getReview());
holder.tvTglRating.setText(String.valueOf(model.getTimeStamp()));
holder.tvNamaPasien.setText(model.getName());
}
@Override
public int getItemCount() {
return listReview.size();
}
public class ReviewViewHolder extends RecyclerView.ViewHolder {
@BindView(R.id.tv_nama_pasien)
TextView tvNamaPasien;
@BindView(R.id.total_star_rating)
MaterialRatingBar totalStarRating;
@BindView(R.id.tv_tgl_rating)
TextView tvTglRating;
@BindView(R.id.tv_desc_review)
TextView tvDescReview;
public ReviewViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}
After the adapter created, then create the logic how to show rating by stars and rating by color, take a look at the following images :

Rating using stars and colors 


To achieve the goal like the image above, there are several process that you have to do :

1. Insert Review To Firestore

/**
* Insert data review to collection of product
* @param review
*/
private void insertDataReview(ReviewModel review) {
ReviewModel reviewModel = new ReviewModel(review.getName(), review.getReview(), review.getTimeStamp(), review.getTotalStarGiven());
CollectionReference collectionReference = firebaseFirestore.collection("product");
DocumentReference documentReference = collectionReference.document(productModelGlobal.getIdProduct());
documentReference.collection("review")
.add(reviewModel)
.addOnSuccessListener(documentReference1 -> {
progressDialog.dismiss();
//after success, then update the rating in product
updateRating(review, productModelGlobal);
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
progressDialog.dismiss();
Toast.makeText(ReviewActivity.this, "Failed : " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
The code above will store the data to collection review. Take a look at the following image :

Data review has stored into Firebase Firestore


Recommended : How to insert and display file image from Firebase Firestore

After data review stored successfully, the update the rating in product

2. Update Rating Product

The following code will update the rating in data product, after that will change the display of rating view and rating color.


/**
* this method used to update rating of product
*
* @param reviewModel
* @param productModel
*/
private void updateRating(ReviewModel reviewModel, ProductModel productModel) {
ProductModel rate = new ProductModel();
rate.setIdProduct(productModel.getIdProduct());
rate.setProductName(productModel.getProductName());
//update stars
double totalStars;
int totalVoters = 0;
if (reviewModel.getTotalStarGiven() == 1.0) {
totalStars = 1.0 + (double) productModel.getStar1();
rate.setStar1((int) totalStars);
rate.setStar2(productModel.getStar2());
rate.setStar3(productModel.getStar3());
rate.setStar4(productModel.getStar4());
rate.setStar5(productModel.getStar5());
totalVoters = (int) (totalStars + productModel.getStar2() + productModel.getStar3() + productModel.getStar4() + productModel.getStar5());
if (productModel.getTotalVoters() == 0) {
rate.setTotalVoters(1);
} else {
rate.setTotalVoters(totalVoters);
}
} else if (reviewModel.getTotalStarGiven() == 2.0) {
totalStars = 1.0 + (double) productModel.getStar2();
rate.setStar1(productModel.getStar1());
rate.setStar2((int) totalStars);
rate.setStar3(productModel.getStar3());
rate.setStar4(productModel.getStar4());
rate.setStar5(productModel.getStar5());
totalVoters = (int) (totalStars + productModel.getStar1() + productModel.getStar3() + productModel.getStar4() + productModel.getStar5());
if (productModel.getTotalVoters() == 0) {
rate.setTotalVoters(1);
} else {
rate.setTotalVoters(totalVoters);
}
} else if (reviewModel.getTotalStarGiven() == 3.0) {
totalStars = 1.0 + (double) productModel.getStar3();
rate.setStar1(productModel.getStar1());
rate.setStar2(productModel.getStar2());
rate.setStar3((int) totalStars);
rate.setStar4(productModel.getStar4());
rate.setStar5(productModel.getStar5());
totalVoters = (int) (totalStars + productModel.getStar1() + productModel.getStar2() + productModel.getStar4() + productModel.getStar5());
if (productModel.getTotalVoters() == 0) {
rate.setTotalVoters(1);
} else {
rate.setTotalVoters(totalVoters);
}
} else if (reviewModel.getTotalStarGiven() == 4.0) {
totalStars = 1.0 + (double) productModel.getStar4();
rate.setStar1(productModel.getStar1());
rate.setStar2(productModel.getStar2());
rate.setStar3(productModel.getStar3());
rate.setStar4((int) totalStars);
rate.setStar5(productModel.getStar5());
totalVoters = (int) (totalStars + productModel.getStar1() + productModel.getStar2() + productModel.getStar3() + productModel.getStar5());
if (productModel.getTotalVoters() == 0) {
rate.setTotalVoters(1);
} else {
rate.setTotalVoters(totalVoters);
}
} else if (reviewModel.getTotalStarGiven() == 5.0) {
totalStars = 1.0 + (double) productModel.getStar5();
rate.setStar1(productModel.getStar1());
rate.setStar2(productModel.getStar2());
rate.setStar3(productModel.getStar3());
rate.setStar4(productModel.getStar4());
rate.setStar5((int) totalStars);
totalVoters = (int) (totalStars + productModel.getStar1() + productModel.getStar2() + productModel.getStar3() + productModel.getStar4());
if (productModel.getTotalVoters() == 0) {
rate.setTotalVoters(1);
} else {
rate.setTotalVoters(totalVoters);
}
}
//update rate
int totalStar1 = rate.getStar1() * 1;
int totalStar2 = rate.getStar2() * 2;
int totalStar3 = rate.getStar3() * 3;
int totalStar4 = rate.getStar4() * 4;
int totalStar5 = rate.getStar5() * 5;
double sumOfStars = totalStar1 + totalStar2 + totalStar3 + totalStar4 + totalStar5;
double totalRating = sumOfStars / (double) totalVoters;
DecimalFormat format = new DecimalFormat(".#");
rate.setTotalRating(Double.parseDouble(format.format(totalRating)));
CollectionReference collectionReference = firebaseFirestore.collection("product");
collectionReference.document(productModel.getIdProduct())
.set(rate)
.addOnSuccessListener(aVoid -> {
progressDialog.dismiss();
Toast.makeText(ReviewActivity.this, "Successfully update Rating", Toast.LENGTH_SHORT).show();
productModelGlobal = rate;
//after success, then update the rating color and populate the recyclerview with the data of reviews
setRatingByColor(rate);
getAllReview(productModel.getIdProduct());
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
progressDialog.dismiss();
Toast.makeText(ReviewActivity.this, "Failed Update Rating : " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}

3. Update the rating color

/**
* This method used to display rating by colors
*
* @param productModel
*/
private void setRatingByColor(ProductModel productModel) {
int widthView = constrainLayout1.getWidth();
int totalAllVoters = productModel.getTotalVoters();
int totalRateStar1 = productModel.getStar1();
int totalRateStar2 = productModel.getStar2();
int totalRateStar3 = productModel.getStar3();
int totalRateStar4 = productModel.getStar4();
int totalRateStar5 = productModel.getStar5();
//convert to double
double votersInDouble = (double) totalAllVoters;
//RATING STAR 1
double star1 = (double) totalRateStar1;
double sum1 = (star1 / votersInDouble);
int rating1 = (int) (sum1 * widthView);
ConstraintLayout.LayoutParams layoutParams1 = new ConstraintLayout.LayoutParams(rating1, ConstraintLayout.LayoutParams.MATCH_PARENT);
layoutParams1.setMargins(0, 5, 0, 5);
llPercentage1.setBackgroundColor(Color.parseColor("#ff6f31"));
llPercentage1.setLayoutParams(layoutParams1);
//RATING STAR 2
double star2 = (double) totalRateStar2;
double sum2 = (star2 / votersInDouble);
int rating2 = (int) (sum2 * widthView);
ConstraintLayout.LayoutParams layoutParams2 = new ConstraintLayout.LayoutParams(rating2, ConstraintLayout.LayoutParams.MATCH_PARENT);
layoutParams2.setMargins(0, 5, 0, 5);
llPercentage2.setBackgroundColor(Color.parseColor("#ff9f02"));
llPercentage2.setLayoutParams(layoutParams2);
//RATING STAR 3
double star3 = (double) totalRateStar3;
double sum3 = (star3 / votersInDouble);
int rating3 = (int) (sum3 * widthView);
ConstraintLayout.LayoutParams layoutParams3 = new ConstraintLayout.LayoutParams(rating3, ConstraintLayout.LayoutParams.MATCH_PARENT);
layoutParams3.setMargins(0, 5, 0, 5);
llPercentage3.setBackgroundColor(Color.parseColor("#ffcf02"));
llPercentage3.setLayoutParams(layoutParams3);
//RATING STAR 4
double star4 = (double) totalRateStar4;
double sum4 = (star4 / votersInDouble);
int rating4 = (int) (sum4 * widthView);
ConstraintLayout.LayoutParams layoutParams4 = new ConstraintLayout.LayoutParams(rating4, ConstraintLayout.LayoutParams.MATCH_PARENT);
layoutParams4.setMargins(0, 5, 0, 5);
llPercentage4.setBackgroundColor(Color.parseColor("#9ace6a"));
llPercentage4.setLayoutParams(layoutParams4);
//RATING STAR 5
double star5 = (double) totalRateStar5;
double sum5 = (star5 / votersInDouble);
int rating5 = (int) (sum5 * widthView);
ConstraintLayout.LayoutParams layoutParams5 = new ConstraintLayout.LayoutParams(rating5, ConstraintLayout.LayoutParams.MATCH_PARENT);
layoutParams5.setMargins(0, 5, 0, 5);
llPercentage5.setBackgroundColor(Color.parseColor("#57bb8a"));
llPercentage5.setLayoutParams(layoutParams5);
// menampilkan rating berdasarkan angka
int totalBintangSatu = totalRateStar1 * 1;
int totalBintangDua = totalRateStar2 * 2;
int totalBintangTiga = totalRateStar3 * 3;
int totalBintangEmpat = totalRateStar4 * 5;
int totalBintangLima = totalRateStar5 * 5;
double sumBintang = totalBintangSatu +
totalBintangDua +
totalBintangTiga +
totalBintangEmpat +
totalBintangLima;
double rating = (sumBintang / votersInDouble);
DecimalFormat format = new DecimalFormat(".#");
tvTotalNumberRating.setText(String.valueOf(format.format(rating)));
totalStarRating.setRating(Float.parseFloat(String.valueOf(rating)));
tvTotalPemberiBintang.setText(String.valueOf(totalAllVoters) + " total");
}

4. Populating the recyclerview with data of reviews

/**
* the method used to get all reviews in firebase firestore
* @param idProduct
*/
private void getAllReview(String idProduct) {
progressBar.setVisibility(View.VISIBLE);
rvReview.setVisibility(View.GONE);
CollectionReference collectionReference = firebaseFirestore.collection("product");
DocumentReference documentReference = collectionReference.document(idProduct);
documentReference.collection("review")
.get()
.addOnCompleteListener(task -> {
progressBar.setVisibility(View.GONE);
rvReview.setVisibility(View.VISIBLE);
if (task.getResult().isEmpty()) {
} else if (task.isSuccessful()) {
List<ReviewModel> listReview = new ArrayList<>();
for (DocumentSnapshot documentSnapshot : task.getResult()) {
ReviewModel reviewModel = new ReviewModel();
try {
reviewModel.setName(documentSnapshot.get("name").toString());
reviewModel.setReview(documentSnapshot.get("review").toString());
reviewModel.setTimeStamp(new Date(documentSnapshot.get("timeStamp").toString()));
reviewModel.setTotalStarGiven(Double.parseDouble(documentSnapshot.get("totalStarGiven").toString()));
} catch (Exception e) {
e.printStackTrace();
}
listReview.add(reviewModel);
initListReview(listReview);
}
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
}
});
}
//this method used to populating the recyclerview with data of reviews
private void initListReview(List<ReviewModel> reviewModels) {
adapter = new ReviewAdapter(reviewModels);
rvReview.setLayoutManager(new LinearLayoutManager(this));
rvReview.setAdapter(adapter);
}
Take a learn of those codes above, that will guide you to understand the formula of displaying rating by stars and by colors.

Recommended : Insert image from android to database (server using PHP & MySQL)

Here is the full code of ReviewActivity.java :

package com.putuguna.ratinggoogleplaystore.reviews;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.constraint.ConstraintLayout;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.android.gms.tasks.Task;
import com.google.firebase.firestore.CollectionReference;
import com.google.firebase.firestore.DocumentReference;
import com.google.firebase.firestore.DocumentSnapshot;
import com.google.firebase.firestore.FirebaseFirestore;
import com.google.firebase.firestore.QuerySnapshot;
import com.google.gson.Gson;
import com.putuguna.ratinggoogleplaystore.R;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import me.zhanghai.android.materialratingbar.MaterialRatingBar;
public class ReviewActivity extends AppCompatActivity {
public static String EXTRA_PRODUCT_MODEL = "EXTRA_PRODUCT_MODEL";
@BindView(R.id.tv_total_number_rating)
TextView tvTotalNumberRating;
@BindView(R.id.total_star_rating)
MaterialRatingBar totalStarRating;
@BindView(R.id.tv_total_pemberi_bintang)
TextView tvTotalPemberiBintang;
@BindView(R.id.ll_percentage_5)
LinearLayout llPercentage5;
@BindView(R.id.constrain_layout_5)
ConstraintLayout constrainLayout5;
@BindView(R.id.ll_percentage_4)
LinearLayout llPercentage4;
@BindView(R.id.constrain_layout_4)
ConstraintLayout constrainLayout4;
@BindView(R.id.ll_percentage_3)
LinearLayout llPercentage3;
@BindView(R.id.constrain_layout_3)
ConstraintLayout constrainLayout3;
@BindView(R.id.ll_percentage_2)
LinearLayout llPercentage2;
@BindView(R.id.constrain_layout_2)
ConstraintLayout constrainLayout2;
@BindView(R.id.ll_percentage_1)
LinearLayout llPercentage1;
@BindView(R.id.constrain_layout_1)
ConstraintLayout constrainLayout1;
@BindView(R.id.progressbar)
ProgressBar progressBar;
@BindView(R.id.rv_review)
RecyclerView rvReview;
private ProgressDialog progressDialog;
private Handler handler = new Handler();
private ProductModel productModelGlobal;
private FirebaseFirestore firebaseFirestore = FirebaseFirestore.getInstance();
private ReviewAdapter adapter;
public static void start(Context context, String productModel) {
Intent starter = new Intent(context, ReviewActivity.class);
starter.putExtra(EXTRA_PRODUCT_MODEL, productModel);
context.startActivity(starter);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_review);
ButterKnife.bind(this);
initView();
}
private void initView() {
progressDialog = new ProgressDialog(this);
productModelGlobal = new Gson().fromJson(getIntent().getStringExtra(EXTRA_PRODUCT_MODEL), ProductModel.class);
//this method used to get the width of view
progressDialog.setMessage("Count Width Of View");
progressDialog.show();
handler.postDelayed(new Runnable() {
@Override
public void run() {
progressDialog.dismiss();
setRatingByColor(productModelGlobal);
getAllReview(productModelGlobal.getIdProduct());
}
}, 3000);
}
/**
* Insert data review to collection of product
* @param review
*/
private void insertDataReview(ReviewModel review) {
ReviewModel reviewModel = new ReviewModel(review.getName(), review.getReview(), review.getTimeStamp(), review.getTotalStarGiven());
CollectionReference collectionReference = firebaseFirestore.collection("product");
DocumentReference documentReference = collectionReference.document(productModelGlobal.getIdProduct());
documentReference.collection("review")
.add(reviewModel)
.addOnSuccessListener(documentReference1 -> {
progressDialog.dismiss();
//after success, then update the rating in product
updateRating(review, productModelGlobal);
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
progressDialog.dismiss();
Toast.makeText(ReviewActivity.this, "Failed : " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
/**
* this method used to update rating of product
*
* @param reviewModel
* @param productModel
*/
private void updateRating(ReviewModel reviewModel, ProductModel productModel) {
ProductModel rate = new ProductModel();
rate.setIdProduct(productModel.getIdProduct());
rate.setProductName(productModel.getProductName());
//update stars
double totalStars;
int totalVoters = 0;
if (reviewModel.getTotalStarGiven() == 1.0) {
totalStars = 1.0 + (double) productModel.getStar1();
rate.setStar1((int) totalStars);
rate.setStar2(productModel.getStar2());
rate.setStar3(productModel.getStar3());
rate.setStar4(productModel.getStar4());
rate.setStar5(productModel.getStar5());
totalVoters = (int) (totalStars + productModel.getStar2() + productModel.getStar3() + productModel.getStar4() + productModel.getStar5());
if (productModel.getTotalVoters() == 0) {
rate.setTotalVoters(1);
} else {
rate.setTotalVoters(totalVoters);
}
} else if (reviewModel.getTotalStarGiven() == 2.0) {
totalStars = 1.0 + (double) productModel.getStar2();
rate.setStar1(productModel.getStar1());
rate.setStar2((int) totalStars);
rate.setStar3(productModel.getStar3());
rate.setStar4(productModel.getStar4());
rate.setStar5(productModel.getStar5());
totalVoters = (int) (totalStars + productModel.getStar1() + productModel.getStar3() + productModel.getStar4() + productModel.getStar5());
if (productModel.getTotalVoters() == 0) {
rate.setTotalVoters(1);
} else {
rate.setTotalVoters(totalVoters);
}
} else if (reviewModel.getTotalStarGiven() == 3.0) {
totalStars = 1.0 + (double) productModel.getStar3();
rate.setStar1(productModel.getStar1());
rate.setStar2(productModel.getStar2());
rate.setStar3((int) totalStars);
rate.setStar4(productModel.getStar4());
rate.setStar5(productModel.getStar5());
totalVoters = (int) (totalStars + productModel.getStar1() + productModel.getStar2() + productModel.getStar4() + productModel.getStar5());
if (productModel.getTotalVoters() == 0) {
rate.setTotalVoters(1);
} else {
rate.setTotalVoters(totalVoters);
}
} else if (reviewModel.getTotalStarGiven() == 4.0) {
totalStars = 1.0 + (double) productModel.getStar4();
rate.setStar1(productModel.getStar1());
rate.setStar2(productModel.getStar2());
rate.setStar3(productModel.getStar3());
rate.setStar4((int) totalStars);
rate.setStar5(productModel.getStar5());
totalVoters = (int) (totalStars + productModel.getStar1() + productModel.getStar2() + productModel.getStar3() + productModel.getStar5());
if (productModel.getTotalVoters() == 0) {
rate.setTotalVoters(1);
} else {
rate.setTotalVoters(totalVoters);
}
} else if (reviewModel.getTotalStarGiven() == 5.0) {
totalStars = 1.0 + (double) productModel.getStar5();
rate.setStar1(productModel.getStar1());
rate.setStar2(productModel.getStar2());
rate.setStar3(productModel.getStar3());
rate.setStar4(productModel.getStar4());
rate.setStar5((int) totalStars);
totalVoters = (int) (totalStars + productModel.getStar1() + productModel.getStar2() + productModel.getStar3() + productModel.getStar4());
if (productModel.getTotalVoters() == 0) {
rate.setTotalVoters(1);
} else {
rate.setTotalVoters(totalVoters);
}
}
//update rate
int totalStar1 = rate.getStar1() * 1;
int totalStar2 = rate.getStar2() * 2;
int totalStar3 = rate.getStar3() * 3;
int totalStar4 = rate.getStar4() * 4;
int totalStar5 = rate.getStar5() * 5;
double sumOfStars = totalStar1 + totalStar2 + totalStar3 + totalStar4 + totalStar5;
double totalRating = sumOfStars / (double) totalVoters;
DecimalFormat format = new DecimalFormat(".#");
rate.setTotalRating(Double.parseDouble(format.format(totalRating)));
CollectionReference collectionReference = firebaseFirestore.collection("product");
collectionReference.document(productModel.getIdProduct())
.set(rate)
.addOnSuccessListener(aVoid -> {
progressDialog.dismiss();
Toast.makeText(ReviewActivity.this, "Successfully update Rating", Toast.LENGTH_SHORT).show();
productModelGlobal = rate;
setRatingByColor(rate);
getAllReview(productModel.getIdProduct());
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
progressDialog.dismiss();
Toast.makeText(ReviewActivity.this, "Failed Update Rating : " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
/**
* This method used to display rating by colors
*
* @param productModel
*/
private void setRatingByColor(ProductModel productModel) {
int widthView = constrainLayout1.getWidth();
int totalAllVoters = productModel.getTotalVoters();
int totalRateStar1 = productModel.getStar1();
int totalRateStar2 = productModel.getStar2();
int totalRateStar3 = productModel.getStar3();
int totalRateStar4 = productModel.getStar4();
int totalRateStar5 = productModel.getStar5();
//convert to double
double votersInDouble = (double) totalAllVoters;
//RATING STAR 1
double star1 = (double) totalRateStar1;
double sum1 = (star1 / votersInDouble);
int rating1 = (int) (sum1 * widthView);
ConstraintLayout.LayoutParams layoutParams1 = new ConstraintLayout.LayoutParams(rating1, ConstraintLayout.LayoutParams.MATCH_PARENT);
layoutParams1.setMargins(0, 5, 0, 5);
llPercentage1.setBackgroundColor(Color.parseColor("#ff6f31"));
llPercentage1.setLayoutParams(layoutParams1);
//RATING STAR 2
double star2 = (double) totalRateStar2;
double sum2 = (star2 / votersInDouble);
int rating2 = (int) (sum2 * widthView);
ConstraintLayout.LayoutParams layoutParams2 = new ConstraintLayout.LayoutParams(rating2, ConstraintLayout.LayoutParams.MATCH_PARENT);
layoutParams2.setMargins(0, 5, 0, 5);
llPercentage2.setBackgroundColor(Color.parseColor("#ff9f02"));
llPercentage2.setLayoutParams(layoutParams2);
//RATING STAR 3
double star3 = (double) totalRateStar3;
double sum3 = (star3 / votersInDouble);
int rating3 = (int) (sum3 * widthView);
ConstraintLayout.LayoutParams layoutParams3 = new ConstraintLayout.LayoutParams(rating3, ConstraintLayout.LayoutParams.MATCH_PARENT);
layoutParams3.setMargins(0, 5, 0, 5);
llPercentage3.setBackgroundColor(Color.parseColor("#ffcf02"));
llPercentage3.setLayoutParams(layoutParams3);
//RATING STAR 4
double star4 = (double) totalRateStar4;
double sum4 = (star4 / votersInDouble);
int rating4 = (int) (sum4 * widthView);
ConstraintLayout.LayoutParams layoutParams4 = new ConstraintLayout.LayoutParams(rating4, ConstraintLayout.LayoutParams.MATCH_PARENT);
layoutParams4.setMargins(0, 5, 0, 5);
llPercentage4.setBackgroundColor(Color.parseColor("#9ace6a"));
llPercentage4.setLayoutParams(layoutParams4);
//RATING STAR 5
double star5 = (double) totalRateStar5;
double sum5 = (star5 / votersInDouble);
int rating5 = (int) (sum5 * widthView);
ConstraintLayout.LayoutParams layoutParams5 = new ConstraintLayout.LayoutParams(rating5, ConstraintLayout.LayoutParams.MATCH_PARENT);
layoutParams5.setMargins(0, 5, 0, 5);
llPercentage5.setBackgroundColor(Color.parseColor("#57bb8a"));
llPercentage5.setLayoutParams(layoutParams5);
// menampilkan rating berdasarkan angka
int totalBintangSatu = totalRateStar1 * 1;
int totalBintangDua = totalRateStar2 * 2;
int totalBintangTiga = totalRateStar3 * 3;
int totalBintangEmpat = totalRateStar4 * 5;
int totalBintangLima = totalRateStar5 * 5;
double sumBintang = totalBintangSatu +
totalBintangDua +
totalBintangTiga +
totalBintangEmpat +
totalBintangLima;
double rating = (sumBintang / votersInDouble);
DecimalFormat format = new DecimalFormat(".#");
tvTotalNumberRating.setText(String.valueOf(format.format(rating)));
totalStarRating.setRating(Float.parseFloat(String.valueOf(rating)));
tvTotalPemberiBintang.setText(String.valueOf(totalAllVoters) + " total");
}
/**
* this method used to open dialog input review
*/
private void openDialogReview() {
final Dialog dialog = new Dialog(this);
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
dialog.setContentView(R.layout.dialog_review);
EditText etReview = dialog.findViewById(R.id.et_review);
EditText etName = dialog.findViewById(R.id.et_name);
MaterialRatingBar rate = dialog.findViewById(R.id.rate_star);
Button btnKirimUlasan = dialog.findViewById(R.id.btn_send_review);
btnKirimUlasan.setOnClickListener(v -> {
dialog.dismiss();
if (TextUtils.isEmpty(etReview.getText().toString())) {
etReview.setError("Required field");
} else {
progressDialog.setMessage("Please wait ...");
progressDialog.show();
ReviewModel reviewModel = new ReviewModel();
reviewModel.setName(etName.getText().toString());
reviewModel.setReview(etReview.getText().toString());
reviewModel.setTimeStamp(new Date());
reviewModel.setTotalStarGiven(Math.round(rate.getRating()));
insertDataReview(reviewModel);
}
});
dialog.show();
}
/**
* the method used to get all reviews in firebase firestore
* @param idProduct
*/
private void getAllReview(String idProduct) {
progressBar.setVisibility(View.VISIBLE);
rvReview.setVisibility(View.GONE);
CollectionReference collectionReference = firebaseFirestore.collection("product");
DocumentReference documentReference = collectionReference.document(idProduct);
documentReference.collection("review")
.get()
.addOnCompleteListener(task -> {
progressBar.setVisibility(View.GONE);
rvReview.setVisibility(View.VISIBLE);
if (task.getResult().isEmpty()) {
} else if (task.isSuccessful()) {
List<ReviewModel> listReview = new ArrayList<>();
for (DocumentSnapshot documentSnapshot : task.getResult()) {
ReviewModel reviewModel = new ReviewModel();
try {
reviewModel.setName(documentSnapshot.get("name").toString());
reviewModel.setReview(documentSnapshot.get("review").toString());
reviewModel.setTimeStamp(new Date(documentSnapshot.get("timeStamp").toString()));
reviewModel.setTotalStarGiven(Double.parseDouble(documentSnapshot.get("totalStarGiven").toString()));
} catch (Exception e) {
e.printStackTrace();
}
listReview.add(reviewModel);
initListReview(listReview);
}
}
})
.addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
}
});
}
//this method used to populating the recyclerview with data of reviews
private void initListReview(List<ReviewModel> reviewModels) {
adapter = new ReviewAdapter(reviewModels);
rvReview.setLayoutManager(new LinearLayoutManager(this));
rvReview.setAdapter(adapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.main_menu, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_add_review) {
openDialogReview();
}
return super.onOptionsItemSelected(item);
}
}
Don't forget to add permission of INTERNET in your AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>
view raw Manifest.xml hosted with ❤ by GitHub
Okay, that's all about the tutorial how to create rating or review look like Google Play Store. I hope this article will help you. Thank you.

Download the project : LINK GITHUB

Related Posts

4 komentar

when i copy all code in tpo my app it give error and run failed

This comment has been removed by the author.

I executed successfully . I tried to import in my current project application.. I copy all the codes accordingly. But there is one small problem i cannot fix.
Inside the ReviewActivity, in RecyclerView (rv_review), the date and rating is showing a null value.. can you please help me???


EmoticonEmoticon

:)
:(
hihi
:-)
:D
=D
:-d
;(
;-(
@-)
:o
:>)
(o)
:p
:-?
(p)
:-s
8-)
:-t
:-b
b-(
(y)
x-)
(h)