diff --git a/Foodify/app/build.gradle b/Foodify/app/build.gradle
index 0d8e469..0790b12 100644
--- a/Foodify/app/build.gradle
+++ b/Foodify/app/build.gradle
@@ -43,6 +43,7 @@ dependencies {
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
implementation 'androidx.navigation:navigation-fragment:2.3.5'
implementation 'androidx.navigation:navigation-ui:2.3.5'
+ implementation fileTree(dir: 'D:\\ZaloPay', include: ['*.aar', '*.jar'], exclude: [])
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
@@ -68,6 +69,8 @@ dependencies {
implementation 'com.github.rey5137:material:1.2.4'
implementation 'com.squareup.okhttp3:okhttp:4.9.2'
+ implementation("commons-codec:commons-codec:1.14")
+ implementation fileTree(dir: 'D:\\ZaloPay', includes: ['*.aar', '*.jar'], excludes: [])
implementation 'io.github.inflationx:calligraphy3:3.1.1'
implementation 'io.github.inflationx:viewpump:2.0.3'
diff --git a/Foodify/app/src/main/AndroidManifest.xml b/Foodify/app/src/main/AndroidManifest.xml
index 788325c..cac6fa1 100644
--- a/Foodify/app/src/main/AndroidManifest.xml
+++ b/Foodify/app/src/main/AndroidManifest.xml
@@ -7,6 +7,7 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Foodify/app/src/main/java/com/waterbase/foodify/Cart.java b/Foodify/app/src/main/java/com/waterbase/foodify/Cart.java
index 6adb614..a8733fe 100644
--- a/Foodify/app/src/main/java/com/waterbase/foodify/Cart.java
+++ b/Foodify/app/src/main/java/com/waterbase/foodify/Cart.java
@@ -3,6 +3,7 @@ package com.waterbase.foodify;
import android.Manifest;
import android.content.Context;
import android.content.DialogInterface;
+import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.os.Bundle;
@@ -314,20 +315,24 @@ public class Cart extends AppCompatActivity implements GoogleApiClient.Connectio
txtTotalPrice.getText().toString(),
"0",
edtComment.getText().toString(),
+ "Chưa thanh toán!",
cart
);
+ //Pass object to another activity!
+ Intent intent = new Intent(Cart.this, OrderDetail.class);
+ intent.putExtra("requests", request);
+ startActivity(intent);
+
//Summit to Firebase
//We will using System.CurrentMilli to key
- String order_number = String.valueOf(System.currentTimeMillis());
- requests.child(order_number).setValue(request);
+// String order_number = String.valueOf(System.currentTimeMillis());
+// requests.child(order_number).setValue(request);
+//
+// sendNotificationOrder(order_number);
+
- sendNotificationOrder(order_number);
- //Delete Cart
- new Database(getBaseContext()).cleanCart();
- Toast.makeText(Cart.this, "Đặt hàng thành công!", Toast.LENGTH_SHORT).show();
- finish();
}
});
@@ -341,51 +346,7 @@ public class Cart extends AppCompatActivity implements GoogleApiClient.Connectio
alertDialog.show();
}
- private void sendNotificationOrder(String order_number) {
- DatabaseReference tokens = FirebaseDatabase.getInstance().getReference("Tokens");
- Query data = tokens.orderByChild("serverToken").equalTo(true); //Get all node with isServerToken is true;
- data.addValueEventListener(new ValueEventListener() {
- @Override
- public void onDataChange(DataSnapshot dataSnapshot) {
- for (DataSnapshot postSnapShot : dataSnapshot.getChildren()) {
- Token serverToken = postSnapShot.getValue(Token.class);
-
- //Create raw payload to send
- Notification notification = new Notification("Foodify", "Bạn có 1 đơn hàng mới " + order_number);
- Sender content = new Sender(serverToken.getToken(), notification);
-
- mService.sendNotification(content)
- .enqueue(new Callback() {
- @Override
- public void onResponse(Call call, Response response) {
-
- //Only run when get result
- if (response.code() == 200) {
- if (response.body().success == 1) {
- new Database(getBaseContext()).cleanCart();
- Toast.makeText(Cart.this, "Đặt hàng thành công!", Toast.LENGTH_SHORT).show();
- finish();
- } else {
- Toast.makeText(Cart.this, "Hệ thống bị lỗi. Vui lòng thử lại sau!", Toast.LENGTH_SHORT).show();
- }
- }
- }
-
- @Override
- public void onFailure(Call call, Throwable t) {
- Log.e("ERROR", t.getMessage());
- }
- });
- }
- }
-
- @Override
- public void onCancelled(DatabaseError databaseError) {
-
- }
- });
- }
private void loadListFood() {
cart = new Database(this).getCarts();
diff --git a/Foodify/app/src/main/java/com/waterbase/foodify/Model/Order.java b/Foodify/app/src/main/java/com/waterbase/foodify/Model/Order.java
index 1bcb6fa..40a69a5 100644
--- a/Foodify/app/src/main/java/com/waterbase/foodify/Model/Order.java
+++ b/Foodify/app/src/main/java/com/waterbase/foodify/Model/Order.java
@@ -1,6 +1,8 @@
package com.waterbase.foodify.Model;
-public class Order {
+import java.io.Serializable;
+
+public class Order implements Serializable {
private int ID;
private String ProductId;
diff --git a/Foodify/app/src/main/java/com/waterbase/foodify/Model/Request.java b/Foodify/app/src/main/java/com/waterbase/foodify/Model/Request.java
index 7a8943e..41b6816 100644
--- a/Foodify/app/src/main/java/com/waterbase/foodify/Model/Request.java
+++ b/Foodify/app/src/main/java/com/waterbase/foodify/Model/Request.java
@@ -1,26 +1,29 @@
package com.waterbase.foodify.Model;
+import java.io.Serializable;
import java.util.List;
-public class Request {
+public class Request implements Serializable {
private String phone;
private String name;
private String address;
private String total;
private String status;
private String comment;
+ private String paymentStatus;
private List foods; // list of food order
public Request() {
}
- public Request(String phone, String name, String address, String total, String status, String comment, List foods) {
+ public Request(String phone, String name, String address, String total, String status, String comment, String paymentStatus, List foods) {
this.phone = phone;
this.name = name;
this.address = address;
this.total = total;
this.status = status;
this.comment = comment;
+ this.paymentStatus = paymentStatus;
this.foods = foods;
}
@@ -72,6 +75,14 @@ public class Request {
this.comment = comment;
}
+ public String getPaymentStatus() {
+ return paymentStatus;
+ }
+
+ public void setPaymentStatus(String paymentStatus) {
+ this.paymentStatus = paymentStatus;
+ }
+
public List getFoods() {
return foods;
}
diff --git a/Foodify/app/src/main/java/com/waterbase/foodify/OrderDetail.java b/Foodify/app/src/main/java/com/waterbase/foodify/OrderDetail.java
new file mode 100644
index 0000000..2a51289
--- /dev/null
+++ b/Foodify/app/src/main/java/com/waterbase/foodify/OrderDetail.java
@@ -0,0 +1,264 @@
+package com.waterbase.foodify;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.RequiresApi;
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.recyclerview.widget.LinearLayoutManager;
+import androidx.recyclerview.widget.RecyclerView;
+
+import android.annotation.SuppressLint;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.StrictMode;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.google.android.material.button.MaterialButton;
+import com.google.firebase.database.DataSnapshot;
+import com.google.firebase.database.DatabaseError;
+import com.google.firebase.database.DatabaseReference;
+import com.google.firebase.database.FirebaseDatabase;
+import com.google.firebase.database.Query;
+import com.google.firebase.database.ValueEventListener;
+import com.waterbase.foodify.Common.Common;
+import com.waterbase.foodify.Database.Database;
+import com.waterbase.foodify.Model.MyResponse;
+import com.waterbase.foodify.Model.Notification;
+import com.waterbase.foodify.Model.Order;
+import com.waterbase.foodify.Model.Request;
+import com.waterbase.foodify.Model.Sender;
+import com.waterbase.foodify.Model.Token;
+import com.waterbase.foodify.Remote.APIService;
+import com.waterbase.foodify.ViewHolder.OrderDetailAdapter;
+import com.waterbase.foodify.Zalopay.Api.CreateOrder;
+
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import retrofit2.Call;
+import retrofit2.Callback;
+import retrofit2.Response;
+import vn.zalopay.sdk.Environment;
+import vn.zalopay.sdk.ZaloPayError;
+import vn.zalopay.sdk.ZaloPaySDK;
+import vn.zalopay.sdk.listeners.PayOrderListener;
+
+public class OrderDetail extends AppCompatActivity {
+
+ TextView order_address, order_total, order_comment;
+ Request request;
+ RecyclerView lstFoods;
+ RecyclerView.LayoutManager layoutManager;
+ MaterialButton btnPay, btnZaloPay;
+
+ FirebaseDatabase database;
+ DatabaseReference requests;
+
+ APIService mService;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_order_detail);
+
+ String comment = "";
+
+ setTitle("Thông tin chi tiết đơn hàng");
+
+ StrictMode.ThreadPolicy policy = new
+ StrictMode.ThreadPolicy.Builder().permitAll().build();
+ StrictMode.setThreadPolicy(policy);
+
+ // ZaloPay SDK Init
+ ZaloPaySDK.init(2554, Environment.SANDBOX);
+
+ order_address = (TextView) findViewById(R.id.order_address);
+ order_total = (TextView) findViewById(R.id.order_total);
+ order_comment = (TextView) findViewById(R.id.order_comment);
+
+ btnPay = findViewById(R.id.btnPay);
+ btnZaloPay = findViewById(R.id.btnZaloPay);
+
+ lstFoods = (RecyclerView) findViewById(R.id.lstFoods);
+ lstFoods.setHasFixedSize(true);
+ layoutManager = new LinearLayoutManager(this);
+ lstFoods.setLayoutManager(layoutManager);
+
+ //Firebase
+ database = FirebaseDatabase.getInstance();
+ requests = database.getReference("Requests");
+
+ mService = Common.getFCMService();
+
+ if (getIntent() != null)
+ request = (Request) getIntent().getSerializableExtra("requests");
+
+ //Set value
+ order_total.setText("Tổng cộng: " + request.getTotal());
+ order_address.setText("Địa chỉ giao: " + request.getAddress());
+ if (TextUtils.isEmpty(request.getComment()))
+ comment = "Không có";
+ else
+ comment = request.getComment();
+ order_comment.setText("Ghi chú: " + comment);
+
+ OrderDetailAdapter adapter = new OrderDetailAdapter(request.getFoods(), this);
+ adapter.notifyDataSetChanged();
+ lstFoods.setAdapter(adapter);
+
+ btnPay.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ //Summit to Firebase
+ //We will using System.CurrentMilli to key
+ String order_number = String.valueOf(System.currentTimeMillis());
+ requests.child(order_number).setValue(request);
+
+ sendNotificationOrder(order_number);
+
+ //Delete Cart
+ new Database(getBaseContext()).cleanCart();
+ Toast.makeText(OrderDetail.this, "Đặt hàng thành công!", Toast.LENGTH_SHORT).show();
+ startActivity(new Intent(OrderDetail.this, Home.class));
+ finish();
+ }
+ });
+
+ btnZaloPay.setOnClickListener(new View.OnClickListener() {
+ @RequiresApi(api = Build.VERSION_CODES.O)
+ @SuppressLint("SetTextI18n")
+ @Override
+ public void onClick(View v) {
+
+ String totalPrice = request.getTotal().substring(0, request.getTotal().length() - 2).replace(".", ""); //Remove character " đ"
+
+ CreateOrder orderApi = new CreateOrder();
+
+ try {
+ JSONObject data = orderApi.createOrder(totalPrice);
+ Log.d("Amount", totalPrice);
+ String code = data.getString("return_code");
+
+ if (code.equals("1")) {
+ String token = data.getString("zp_trans_token");
+ ZaloPaySDK.getInstance().payOrder(OrderDetail.this, token, "demozpdk://app", new PayOrderListener() {
+ @Override
+ public void onPaymentSucceeded(final String transactionId, final String transToken, final String appTransID) {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ request.setPaymentStatus("Đã thanh toán!");
+ //Summit to Firebase
+ //We will using System.CurrentMilli to key
+ String order_number = String.valueOf(System.currentTimeMillis());
+ requests.child(order_number).setValue(request);
+
+ sendNotificationOrder(order_number);
+
+ //Delete Cart
+ new Database(getBaseContext()).cleanCart();
+ Toast.makeText(OrderDetail.this, "Đặt hàng thành công!", Toast.LENGTH_SHORT).show();
+ startActivity(new Intent(OrderDetail.this, Home.class));
+ finish();
+ }
+
+ });
+ }
+
+ @Override
+ public void onPaymentCanceled(String zpTransToken, String appTransID) {
+ Toast.makeText(OrderDetail.this, "Bạn đã huỷ thanh toán!", Toast.LENGTH_SHORT).show();
+ }
+
+ @Override
+ public void onPaymentError(ZaloPayError zaloPayError, String zpTransToken, String appTransID) {
+ Toast.makeText(OrderDetail.this, "Đã xảy ra lỗi hệ thống! Xin vui lòng thử lại sau!", Toast.LENGTH_SHORT).show();
+ }
+ });
+ }
+
+ } catch (Exception e) {
+ Log.e("ERROR", "" + e.getMessage());
+ }
+ }
+ });
+
+ // calling the action bar
+ ActionBar actionBar = getSupportActionBar();
+
+ // showing the back button in action bar
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ }
+
+ private void sendNotificationOrder(String order_number) {
+ DatabaseReference tokens = FirebaseDatabase.getInstance().getReference("Tokens");
+ Query data = tokens.orderByChild("serverToken").equalTo(true); //Get all node with isServerToken is true;
+ data.addValueEventListener(new ValueEventListener() {
+ @Override
+ public void onDataChange(DataSnapshot dataSnapshot) {
+ for (DataSnapshot postSnapShot : dataSnapshot.getChildren()) {
+
+ Token serverToken = postSnapShot.getValue(Token.class);
+
+ //Create raw payload to send
+ Notification notification = new Notification("Foodify", "Bạn có 1 đơn hàng mới " + order_number);
+ Sender content = new Sender(serverToken.getToken(), notification);
+
+ mService.sendNotification(content)
+ .enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+
+ //Only run when get result
+ if (response.code() == 200) {
+ if (response.body().success == 1) {
+ new Database(getBaseContext()).cleanCart();
+ Toast.makeText(OrderDetail.this, "Đặt hàng thành công!", Toast.LENGTH_SHORT).show();
+ finish();
+ } else {
+ Toast.makeText(OrderDetail.this, "Hệ thống bị lỗi. Vui lòng thử lại sau!", Toast.LENGTH_SHORT).show();
+ }
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ Log.e("ERROR", t.getMessage());
+ }
+ });
+ }
+ }
+
+ @Override
+ public void onCancelled(DatabaseError databaseError) {
+
+ }
+ });
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ ZaloPaySDK.getInstance().onResult(intent);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
+ switch (item.getItemId()) {
+ case android.R.id.home:
+ this.finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
\ No newline at end of file
diff --git a/Foodify/app/src/main/java/com/waterbase/foodify/ViewHolder/CartAdapter.java b/Foodify/app/src/main/java/com/waterbase/foodify/ViewHolder/CartAdapter.java
index a31c804..a91ea3e 100644
--- a/Foodify/app/src/main/java/com/waterbase/foodify/ViewHolder/CartAdapter.java
+++ b/Foodify/app/src/main/java/com/waterbase/foodify/ViewHolder/CartAdapter.java
@@ -94,7 +94,7 @@ public class CartAdapter extends RecyclerView.Adapter{
holder.btn_quantity.setOnValueChangeListener(new ElegantNumberButton.OnValueChangeListener() {
@Override
public void onValueChange(ElegantNumberButton view, int oldValue, int newValue) {
- Order order = listData.get(position);
+ Order order = listData.get(holder.getAdapterPosition());
order.setQuantity(String.valueOf(newValue));
new Database(cart).updateCart(order);
diff --git a/Foodify/app/src/main/java/com/waterbase/foodify/ViewHolder/OrderDetailAdapter.java b/Foodify/app/src/main/java/com/waterbase/foodify/ViewHolder/OrderDetailAdapter.java
new file mode 100644
index 0000000..96e7caa
--- /dev/null
+++ b/Foodify/app/src/main/java/com/waterbase/foodify/ViewHolder/OrderDetailAdapter.java
@@ -0,0 +1,83 @@
+package com.waterbase.foodify.ViewHolder;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+
+import com.squareup.picasso.Picasso;
+import com.waterbase.foodify.Cart;
+import com.waterbase.foodify.Model.Order;
+import com.waterbase.foodify.OrderDetail;
+import com.waterbase.foodify.R;
+
+import java.text.NumberFormat;
+import java.util.List;
+import java.util.Locale;
+
+class MyViewHolder extends RecyclerView.ViewHolder {
+
+ public TextView name, quantity, price, discount;
+ public ImageView cart_image;
+
+ public MyViewHolder(@NonNull View itemView) {
+ super(itemView);
+ name = (TextView) itemView.findViewById(R.id.product_name);
+ quantity = (TextView) itemView.findViewById(R.id.product_quantity);
+ price = (TextView) itemView.findViewById(R.id.product_price);
+ discount = (TextView) itemView.findViewById(R.id.product_discount);
+ cart_image = (ImageView) itemView.findViewById(R.id.cart_image);
+ }
+}
+
+public class OrderDetailAdapter extends RecyclerView.Adapter{
+
+ List myOrders;
+ private OrderDetail orderDetail;
+
+ public OrderDetailAdapter(List myOrders, OrderDetail orderDetail) {
+ this.myOrders = myOrders;
+ this.orderDetail = orderDetail;
+ }
+
+ @NonNull
+ @Override
+ public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View itemView = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.order_detail_layout, parent, false);
+ return new MyViewHolder(itemView);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
+ double totalPrice;
+ Order order = myOrders.get(position);
+
+ Picasso.with(orderDetail.getBaseContext())
+ .load(myOrders.get(position).getImage())
+ .resize(70,70)
+ .centerCrop()
+ .into(holder.cart_image);
+
+ totalPrice = Double.parseDouble(order.getQuantity()) * Double.parseDouble(order.getPrice());
+ Locale locale = new Locale("vi", "VN");
+ NumberFormat fmt = NumberFormat.getCurrencyInstance(locale);
+
+
+ holder.name.setText(String.format("Món ăn: %s", order.getProductName()));
+ holder.quantity.setText(String.format("Số lượng: %s", order.getQuantity()));
+ holder.price.setText("Giá: " + fmt.format(totalPrice));
+ holder.discount.setText(String.format("Giảm giá: %s", order.getDiscount()));
+
+ }
+
+ @Override
+ public int getItemCount() {
+ return myOrders.size();
+ }
+}
diff --git a/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Api/CreateOrder.java b/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Api/CreateOrder.java
new file mode 100644
index 0000000..1c56f97
--- /dev/null
+++ b/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Api/CreateOrder.java
@@ -0,0 +1,70 @@
+package com.waterbase.foodify.Zalopay.Api;
+
+import com.waterbase.foodify.Zalopay.Constant.AppInfo;
+import com.waterbase.foodify.Zalopay.Helper.Helpers;
+
+import org.json.JSONObject;
+
+import java.util.Date;
+
+import okhttp3.FormBody;
+import okhttp3.RequestBody;
+
+public class CreateOrder {
+ private class CreateOrderData {
+ String AppId;
+ String AppUser;
+ String AppTime;
+ String Amount;
+ String AppTransId;
+ String EmbedData;
+ String Items;
+ String BankCode;
+ String Description;
+ String Mac;
+
+ private CreateOrderData(String amount) throws Exception {
+ long appTime = new Date().getTime();
+ AppId = String.valueOf(AppInfo.APP_ID);
+ AppUser = "Android_Demo";
+ AppTime = String.valueOf(appTime);
+ Amount = amount;
+ AppTransId = Helpers.getAppTransId();
+ EmbedData = "{}";
+ Items = "[]";
+ BankCode = "zalopayapp";
+ Description = "Merchant pay for order #" + Helpers.getAppTransId();
+ String inputHMac = String.format("%s|%s|%s|%s|%s|%s|%s",
+ this.AppId,
+ this.AppTransId,
+ this.AppUser,
+ this.Amount,
+ this.AppTime,
+ this.EmbedData,
+ this.Items);
+
+ Mac = Helpers.getMac(AppInfo.MAC_KEY, inputHMac);
+ }
+ }
+
+ public JSONObject createOrder(String amount) throws Exception {
+ CreateOrderData input = new CreateOrderData(amount);
+
+ RequestBody formBody = new FormBody.Builder()
+ .add("app_id", input.AppId)
+ .add("app_user", input.AppUser)
+ .add("app_time", input.AppTime)
+ .add("amount", input.Amount)
+ .add("app_trans_id", input.AppTransId)
+ .add("embed_data", input.EmbedData)
+ .add("item", input.Items)
+ .add("bank_code", input.BankCode)
+ .add("description", input.Description)
+ .add("mac", input.Mac)
+ .build();
+
+ JSONObject data = HttpProvider.sendPost(AppInfo.URL_CREATE_ORDER, formBody);
+ return data;
+ }
+}
+
diff --git a/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Api/HttpProvider.java b/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Api/HttpProvider.java
new file mode 100644
index 0000000..d0ae765
--- /dev/null
+++ b/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Api/HttpProvider.java
@@ -0,0 +1,58 @@
+package com.waterbase.foodify.Zalopay.Api;
+
+import android.util.Log;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+
+import okhttp3.CipherSuite;
+import okhttp3.ConnectionSpec;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okhttp3.TlsVersion;
+
+public class HttpProvider {
+ public static JSONObject sendPost(String URL, RequestBody formBody) {
+ JSONObject data = new JSONObject();
+ try {
+ ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
+ .tlsVersions(TlsVersion.TLS_1_2)
+ .cipherSuites(
+ CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
+ .build();
+
+ OkHttpClient client = new OkHttpClient.Builder()
+ .connectionSpecs(Collections.singletonList(spec))
+ .callTimeout(5000, TimeUnit.MILLISECONDS)
+ .build();
+
+ Request request = new Request.Builder()
+ .url(URL)
+ .addHeader("Content-Type", "application/x-www-form-urlencoded")
+ .post(formBody)
+ .build();
+
+ Response response = client.newCall(request).execute();
+
+ if (!response.isSuccessful()) {
+ Log.println(Log.ERROR, "BAD_REQUEST", response.body().string());
+ data = null;
+ } else {
+ data = new JSONObject(response.body().string());
+ }
+
+ } catch (IOException | JSONException e) {
+ e.printStackTrace();
+ }
+
+ return data;
+ }
+}
diff --git a/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Constant/AppInfo.java b/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Constant/AppInfo.java
new file mode 100644
index 0000000..569bdf0
--- /dev/null
+++ b/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Constant/AppInfo.java
@@ -0,0 +1,7 @@
+package com.waterbase.foodify.Zalopay.Constant;
+
+public class AppInfo {
+ public static final int APP_ID = 2554;
+ public static final String MAC_KEY = "sdngKKJmqEMzvh5QQcdD2A9XBSKUNaYn";
+ public static final String URL_CREATE_ORDER = "https://sb-openapi.zalopay.vn/v2/create";
+}
diff --git a/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Helper/HMac/HMacUtil.java b/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Helper/HMac/HMacUtil.java
new file mode 100644
index 0000000..b619607
--- /dev/null
+++ b/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Helper/HMac/HMacUtil.java
@@ -0,0 +1,93 @@
+package com.waterbase.foodify.Zalopay.Helper.HMac;
+
+import android.os.Build;
+
+import androidx.annotation.RequiresApi;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.LinkedList;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+public class HMacUtil {
+ public final static String HMACMD5 = "HmacMD5";
+ public final static String HMACSHA1 = "HmacSHA1";
+ public final static String HMACSHA256 = "HmacSHA256";
+ public final static String HMACSHA512 = "HmacSHA512";
+ public final static Charset UTF8CHARSET = StandardCharsets.UTF_8;
+
+ public final static LinkedList HMACS = new LinkedList(Arrays.asList("UnSupport", "HmacSHA256", "HmacMD5", "HmacSHA384", "HMacSHA1", "HmacSHA512"));
+ // @formatter:on
+
+ private static byte[] HMacEncode(final String algorithm, final String key, final String data) {
+ Mac macGenerator = null;
+ try {
+ macGenerator = Mac.getInstance(algorithm);
+ SecretKeySpec signingKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), algorithm);
+ macGenerator.init(signingKey);
+ } catch (Exception ex) {
+ }
+
+ if (macGenerator == null) {
+ return null;
+ }
+
+ byte[] dataByte = null;
+ try {
+ dataByte = data.getBytes("UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ }
+
+ return macGenerator.doFinal(dataByte);
+ }
+
+ /**
+ * Calculating a message authentication code (MAC) involving a cryptographic
+ * hash function in combination with a secret cryptographic key.
+ *
+ * The result will be represented base64-encoded string.
+ *
+ * @param algorithm A cryptographic hash function (such as MD5 or SHA-1)
+ *
+ * @param key A secret cryptographic key
+ *
+ * @param data The message to be authenticated
+ *
+ * @return Base64-encoded HMAC String
+ */
+ @RequiresApi(api = Build.VERSION_CODES.O)
+ public static String HMacBase64Encode(final String algorithm, final String key, final String data) {
+ byte[] hmacEncodeBytes = HMacEncode(algorithm, key, data);
+ if (hmacEncodeBytes == null) {
+ return null;
+ }
+ return Base64.getEncoder().encodeToString(hmacEncodeBytes);
+ }
+
+ /**
+ * Calculating a message authentication code (MAC) involving a cryptographic
+ * hash function in combination with a secret cryptographic key.
+ *
+ * The result will be represented hex string.
+ *
+ * @param algorithm A cryptographic hash function (such as MD5 or SHA-1)
+ *
+ * @param key A secret cryptographic key
+ *
+ * @param data The message to be authenticated
+ *
+ * @return Hex HMAC String
+ */
+ public static String HMacHexStringEncode(final String algorithm, final String key, final String data) {
+ byte[] hmacEncodeBytes = HMacEncode(algorithm, key, data);
+ if (hmacEncodeBytes == null) {
+ return null;
+ }
+ return HexStringUtil.byteArrayToHexString(hmacEncodeBytes);
+ }
+}
diff --git a/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Helper/HMac/HexStringUtil.java b/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Helper/HMac/HexStringUtil.java
new file mode 100644
index 0000000..22d01bc
--- /dev/null
+++ b/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Helper/HMac/HexStringUtil.java
@@ -0,0 +1,69 @@
+package com.waterbase.foodify.Zalopay.Helper.HMac;
+
+import java.util.Locale;
+
+public class HexStringUtil {
+ private static final byte[] HEX_CHAR_TABLE = {
+ (byte) '0', (byte) '1', (byte) '2', (byte) '3',
+ (byte) '4', (byte) '5', (byte) '6', (byte) '7',
+ (byte) '8', (byte) '9', (byte) 'a', (byte) 'b',
+ (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f'
+ };
+ // @formatter:on
+
+ /**
+ * Convert a byte array to a hexadecimal string
+ *
+ * @param raw
+ * A raw byte array
+ *
+ * @return Hexadecimal string
+ */
+ public static String byteArrayToHexString(byte[] raw) {
+ byte[] hex = new byte[2 * raw.length];
+ int index = 0;
+
+ for (byte b : raw) {
+ int v = b & 0xFF;
+ hex[index++] = HEX_CHAR_TABLE[v >>> 4];
+ hex[index++] = HEX_CHAR_TABLE[v & 0xF];
+ }
+ return new String(hex);
+ }
+
+ /**
+ * Convert a hexadecimal string to a byte array
+ *
+ * @param hex
+ * A hexadecimal string
+ *
+ * @return The byte array
+ */
+ public static byte[] hexStringToByteArray(String hex) {
+ String hexstandard = hex.toLowerCase(Locale.ENGLISH);
+ int sz = hexstandard.length() / 2;
+ byte[] bytesResult = new byte[sz];
+
+ int idx = 0;
+ for (int i = 0; i < sz; i++) {
+ bytesResult[i] = (byte) (hexstandard.charAt(idx));
+ ++idx;
+ byte tmp = (byte) (hexstandard.charAt(idx));
+ ++idx;
+
+ if (bytesResult[i] > HEX_CHAR_TABLE[9]) {
+ bytesResult[i] -= ((byte) ('a') - 10);
+ } else {
+ bytesResult[i] -= (byte) ('0');
+ }
+ if (tmp > HEX_CHAR_TABLE[9]) {
+ tmp -= ((byte) ('a') - 10);
+ } else {
+ tmp -= (byte) ('0');
+ }
+
+ bytesResult[i] = (byte) (bytesResult[i] * 16 + tmp);
+ }
+ return bytesResult;
+ }
+}
diff --git a/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Helper/Helpers.java b/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Helper/Helpers.java
new file mode 100644
index 0000000..c194235
--- /dev/null
+++ b/Foodify/app/src/main/java/com/waterbase/foodify/Zalopay/Helper/Helpers.java
@@ -0,0 +1,35 @@
+package com.waterbase.foodify.Zalopay.Helper;
+
+import android.annotation.SuppressLint;
+
+import com.waterbase.foodify.Zalopay.Helper.HMac.HMacUtil;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Objects;
+
+public class Helpers {
+ private static int transIdDefault = 1;
+
+ @NotNull
+ @SuppressLint("DefaultLocale")
+ public static String getAppTransId() {
+ if (transIdDefault >= 100000) {
+ transIdDefault = 1;
+ }
+
+ transIdDefault += 1;
+ @SuppressLint("SimpleDateFormat") SimpleDateFormat formatDateTime = new SimpleDateFormat("yyMMdd_hhmmss");
+ String timeString = formatDateTime.format(new Date());
+ return String.format("%s%06d", timeString, transIdDefault);
+ }
+
+ @NotNull
+ public static String getMac(@NotNull String key, @NotNull String data) throws NoSuchAlgorithmException, InvalidKeyException {
+ return Objects.requireNonNull(HMacUtil.HMacHexStringEncode(HMacUtil.HMACSHA256, key, data));
+ }
+}
diff --git a/Foodify/app/src/main/res/drawable/zalopayfix.png b/Foodify/app/src/main/res/drawable/zalopayfix.png
new file mode 100644
index 0000000..7b5c824
Binary files /dev/null and b/Foodify/app/src/main/res/drawable/zalopayfix.png differ
diff --git a/Foodify/app/src/main/res/layout/activity_cart.xml b/Foodify/app/src/main/res/layout/activity_cart.xml
index f900110..b6f543d 100644
--- a/Foodify/app/src/main/res/layout/activity_cart.xml
+++ b/Foodify/app/src/main/res/layout/activity_cart.xml
@@ -8,13 +8,25 @@
android:padding="16dp"
tools:context=".Cart">
-
+ android:layout_height="match_parent"
+ >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Foodify/app/src/main/res/layout/order_detail_layout.xml b/Foodify/app/src/main/res/layout/order_detail_layout.xml
new file mode 100644
index 0000000..0a195bc
--- /dev/null
+++ b/Foodify/app/src/main/res/layout/order_detail_layout.xml
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file