From 01a900892e256f0f7eed21558365b3b55d22f87d Mon Sep 17 00:00:00 2001 From: Nezumi <123229563+Nez27@users.noreply.github.com> Date: Thu, 23 Mar 2023 16:56:25 +0700 Subject: [PATCH] Add calculate shipper cost depend on distance --- .idea/misc.xml | 2 +- app/build.gradle | 2 + .../capstone/foodify/API/GoogleMapApi.java | 24 + .../Activity/AddressManagerActivity.java | 14 +- .../Activity/OrderCheckOutActivity.java | 113 ++- .../java/com/capstone/foodify/Common.java | 1 + .../Model/GoogleMap/AddressComponent.java | 44 + .../foodify/Model/GoogleMap/Geometry.java | 43 + .../Model/GoogleMap/GoogleMapResponse.java | 34 + .../foodify/Model/GoogleMap/Location.java | 32 + .../foodify/Model/GoogleMap/Northeast.java | 32 + .../foodify/Model/GoogleMap/Result.java | 66 ++ .../foodify/Model/GoogleMap/Southwest.java | 32 + .../foodify/Model/GoogleMap/Viewport.java | 32 + .../res/layout/activity_order_check_out.xml | 834 ++++++++++-------- 15 files changed, 911 insertions(+), 394 deletions(-) create mode 100644 app/src/main/java/com/capstone/foodify/API/GoogleMapApi.java create mode 100644 app/src/main/java/com/capstone/foodify/Model/GoogleMap/AddressComponent.java create mode 100644 app/src/main/java/com/capstone/foodify/Model/GoogleMap/Geometry.java create mode 100644 app/src/main/java/com/capstone/foodify/Model/GoogleMap/GoogleMapResponse.java create mode 100644 app/src/main/java/com/capstone/foodify/Model/GoogleMap/Location.java create mode 100644 app/src/main/java/com/capstone/foodify/Model/GoogleMap/Northeast.java create mode 100644 app/src/main/java/com/capstone/foodify/Model/GoogleMap/Result.java create mode 100644 app/src/main/java/com/capstone/foodify/Model/GoogleMap/Southwest.java create mode 100644 app/src/main/java/com/capstone/foodify/Model/GoogleMap/Viewport.java diff --git a/.idea/misc.xml b/.idea/misc.xml index 8978d23..773fe0f 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + diff --git a/app/build.gradle b/app/build.gradle index 211f9f7..7a83652 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -50,6 +50,7 @@ dependencies { implementation 'com.google.firebase:firebase-storage:20.1.0' implementation 'com.google.android.gms:play-services-auth:20.4.1' implementation 'com.google.android.gms:play-services-auth-api-phone:18.0.1' + implementation 'com.google.android.gms:play-services-maps:18.1.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' @@ -61,6 +62,7 @@ dependencies { implementation 'com.google.android.material:material:1.8.0' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' + implementation 'com.squareup.retrofit2:converter-scalars:2.9.0' implementation 'com.github.denzcoskun:ImageSlideshow:0.1.0' implementation 'com.makeramen:roundedimageview:2.3.0' diff --git a/app/src/main/java/com/capstone/foodify/API/GoogleMapApi.java b/app/src/main/java/com/capstone/foodify/API/GoogleMapApi.java new file mode 100644 index 0000000..17c6676 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/API/GoogleMapApi.java @@ -0,0 +1,24 @@ +package com.capstone.foodify.API; + +import com.capstone.foodify.Model.GoogleMap.GoogleMapResponse; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import retrofit2.Call; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; +import retrofit2.http.GET; +import retrofit2.http.Query; + +public interface GoogleMapApi { + + Gson gson = new GsonBuilder().setDateFormat("HH:mm:ss dd-MM-yyyy").setLenient().create(); + + GoogleMapApi apiService = new Retrofit.Builder() + .baseUrl("https://maps.googleapis.com/").addConverterFactory(GsonConverterFactory.create(gson)) + .build() + .create(GoogleMapApi.class); + + @GET("maps/api/geocode/json") + Call getGeoCode(@Query("address") String address, @Query("key") String key); +} diff --git a/app/src/main/java/com/capstone/foodify/Activity/AddressManagerActivity.java b/app/src/main/java/com/capstone/foodify/Activity/AddressManagerActivity.java index 3ece135..799fbf8 100644 --- a/app/src/main/java/com/capstone/foodify/Activity/AddressManagerActivity.java +++ b/app/src/main/java/com/capstone/foodify/Activity/AddressManagerActivity.java @@ -130,7 +130,15 @@ public class AddressManagerActivity extends AppCompatActivity { private void initDefaultAddress(){ //Create a full address string - String fullAddress = defaultAddress.getAddress() + ", " + defaultAddress.getWard() + ", " + defaultAddress.getDistrict(); + + String fullAddress; + //If user choice "Huyện Hoàng Sa" District + if(defaultAddress.getWard().equals("---Phường")){ + //Create a full address string + fullAddress = defaultAddress.getAddress() + ", " + defaultAddress.getDistrict(); + } else { + fullAddress = defaultAddress.getAddress() + ", " + defaultAddress.getWard() + ", " + defaultAddress.getDistrict(); + } //Bind data to component txt_Address.setText(fullAddress); @@ -164,11 +172,13 @@ public class AddressManagerActivity extends AppCompatActivity { CustomResponse responseData = response.body(); - if(responseData.getTitle().equals("Create address")){ + if(response.code() == 200){ Toast.makeText(AddressManagerActivity.this, "Đã thêm địa chỉ thành công!", Toast.LENGTH_SHORT).show(); //Update data user updateUser(isChecked); + } else { + Toast.makeText(AddressManagerActivity.this, "Đã có lỗi từ hệ thống, vui lòng thử lại sau!", Toast.LENGTH_SHORT).show(); } } diff --git a/app/src/main/java/com/capstone/foodify/Activity/OrderCheckOutActivity.java b/app/src/main/java/com/capstone/foodify/Activity/OrderCheckOutActivity.java index fe66bac..9d3c407 100644 --- a/app/src/main/java/com/capstone/foodify/Activity/OrderCheckOutActivity.java +++ b/app/src/main/java/com/capstone/foodify/Activity/OrderCheckOutActivity.java @@ -1,10 +1,5 @@ package com.capstone.foodify.Activity; -import androidx.appcompat.app.AppCompatActivity; -import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; - import android.content.Context; import android.content.Intent; import android.graphics.Typeface; @@ -22,16 +17,24 @@ import android.widget.Spinner; import android.widget.TextView; import android.widget.Toast; +import androidx.appcompat.app.AppCompatActivity; +import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.core.widget.NestedScrollView; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + import com.capstone.foodify.API.FoodApi; +import com.capstone.foodify.API.GoogleMapApi; import com.capstone.foodify.Adapter.OrderDetailAdapter; import com.capstone.foodify.Common; import com.capstone.foodify.Model.Address; -import com.capstone.foodify.Model.Basket; import com.capstone.foodify.Model.DistrictWardResponse; -import com.capstone.foodify.Model.OrderDetail; +import com.capstone.foodify.Model.GoogleMap.GoogleMapResponse; import com.capstone.foodify.R; +import com.google.android.gms.maps.model.LatLng; import com.google.android.material.textfield.TextInputLayout; +import java.text.DecimalFormat; import java.util.ArrayList; import java.util.List; @@ -40,18 +43,21 @@ import retrofit2.Callback; import retrofit2.Response; public class OrderCheckOutActivity extends AppCompatActivity { + private static final Double LAT_SHOP = 16.0500622; + private static final Double LNG_SHOP = 108.2351611; private static String finalAddress = null; ImageView back_image; OrderDetailAdapter adapter; RecyclerView recyclerView; - TextView txt_userName, txt_phone, edt_address_detect, errorTextDistrictWard, txt_total; + TextView txt_userName, txt_phone, edt_address_detect, errorTextDistrictWard, txt_total, txt_distance, txt_ship_cost; TextInputLayout textInput_address; EditText edt_address; Spinner spn_list_address, spn_district, spn_ward; ConstraintLayout manual_input_address_layout; Button change_address_button, confirm_address_button; - RadioButton list_address_input, auto_detect_location, manual_input_address, radio_button_selected; + RadioButton list_address_input, auto_detect_location, manual_input_address, radio_button_selected, take_food_from_shop; RadioGroup address_option; + ConstraintLayout progress_layout; float total; private static final ArrayList wardList = new ArrayList<>(); private static final ArrayList districtList = new ArrayList<>(); @@ -87,6 +93,11 @@ public class OrderCheckOutActivity extends AppCompatActivity { errorTextDistrictWard = findViewById(R.id.errorTextDistrictWard); textInput_address = findViewById(R.id.textInput_address); txt_total = findViewById(R.id.txt_total); + take_food_from_shop = findViewById(R.id.take_food_from_shop); + progress_layout = findViewById(R.id.progress_layout); + txt_distance = findViewById(R.id.txt_distance); + txt_ship_cost = findViewById(R.id.txt_ship_cost); + if(getIntent() != null){ total = getIntent().getFloatExtra("total", 0); @@ -152,12 +163,13 @@ public class OrderCheckOutActivity extends AppCompatActivity { if(finalAddress == null){ Toast.makeText(OrderCheckOutActivity.this, "Bạn chưa chọn địa chỉ!", Toast.LENGTH_SHORT).show(); } else { - Toast.makeText(OrderCheckOutActivity.this, finalAddress, Toast.LENGTH_SHORT).show(); - + progress_layout.setVisibility(View.VISIBLE); confirm_address_button.setEnabled(false); change_address_button.setVisibility(View.VISIBLE); disableAllInputAddressOption(); + + getDistanceAndCalculateShipCost(finalAddress); } } }); @@ -171,6 +183,76 @@ public class OrderCheckOutActivity extends AppCompatActivity { }); } + private void getDistanceAndCalculateShipCost(String address) { + //Get location from address + + GoogleMapApi.apiService.getGeoCode(address, Common.MAP_API).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + GoogleMapResponse jsonResponse = response.body(); + + Double lat = jsonResponse.getResults().get(0).getGeometry().getLocation().getLat(); + Double lng = jsonResponse.getResults().get(0).getGeometry().getLocation().getLng(); + + LatLng addressFrom = new LatLng(lat, lng); + LatLng addressTo = new LatLng(LAT_SHOP, LNG_SHOP); + + double distance = CalculationByDistance(addressFrom, addressTo); + + double roundDistance = Math.round(distance * 100.0) / 100.0; + + //Show distance to user + txt_distance.setText(roundDistance + " km"); + + //Calculate ship cost + float shipCost = 0; + if(roundDistance <= 3){ + shipCost = 15000; + } else if(roundDistance > 3 && roundDistance <= 10){ + shipCost = 5000 * (float) roundDistance; + } else { + shipCost = 3000 * (float) roundDistance; + } + + txt_ship_cost.setText(Common.changeCurrencyUnit(shipCost)); + + //Update total order + total = total + shipCost; + txt_total.setText(Common.changeCurrencyUnit(total)); + + progress_layout.setVisibility(View.GONE); + } + + @Override + public void onFailure(Call call, Throwable t) { + Toast.makeText(OrderCheckOutActivity.this, "Error: " + t, Toast.LENGTH_SHORT).show(); + } + }); + } + + public double CalculationByDistance(LatLng from, LatLng to) { + int Radius = 6371;// radius of earth in Km + double lat1 = from.latitude; + double lat2 = to.latitude; + double lon1 = from.longitude; + double lon2 = to.longitude; + double dLat = Math.toRadians(lat2 - lat1); + double dLon = Math.toRadians(lon2 - lon1); + double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.cos(Math.toRadians(lat1)) + * Math.cos(Math.toRadians(lat2)) * Math.sin(dLon / 2) + * Math.sin(dLon / 2); + double c = 2 * Math.asin(Math.sqrt(a)); + double valueResult = Radius * c; + double km = valueResult / 1; + DecimalFormat newFormat = new DecimalFormat("####"); + int kmInDec = Integer.valueOf(newFormat.format(km)); + double meter = valueResult % 1000; + int meterInDec = Integer.valueOf(newFormat.format(meter)); + + return Radius * c; + } + private boolean validForm(){ //Valid data boolean dataHasValidate = true; @@ -226,6 +308,7 @@ public class OrderCheckOutActivity extends AppCompatActivity { list_address_input.setEnabled(false); auto_detect_location.setEnabled(false); manual_input_address.setEnabled(false); + take_food_from_shop.setEnabled(false); spn_list_address.setEnabled(false); edt_address.setEnabled(false); @@ -237,6 +320,7 @@ public class OrderCheckOutActivity extends AppCompatActivity { list_address_input.setEnabled(true); auto_detect_location.setEnabled(true); manual_input_address.setEnabled(true); + take_food_from_shop.setEnabled(true); spn_list_address.setEnabled(true); edt_address.setEnabled(true); @@ -317,6 +401,13 @@ public class OrderCheckOutActivity extends AppCompatActivity { finalAddress = null; } break; + + case R.id.take_food_from_shop: + if(checked){ + manual_input_address_layout.setVisibility(View.GONE); + spn_list_address.setVisibility(View.GONE); + edt_address_detect.setVisibility(View.GONE); + } } } diff --git a/app/src/main/java/com/capstone/foodify/Common.java b/app/src/main/java/com/capstone/foodify/Common.java index b7d984f..a4089ea 100644 --- a/app/src/main/java/com/capstone/foodify/Common.java +++ b/app/src/main/java/com/capstone/foodify/Common.java @@ -32,6 +32,7 @@ import retrofit2.Callback; import retrofit2.Response; public class Common { + public static final String MAP_API = "AIzaSyCR46ZE1kbE7zkTehhflB9jZgDjDT_2944"; public static final String IS_FORGOT_PASSWORD = "isForgotPassword"; public static final String FORMAT_DATE="dd-MM-yyyy"; public static final String VALID_EMAIL_ADDRESS_REGEX = "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$"; diff --git a/app/src/main/java/com/capstone/foodify/Model/GoogleMap/AddressComponent.java b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/AddressComponent.java new file mode 100644 index 0000000..9977584 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/AddressComponent.java @@ -0,0 +1,44 @@ + +package com.capstone.foodify.Model.GoogleMap; + +import java.util.List; +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class AddressComponent { + + @SerializedName("long_name") + @Expose + private String longName; + @SerializedName("short_name") + @Expose + private String shortName; + @SerializedName("types") + @Expose + private List types; + + public String getLongName() { + return longName; + } + + public void setLongName(String longName) { + this.longName = longName; + } + + public String getShortName() { + return shortName; + } + + public void setShortName(String shortName) { + this.shortName = shortName; + } + + public List getTypes() { + return types; + } + + public void setTypes(List types) { + this.types = types; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Geometry.java b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Geometry.java new file mode 100644 index 0000000..42b6b0f --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Geometry.java @@ -0,0 +1,43 @@ + +package com.capstone.foodify.Model.GoogleMap; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Geometry { + + @SerializedName("location") + @Expose + private Location location; + @SerializedName("location_type") + @Expose + private String locationType; + @SerializedName("viewport") + @Expose + private Viewport viewport; + + public Location getLocation() { + return location; + } + + public void setLocation(Location location) { + this.location = location; + } + + public String getLocationType() { + return locationType; + } + + public void setLocationType(String locationType) { + this.locationType = locationType; + } + + public Viewport getViewport() { + return viewport; + } + + public void setViewport(Viewport viewport) { + this.viewport = viewport; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/Model/GoogleMap/GoogleMapResponse.java b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/GoogleMapResponse.java new file mode 100644 index 0000000..68dc2b3 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/GoogleMapResponse.java @@ -0,0 +1,34 @@ + +package com.capstone.foodify.Model.GoogleMap; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +import java.util.List; + +public class GoogleMapResponse { + + @SerializedName("results") + @Expose + private List results; + @SerializedName("status") + @Expose + private String status; + + public List getResults() { + return results; + } + + public void setResults(List results) { + this.results = results; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Location.java b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Location.java new file mode 100644 index 0000000..000635a --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Location.java @@ -0,0 +1,32 @@ + +package com.capstone.foodify.Model.GoogleMap; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Location { + + @SerializedName("lat") + @Expose + private Double lat; + @SerializedName("lng") + @Expose + private Double lng; + + public Double getLat() { + return lat; + } + + public void setLat(Double lat) { + this.lat = lat; + } + + public Double getLng() { + return lng; + } + + public void setLng(Double lng) { + this.lng = lng; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Northeast.java b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Northeast.java new file mode 100644 index 0000000..15d88c1 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Northeast.java @@ -0,0 +1,32 @@ + +package com.capstone.foodify.Model.GoogleMap; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Northeast { + + @SerializedName("lat") + @Expose + private Double lat; + @SerializedName("lng") + @Expose + private Double lng; + + public Double getLat() { + return lat; + } + + public void setLat(Double lat) { + this.lat = lat; + } + + public Double getLng() { + return lng; + } + + public void setLng(Double lng) { + this.lng = lng; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Result.java b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Result.java new file mode 100644 index 0000000..dbd8bfd --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Result.java @@ -0,0 +1,66 @@ + +package com.capstone.foodify.Model.GoogleMap; + +import java.util.List; +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Result { + + @SerializedName("address_components") + @Expose + private List addressComponents; + @SerializedName("formatted_address") + @Expose + private String formattedAddress; + @SerializedName("geometry") + @Expose + private Geometry geometry; + @SerializedName("place_id") + @Expose + private String placeId; + @SerializedName("types") + @Expose + private List types; + + public List getAddressComponents() { + return addressComponents; + } + + public void setAddressComponents(List addressComponents) { + this.addressComponents = addressComponents; + } + + public String getFormattedAddress() { + return formattedAddress; + } + + public void setFormattedAddress(String formattedAddress) { + this.formattedAddress = formattedAddress; + } + + public Geometry getGeometry() { + return geometry; + } + + public void setGeometry(Geometry geometry) { + this.geometry = geometry; + } + + public String getPlaceId() { + return placeId; + } + + public void setPlaceId(String placeId) { + this.placeId = placeId; + } + + public List getTypes() { + return types; + } + + public void setTypes(List types) { + this.types = types; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Southwest.java b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Southwest.java new file mode 100644 index 0000000..b783854 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Southwest.java @@ -0,0 +1,32 @@ + +package com.capstone.foodify.Model.GoogleMap; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Southwest { + + @SerializedName("lat") + @Expose + private Double lat; + @SerializedName("lng") + @Expose + private Double lng; + + public Double getLat() { + return lat; + } + + public void setLat(Double lat) { + this.lat = lat; + } + + public Double getLng() { + return lng; + } + + public void setLng(Double lng) { + this.lng = lng; + } + +} diff --git a/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Viewport.java b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Viewport.java new file mode 100644 index 0000000..4eac71f --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/Model/GoogleMap/Viewport.java @@ -0,0 +1,32 @@ + +package com.capstone.foodify.Model.GoogleMap; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Viewport { + + @SerializedName("northeast") + @Expose + private Northeast northeast; + @SerializedName("southwest") + @Expose + private Southwest southwest; + + public Northeast getNortheast() { + return northeast; + } + + public void setNortheast(Northeast northeast) { + this.northeast = northeast; + } + + public Southwest getSouthwest() { + return southwest; + } + + public void setSouthwest(Southwest southwest) { + this.southwest = southwest; + } + +} diff --git a/app/src/main/res/layout/activity_order_check_out.xml b/app/src/main/res/layout/activity_order_check_out.xml index 6ccc4a6..039f41c 100644 --- a/app/src/main/res/layout/activity_order_check_out.xml +++ b/app/src/main/res/layout/activity_order_check_out.xml @@ -1,433 +1,507 @@ - - + android:layout_height="match_parent" + android:clickable="false" + > - - - - - + android:layout_height="match_parent"> - - - - - - - + + android:textSize="30sp" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="@id/back_image" /> - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + - - + -