Tracking realtime shipper

This commit is contained in:
Nezumi
2023-04-08 15:22:42 +07:00
parent 93a0b970d9
commit 933174a8c1
21 changed files with 564 additions and 25 deletions
@@ -0,0 +1,19 @@
package com.capstone.foodify.API;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.scalars.ScalarsConverterFactory;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface GoogleMapDirectionApi {
GoogleMapDirectionApi apiService = new Retrofit.Builder()
.baseUrl("https://maps.googleapis.com/").addConverterFactory(ScalarsConverterFactory.create())
.build()
.create(GoogleMapDirectionApi.class);
@GET("maps/api/directions/json")
Call<String> getDirections(@Query("origin") String origin, @Query("destination") String destination,
@Query("key") String key);
}
@@ -77,7 +77,6 @@ public class MainActivity extends AppCompatActivity {
//Location
private static final int REQUEST_CHECK_SETTINGS = 100;
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 1000;
private static final long FASTEST_UPDATE_IN_MILLISECONDS = 3000;
private static final long MAX_WAIT_TIME_IN_MILLISECONDS = 1000;
private static final int LOCATION_REQUEST_CODE = 100;
private static final String TAG = MainActivity.class.getSimpleName();
@@ -167,7 +166,7 @@ public class MainActivity extends AppCompatActivity {
mLocationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, UPDATE_INTERVAL_IN_MILLISECONDS)
.setWaitForAccurateLocation(false)
.setMinUpdateDistanceMeters(FASTEST_UPDATE_IN_MILLISECONDS)
.setMinUpdateIntervalMillis(1000)
.setMaxUpdateDelayMillis(MAX_WAIT_TIME_IN_MILLISECONDS)
.build();
@@ -367,7 +366,6 @@ public class MainActivity extends AppCompatActivity {
@Override
protected void onResume() {
super.onResume();
HomeFragment.setNameUser();
if (mRequestingLocationUpdates && checkPermission() && Common.CURRENT_LOCATION == null) {
startLocationUpdates();
}
@@ -358,7 +358,6 @@ public class OrderCheckOutActivity extends AppCompatActivity {
// handle CreateOrder
btn_ZaloPay.setOnClickListener(new View.OnClickListener() {
@RequiresApi(api = Build.VERSION_CODES.O)
@SuppressLint("SetTextI18n")
@Override
public void onClick(View v) {
@@ -438,10 +437,9 @@ public class OrderCheckOutActivity extends AppCompatActivity {
Common.showErrorServerNotification(OrderCheckOutActivity.this, "Tài khoản của bạn đã bị khoá!");
}
progress_layout.setVisibility(View.GONE);
}
});
progress_layout.setVisibility(View.GONE);
}
private void createOrderFood(String transactionId, String paymentMethod) {
@@ -40,13 +40,15 @@ import retrofit2.Response;
public class OrderDetailActivity extends AppCompatActivity {
private static final String AWAITING = "AWAITING";
private static final String SHIPPING = "SHIPPING";
private TextView order_tracking_number, user_name, phone, address, orderTime, total, status;
private ImageView back_image;
private List<Basket> listOrderDetails = new ArrayList<>();
OrderDetailAdapter adapter;
RecyclerView recyclerView;
private Order order;
private Button btn_cancel_order;
private Button btn_cancel_order, btn_tracking_location_shipper;
private View line_cancel_order, line_tracking_order;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -60,8 +62,18 @@ public class OrderDetailActivity extends AppCompatActivity {
if(getIntent() != null)
order = (Order) getIntent().getSerializableExtra("order");
if(order.getStatus().equals(AWAITING))
if(order.getStatus().equals(AWAITING)){
btn_cancel_order.setVisibility(View.VISIBLE);
line_tracking_order.setVisibility(View.GONE);
}
if(order.getStatus().equals(SHIPPING)){
btn_tracking_location_shipper.setVisibility(View.VISIBLE);
line_cancel_order.setVisibility(View.GONE);
}
//Init data
order_tracking_number.setText("Order Id: #" + order.getOrderTrackingNumber());
@@ -101,6 +113,17 @@ public class OrderDetailActivity extends AppCompatActivity {
showDeleteDialogConfirm();
}
});
btn_tracking_location_shipper.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(OrderDetailActivity.this, TrackingOrderActivity.class);
intent.putExtra("trackingOrderNumber", order.getOrderTrackingNumber());
intent.putExtra("latOrder", order.getLat());
intent.putExtra("lngOrder", order.getLng());
startActivity(intent);
}
});
}
private void showDeleteDialogConfirm(){
@@ -141,8 +164,6 @@ public class OrderDetailActivity extends AppCompatActivity {
@Override
public void onClick(@NonNull AestheticDialog.Builder builder) {
OrderActivity.orderActivity.finish();
startActivity(new Intent(OrderDetailActivity.this, OrderActivity.class));
builder.dismiss();
finish();
@@ -173,6 +194,10 @@ public class OrderDetailActivity extends AppCompatActivity {
back_image = findViewById(R.id.back_image);
btn_cancel_order = findViewById(R.id.cancel_order_button);
status = findViewById(R.id.status);
btn_tracking_location_shipper = findViewById(R.id.tracking_shipper_location_button);
line_cancel_order = findViewById(R.id.line_view_cancel_order);
line_tracking_order = findViewById(R.id.line_view_tracking_order);
}
private String translateStatus(String status){
@@ -0,0 +1,255 @@
package com.capstone.foodify.Activity;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;
import com.capstone.foodify.API.GoogleMapDirectionApi;
import com.capstone.foodify.Common;
import com.capstone.foodify.DirectionJSONParser;
import com.capstone.foodify.Model.GoogleMap.Location;
import com.capstone.foodify.R;
import com.capstone.foodify.databinding.ActivityTrackingOrderBinding;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.gms.maps.model.Polyline;
import com.google.android.gms.maps.model.PolylineOptions;
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.ValueEventListener;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class TrackingOrderActivity extends FragmentActivity implements OnMapReadyCallback, ValueEventListener {
private GoogleMap mMap;
private ActivityTrackingOrderBinding binding;
private String trackingOrderNumber, latOrder, lngOrder = null;
private ImageView back_image;
private FirebaseDatabase database;
private DatabaseReference orderDatabase;
private Marker shippingMarker;
private Polyline polyline;
private static final String TAG = "TrackingOrderActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Get tracking number order
if(getIntent() != null){
trackingOrderNumber = getIntent().getStringExtra("trackingOrderNumber");
latOrder = getIntent().getStringExtra("latOrder");
lngOrder = getIntent().getStringExtra("lngOrder");
}
if(trackingOrderNumber == null){
Toast.makeText(this, "Chưa lấy được mã đơn hàng! Xin vui lòng thử lại sau!", Toast.LENGTH_SHORT).show();
finish();
}
binding = ActivityTrackingOrderBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
database = FirebaseDatabase.getInstance();
orderDatabase = database.getReference("Order");
orderDatabase.addValueEventListener(this);
//Init component
back_image = findViewById(R.id.back_image);
back_image.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
finish();
}
});
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
@SuppressLint("MissingPermission")
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
mMap.getUiSettings().setZoomControlsEnabled(true);
mMap.getUiSettings().setMapToolbarEnabled(true);
mMap.getUiSettings().setCompassEnabled(true);
trackingLocation();
}
private void trackingLocation() {
//Get order location
LatLng location = new LatLng(Double.parseDouble(latOrder), Double.parseDouble(lngOrder));
mMap.addMarker(new MarkerOptions().position(location)
.title("Đơn hàng #" + trackingOrderNumber)
.icon(BitmapDescriptorFactory.defaultMarker()));
//Set shipper location
orderDatabase.child(trackingOrderNumber).addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
Location shipperLocation = snapshot.getValue(Location.class);
LatLng latLng = new LatLng(shipperLocation.getLat(), shipperLocation.getLng());
if(shippingMarker == null){
shippingMarker = mMap.addMarker(new MarkerOptions()
.position(latLng)
.title("Người giao")
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)));
} else {
shippingMarker.setPosition(latLng);
}
//Update camera
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(latLng)
.zoom(16)
.bearing(0)
.tilt(45)
.build();
mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
//Draw routes
if(polyline != null)
polyline.remove();
GoogleMapDirectionApi.apiService.getDirections(shipperLocation.getLat() + "," + shipperLocation.getLng(),
latOrder + "," + lngOrder, Common.MAP_API
).enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
assert response.body() != null;
new ParserTask().execute(response.body());
}
@Override
public void onFailure(Call<String> call, Throwable t) {
Toast.makeText(TrackingOrderActivity.this, "Có lỗi kết nối!", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
});
}
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
trackingLocation();
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
}
private class ParserTask extends AsyncTask<String, Integer, List<List<HashMap<String, String>>>> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected List<List<HashMap<String, String>>> doInBackground(String... strings) {
JSONObject jsonObject;
List<List<HashMap<String, String>>> routes = null;
try {
jsonObject = new JSONObject(strings[0]);
DirectionJSONParser parser = new DirectionJSONParser();
routes = parser.parse(jsonObject);
} catch (JSONException e) {
e.printStackTrace();
}
return routes;
}
@Override
protected void onPostExecute(List<List<HashMap<String, String>>> lists) {
ArrayList points = new ArrayList();
PolylineOptions lineOptions = new PolylineOptions();
for(int i = 0; i < lists.size(); i++){
List<HashMap<String, String>> path = lists.get(i);
for(int j = 0; j < path.size(); j++) {
HashMap<String, String> point = path.get(j);
double lat = Double.parseDouble(point.get("lat"));
double lng = Double.parseDouble(point.get("lng"));
LatLng position = new LatLng(lat, lng);
points.add(position);
}
lineOptions.addAll(points);
lineOptions.width(12);
lineOptions.color(Color.RED);
lineOptions.geodesic(true);
}
polyline = mMap.addPolyline(lineOptions);
}
}
@Override
protected void onStop() {
orderDatabase.removeEventListener(this);
super.onStop();
}
}
@@ -112,6 +112,8 @@ public class BasketAdapter extends RecyclerView.Adapter<BasketAdapter.BasketView
//Update total price
calculateTotalPrice();
Common.FINAL_SHOP = null;
} else {
foodBasket.setQuantity(String.valueOf(quantity));
holder.value.setText(String.valueOf(quantity));
@@ -129,6 +131,7 @@ public class BasketAdapter extends RecyclerView.Adapter<BasketAdapter.BasketView
for(Basket foodTemp: listBasketFood){
total += (foodTemp.getCost()) * (Float.parseFloat(foodTemp.getQuantity())) * (100 - foodTemp.getDiscountPercent())/100;
}
basketFragment.total.setText(Common.changeCurrencyUnit(total));
basketFragment.totalFloat = total;
}
@@ -0,0 +1,100 @@
package com.capstone.foodify;
import com.google.android.gms.maps.model.LatLng;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class DirectionJSONParser {
/**
* Receives a JSONObject and returns a list of lists containing latitude and longitude
*/
public List<List<HashMap<String, String>>> parse(JSONObject jObject) {
List<List<HashMap<String, String>>> routes = new ArrayList<List<HashMap<String, String>>>();
JSONArray jRoutes = null;
JSONArray jLegs = null;
JSONArray jSteps = null;
try {
jRoutes = jObject.getJSONArray("routes");
/** Traversing all routes */
for (int i = 0; i < jRoutes.length(); i++) {
jLegs = ((JSONObject) jRoutes.get(i)).getJSONArray("legs");
List path = new ArrayList<HashMap<String, String>>();
/** Traversing all legs */
for (int j = 0; j < jLegs.length(); j++) {
jSteps = ((JSONObject) jLegs.get(j)).getJSONArray("steps");
/** Traversing all steps */
for (int k = 0; k < jSteps.length(); k++) {
String polyline = "";
polyline = (String) ((JSONObject) ((JSONObject) jSteps.get(k)).get("polyline")).get("points");
List list = decodePoly(polyline);
/** Traversing all points */
for (int l = 0; l < list.size(); l++) {
HashMap<String, String> hm = new HashMap<String, String>();
hm.put("lat", Double.toString(((LatLng) list.get(l)).latitude));
hm.put("lng", Double.toString(((LatLng) list.get(l)).longitude));
path.add(hm);
}
}
routes.add(path);
}
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e) {
}
return routes;
}
/**
* Method to decode polyline points
* Courtesy : http://jeffreysambells.com/2010/05/27/decoding-polylines-from-google-maps-direction-api-with-java
*/
private List decodePoly(String encoded) {
List poly = new ArrayList();
int index = 0, len = encoded.length();
int lat = 0, lng = 0;
while (index < len) {
int b, shift = 0, result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lat += dlat;
shift = 0;
result = 0;
do {
b = encoded.charAt(index++) - 63;
result |= (b & 0x1f) << shift;
shift += 5;
} while (b >= 0x20);
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
lng += dlng;
LatLng p = new LatLng((((double) lat / 1E5)),
(((double) lng / 1E5)));
poly.add(p);
}
return poly;
}
}
@@ -61,9 +61,6 @@ public class BasketFragment extends Fragment implements ItemTouchHelperListener
btnCheckOut = view.findViewById(R.id.btnCheckOut);
listBasketFoodLayout = view.findViewById(R.id.list_basket_food_layout);
//Init data
total.setText(Common.changeCurrencyUnit(0));
//Check list basket is null or not!
checkListBasket();
@@ -71,6 +71,8 @@ public class HomeFragment extends Fragment {
rcvMenu.setAdapter(menuAdapter);
}
setNameUser();
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false);
rcvMenu.setLayoutManager(linearLayoutManager);
@@ -91,10 +93,12 @@ public class HomeFragment extends Fragment {
}
public static void setNameUser(){
//Set name user while user already login
if(Common.CURRENT_USER != null)
welcomeText.setText("Xin chào, " + Common.CURRENT_USER.getFullName() + "!");
else
if(Common.CURRENT_USER != null){
//Set name user while user already login
String[] arrayOfName = Common.CURRENT_USER.getFullName().split(" ");
String name = arrayOfName[arrayOfName.length - 1];
welcomeText.setText("Xin chào, " + name + "!");
} else
welcomeText.setText("Xin chào, khách!");
}
@@ -108,6 +108,7 @@ public class ProfileFragment extends Fragment {
Common.TOKEN = null;
Common.CURRENT_USER = null;
dialog.dismiss();
getActivity().startActivity(new Intent(getContext(), MainActivity.class));
getActivity().finish();
}