diff --git a/.idea/androidTestResultsUserPreferences.xml b/.idea/androidTestResultsUserPreferences.xml new file mode 100644 index 0000000..abd2b2e --- /dev/null +++ b/.idea/androidTestResultsUserPreferences.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5df1573..e6a3e84 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -19,7 +19,8 @@ tools:targetApi="31"> + android:exported="false" + /> diff --git a/app/src/main/java/com/capstone/foodify/API/FoodApi.java b/app/src/main/java/com/capstone/foodify/API/FoodApi.java index 93cb508..e776f42 100644 --- a/app/src/main/java/com/capstone/foodify/API/FoodApi.java +++ b/app/src/main/java/com/capstone/foodify/API/FoodApi.java @@ -5,6 +5,7 @@ import com.capstone.foodify.Model.DistrictWard.DistrictWardResponse; import com.capstone.foodify.Model.Food.Food; import com.capstone.foodify.Model.Response.Foods; import com.capstone.foodify.Model.Response.Shops; +import com.capstone.foodify.Model.Shop.Shop; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -54,8 +55,11 @@ public interface FoodApi { @GET("products/{id}") Call detailFood(@Path("id") String id); -// @GET("detail/{id}/image") -// Call> getImageFoodById(@Path("id") String id); + @GET("shops/{id}") + Call detailShop(@Path("id") int id); + + @GET("products/shops/{id}") + Call listFoodByShopId(@Path("id") int id, @Query("pageNo") int pageNo, @Query("pageSize") int pageSize, @Query("sortBy") String sortBy, @Query("sortDir") String sortDir); @GET("district/{districtId}/ward") Call> wardResponse(@Path("districtId") int district_id); diff --git a/app/src/main/java/com/capstone/foodify/Activity/ShopDetailActivity.java b/app/src/main/java/com/capstone/foodify/Activity/ShopDetailActivity.java index afadec7..d806031 100644 --- a/app/src/main/java/com/capstone/foodify/Activity/ShopDetailActivity.java +++ b/app/src/main/java/com/capstone/foodify/Activity/ShopDetailActivity.java @@ -1,6 +1,8 @@ package com.capstone.foodify.Activity; +import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; +import androidx.core.widget.NestedScrollView; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -8,21 +10,48 @@ import androidx.recyclerview.widget.RecyclerView; import android.os.Bundle; import android.view.View; import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; +import android.widget.Toast; +import com.capstone.foodify.API.FoodApi; +import com.capstone.foodify.Common; import com.capstone.foodify.Model.Food.Food; import com.capstone.foodify.Adapter.FoodShopAdapter; +import com.capstone.foodify.Model.Response.Foods; +import com.capstone.foodify.Model.Response.Shops; +import com.capstone.foodify.Model.Shop.Shop; import com.capstone.foodify.R; +import com.google.android.material.appbar.CollapsingToolbarLayout; +import com.saadahmedsoft.popupdialog.PopupDialog; +import com.saadahmedsoft.popupdialog.Styles; import com.squareup.picasso.Picasso; import java.util.ArrayList; import java.util.List; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + public class ShopDetailActivity extends AppCompatActivity { + private static int CURRENT_PAGE; + private static int PAGE_SIZE = 8; + private static String SORT_BY = "name"; + private static String SORT_DIR = "asc"; + private static boolean LAST_PAGE = false; + private int shopId; private List listFood = new ArrayList<>(); + TextView content_description_text_view, student_shop_text_view, end_of_list_text_view; ImageView imageShop, back_image; RecyclerView recycler_view_food_shop; FoodShopAdapter adapter; + private CollapsingToolbarLayout collapsingToolbarLayout; + private PopupDialog popupDialog; + private NestedScrollView nestedScrollView; + private ProgressBar progressBar; + private Shop shop; @Override protected void onCreate(Bundle savedInstanceState) { @@ -33,14 +62,26 @@ public class ShopDetailActivity extends AppCompatActivity { imageShop = findViewById(R.id.image_shop); recycler_view_food_shop = findViewById(R.id.recycler_view_food_shop); back_image = findViewById(R.id.back_image); - adapter = new FoodShopAdapter(); + adapter = new FoodShopAdapter(this); + collapsingToolbarLayout = findViewById(R.id.collapsing); + content_description_text_view = findViewById(R.id.content_description_text_view); + student_shop_text_view = findViewById(R.id.student_shop_text_view); + nestedScrollView = findViewById(R.id.food_detail); + progressBar = findViewById(R.id.progress_bar); + end_of_list_text_view = findViewById(R.id.end_of_list_text); - //Init temp data - Picasso.get().load("https://firebasestorage.googleapis.com/v0/b/foodify-55954.appspot.com/o/Free%20Food%20Advertising%20Banner%20Template.jpg?alt=media&token=8b836fd7-f18f-46c6-a14f-27680e51a1d5").into(imageShop); + popupDialog = PopupDialog.getInstance(this); + popupDialog.setStyle(Styles.PROGRESS).setProgressDialogTint(getResources().getColor(R.color.primaryColor, null)) + .setCancelable(false).showDialog(); -// for(int i = 1; i <= 10; i++){ -// listFood.add(new Food("https://images.unsplash.com/photo-1546069901-ba9599a7e63c?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxleHBsb3JlLWZlZWR8MXx8fGVufDB8fHx8&w=1000&q=80", "Food " + i, "50.000đ")); -// } + //Get data + if (getIntent() != null) + shopId = getIntent().getIntExtra("ShopId", 0); + + //Set the first page after call api + CURRENT_PAGE = 0; + getDetailShop(shopId); + nestedScrollView.setVisibility(View.GONE); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); recycler_view_food_shop.setLayoutManager(linearLayoutManager); @@ -48,9 +89,6 @@ public class ShopDetailActivity extends AppCompatActivity { RecyclerView.ItemDecoration itemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL); recycler_view_food_shop.addItemDecoration(itemDecoration); - adapter.setData(listFood); - recycler_view_food_shop.setAdapter(adapter); - back_image.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -58,5 +96,98 @@ public class ShopDetailActivity extends AppCompatActivity { } }); + if (nestedScrollView != null) { + nestedScrollView.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(); + } + } + }); + } + + } + + private void getListFood(int shopId){ + FoodApi.apiService.listFoodByShopId(shopId, CURRENT_PAGE++, PAGE_SIZE, SORT_BY, SORT_DIR).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + Foods tempFood = response.body(); + + if(tempFood == null) + return; + + //Init last page from api + LAST_PAGE = tempFood.getPage().isLast(); + + //Add food to list + listFood.addAll(tempFood.getProducts()); + + adapter.setData(listFood); + recycler_view_food_shop.setAdapter(adapter); + + initData(shop); + } + + @Override + public void onFailure(Call call, Throwable t) { + //Check internet connection + Common.showNotificationError(t, getBaseContext(), ShopDetailActivity.this); + } + }); + } + + private void getDetailShop(int shopId) { + FoodApi.apiService.detailShop(shopId).enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + Shop tempShop = response.body(); + + //Init shop data to "local data" shop; + if(tempShop != null) + shop = tempShop; + + getListFood(shopId); + } + + @Override + public void onFailure(Call call, Throwable t) { + Common.showNotificationError(t, getBaseContext(), ShopDetailActivity.this); + } + }); + } + + private void initData(Shop shop) { + //Init data + Picasso.get().load(shop.getImageUrl()).into(imageShop); + collapsingToolbarLayout.setTitle(shop.getName()); + content_description_text_view.setText(shop.getDescription()); + + //If shop is studentShop, enable tag student shop + if(shop.isStudent()){ + student_shop_text_view.setVisibility(View.VISIBLE); + } + + //If list data don't have pagination + if(LAST_PAGE) + hideProgressBarAndShowEndOfListText(); + + nestedScrollView.setVisibility(View.VISIBLE); + popupDialog.dismissDialog(); + } + + private void hideProgressBarAndShowEndOfListText(){ + progressBar.setVisibility(View.GONE); + end_of_list_text_view.setVisibility(View.VISIBLE); + } + + private void dataLoadMore() { + if(!LAST_PAGE){ + getListFood(shopId); + } else { + hideProgressBarAndShowEndOfListText(); + } } } \ No newline at end of file diff --git a/app/src/main/java/com/capstone/foodify/Adapter/BasketAdapter.java b/app/src/main/java/com/capstone/foodify/Adapter/BasketAdapter.java index 7dc4f3e..57ca176 100644 --- a/app/src/main/java/com/capstone/foodify/Adapter/BasketAdapter.java +++ b/app/src/main/java/com/capstone/foodify/Adapter/BasketAdapter.java @@ -55,9 +55,15 @@ public class BasketAdapter extends RecyclerView.Adapter { private List listFoodShop; + private Context context; - public FoodShopAdapter() { + public FoodShopAdapter(Context context) { + this.context = context; } public void setData(List listFoodShop){ @@ -39,10 +48,61 @@ public class FoodShopAdapter extends RecyclerView.Adapter 0) + imageTemp = food.getImages().get(0).getImageUrl(); + + Common.LIST_BASKET_FOOD.add(new Basket(food.getId(), imageTemp, food.getName(), food.getCost(), food.getShop().getName(), + "1", food.getDiscountPercent())); + } else { + //If item is exist in basket + + for(int i = 0; i < Common.LIST_BASKET_FOOD.size(); i++){ + String foodId = Common.LIST_BASKET_FOOD.get(i).getId(); + //Find foodId exist + if(foodId.equals(food.getId())){ + //Get quantity food from basket + String quantity = Common.LIST_BASKET_FOOD.get(i).getQuantity(); + + //Change quantity food from basket + int quantityInt = Integer.parseInt(quantity) + 1; + Common.LIST_BASKET_FOOD.get(i).setQuantity(String.valueOf(quantityInt)); + break; + } + } + + } + Toast.makeText(context, "Đã thêm " + food.getName() + " vào giỏ hàng!", Toast.LENGTH_SHORT).show(); + } + }); } @Override @@ -54,7 +114,7 @@ public class FoodShopAdapter extends RecyclerView.Adapter call, Response response) { //Init total page and total elements value - TOTAL_PAGE = response.body().getPage().getTotalPages(); + LAST_PAGE = response.body().getPage().isLast(); loadFoodAdapter(response); @@ -158,7 +158,8 @@ public class SearchFragment extends Fragment { @Override public void onFailure(Call call, Throwable t) { - + //Check internet connection + Common.showNotificationError(t, getContext(), getActivity()); } }); } @@ -173,7 +174,7 @@ public class SearchFragment extends Fragment { foodAdapter.notifyDataSetChanged(); //If list data don't have pagination - if(TOTAL_PAGE == 1) + if(LAST_PAGE) hideProgressBarAndShowEndOfListText(); //If search not found @@ -236,13 +237,7 @@ public class SearchFragment extends Fragment { @Override public void onFailure(Call> call, Throwable t) { //Check internet connection - if(Common.checkInternetConnection(getContext())){ - //Has internet connection - Toast.makeText(getContext(), "Error: " + t, Toast.LENGTH_SHORT).show(); - } else { - //No internet, show notification - Common.showErrorInternetConnectionNotification(getActivity()); - } + Common.showNotificationError(t, getContext(), getActivity()); } }); } @@ -252,20 +247,15 @@ public class SearchFragment extends Fragment { @Override public void onResponse(Call call, Response response) { //Init total page and total elements value - TOTAL_PAGE = response.body().getPage().getTotalPages(); + LAST_PAGE = response.body().getPage().isLast(); loadFoodAdapter(response); } @Override public void onFailure(Call call, Throwable t) { //Check internet connection - if(Common.checkInternetConnection(getContext())){ - //Has internet connection - Toast.makeText(getContext(), "Error: " + t, Toast.LENGTH_SHORT).show(); - } else { - //No internet, show notification - Common.showErrorInternetConnectionNotification(getActivity()); - } + //Check internet connection + Common.showNotificationError(t, getContext(), getActivity()); } }); } @@ -274,20 +264,14 @@ public class SearchFragment extends Fragment { FoodApi.apiService.listFood(page, LIMIT, "id", "asc").enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { - TOTAL_PAGE = response.body().getPage().getTotalPages(); + LAST_PAGE = response.body().getPage().isLast(); loadFoodAdapter(response); } @Override public void onFailure(Call call, Throwable t) { //Check internet connection - if(Common.checkInternetConnection(getContext())){ - //Has internet connection - Toast.makeText(getContext(), "Error: " + t, Toast.LENGTH_SHORT).show(); - } else { - //No internet, show notification - Common.showErrorInternetConnectionNotification(getActivity()); - } + Common.showNotificationError(t, getContext(), getActivity()); } }); } @@ -295,7 +279,7 @@ public class SearchFragment extends Fragment { private void dataLoadMore() { switch (ACTION_CODE){ case LIST_FOOD:{ - if(CURRENT_PAGE < TOTAL_PAGE - 1){ + if(!LAST_PAGE){ getListFood(++CURRENT_PAGE); } else { hideProgressBarAndShowEndOfListText(); @@ -303,7 +287,7 @@ public class SearchFragment extends Fragment { break; } case SEARCH_FOOD:{ - if(CURRENT_PAGE < TOTAL_PAGE - 1){ + if(!LAST_PAGE){ getListFoodBySearch(searchQuery, ++CURRENT_PAGE); } else { hideProgressBarAndShowEndOfListText(); @@ -311,7 +295,7 @@ public class SearchFragment extends Fragment { break; } case LIST_FOOD_BY_CATEGORY:{ - if(CURRENT_PAGE < TOTAL_PAGE - 1){ + if(!LAST_PAGE){ getListFoodByCategory(++CURRENT_PAGE); } else { hideProgressBarAndShowEndOfListText(); diff --git a/app/src/main/res/layout/activity_shop_detail.xml b/app/src/main/res/layout/activity_shop_detail.xml index 3ab1780..1c5dc20 100644 --- a/app/src/main/res/layout/activity_shop_detail.xml +++ b/app/src/main/res/layout/activity_shop_detail.xml @@ -76,6 +76,7 @@ android:layout_height="wrap_content" app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="parent" + android:visibility="gone" /> + + + + diff --git a/app/src/main/res/layout/item_food_shop.xml b/app/src/main/res/layout/item_food_shop.xml index 2b26d31..34ecc86 100644 --- a/app/src/main/res/layout/item_food_shop.xml +++ b/app/src/main/res/layout/item_food_shop.xml @@ -122,6 +122,7 @@ android:layout_height="wrap_content" android:src="@drawable/basket_icon" android:layout_gravity="center_vertical" + android:id="@+id/basket_icon" />