From 07aa4da7870d900408ca99feff9b1fc47ed678c7 Mon Sep 17 00:00:00 2001 From: Nezumi <123229563+Nez27@users.noreply.github.com> Date: Thu, 6 Apr 2023 22:26:36 +0700 Subject: [PATCH] Fix bug and improve layout app --- app/src/main/AndroidManifest.xml | 7 +- .../foodify/shipper/API/FoodApiToken.java | 4 + .../shipper/Activity/MainActivity.java | 87 ++--- .../shipper/Activity/OrderDetailActivity.java | 321 ++++++++++++++++-- .../shipper/Activity/SignInActivity.java | 2 +- .../Fragment/Order/CompletedOrder.java | 124 +++++++ .../Fragment/Order/OrderViewPagerAdapter.java | 34 ++ .../shipper/Fragment/Order/ShippingOrder.java | 124 +++++++ .../shipper/Fragment/OrderFragment.java | 115 +++---- .../GoogleMap/GeofenceBroadcastReceiver.java | 17 +- .../shipper/GoogleMap/NotificationHelper.java | 18 + .../foodify/shipper/Model/CustomResponse.java | 22 ++ app/src/main/res/layout/activity_main.xml | 21 ++ .../res/layout/fragment_completed_order.xml | 49 +++ app/src/main/res/layout/fragment_order.xml | 174 ++++------ .../res/layout/fragment_shipping_order.xml | 49 +++ app/src/main/res/values/themes.xml | 5 + 17 files changed, 903 insertions(+), 270 deletions(-) create mode 100644 app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/CompletedOrder.java create mode 100644 app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/OrderViewPagerAdapter.java create mode 100644 app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/ShippingOrder.java create mode 100644 app/src/main/java/com/capstone/foodify/shipper/Model/CustomResponse.java create mode 100644 app/src/main/res/layout/fragment_completed_order.xml create mode 100644 app/src/main/res/layout/fragment_shipping_order.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e0d7d6c..f713a29 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ + + android:exported="true"> + + + + getListOrder(@Path("shipperId") int shipperId, @Query("pageNo") int pageNo, @Query("pageSize") int pageSize, @Query("sortBy") String sortBy, @Query("sortDir") String sortDir); + + @PUT("users/{userId}/orders/{orderId}/status") + Call changeStatusOrder(@Path("userId") int userId, @Path("orderId") int orderId, @Query("status") String status); } diff --git a/app/src/main/java/com/capstone/foodify/shipper/Activity/MainActivity.java b/app/src/main/java/com/capstone/foodify/shipper/Activity/MainActivity.java index daee8ba..fb55ad5 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/Activity/MainActivity.java +++ b/app/src/main/java/com/capstone/foodify/shipper/Activity/MainActivity.java @@ -4,6 +4,7 @@ import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatDelegate; +import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.core.splashscreen.SplashScreen; @@ -23,6 +24,7 @@ import android.os.Looper; import android.provider.Settings; import android.util.Log; import android.view.MenuItem; +import android.view.View; import android.widget.Toast; import com.capstone.foodify.shipper.BuildConfig; @@ -67,6 +69,7 @@ public class MainActivity extends AppCompatActivity { private LocationCallback mLocationCallBack; private Location mCurrentLocation; private boolean mRequestingLocationUpdates = false; + private ConstraintLayout progressLayout; @Override protected void onCreate(Bundle savedInstanceState) { @@ -77,50 +80,15 @@ public class MainActivity extends AppCompatActivity { //Init Component bottomNavigationView = findViewById(R.id.bottom_nav); viewPager2 = findViewById(R.id.viewPager); + progressLayout = findViewById(R.id.progress_layout); bottomNavigation(); if (Common.CURRENT_LOCATION == null) { - mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this); - mSettingsClient = LocationServices.getSettingsClient(this); - - mLocationCallBack = new LocationCallback() { - @Override - public void onLocationResult(@NonNull LocationResult locationResult) { - super.onLocationResult(locationResult); - mCurrentLocation = locationResult.getLastLocation(); - Common.CURRENT_LOCATION = mCurrentLocation; - } - }; - - mLocationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, UPDATE_INTERVAL_IN_MILLISECONDS) - .setWaitForAccurateLocation(false) - .setMinUpdateDistanceMeters(FASTEST_UPDATE_IN_MILLISECONDS) - .setMaxUpdateDelayMillis(MAX_WAIT_TIME_IN_MILLISECONDS) - .build(); - - LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder(); - builder.addLocationRequest(mLocationRequest); - mLocationSettingsRequest = builder.build(); - - checkLocationPermission(); - + getLocation(); } - //Init location user - final Handler handler = new Handler(); - handler.postDelayed(new Runnable() { - @Override - public void run() { - if(mCurrentLocation != null){ - Common.CURRENT_LOCATION = mCurrentLocation; - stopLocationUpdates(); - } - - } - }, 3000); } - private void bottomNavigation() { viewPagerAdapter = new ViewPagerAdapter(this); viewPager2.setAdapter(viewPagerAdapter); @@ -160,6 +128,34 @@ public class MainActivity extends AppCompatActivity { } //Location + + private void getLocation() { + mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this); + mSettingsClient = LocationServices.getSettingsClient(this); + + mLocationCallBack = new LocationCallback() { + @Override + public void onLocationResult(@NonNull LocationResult locationResult) { + super.onLocationResult(locationResult); + mCurrentLocation = locationResult.getLastLocation(); + Common.CURRENT_LOCATION = mCurrentLocation; + stopLocationUpdates(); + progressLayout.setVisibility(View.GONE); + } + }; + + mLocationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, UPDATE_INTERVAL_IN_MILLISECONDS) + .setWaitForAccurateLocation(false) + .setMinUpdateDistanceMeters(FASTEST_UPDATE_IN_MILLISECONDS) + .setMaxUpdateDelayMillis(MAX_WAIT_TIME_IN_MILLISECONDS) + .build(); + + LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder(); + builder.addLocationRequest(mLocationRequest); + mLocationSettingsRequest = builder.build(); + + checkLocationPermission(); + } private void checkLocationPermission(){ if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){ @@ -229,7 +225,6 @@ public class MainActivity extends AppCompatActivity { @Override public void onSuccess(LocationSettingsResponse locationSettingsResponse) { mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallBack, Looper.myLooper()); - } }).addOnFailureListener(this, new OnFailureListener() { @Override @@ -268,21 +263,9 @@ public class MainActivity extends AppCompatActivity { @Override protected void onResume() { super.onResume(); - if (mRequestingLocationUpdates && checkPermission() && Common.CURRENT_LOCATION == null) { + getLocation(); + if (mRequestingLocationUpdates && checkPermission()) { startLocationUpdates(); } } - - @Override - protected void onPause() { - super.onPause(); - if (mRequestingLocationUpdates) { - stopLocationUpdates(); - - if(Common.CURRENT_LOCATION == null){ - if(mCurrentLocation != null) - Common.CURRENT_LOCATION = mCurrentLocation; - } - } - } } \ No newline at end of file diff --git a/app/src/main/java/com/capstone/foodify/shipper/Activity/OrderDetailActivity.java b/app/src/main/java/com/capstone/foodify/shipper/Activity/OrderDetailActivity.java index 88e6868..96e1c5d 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/Activity/OrderDetailActivity.java +++ b/app/src/main/java/com/capstone/foodify/shipper/Activity/OrderDetailActivity.java @@ -1,6 +1,26 @@ package com.capstone.foodify.shipper.Activity; +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.PendingIntent; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.IntentSender; +import android.content.pm.PackageManager; +import android.location.Location; +import android.net.Uri; +import android.os.Bundle; +import android.os.Looper; +import android.provider.Settings; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; + import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.app.ActivityCompat; @@ -8,42 +28,42 @@ import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; -import android.Manifest; -import android.annotation.SuppressLint; -import android.app.Activity; -import android.app.PendingIntent; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.net.Uri; -import android.os.Bundle; -import android.util.Log; -import android.view.View; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.TextView; -import android.widget.Toast; - +import com.capstone.foodify.shipper.API.FoodApiToken; import com.capstone.foodify.shipper.API.GoogleMapApi; import com.capstone.foodify.shipper.Adapter.OrderDetailAdapter; +import com.capstone.foodify.shipper.BuildConfig; import com.capstone.foodify.shipper.Common; import com.capstone.foodify.shipper.GoogleMap.GeofenceHelper; +import com.capstone.foodify.shipper.Model.CustomResponse; import com.capstone.foodify.shipper.Model.GoogleMap.GoogleMapResponse; import com.capstone.foodify.shipper.Model.Order; import com.capstone.foodify.shipper.R; +import com.google.android.gms.common.api.ApiException; +import com.google.android.gms.common.api.ResolvableApiException; +import com.google.android.gms.location.FusedLocationProviderClient; import com.google.android.gms.location.Geofence; import com.google.android.gms.location.GeofencingClient; import com.google.android.gms.location.GeofencingRequest; +import com.google.android.gms.location.LocationCallback; +import com.google.android.gms.location.LocationRequest; +import com.google.android.gms.location.LocationResult; import com.google.android.gms.location.LocationServices; +import com.google.android.gms.location.LocationSettingsRequest; +import com.google.android.gms.location.LocationSettingsResponse; +import com.google.android.gms.location.LocationSettingsStatusCodes; +import com.google.android.gms.location.Priority; +import com.google.android.gms.location.SettingsClient; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.tasks.OnFailureListener; import com.google.android.gms.tasks.OnSuccessListener; import com.thecode.aestheticdialogs.AestheticDialog; -import com.thecode.aestheticdialogs.DialogAnimation; import com.thecode.aestheticdialogs.DialogStyle; import com.thecode.aestheticdialogs.DialogType; +import com.thecode.aestheticdialogs.OnDialogClickListener; import java.text.DecimalFormat; +import java.util.Timer; +import java.util.TimerTask; import retrofit2.Call; import retrofit2.Callback; @@ -52,42 +72,59 @@ import retrofit2.Response; public class OrderDetailActivity extends AppCompatActivity { private static final String TAG = "OrderDetailActivity"; - private static final int REQUEST_PHONE_CALL = 1; + private static final String STATUS = "COMPLETED"; Order order; Button btn_shipping, btn_call, btn_confirm_ship_completed; TextView order_tracking_number, txt_user_name, txt_phone, txt_address, txt_distance, txt_status, txt_total, txt_order_time; - String status = ""; ConstraintLayout progressLayout; RecyclerView rcv_list_order; OrderDetailAdapter adapter; LinearLayout layoutConfirmOrder; private GeofencingClient geofencingClient; private GeofenceHelper geofenceHelper; - private float GEOFENCE_RADIUS = 100; + private float GEOFENCE_RADIUS = 150; private String GEOFENCE_ID = "SOME_GEOFENCE_ID"; + //Location + private static final int REQUEST_CHECK_SETTINGS = 100; + private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000; + 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 FusedLocationProviderClient mFusedLocationClient; + private SettingsClient mSettingClient; + private LocationRequest mLocationRequest; + private LocationSettingsRequest mLocationSettingsRequest; + private LocationCallback mLocationCallBack; + private Location mCurrentLocation; + private boolean mRequestingLocationUpdates = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_order_detail); //Get information order - if(getIntent() != null){ + if (getIntent() != null) { order = (Order) getIntent().getSerializableExtra("order"); - status = getIntent().getStringExtra("status"); } + if (order == null && Common.CURRENT_ORDER != null) { + order = Common.CURRENT_ORDER; + } + + if (order == null) { + Toast.makeText(OrderDetailActivity.this, "Có lỗi xảy ra!", Toast.LENGTH_SHORT).show(); + finishAffinity(); + System.exit(0); + } + initComponent(); initData(); - //Check status shipping - if(status != null){ - btn_shipping.setVisibility(View.GONE); - layoutConfirmOrder.setVisibility(View.VISIBLE); - } getDistanceAndCalculateShipCost(order.getAddress()); + progressLayout.setVisibility(View.GONE); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false); rcv_list_order.setLayoutManager(linearLayoutManager); @@ -98,14 +135,14 @@ public class OrderDetailActivity extends AppCompatActivity { btn_shipping.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if(Common.CURRENT_ORDER == null){ + if (Common.CURRENT_ORDER == null) { LatLng latLng = new LatLng(order.getLat(), order.getLng()); addGeofence(latLng, GEOFENCE_RADIUS); Common.CURRENT_ORDER = order; Intent intent = new Intent(Intent.ACTION_VIEW, - Uri.parse("google.navigation:q="+ order.getLat() + "," + order.getLng() + "&mode=l")); + Uri.parse("google.navigation:q=" + order.getLat() + "," + order.getLng() + "&mode=l")); intent.setPackage("com.google.android.apps.maps"); startActivity(intent); } @@ -119,12 +156,48 @@ public class OrderDetailActivity extends AppCompatActivity { startActivity(intent); } }); - + + btn_confirm_ship_completed.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + changeOrderStatus(); + } + }); + //Register geofence geofencingClient = LocationServices.getGeofencingClient(this); geofenceHelper = new GeofenceHelper(this); + + + getLocation(); } + private void changeOrderStatus(){ + FoodApiToken.apiService.changeStatusOrder(order.getUser().getId(), order.getId(), STATUS).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if(response.code() == 200){ + new AestheticDialog.Builder(OrderDetailActivity.this, DialogStyle.TOASTER, DialogType.SUCCESS) + .setTitle("THÔNG BÁO!") + .setMessage("Đã thay đổi trạng thái đơn thành công!") + .setCancelable(false) + .setOnClickListener(new OnDialogClickListener() { + @Override + public void onClick(@NonNull AestheticDialog.Builder builder) { + startActivity(new Intent(OrderDetailActivity.this, MainActivity.class)); + builder.dismiss(); + finish(); + } + }).show(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + + } + }); + } private void initComponent(){ adapter = new OrderDetailAdapter(); @@ -219,7 +292,6 @@ public class OrderDetailActivity extends AppCompatActivity { LatLng addressTo = new LatLng(lat, lng); int distance = CalculationByDistance(addressFrom, addressTo); - txt_distance.setText(distance + " km"); progressLayout.setVisibility(View.GONE); } @@ -251,5 +323,190 @@ public class OrderDetailActivity extends AppCompatActivity { return Integer.valueOf(newFormat.format(km)); } - + + /** calculates the distance between two locations in MILES */ + private double distance(double lat1, double lng1, double lat2, double lng2) { + + double earthRadius = 3958.75; // in miles, change to 6371 for kilometer output + + double dLat = Math.toRadians(lat2-lat1); + double dLng = Math.toRadians(lng2-lng1); + + double sindLat = Math.sin(dLat / 2); + double sindLng = Math.sin(dLng / 2); + + double a = Math.pow(sindLat, 2) + Math.pow(sindLng, 2) + * Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)); + + double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); + + double dist = earthRadius * c; + + return dist; // output distance, in MILES + } + + //Location + + private void getLocation() { + mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this); + mSettingClient = LocationServices.getSettingsClient(this); + + mLocationCallBack = new LocationCallback() { + @Override + public void onLocationResult(@NonNull LocationResult locationResult) { + super.onLocationResult(locationResult); + + mCurrentLocation = locationResult.getLastLocation(); + + double lat1 = mCurrentLocation.getLatitude(); + double lng1 = mCurrentLocation.getLongitude(); + double lat2 = order.getLat(); + double lng2 = order.getLng(); + + if(distance(lat1, lng1, lat2, lng2) < 0.2){ + btn_shipping.setVisibility(View.GONE); + layoutConfirmOrder.setVisibility(View.VISIBLE); + } else { + btn_shipping.setVisibility(View.VISIBLE); + layoutConfirmOrder.setVisibility(View.GONE); + } + + progressLayout.setVisibility(View.GONE); + } + }; + + mLocationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, UPDATE_INTERVAL_IN_MILLISECONDS) + .setWaitForAccurateLocation(false) + .setMinUpdateDistanceMeters(FASTEST_UPDATE_IN_MILLISECONDS) + .setMaxUpdateDelayMillis(MAX_WAIT_TIME_IN_MILLISECONDS) + .build(); + + LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder(); + builder.addLocationRequest(mLocationRequest); + mLocationSettingsRequest = builder.build(); + + checkLocationPermission(); + } + + private void checkLocationPermission(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && + ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){ + + requestForPermission(); + + }else { + //Get location + mRequestingLocationUpdates = true; + startLocationUpdates(); + } + } + + private void requestForPermission() { + ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); + } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + super.onRequestPermissionsResult(requestCode, permissions, grantResults); + + if(requestCode == LOCATION_REQUEST_CODE){ + if(grantResults[0] == PackageManager.PERMISSION_GRANTED){ + Toast.makeText(this, "Đã cấp quyền thành công!", Toast.LENGTH_SHORT).show(); + } else { + showDialogPermission(); + } + } + } + + private void showDialogPermission() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + + builder.setMessage("Hãy cho ứng dụng truy cập vào vị trí của bạn để trải nghiệm tốt hơn!") + .setCancelable(false) + .setPositiveButton("Ok", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + openSettings(); + dialog.cancel(); + } + }) + .setNegativeButton("Để sau", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + AlertDialog alertDialog = builder.create(); + alertDialog.setTitle("Thông báo!"); + alertDialog.show(); + } + private void openSettings(){ + Intent intent = new Intent(); + intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + Uri uri = Uri.fromParts("package", BuildConfig.APPLICATION_ID, null); + intent.setData(uri); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + } + + private void startLocationUpdates(){ + mSettingClient.checkLocationSettings(mLocationSettingsRequest) + .addOnSuccessListener(this, new OnSuccessListener() { + @SuppressLint("MissingPermission") + @Override + public void onSuccess(LocationSettingsResponse locationSettingsResponse) { + mFusedLocationClient.requestLocationUpdates(mLocationRequest, mLocationCallBack, Looper.myLooper()); + } + }) + .addOnFailureListener(this, new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + int statusCode = ((ApiException) e).getStatusCode(); + switch (statusCode){ + case LocationSettingsStatusCodes.RESOLUTION_REQUIRED: + Log.i(TAG, "Location settings are not satisfied. Attempting to upgrade location settings."); + + try { + ResolvableApiException rae = (ResolvableApiException) e; + rae.startResolutionForResult(OrderDetailActivity.this, REQUEST_CHECK_SETTINGS); + } catch (IntentSender.SendIntentException sie){ + Log.i(TAG, "PendingIntent unable to execute request"); + } + break; + case LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE: + String errorMessage = "Location settings are inadequate, and cannot be fix here. Fix in Settings"; + Log.e(TAG, errorMessage); + + Toast.makeText(OrderDetailActivity.this, errorMessage, Toast.LENGTH_SHORT).show(); + } + } + }); + } + + private void stopLocationUpdates(){ + mFusedLocationClient.removeLocationUpdates(mLocationCallBack).addOnCompleteListener(this, task -> Log.d(TAG, "Location stop update!")); + } + + private boolean checkPermissions(){ + int permissionState = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION); + return permissionState == PackageManager.PERMISSION_GRANTED; + } + + @Override + protected void onResume() { + super.onResume(); + progressLayout.setVisibility(View.VISIBLE); + if(mRequestingLocationUpdates && checkPermissions()){ + startLocationUpdates(); + } + } + + @Override + protected void onPause() { + super.onPause(); + if(mRequestingLocationUpdates){ + stopLocationUpdates(); + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/capstone/foodify/shipper/Activity/SignInActivity.java b/app/src/main/java/com/capstone/foodify/shipper/Activity/SignInActivity.java index 0881bb9..b298d73 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/Activity/SignInActivity.java +++ b/app/src/main/java/com/capstone/foodify/shipper/Activity/SignInActivity.java @@ -278,7 +278,7 @@ public class SignInActivity extends AppCompatActivity { @Override public void onResponse(Call call, Response response) { if(response.code() == 200){ - Common.CURRENT_SHIPPER = response.body(); + Common.CURRENT_SHIPPER = response.body(); //Dismiss progress bar progressLayout.setVisibility(View.GONE); } diff --git a/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/CompletedOrder.java b/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/CompletedOrder.java new file mode 100644 index 0000000..548123e --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/CompletedOrder.java @@ -0,0 +1,124 @@ +package com.capstone.foodify.shipper.Fragment.Order; + +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.core.widget.NestedScrollView; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import com.capstone.foodify.shipper.API.FoodApiToken; +import com.capstone.foodify.shipper.Adapter.OrderAdapter; +import com.capstone.foodify.shipper.Common; +import com.capstone.foodify.shipper.Model.Order; +import com.capstone.foodify.shipper.Model.Response.Orders; +import com.capstone.foodify.shipper.R; + +import java.util.ArrayList; +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class CompletedOrder extends Fragment { + private static int CURRENT_PAGE = 0; + private static int PAGE_SIZE = 8; + private static String SORT_BY = "id"; + private static String SORT_DIR = "asc"; + private static boolean LAST_PAGE = false; + private List listOrders = new ArrayList<>(); + RecyclerView recyclerView; + OrderAdapter orderAdapter; + TextView end_of_list_text_view; + NestedScrollView list_order_layout; + ProgressBar progressBar; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View view = inflater.inflate(R.layout.fragment_completed_order, container, false); + + //Init component + recyclerView = view.findViewById(R.id.rcv_list_order); + list_order_layout = view.findViewById(R.id.list_order_layout); + progressBar = view.findViewById(R.id.progress_bar); + end_of_list_text_view = view.findViewById(R.id.end_of_list_text); + + orderAdapter = new OrderAdapter(getActivity()); + + getListOrder(); + + + LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false); + recyclerView.setLayoutManager(linearLayoutManager); + + recyclerView.setAdapter(orderAdapter); + + if (list_order_layout != null) { + list_order_layout.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() { + @Override + public void onScrollChange(@NonNull NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { + if (scrollY == (v.getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight())) { + //When user scroll to bottom, load more data + dataLoadMore(); + } + } + }); + } + return view; + } + + private void getListOrder(){ + if(Common.CURRENT_SHIPPER != null){ + FoodApiToken.apiService.getListOrder(Common.CURRENT_SHIPPER.getId(), CURRENT_PAGE++, PAGE_SIZE, SORT_BY, SORT_DIR).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if(response.code() == 200){ + + for(Order tempOrder: response.body().getOrders()){ + if(tempOrder.getStatus().equals("COMPLETED")){ + listOrders.add(tempOrder); + } + } + orderAdapter.setData(listOrders); + + LAST_PAGE = response.body().getPage().isLast(); + + if(LAST_PAGE) + hideProgressBarAndShowEndOfListText(); + } else { + Toast.makeText(getContext(), "Đã có lỗi hệ thống! Mã lỗi: " + response.code(), Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + Toast.makeText(getContext(), Common.ERROR_CONNECT_SERVER, Toast.LENGTH_SHORT).show(); + } + }); + } + } + + private void hideProgressBarAndShowEndOfListText(){ + progressBar.setVisibility(View.GONE); + end_of_list_text_view.setVisibility(View.VISIBLE); + } + + private void dataLoadMore() { + if(!LAST_PAGE){ + getListOrder(); + } else { + hideProgressBarAndShowEndOfListText(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/OrderViewPagerAdapter.java b/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/OrderViewPagerAdapter.java new file mode 100644 index 0000000..9f27d87 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/OrderViewPagerAdapter.java @@ -0,0 +1,34 @@ +package com.capstone.foodify.shipper.Fragment.Order; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentActivity; +import androidx.viewpager2.adapter.FragmentStateAdapter; + +import com.capstone.foodify.shipper.Fragment.OrderFragment; +import com.capstone.foodify.shipper.Fragment.ProfileFragment; + +public class OrderViewPagerAdapter extends FragmentStateAdapter { + + public OrderViewPagerAdapter(@NonNull FragmentActivity fragmentActivity) { + super(fragmentActivity); + } + + @NonNull + @Override + public Fragment createFragment(int position) { + switch(position) { + case 1: return new CompletedOrder(); + default: return new ShippingOrder(); + } + } + @Override + public int getItemCount() { + return 2; + } + + @Override + public long getItemId(int position) { + return super.getItemId(position); + } +} diff --git a/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/ShippingOrder.java b/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/ShippingOrder.java new file mode 100644 index 0000000..f749bf2 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/ShippingOrder.java @@ -0,0 +1,124 @@ +package com.capstone.foodify.shipper.Fragment.Order; + +import android.os.Bundle; + +import androidx.annotation.NonNull; +import androidx.core.widget.NestedScrollView; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; + +import com.capstone.foodify.shipper.API.FoodApiToken; +import com.capstone.foodify.shipper.Adapter.OrderAdapter; +import com.capstone.foodify.shipper.Common; +import com.capstone.foodify.shipper.Model.Order; +import com.capstone.foodify.shipper.Model.Response.Orders; +import com.capstone.foodify.shipper.R; + +import java.util.ArrayList; +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +public class ShippingOrder extends Fragment { + private static int CURRENT_PAGE = 0; + private static int PAGE_SIZE = 8; + private static String SORT_BY = "id"; + private static String SORT_DIR = "asc"; + private static boolean LAST_PAGE = false; + private List listOrders = new ArrayList<>(); + RecyclerView recyclerView; + OrderAdapter orderAdapter; + TextView end_of_list_text_view; + NestedScrollView list_order_layout; + ProgressBar progressBar; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + // Inflate the layout for this fragment + View view = inflater.inflate(R.layout.fragment_shipping_order, container, false); + + //Init component + recyclerView = view.findViewById(R.id.rcv_list_order); + list_order_layout = view.findViewById(R.id.list_order_layout); + progressBar = view.findViewById(R.id.progress_bar); + end_of_list_text_view = view.findViewById(R.id.end_of_list_text); + + orderAdapter = new OrderAdapter(getActivity()); + + getListOrder(); + + + LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false); + recyclerView.setLayoutManager(linearLayoutManager); + + recyclerView.setAdapter(orderAdapter); + + if (list_order_layout != null) { + list_order_layout.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() { + @Override + public void onScrollChange(@NonNull NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { + if (scrollY == (v.getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight())) { + //When user scroll to bottom, load more data + dataLoadMore(); + } + } + }); + } + return view; + } + + private void getListOrder(){ + if(Common.CURRENT_SHIPPER != null){ + FoodApiToken.apiService.getListOrder(Common.CURRENT_SHIPPER.getId(), CURRENT_PAGE++, PAGE_SIZE, SORT_BY, SORT_DIR).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if(response.code() == 200){ + + for(Order tempOrder: response.body().getOrders()){ + if(tempOrder.getStatus().equals("SHIPPING")){ + listOrders.add(tempOrder); + } + } + orderAdapter.setData(listOrders); + + LAST_PAGE = response.body().getPage().isLast(); + + if(LAST_PAGE) + hideProgressBarAndShowEndOfListText(); + } else { + Toast.makeText(getContext(), "Đã có lỗi hệ thống! Mã lỗi: " + response.code(), Toast.LENGTH_SHORT).show(); + } + } + + @Override + public void onFailure(Call call, Throwable t) { + Toast.makeText(getContext(), Common.ERROR_CONNECT_SERVER, Toast.LENGTH_SHORT).show(); + } + }); + } + } + + private void hideProgressBarAndShowEndOfListText(){ + progressBar.setVisibility(View.GONE); + end_of_list_text_view.setVisibility(View.VISIBLE); + } + + private void dataLoadMore() { + if(!LAST_PAGE){ + getListOrder(); + } else { + hideProgressBarAndShowEndOfListText(); + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/capstone/foodify/shipper/Fragment/OrderFragment.java b/app/src/main/java/com/capstone/foodify/shipper/Fragment/OrderFragment.java index fbaa18d..a40ae69 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/Fragment/OrderFragment.java +++ b/app/src/main/java/com/capstone/foodify/shipper/Fragment/OrderFragment.java @@ -7,6 +7,7 @@ import androidx.core.widget.NestedScrollView; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.viewpager2.widget.ViewPager2; import android.view.LayoutInflater; import android.view.View; @@ -16,11 +17,15 @@ import android.widget.TextView; import android.widget.Toast; import com.capstone.foodify.shipper.API.FoodApiToken; +import com.capstone.foodify.shipper.Activity.MainActivity; import com.capstone.foodify.shipper.Adapter.OrderAdapter; import com.capstone.foodify.shipper.Common; +import com.capstone.foodify.shipper.Fragment.Order.OrderViewPagerAdapter; import com.capstone.foodify.shipper.Model.Order; import com.capstone.foodify.shipper.Model.Response.Orders; import com.capstone.foodify.shipper.R; +import com.capstone.foodify.shipper.ViewPagerAdapter; +import com.google.android.material.tabs.TabLayout; import com.squareup.picasso.Picasso; import java.util.ArrayList; @@ -31,18 +36,10 @@ import retrofit2.Callback; import retrofit2.Response; public class OrderFragment extends Fragment { - - private static int CURRENT_PAGE = 0; - private static int PAGE_SIZE = 8; - private static String SORT_BY = "id"; - private static String SORT_DIR = "asc"; - private static boolean LAST_PAGE = false; - private List listOrders = new ArrayList<>(); - RecyclerView recyclerView; - OrderAdapter orderAdapter; - TextView welcome_text, end_of_list_text_view; - NestedScrollView list_order_layout; - ProgressBar progressBar; + TabLayout tabLayout; + ViewPager2 viewPager2; + OrderViewPagerAdapter orderViewPagerAdapter; + TextView welcome_text; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, @@ -51,79 +48,47 @@ public class OrderFragment extends Fragment { View view = inflater.inflate(R.layout.fragment_order, container, false); //Init Component - recyclerView = view.findViewById(R.id.rcv_list_order); welcome_text = view.findViewById(R.id.welcome_text); - list_order_layout = view.findViewById(R.id.list_order_layout); - progressBar = view.findViewById(R.id.progress_bar); - end_of_list_text_view = view.findViewById(R.id.end_of_list_text); + + tabLayout = view.findViewById(R.id.tab_layout); + viewPager2 = view.findViewById(R.id.view_pager); + + orderViewPagerAdapter = new OrderViewPagerAdapter(getActivity()); + viewPager2.setAdapter(orderViewPagerAdapter); + + tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { + @Override + public void onTabSelected(TabLayout.Tab tab) { + viewPager2.setCurrentItem(tab.getPosition(), false); + } + + @Override + public void onTabUnselected(TabLayout.Tab tab) { + + } + + @Override + public void onTabReselected(TabLayout.Tab tab) { + + } + }); + + viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() { + @Override + public void onPageSelected(int position) { + super.onPageSelected(position); + tabLayout.getTabAt(position).select(); + } + }); if(Common.CURRENT_USER != null){ welcome_text.setText("Xin chào, " + Common.CURRENT_USER.getFullName() + "!"); } - orderAdapter = new OrderAdapter(getActivity()); - - getListOrder(); - - - LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext(), RecyclerView.VERTICAL, false); - recyclerView.setLayoutManager(linearLayoutManager); - - recyclerView.setAdapter(orderAdapter); - - if (list_order_layout != null) { - list_order_layout.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() { - @Override - public void onScrollChange(@NonNull NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { - if (scrollY == (v.getChildAt(0).getMeasuredHeight() - v.getMeasuredHeight())) { - //When user scroll to bottom, load more data - dataLoadMore(); - } - } - }); - } - return view; } - private void getListOrder(){ - if(Common.CURRENT_SHIPPER != null){ - FoodApiToken.apiService.getListOrder(Common.CURRENT_SHIPPER.getId(), CURRENT_PAGE++, PAGE_SIZE, SORT_BY, SORT_DIR).enqueue(new Callback() { - @Override - public void onResponse(Call call, Response response) { - if(response.code() == 200){ - listOrders.addAll(response.body().getOrders()); - orderAdapter.setData(listOrders); - LAST_PAGE = response.body().getPage().isLast(); - - if(LAST_PAGE) - hideProgressBarAndShowEndOfListText(); - } else { - Toast.makeText(getContext(), "Đã có lỗi hệ thống! Mã lỗi: " + response.code(), Toast.LENGTH_SHORT).show(); - } - } - - @Override - public void onFailure(Call call, Throwable t) { - Toast.makeText(getContext(), Common.ERROR_CONNECT_SERVER, Toast.LENGTH_SHORT).show(); - } - }); - } - } - - private void hideProgressBarAndShowEndOfListText(){ - progressBar.setVisibility(View.GONE); - end_of_list_text_view.setVisibility(View.VISIBLE); - } - - private void dataLoadMore() { - if(!LAST_PAGE){ - getListOrder(); - } else { - hideProgressBarAndShowEndOfListText(); - } - } @Override public void onResume() { super.onResume(); diff --git a/app/src/main/java/com/capstone/foodify/shipper/GoogleMap/GeofenceBroadcastReceiver.java b/app/src/main/java/com/capstone/foodify/shipper/GoogleMap/GeofenceBroadcastReceiver.java index d691ae8..233f8bd 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/GoogleMap/GeofenceBroadcastReceiver.java +++ b/app/src/main/java/com/capstone/foodify/shipper/GoogleMap/GeofenceBroadcastReceiver.java @@ -1,13 +1,17 @@ package com.capstone.foodify.shipper.GoogleMap; import android.content.BroadcastReceiver; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; import android.util.Log; import android.widget.Toast; import com.capstone.foodify.shipper.Activity.OrderDetailActivity; import com.capstone.foodify.shipper.Common; +import com.capstone.foodify.shipper.Model.Order; import com.google.android.gms.location.Geofence; import com.google.android.gms.location.GeofencingEvent; @@ -21,6 +25,7 @@ public class GeofenceBroadcastReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent); + NotificationHelper notificationHelper = new NotificationHelper(context); if (geofencingEvent.hasError()) { Log.d(TAG, "onReceive: Error receiving geofence event..."); @@ -34,15 +39,11 @@ public class GeofenceBroadcastReceiver extends BroadcastReceiver { int transitionType = geofencingEvent.getGeofenceTransition(); - switch (transitionType) { - case Geofence.GEOFENCE_TRANSITION_ENTER: - Intent newIntent = new Intent(context.getApplicationContext(), OrderDetailActivity.class); - newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - newIntent.putExtra("order", Common.CURRENT_ORDER); - newIntent.putExtra("status", Common.SHIPPING_COMPLETED); - context.startActivity(newIntent); - break; + if(transitionType == Geofence.GEOFENCE_TRANSITION_ENTER){ + notificationHelper.sendHighPriorityNotification("Đã tới khu vực giao!", "Nhấp vào đây để quay về app!", OrderDetailActivity.class); } + + } } diff --git a/app/src/main/java/com/capstone/foodify/shipper/GoogleMap/NotificationHelper.java b/app/src/main/java/com/capstone/foodify/shipper/GoogleMap/NotificationHelper.java index f94844f..cb0e2a0 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/GoogleMap/NotificationHelper.java +++ b/app/src/main/java/com/capstone/foodify/shipper/GoogleMap/NotificationHelper.java @@ -43,5 +43,23 @@ public class NotificationHelper extends ContextWrapper { manager.createNotificationChannel(notificationChannel); } + public void sendHighPriorityNotification(String title, String body, Class activityName) { + Intent intent = new Intent(this, activityName); + PendingIntent pendingIntent = PendingIntent.getActivity(this, 267, intent, PendingIntent.FLAG_UPDATE_CURRENT); + + Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID) +// .setContentTitle(title) +// .setContentText(body) + .setSmallIcon(R.drawable.ic_launcher_background) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setStyle(new NotificationCompat.BigTextStyle().setSummaryText("summary").setBigContentTitle(title).bigText(body)) + .setContentIntent(pendingIntent) + .setAutoCancel(true) + .build(); + + NotificationManagerCompat.from(this).notify(new Random().nextInt(), notification); + + + } } diff --git a/app/src/main/java/com/capstone/foodify/shipper/Model/CustomResponse.java b/app/src/main/java/com/capstone/foodify/shipper/Model/CustomResponse.java new file mode 100644 index 0000000..592294d --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/Model/CustomResponse.java @@ -0,0 +1,22 @@ +package com.capstone.foodify.shipper.Model; + +public class CustomResponse { + private String isTitle; + private boolean isTrue; + + public String getIsTitle() { + return isTitle; + } + + public void setIsTitle(String isTitle) { + this.isTitle = isTitle; + } + + public boolean isTrue() { + return isTrue; + } + + public void setTrue(boolean aTrue) { + isTrue = aTrue; + } +} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 3743382..68bc07d 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -32,4 +32,25 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_completed_order.xml b/app/src/main/res/layout/fragment_completed_order.xml new file mode 100644 index 0000000..f393ef4 --- /dev/null +++ b/app/src/main/res/layout/fragment_completed_order.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_order.xml b/app/src/main/res/layout/fragment_order.xml index 3694b6a..04f1ffb 100644 --- a/app/src/main/res/layout/fragment_order.xml +++ b/app/src/main/res/layout/fragment_order.xml @@ -1,118 +1,90 @@ - + tools:context=".Fragment.OrderFragment" + android:orientation="vertical" + > - - - - - - - - - - - - - - - - - - - - - + + + + + - \ No newline at end of file + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_shipping_order.xml b/app/src/main/res/layout/fragment_shipping_order.xml new file mode 100644 index 0000000..3e8f288 --- /dev/null +++ b/app/src/main/res/layout/fragment_shipping_order.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index d5b0e77..c69b99e 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -29,4 +29,9 @@ @color/primaryColor @color/primaryColor + + \ No newline at end of file