diff --git a/Lambdas/Lists/ItemSearch/src/ItemSearcher.java b/Lambdas/Lists/ItemSearch/src/ItemSearcher.java index 29bc78c..a3a7381 100644 --- a/Lambdas/Lists/ItemSearch/src/ItemSearcher.java +++ b/Lambdas/Lists/ItemSearch/src/ItemSearcher.java @@ -7,26 +7,24 @@ import java.util.Map; public class ItemSearcher implements CallHandler { - DBConnector connector; + Connection connection; String cognitoID; - private final String GET_ITEM_MATCHES = "SELECT * FROM Product WHERE description LIKE ?"; + private final String GET_ITEM_MATCHES = "SELECT * FROM Product WHERE description LIKE ? LIMIT 100;"; - public ItemSearcher(DBConnector connector, String cognitoID) { - this.connector = connector; + public ItemSearcher(Connection connection, String cognitoID) { + this.connection = connection; this.cognitoID = cognitoID; } @Override public Object conductAction(Map body, HashMap queryParams, String s) throws SQLException { - try (Connection connection = connector.getConnection()) { - PreparedStatement getItemMatches = connection.prepareStatement(GET_ITEM_MATCHES); - getItemMatches.setString(1, "%" + queryParams.get("id") + "%"); - System.out.println(getItemMatches); - ResultSet searchResults = getItemMatches.executeQuery(); - ItemSearch searchResultsObject = new ItemSearch(searchResults); - System.out.println(searchResultsObject); - return searchResultsObject; - } + PreparedStatement getItemMatches = connection.prepareStatement(GET_ITEM_MATCHES); + getItemMatches.setString(1, "%" + queryParams.get("id") + "%"); + System.out.println(getItemMatches); + ResultSet searchResults = getItemMatches.executeQuery(); + ItemSearch searchResultsObject = new ItemSearch(searchResults); + System.out.println(searchResultsObject); + return searchResultsObject; } } diff --git a/Listify/app/src/main/java/com/example/listify/ItemDetails.java b/Listify/app/src/main/java/com/example/listify/ItemDetails.java index 415d1a4..46dd926 100644 --- a/Listify/app/src/main/java/com/example/listify/ItemDetails.java +++ b/Listify/app/src/main/java/com/example/listify/ItemDetails.java @@ -1,5 +1,8 @@ package com.example.listify; +import android.app.Dialog; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import com.amplifyframework.auth.AuthException; @@ -11,6 +14,8 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import android.view.View; +import android.view.Window; +import android.view.WindowManager; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.LinearLayout; @@ -71,6 +76,8 @@ public class ItemDetails extends AppCompatActivity implements ListPickerDialogFr @Override public void onClick(View v) { closeFABMenu(); + LoadingCircleDialog loadingDialog = new LoadingCircleDialog(ItemDetails.this); + loadingDialog.show(); Properties configs = new Properties(); try { @@ -81,21 +88,57 @@ public class ItemDetails extends AppCompatActivity implements ListPickerDialogFr Requestor requestor = new Requestor(am, configs.getProperty("apiKey")); SynchronousReceiver listIdsReceiver = new SynchronousReceiver<>(); - SynchronousReceiver listReceiver = new SynchronousReceiver<>(); - requestor.getListOfIds(List.class, listIdsReceiver, listIdsReceiver); - try { - Integer[] listIds = listIdsReceiver.await(); - for (int i = 0; i < listIds.length; i++) { - requestor.getObject(Integer.toString(listIds[i]), List.class, listReceiver, listReceiver); - shoppingLists.add(listReceiver.await()); - } - } catch (Exception e) { - e.printStackTrace(); - } - ListPickerDialogFragment listPickerDialog = new ListPickerDialogFragment(shoppingLists); - listPickerDialog.show(getSupportFragmentManager(), "User Lists"); + Thread t = new Thread(new Runnable() { + @Override + public void run() { + Integer[] listIds = null; + try { + listIds = listIdsReceiver.await(); + } catch (Exception e) { + e.printStackTrace(); + } + + // Create threads and add them to a list + Thread[] threads = new Thread[listIds.length]; + List[] results = new List[listIds.length]; + for (int i = 0; i < listIds.length; i++) { + SynchronousReceiver listReceiver = new SynchronousReceiver<>(); + requestor.getObject(Integer.toString(listIds[i]), List.class, listReceiver, listReceiver); + final int finalI = i; + Thread l = new Thread(new Runnable() { + @Override + public void run() { + try { + results[finalI] = listReceiver.await(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + threads[i] = l; + l.start(); + } + + shoppingLists.clear(); + // Wait for each thread to finish and add results to shoppingLists + for (int i = 0; i < threads.length; i++) { + try { + threads[i].join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + shoppingLists.add(results[i]); + } + + + loadingDialog.cancel(); + ListPickerDialogFragment listPickerDialog = new ListPickerDialogFragment(shoppingLists); + listPickerDialog.show(getSupportFragmentManager(), "User Lists"); + } + }); + t.start(); } }); @@ -157,7 +200,7 @@ public class ItemDetails extends AppCompatActivity implements ListPickerDialogFr } - // Add the viewed item to the selected list + // Add the selected item to the selected list @Override public void sendListSelection(int selectedListIndex, int quantity) { @@ -184,6 +227,8 @@ public class ItemDetails extends AppCompatActivity implements ListPickerDialogFr // Create a new list and add the item to it @Override public void sendNewListName(String name, int quantity) { + LoadingCircleDialog loadingDialog = new LoadingCircleDialog(this); + loadingDialog.show(); Properties configs = new Properties(); try { @@ -196,16 +241,34 @@ public class ItemDetails extends AppCompatActivity implements ListPickerDialogFr com.example.listify.data.List newList = new List(-1, name, "user filled by lambda", Instant.now().toEpochMilli()); - try { - requestor.postObject(newList, idReceiver, idReceiver); - int newListId = idReceiver.await(); - ListEntry entry = new ListEntry(newListId, curProduct.getItemId(), quantity, Instant.now().toEpochMilli(),false); - requestor.postObject(entry); + Thread t = new Thread(new Runnable() { + @Override + public void run() { + try { + requestor.postObject(newList, idReceiver, idReceiver); + int newListId = idReceiver.await(); + ListEntry entry = new ListEntry(newListId, curProduct.getItemId(), quantity, Instant.now().toEpochMilli(),false); + requestor.postObject(entry); - Toast.makeText(this, String.format("%s created and item added", name), Toast.LENGTH_LONG).show(); - } catch (Exception e) { - Toast.makeText(this, "An error occurred", Toast.LENGTH_LONG).show(); - e.printStackTrace(); - } + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(ItemDetails.this, String.format("%s created and item added", name), Toast.LENGTH_LONG).show(); + loadingDialog.cancel(); + } + }); + } catch (Exception e) { + runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(ItemDetails.this, "An error occurred", Toast.LENGTH_LONG).show(); + loadingDialog.cancel(); + e.printStackTrace(); + } + }); + } + } + }); + t.start(); } } \ No newline at end of file diff --git a/Listify/app/src/main/java/com/example/listify/ListPage.java b/Listify/app/src/main/java/com/example/listify/ListPage.java index 580bb65..dd6a28b 100644 --- a/Listify/app/src/main/java/com/example/listify/ListPage.java +++ b/Listify/app/src/main/java/com/example/listify/ListPage.java @@ -10,42 +10,76 @@ import android.widget.*; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; + +import com.bumptech.glide.Glide; + import com.example.listify.data.Item; import com.example.listify.data.List; import com.example.listify.data.ListEntry; -import org.json.JSONException; import java.io.IOException; +import java.text.DecimalFormat; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import java.util.Properties; +import org.json.JSONException; + import static com.example.listify.MainActivity.am; -public class ListPage extends AppCompatActivity { +public class ListPage extends AppCompatActivity implements Requestor.Receiver { ListView listView; MyAdapter myAdapter; + Requestor requestor; Button incrQuan; Button decrQuan; Button removeItem; TextView tvTotalPrice; + ProgressBar loadingListItems; ArrayList pNames = new ArrayList<>(); ArrayList pStores = new ArrayList<>(); ArrayList pPrices = new ArrayList<>(); ArrayList pQuantity = new ArrayList<>(); - ArrayList pImages = new ArrayList<>(); + ArrayList pImages = new ArrayList<>(); ArrayList pListItemPair = new ArrayList<>(); Requestor requestor; double totalPrice = 0; + + Map totalPriceByStore = new HashMap<>(); + Map storeHeaderIndex = new HashMap<>(); + DecimalFormat df = new DecimalFormat("0.00"); + + // TODO: Display a message if their list is empty @Override protected void onCreate(@Nullable Bundle savedInstanceState) { // Read list ID from caller final int listID = (int) getIntent().getSerializableExtra("listID"); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_list); + + listView = findViewById(R.id.listView); + myAdapter = new MyAdapter(this, pNames, pStores, pPrices, pQuantity, pImages); + + listView.setAdapter(myAdapter); + + loadingListItems = findViewById(R.id.progress_loading_list_items); + loadingListItems.setVisibility(View.VISIBLE); + + pNames.add("Total Price"); + pStores.add(""); + pPrices.add("0.00"); + pQuantity.add("-1"); + pImages.add("-1"); + pListItemPair.add(null); + + Properties configs = new Properties(); try { configs = AuthManager.loadProperties(this, "android.resource://" + getPackageName() + "/raw/auths.json"); @@ -53,44 +87,8 @@ public class ListPage extends AppCompatActivity { e.printStackTrace(); } requestor = new Requestor(am, configs.getProperty("apiKey")); - SynchronousReceiver lr = new SynchronousReceiver<>(); - //ListReceiver lr = new ListReceiver<>(); - requestor.getObject(Integer.toString(listID), List.class, lr); - List list; - - try { - list = lr.await(); - } - catch (Exception e) { - list = null; - } - - if(list != null) { - for (ListEntry entry : list.getEntries()) { - int product = entry.getProductID(); - SynchronousReceiver pr = new SynchronousReceiver<>(); - requestor.getObject(Integer.toString(product), Item.class, pr, pr); - Item item; - try { - item = pr.await(); - } - catch (Exception e) { - item = null; - } - if(item != null) { - pNames.add(item.getDescription()); - pStores.add("Kroger"); - pPrices.add(item.getPrice().toString()); - pQuantity.add(entry.getQuantity().toString()); - pImages.add(R.drawable.placeholder); - pListItemPair.add(entry); - - // Increment total price - totalPrice += (item.getPrice().doubleValue() * entry.getQuantity()); - } - } - } + requestor.getObject(Integer.toString(listID), List.class, this); /*pNames.add("Half-gallon organic whole milk"); pStores.add("Kroger"); @@ -109,17 +107,86 @@ public class ListPage extends AppCompatActivity { pPrices.add("$7.00"); pQuantity.add("1"); pImages.add(R.drawable.peanutbutter);*/ + } - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_list); + @Override + public void acceptDelivery(Object delivered) { + List list = (List) delivered; - listView = findViewById(R.id.listView); - myAdapter = new MyAdapter(this, pNames, pStores, pPrices, pQuantity, pImages); + if(list != null) { + for (ListEntry entry : list.getEntries()) { + int product = entry.getProductID(); + SynchronousReceiver pr = new SynchronousReceiver<>(); + requestor.getObject(Integer.toString(product), Item.class, pr, pr); + Item item; + try { + item = pr.await(); + } + catch (Exception e) { + item = null; + } + if(item != null) { + if(!totalPriceByStore.containsKey("Kroger")) { + totalPriceByStore.put("Kroger", item.getPrice().doubleValue() * entry.getQuantity()); + storeHeaderIndex.put("Kroger", pNames.size()); - listView.setAdapter(myAdapter); + double newTotal = Double.parseDouble(pPrices.get(0)) + (item.getPrice().doubleValue() * entry.getQuantity()); + pPrices.set(0, String.valueOf(newTotal)); + + pNames.add("Kroger"); + pStores.add(""); + pPrices.add(df.format(totalPriceByStore.get("Kroger"))); + pQuantity.add("-1"); + pImages.add("-1"); + pListItemPair.add(null); + + pNames.add(item.getDescription()); + pStores.add("Kroger"); + pPrices.add(df.format(item.getPrice())); + pQuantity.add(entry.getQuantity().toString()); + pImages.add(item.getImageURL()); + pListItemPair.add(entry); + } + else { + int index = storeHeaderIndex.get("Kroger"); + + totalPriceByStore.put("Kroger", totalPriceByStore.get("Kroger") + (item.getPrice().doubleValue() * entry.getQuantity())); + pPrices.set(index, df.format(totalPriceByStore.get("Kroger"))); + + double newTotal = Double.parseDouble(pPrices.get(0)) + (item.getPrice().doubleValue() * entry.getQuantity()); + pPrices.set(0, df.format(newTotal)); + index++; + + pNames.add(index, item.getDescription()); + pStores.add(index, "Kroger"); + pPrices.add(index, df.format(item.getPrice())); + pQuantity.add(index, entry.getQuantity().toString()); + pImages.add(index, item.getImageURL()); + pListItemPair.add(index, entry); + + // Increment total price + totalPrice += (item.getPrice().doubleValue() * entry.getQuantity()); + + for(String store : storeHeaderIndex.keySet()) { + if(storeHeaderIndex.get(store) > index) { + storeHeaderIndex.put(store, storeHeaderIndex.get(store) + 1); + } + } + } + } + } tvTotalPrice = (TextView) findViewById(R.id.total_price); tvTotalPrice.setText(String.format("$%.2f", totalPrice)); + runOnUiThread(new Runnable() { + @Override + public void run() { + loadingListItems.setVisibility(View.GONE); + myAdapter.notifyDataSetChanged(); + } + }); + } + } class MyAdapter extends ArrayAdapter { @@ -128,9 +195,9 @@ public class ListPage extends AppCompatActivity { ArrayList pStores; ArrayList pPrices; ArrayList pQuantity; - ArrayList pImages; + ArrayList pImages; - MyAdapter (Context c, ArrayList names, ArrayList stores, ArrayList prices, ArrayList quantity, ArrayList images) { + MyAdapter (Context c, ArrayList names, ArrayList stores, ArrayList prices, ArrayList quantity, ArrayList images) { super(c, R.layout.activity_listproductentry, R.id.productView, names); context = c; pNames = names; @@ -155,6 +222,10 @@ public class ListPage extends AppCompatActivity { public void onClick(View v) { int q = Integer.parseInt(pQuantity.get(position)) - 1; pQuantity.set(position, Integer.toString(q)); + totalPriceByStore.put(pStores.get(position), totalPriceByStore.get(pStores.get(position)) - Double.parseDouble(pPrices.get(position))); + pPrices.set(storeHeaderIndex.get(pStores.get(position)), df.format(totalPriceByStore.get(pStores.get(position)))); + double newTotal = Double.parseDouble(pPrices.get(0)) - Double.parseDouble(pPrices.get(position)); + pPrices.set(0, df.format(newTotal)); ListEntry le = pListItemPair.remove(position); le.setQuantity(le.getQuantity() - 1); pListItemPair.add(position, le); @@ -188,6 +259,10 @@ public class ListPage extends AppCompatActivity { public void onClick(View v) { int q = Integer.parseInt(pQuantity.get(position)) + 1; pQuantity.set(position, Integer.toString(q)); + totalPriceByStore.put(pStores.get(position), totalPriceByStore.get(pStores.get(position)) + Double.parseDouble(pPrices.get(position))); + pPrices.set(storeHeaderIndex.get(pStores.get(position)), df.format(totalPriceByStore.get(pStores.get(position)))); + double newTotal = Double.parseDouble(pPrices.get(0)) + Double.parseDouble(pPrices.get(position)); + pPrices.set(0, df.format(newTotal)); ListEntry le = pListItemPair.remove(position); le.setQuantity(le.getQuantity() + 1); pListItemPair.add(position, le); @@ -223,13 +298,41 @@ public class ListPage extends AppCompatActivity { Double.parseDouble(pQuantity.get(position))); tvTotalPrice.setText(String.format("$%.2f", totalPrice)); - pNames.remove(position); - pStores.remove(position); - pPrices.remove(position); - pQuantity.remove(position); - pImages.remove(position); + if(position == 0) { + pNames.clear(); + pStores.clear(); + pPrices.clear(); + pQuantity.clear(); + pImages.clear(); - requestor.deleteObject(pListItemPair.remove(position)); + pNames.add("Total Price"); + pStores.add(""); + pPrices.add("0.00"); + pQuantity.add("-1"); + pImages.add("-1"); + + while(pListItemPair.size() > 1) { + try { + requestor.deleteObject(pListItemPair.remove(1)); + } + catch(Exception e) {} + } + } + else { + totalPriceByStore.put("Kroger", totalPriceByStore.get("Kroger") - (Double.parseDouble(pPrices.get(position)) * Integer.parseInt(pQuantity.get(position)))); + pPrices.set(storeHeaderIndex.get(pStores.get(position)), df.format(totalPriceByStore.get(pStores.get(position)))); + + double newTotal = Double.parseDouble(pPrices.get(0)) - (Double.parseDouble(pPrices.get(position)) * Integer.parseInt(pQuantity.get(position))); + pPrices.set(0, df.format(newTotal)); + + pNames.remove(position); + pStores.remove(position); + pPrices.remove(position); + pQuantity.remove(position); + pImages.remove(position); + + requestor.deleteObject(pListItemPair.remove(position)); + } listView.setAdapter(myAdapter); } @@ -244,36 +347,33 @@ public class ListPage extends AppCompatActivity { if(!pNames.isEmpty()) { name.setText(pNames.get(position)); store.setText(pStores.get(position)); - price.setText(pPrices.get(position)); - quantity.setText(pQuantity.get(position)); - image.setImageResource(pImages.get(position)); + price.setText("$" + pPrices.get(position)); + + if(pQuantity.get(position).equals("-1")) { + quantity.setVisibility(View.INVISIBLE); + decrQuan.setVisibility(View.INVISIBLE); + incrQuan.setVisibility(View.INVISIBLE); + + if(position == 0) { + removeItem.setText("Clear all"); + } + else { + removeItem.setVisibility(View.INVISIBLE); + } + } + else { + quantity.setText(pQuantity.get(position)); + } + + if(pImages.get(position).equals("-1")) { + image.setVisibility(View.INVISIBLE); + } + else { + Glide.with(getContext()).load(pImages.get(position)).into(image); + } } return listproduct; } } - - class ListReceiver implements Requestor.Receiver { - @Override - public void acceptDelivery(T delivered) { - for(ListEntry entry : ((List) delivered).getEntries()) { - int product = entry.getProductID(); - ProductReceiver pr = new ProductReceiver<>(); - requestor.getObject(Integer.toString(product), Item.class, pr); - pQuantity.add(entry.getQuantity().toString()); - pListItemPair.add(entry); - } - } - } - - class ProductReceiver implements Requestor.Receiver { - @Override - public void acceptDelivery(T delivered) { - Item i = (Item) delivered; - pNames.add(i.getDescription()); - pStores.add("Kroger"); - pPrices.add(i.getPrice().toString()); - pImages.add(R.drawable.placeholder); - } - } } diff --git a/Listify/app/src/main/java/com/example/listify/LoadingCircleDialog.java b/Listify/app/src/main/java/com/example/listify/LoadingCircleDialog.java new file mode 100644 index 0000000..d4f6d82 --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/LoadingCircleDialog.java @@ -0,0 +1,36 @@ +package com.example.listify; + +import android.app.Dialog; +import android.content.Context; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; +import android.view.Window; +import android.view.WindowManager; + +public class LoadingCircleDialog { + Dialog loadingDialog; + + public LoadingCircleDialog(Context context) { + loadingDialog = new Dialog(context); + + // Create and show a loading dialog + loadingDialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE); + loadingDialog.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + + // layout to display + loadingDialog.setContentView(R.layout.dialog_loading); + + // set color transpartent + loadingDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); + loadingDialog.setCancelable(false); + loadingDialog.setCanceledOnTouchOutside(false); + } + + public void show() { + loadingDialog.show(); + } + + public void cancel() { + loadingDialog.cancel(); + } +} diff --git a/Listify/app/src/main/java/com/example/listify/SearchResults.java b/Listify/app/src/main/java/com/example/listify/SearchResults.java index d799cca..602b752 100644 --- a/Listify/app/src/main/java/com/example/listify/SearchResults.java +++ b/Listify/app/src/main/java/com/example/listify/SearchResults.java @@ -9,6 +9,7 @@ import android.widget.EditText; import android.widget.ImageButton; import android.widget.ImageView; import android.widget.ListView; +import android.widget.ProgressBar; import android.widget.SearchView; import com.example.listify.adapter.SearchResultsListAdapter; import com.example.listify.data.ItemSearch; @@ -22,8 +23,8 @@ import java.util.Properties; import static com.example.listify.MainActivity.am; -public class SearchResults extends AppCompatActivity implements SortDialogFragment.OnSortingListener { - private ListView listView; +public class SearchResults extends AppCompatActivity implements SortDialogFragment.OnSortingListener, Requestor.Receiver { + private ProgressBar loadingSearch; private SearchResultsListAdapter searchResultsListAdapter; private List resultsProductList = new ArrayList<>(); private List resultsProductListSorted = new ArrayList<>(); @@ -47,6 +48,8 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); + loadingSearch = (ProgressBar) findViewById(R.id.progress_loading_search); + // Back button closes this activity and returns to previous activity (MainActivity) ImageButton backButton = (ImageButton) findViewById(R.id.backToHomeButton); backButton.setOnClickListener(new View.OnClickListener() { @@ -77,7 +80,7 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme } }); - listView = (ListView) findViewById(R.id.search_results_list); + ListView listView = (ListView) findViewById(R.id.search_results_list); searchResultsListAdapter = new SearchResultsListAdapter(this, resultsProductListSorted); listView.setAdapter(searchResultsListAdapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @@ -96,6 +99,15 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { + // Show progress bar + loadingSearch.setVisibility(View.VISIBLE); + + // Clear the old search results + resultsProductList.clear(); + + // Clear old search results from the view + resultsProductListSorted.clear(); + searchResultsListAdapter.notifyDataSetChanged(); doSearch(query); return false; } @@ -122,12 +134,8 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme sortDialog.show(getSupportFragmentManager(), "Sort"); } }); - } - - - // Override default phone back button to add animation @Override public void onBackPressed() { @@ -136,10 +144,6 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme } private void doSearch(String query) { - - // Clear the old search results - resultsProductList.clear(); - Properties configs = new Properties(); try { configs = AuthManager.loadProperties(this, "android.resource://" + getPackageName() + "/raw/auths.json"); @@ -148,32 +152,7 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme } Requestor requestor = new Requestor(am, configs.getProperty("apiKey")); - - SynchronousReceiver itemReceiver = new SynchronousReceiver<>(); - requestor.getObject(query, ItemSearch.class, itemReceiver, itemReceiver); - ItemSearch results; - try { - results = itemReceiver.await(); - for (int i = 0; i < results.getResults().size(); i++) { - // TODO: Change to dynamically grab chain name by id - resultsProductList.add(new Product(results.getResults().get(i).getDescription(), results.getResults().get(i).getProductID(), "Kroger", results.getResults().get(i).getChainID(), results.getResults().get(i).getUpc(), results.getResults().get(i).getDescription(), results.getResults().get(i).getPrice(), results.getResults().get(i).getImageURL(), results.getResults().get(i).getDepartment())); - } - } catch (Exception e) { - e.printStackTrace(); - } - - // Create a list of all stores in the results so the user can filter by store name - for (int i = 0; i < resultsProductList.size(); i++) { - if (!stores.contains(resultsProductList.get(i).getChainName())) { - stores.add(resultsProductList.get(i).getChainName()); - } - } - - // Add all results to the sorted list - resultsProductListSorted.addAll(resultsProductList); - - // Apply selected sorting to the list - sortResults(); + requestor.getObject(query, ItemSearch.class, this); } // TODO: Scroll the list back to the top when a search, sort, or filter is performed @@ -204,7 +183,6 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme }); break; - // TODO: May need to change this depending on if price is stored as a string or a double case 2: resultsProductListSorted.sort(new Comparator() { @Override @@ -258,7 +236,57 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme resultsProductListSorted.clear(); resultsProductListSorted.addAll(temp); } + } - searchResultsListAdapter.notifyDataSetChanged(); + // This is called after the search results come back from the server + // TODO: Display a "no results" message if nothing is found when searching + @Override + public void acceptDelivery(Object delivered) { + ItemSearch results = (ItemSearch) delivered; + + try { + for (int i = 0; i < results.getResults().size(); i++) { + // TODO: Change to dynamically grab chain name by id + resultsProductList.add(new Product( + results.getResults().get(i).getDescription(), + results.getResults().get(i).getProductID(), + "Kroger", + results.getResults().get(i).getChainID(), + results.getResults().get(i).getUpc(), + results.getResults().get(i).getDescription(), + results.getResults().get(i).getPrice(), + results.getResults().get(i).getImageURL(), + results.getResults().get(i).getDepartment() + )); + } + } catch (Exception e) { + e.printStackTrace(); + } + + // Create a list of all stores in the results so the user can filter by store name + for (int i = 0; i < resultsProductList.size(); i++) { + if (!stores.contains(resultsProductList.get(i).getChainName())) { + stores.add(resultsProductList.get(i).getChainName()); + } + } + + // Add all results to the sorted list + resultsProductListSorted.addAll(resultsProductList); + + // Apply selected sorting to the list + sortResults(); + + // Updates the list of search results. Runs on the main UI thread since other threads are + // not allowed to change UI elements + runOnUiThread(new Runnable() { + @Override + public void run() { + searchResultsListAdapter.notifyDataSetChanged(); + + // Hide progress bar + loadingSearch.setVisibility(View.GONE); + + } + }); } } \ No newline at end of file diff --git a/Listify/app/src/main/java/com/example/listify/ui/ForgotPasswordPage.java b/Listify/app/src/main/java/com/example/listify/ui/ForgotPasswordPage.java index 7b58531..fe59b9c 100644 --- a/Listify/app/src/main/java/com/example/listify/ui/ForgotPasswordPage.java +++ b/Listify/app/src/main/java/com/example/listify/ui/ForgotPasswordPage.java @@ -84,9 +84,7 @@ public class ForgotPasswordPage extends AppCompatActivity { }); builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override - public void onClick(DialogInterface dialog, int which) { - return; - } + public void onClick(DialogInterface dialog, int which) {} }); AlertDialog dialog = builder.create(); dialog.show(); diff --git a/Listify/app/src/main/java/com/example/listify/ui/SignupPage.java b/Listify/app/src/main/java/com/example/listify/ui/SignupPage.java index e438f7a..6e1eaeb 100644 --- a/Listify/app/src/main/java/com/example/listify/ui/SignupPage.java +++ b/Listify/app/src/main/java/com/example/listify/ui/SignupPage.java @@ -103,9 +103,7 @@ public class SignupPage extends AppCompatActivity { }); builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override - public void onClick(DialogInterface dialog, int which) { - return; - } + public void onClick(DialogInterface dialog, int which) {} }); AlertDialog dialog = builder.create(); dialog.show(); diff --git a/Listify/app/src/main/java/com/example/listify/ui/home/HomeFragment.java b/Listify/app/src/main/java/com/example/listify/ui/home/HomeFragment.java index 8eb6840..13ddebe 100644 --- a/Listify/app/src/main/java/com/example/listify/ui/home/HomeFragment.java +++ b/Listify/app/src/main/java/com/example/listify/ui/home/HomeFragment.java @@ -70,9 +70,7 @@ public class HomeFragment extends Fragment { }); builder.setNegativeButton("No", new DialogInterface.OnClickListener() { @Override - public void onClick(DialogInterface dialog, int which) { - return; - } + public void onClick(DialogInterface dialog, int which) {} }); AlertDialog dialog = builder.create(); dialog.show(); diff --git a/Listify/app/src/main/java/com/example/listify/ui/lists/ListsFragment.java b/Listify/app/src/main/java/com/example/listify/ui/lists/ListsFragment.java index c7029ba..fdcc4d4 100644 --- a/Listify/app/src/main/java/com/example/listify/ui/lists/ListsFragment.java +++ b/Listify/app/src/main/java/com/example/listify/ui/lists/ListsFragment.java @@ -1,15 +1,22 @@ package com.example.listify.ui.lists; +import android.app.Dialog; import android.content.Intent; +import android.graphics.Color; +import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.view.LayoutInflater; +import android.view.Window; +import android.view.WindowManager; import android.widget.AdapterView; import android.widget.ListView; +import android.widget.ProgressBar; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.fragment.app.ListFragment; import com.amplifyframework.auth.AuthException; import com.example.listify.AuthManager; @@ -17,6 +24,7 @@ import com.example.listify.CreateListAddDialogFragment; import com.example.listify.CreateListDialogFragment; import com.example.listify.ItemDetails; import com.example.listify.ListPage; +import com.example.listify.LoadingCircleDialog; import com.example.listify.R; import com.example.listify.Requestor; import com.example.listify.SearchResults; @@ -34,16 +42,20 @@ import java.util.Properties; import static com.example.listify.MainActivity.am; -public class ListsFragment extends Fragment implements CreateListDialogFragment.OnNewListListener { +public class ListsFragment extends Fragment implements CreateListDialogFragment.OnNewListListener, Requestor.Receiver { ArrayList shoppingLists = new ArrayList<>(); DisplayShoppingListsAdapter displayShoppingListsAdapter; + Requestor requestor; ListView shoppingListsView; + ProgressBar loadingLists; + int resultsIndex; public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.fragment_lists, container, false); shoppingListsView = root.findViewById(R.id.shopping_lists); + loadingLists = (ProgressBar) root.findViewById(R.id.progress_loading_lists); + loadingLists.setVisibility(View.VISIBLE); - // TODO: Switch this to async Properties configs = new Properties(); try { configs = AuthManager.loadProperties(getContext(), "android.resource://" + getActivity().getPackageName() + "/raw/auths.json"); @@ -51,36 +63,13 @@ public class ListsFragment extends Fragment implements CreateListDialogFragment. e.printStackTrace(); } - Requestor requestor = new Requestor(am, configs.getProperty("apiKey")); + requestor = new Requestor(am, configs.getProperty("apiKey")); SynchronousReceiver listIdsReceiver = new SynchronousReceiver<>(); - SynchronousReceiver listReceiver = new SynchronousReceiver<>(); - requestor.getListOfIds(List.class, listIdsReceiver, listIdsReceiver); - try { - Integer[] listIds = listIdsReceiver.await(); - for (int i = 0; i < listIds.length; i++) { - requestor.getObject(Integer.toString(listIds[i]), List.class, listReceiver, listReceiver); - shoppingLists.add(listReceiver.await()); - } - } catch (Exception e) { - e.printStackTrace(); - } + final Requestor.Receiver recv = this; + requestor.getListOfIds(List.class, recv, null); - // Set adapter and display this users lists - displayShoppingListsAdapter = new DisplayShoppingListsAdapter(getActivity(), shoppingLists); - shoppingListsView.setAdapter(displayShoppingListsAdapter); - shoppingListsView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - Intent listPage = new Intent(getContext(), ListPage.class); - - // Send the list ID - listPage.putExtra("listID", shoppingLists.get(position).getItemID()); - startActivity(listPage); - } - }); - FloatingActionButton fab = (FloatingActionButton) root.findViewById(R.id.new_list_fab); Fragment thisFragment = this; fab.setOnClickListener(new View.OnClickListener() { @@ -97,6 +86,8 @@ public class ListsFragment extends Fragment implements CreateListDialogFragment. @Override public void sendNewListName(String name) { + LoadingCircleDialog loadingDialog = new LoadingCircleDialog(getActivity()); + loadingDialog.show(); Properties configs = new Properties(); try { @@ -111,13 +102,95 @@ public class ListsFragment extends Fragment implements CreateListDialogFragment. try { requestor.postObject(newList, idReceiver, idReceiver); - newList.setItemID(idReceiver.await()); - shoppingLists.add(newList); - displayShoppingListsAdapter.notifyDataSetChanged(); - Toast.makeText(getContext(), String.format("%s created", name), Toast.LENGTH_LONG).show(); } catch (Exception e) { Toast.makeText(getContext(), "An error occurred", Toast.LENGTH_LONG).show(); e.printStackTrace(); } + Thread t = new Thread(new Runnable() { + @Override + public void run() { + try { + newList.setItemID(idReceiver.await()); + } catch (Exception e) { + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(getContext(), "An error occurred", Toast.LENGTH_LONG).show(); + loadingDialog.cancel(); + } + }); + e.printStackTrace(); + + } + shoppingLists.add(newList); + + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + displayShoppingListsAdapter.notifyDataSetChanged(); + loadingDialog.cancel(); + Toast.makeText(getContext(), String.format("%s created", name), Toast.LENGTH_LONG).show(); + } + }); + } + }); + t.start(); + } + + @Override + public void acceptDelivery(Object delivered) { + Integer[] listIds = (Integer[]) delivered; + // Create threads and add them to a list + Thread[] threads = new Thread[listIds.length]; + List[] results = new List[listIds.length]; + for (int i = 0; i < listIds.length; i++) { + SynchronousReceiver listReceiver = new SynchronousReceiver<>(); + requestor.getObject(Integer.toString(listIds[i]), List.class, listReceiver, listReceiver); + final int finalI = i; + Thread t = new Thread(new Runnable() { + @Override + public void run() { + try { + results[finalI] = listReceiver.await(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }); + threads[i] = t; + t.start(); + } + + // Wait for each thread to finish and add results to shoppingLists + for (int i = 0; i < threads.length; i++) { + try { + threads[i].join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + shoppingLists.add(results[i]); + } + + // Set adapter and display this users lists + displayShoppingListsAdapter = new DisplayShoppingListsAdapter(getActivity(), shoppingLists); + + getActivity().runOnUiThread(new Runnable() { + @Override + public void run() { + shoppingListsView.setAdapter(displayShoppingListsAdapter); + shoppingListsView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + Intent listPage = new Intent(getContext(), ListPage.class); + + // Send the list ID + listPage.putExtra("listID", shoppingLists.get(position).getItemID()); + startActivity(listPage); + } + }); + loadingLists.setVisibility(View.GONE); + } + }); + } } \ No newline at end of file diff --git a/Listify/app/src/main/res/layout/activity_list.xml b/Listify/app/src/main/res/layout/activity_list.xml index 12e134b..cc262f4 100644 --- a/Listify/app/src/main/res/layout/activity_list.xml +++ b/Listify/app/src/main/res/layout/activity_list.xml @@ -4,13 +4,23 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + - + - + \ No newline at end of file diff --git a/Listify/app/src/main/res/layout/content_search_results.xml b/Listify/app/src/main/res/layout/content_search_results.xml index cd08592..51ff208 100644 --- a/Listify/app/src/main/res/layout/content_search_results.xml +++ b/Listify/app/src/main/res/layout/content_search_results.xml @@ -12,6 +12,16 @@ tools:context=".SearchResults" tools:showIn="@layout/activity_search_results"> + + + + + + \ No newline at end of file diff --git a/Listify/app/src/main/res/layout/fragment_lists.xml b/Listify/app/src/main/res/layout/fragment_lists.xml index 0793341..e595fb9 100644 --- a/Listify/app/src/main/res/layout/fragment_lists.xml +++ b/Listify/app/src/main/res/layout/fragment_lists.xml @@ -12,6 +12,16 @@ tools:context=".ui.lists.ListsFragment" tools:showIn="@layout/fragment_lists"> + + - - - - -