diff --git a/Lambdas/APIs/src/main/java/KroggerAPICaller.java b/Lambdas/APIs/src/main/java/KroggerAPICaller.java new file mode 100644 index 0000000..9b0b22d --- /dev/null +++ b/Lambdas/APIs/src/main/java/KroggerAPICaller.java @@ -0,0 +1,78 @@ +import netscape.javascript.JSObject; + +import java.io.*; +import java.net.ProtocolException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Base64; +import java.util.HashMap; + +public class KroggerAPITester { + + final static String client_id = "listify-f6e083b133a87ab8a98b2ec4f580dedb9125180887245441161"; + final static String client_secret = "hM88WJ3cJGou5jX1vNRZBqKKVmmcMMktTcTbvkRD"; + final static String redirect_uri = "https://example.com/callback"; //subject to change as needed + final static String scope = "product.compact"; + final static String authString = "listify-f6e083b133a87ab8a98b2ec4f580dedb9125180887245441161:hM88WJ3cJGou5jX1vNRZBqKKVmmcMMktTcTbvkRD"; + + + public static String getKroggerAuthKey() { + String token = "not found"; + try { + StringBuilder sb = new StringBuilder("https://api.kroger.com/v1/connect/oauth2/token"); + String urlParameters = "grant_type=client_credentials&scope=product.compact"; + byte[] postData = urlParameters.getBytes( StandardCharsets.UTF_8 ); + int postDataLength = postData.length; + URL url = new URL(sb.toString()); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setDoOutput(true); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + connection.setRequestProperty("Authorization", "Basic " + Base64.getEncoder().encodeToString(authString.getBytes())); + connection.setRequestProperty("charset", "UTF-8"); + connection.setRequestProperty("Content-Length", Integer.toString( postDataLength )); + try( DataOutputStream wr = new DataOutputStream( connection.getOutputStream())) { //write body into POST request + wr.write( postData ); + } + + int responseStatus = connection.getResponseCode(); + if(responseStatus == 200) { + System.out.println("Success"); + try(BufferedReader br = new BufferedReader( + new InputStreamReader(connection.getInputStream(), "utf-8"))) { + StringBuilder response = new StringBuilder(); + String responseLine; + while ((responseLine = br.readLine()) != null) { + response.append(responseLine.trim()); + } + + String jsonString = response.toString(); + jsonString = jsonString.substring(1, jsonString.length() - 1); + HashMap map = new HashMap<>(); + String[] responses = jsonString.split(","); + for(int i = 0; i < responses.length; i++) { + String[] keyValue = responses[i].split(":"); + map.put(keyValue[0], keyValue[1]); + } + + if(map.containsKey("\"access_token\"")) { + token = map.get("\"access_token\""); + token = token.substring(1, token.length() - 1); //removes quotes at start and end + } + + } + } else { + System.out.println(responseStatus); + } + connection.disconnect(); + System.out.println(responseStatus); + + } catch (IOException e) { + e.printStackTrace(); + } + return token; + } + +} diff --git a/Lambdas/Lists/Item/src/Item.java b/Lambdas/Lists/Item/src/Item.java new file mode 100644 index 0000000..bfa12a1 --- /dev/null +++ b/Lambdas/Lists/Item/src/Item.java @@ -0,0 +1,123 @@ +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; + +public class Item { + Integer productID; + Integer chainID; + String upc; + String description; + BigDecimal price; + String imageURL; + String department; + long retrievedDate; + Integer fetchCounts; + + public Item(ResultSet itemRow) throws SQLException { + this.productID = itemRow.getInt(1); + System.out.println(this.productID); + this.chainID = itemRow.getInt(2); + System.out.println(this.chainID); + this.upc = itemRow.getString(3); + System.out.println(this.upc); + this.description = itemRow.getString(4); + System.out.println(this.description); + this.price = itemRow.getBigDecimal(5); + System.out.println(this.price); + this.imageURL = itemRow.getString(6); + System.out.println(imageURL); + this.department = itemRow.getString(7); + System.out.println(department); + this.retrievedDate = itemRow.getTimestamp(8).toInstant().toEpochMilli(); + System.out.println(retrievedDate); + this.fetchCounts = itemRow.getInt(9); + System.out.println(fetchCounts); + } + + @Override + public String toString() { + return "Item{" + + "productID=" + productID + + ", chainID=" + chainID + + ", upc='" + upc + '\'' + + ", description='" + description + '\'' + + ", price=" + price + + ", imageURL='" + imageURL + '\'' + + ", department='" + department + '\'' + + ", retrievedDate=" + retrievedDate + + ", fetchCounts=" + fetchCounts + + '}'; + } + + public Integer getProductID() { + return productID; + } + + public void setProductID(Integer productID) { + this.productID = productID; + } + + public Integer getChainID() { + return chainID; + } + + public void setChainID(Integer chainID) { + this.chainID = chainID; + } + + public String getUpc() { + return upc; + } + + public void setUpc(String upc) { + this.upc = upc; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + public String getImageURL() { + return imageURL; + } + + public void setImageURL(String imageURL) { + this.imageURL = imageURL; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + public long getRetrievedDate() { + return retrievedDate; + } + + public void setRetrievedDate(long retrievedDate) { + this.retrievedDate = retrievedDate; + } + + public Integer getFetchCounts() { + return fetchCounts; + } + + public void setFetchCounts(Integer fetchCounts) { + this.fetchCounts = fetchCounts; + } +} diff --git a/Lambdas/Lists/Item/src/ItemGET.java b/Lambdas/Lists/Item/src/ItemGET.java new file mode 100644 index 0000000..71c0804 --- /dev/null +++ b/Lambdas/Lists/Item/src/ItemGET.java @@ -0,0 +1,11 @@ +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; + +import java.util.Map; + +public class ItemGET implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + return BasicHandler.handleRequest(inputMap, unfilled, ItemGetter.class); + } +} diff --git a/Lambdas/Lists/Item/src/ItemGetter.java b/Lambdas/Lists/Item/src/ItemGetter.java new file mode 100644 index 0000000..2414e3a --- /dev/null +++ b/Lambdas/Lists/Item/src/ItemGetter.java @@ -0,0 +1,36 @@ +import com.google.gson.Gson; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +public class ItemGetter implements CallHandler{ + private final DBConnector connector; + + private final String GET_ITEM = "SELECT * FROM Product WHERE productID = ?;"; + + public ItemGetter(DBConnector connector, String cognitoID) { + this.connector = connector; + } + + @Override + public Object conductAction(Map bodyMap, HashMap queryMap, String cognitoID) throws SQLException { + Connection connection = connector.getConnection(); + try { + PreparedStatement statement = connection.prepareStatement(GET_ITEM); + statement.setInt(1, Integer.parseInt(queryMap.get("id"))); + System.out.println(statement); + ResultSet queryResults = statement.executeQuery(); + queryResults.first(); + System.out.println(queryResults); + Item retrievedItem = new Item(queryResults); + System.out.println(retrievedItem); + return retrievedItem; + } finally { + connection.close(); + } + } +} diff --git a/Lambdas/Lists/ItemSearch/src/ItemSearch.java b/Lambdas/Lists/ItemSearch/src/ItemSearch.java new file mode 100644 index 0000000..17b701a --- /dev/null +++ b/Lambdas/Lists/ItemSearch/src/ItemSearch.java @@ -0,0 +1,29 @@ +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; + +public class ItemSearch { + ArrayList results; + + ItemSearch(ResultSet searchResults) throws SQLException { + results = new ArrayList<>(); + while (searchResults.next()) { + results.add(new Item(searchResults)); + } + } + + @Override + public String toString() { + return "ItemSearch{" + + "results=" + results + + '}'; + } + + public ArrayList getResults() { + return results; + } + + public void setResults(ArrayList results) { + this.results = results; + } +} diff --git a/Lambdas/Lists/ItemSearch/src/ItemSearchGET.java b/Lambdas/Lists/ItemSearch/src/ItemSearchGET.java new file mode 100644 index 0000000..14e146d --- /dev/null +++ b/Lambdas/Lists/ItemSearch/src/ItemSearchGET.java @@ -0,0 +1,11 @@ +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; + +import java.util.Map; + +public class ItemSearchGET implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + return BasicHandler.handleRequest(inputMap, unfilled, ItemSearcher.class); + } +} diff --git a/Lambdas/Lists/ItemSearch/src/ItemSearcher.java b/Lambdas/Lists/ItemSearch/src/ItemSearcher.java new file mode 100644 index 0000000..29bc78c --- /dev/null +++ b/Lambdas/Lists/ItemSearch/src/ItemSearcher.java @@ -0,0 +1,32 @@ +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +public class ItemSearcher implements CallHandler { + + DBConnector connector; + String cognitoID; + + private final String GET_ITEM_MATCHES = "SELECT * FROM Product WHERE description LIKE ?"; + + public ItemSearcher(DBConnector connector, String cognitoID) { + this.connector = connector; + 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; + } + } +} diff --git a/Lambdas/Lists/List/src/ItemEntry.java b/Lambdas/Lists/List/src/ItemEntry.java new file mode 100644 index 0000000..506be09 --- /dev/null +++ b/Lambdas/Lists/List/src/ItemEntry.java @@ -0,0 +1,50 @@ +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.LocalDateTime; + +public class ItemEntry { + Integer listID; + Integer productID; + Integer quantity; + long addedDate; + Boolean purchased; + public ItemEntry(Integer listID, ResultSet listRow) throws SQLException { + this.listID = listID; + productID = listRow.getInt(1); + quantity = listRow.getInt(2); + addedDate = listRow.getTimestamp(3).toInstant().toEpochMilli(); + purchased = listRow.getBoolean(4); + } + + public Integer getProductID() { + return productID; + } + + public void setProductID(Integer productID) { + this.productID = productID; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public long getAddedDate() { + return addedDate; + } + + public void setAddedDate(long addedDate) { + this.addedDate = addedDate; + } + + public Boolean getPurchased() { + return purchased; + } + + public void setPurchased(Boolean purchased) { + this.purchased = purchased; + } +} diff --git a/Lambdas/Lists/List/src/List.java b/Lambdas/Lists/List/src/List.java new file mode 100644 index 0000000..1216c26 --- /dev/null +++ b/Lambdas/Lists/List/src/List.java @@ -0,0 +1,72 @@ +import java.sql.ResultSet; +import java.sql.SQLException; +import java.time.Instant; +import java.time.LocalDateTime; +import java.util.ArrayList; + +public class List { + Integer itemID; + String name; + String owner; + long lastUpdated; + ArrayList entries; + + public List(ResultSet listRow) throws SQLException { + itemID = listRow.getInt("listID"); + name = listRow.getString("name"); + owner = listRow.getString("owner"); + lastUpdated = listRow.getTimestamp("lastUpdated").toInstant().toEpochMilli(); + entries = new ArrayList<>(); + } + + public void addItemEntry(ItemEntry entry) { + entries.add(entry); + } + + @Override + public String toString() { + return "List{" + + "itemID=" + itemID + + ", name='" + name + '\'' + + ", owner='" + owner + '\'' + + ", lastUpdated=" + lastUpdated + + ", entries=" + entries + + '}'; + } + + public ItemEntry[] getEntries() { + return entries.toArray(new ItemEntry[entries.size()]); + } + + public Integer getItemID() { + return itemID; + } + + public void setItemID(Integer itemID) { + this.itemID = itemID; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public long getLastUpdated() { + return lastUpdated; + } + + public void setLastUpdated(long lastUpdated) { + this.lastUpdated = lastUpdated; + } +} diff --git a/Lambdas/Lists/List/src/ListAdder.java b/Lambdas/Lists/List/src/ListAdder.java new file mode 100644 index 0000000..011cbc9 --- /dev/null +++ b/Lambdas/Lists/List/src/ListAdder.java @@ -0,0 +1,33 @@ +import java.sql.*; +import java.time.Instant; +import java.time.ZoneOffset; +import java.util.HashMap; +import java.util.Map; + +public class ListAdder implements CallHandler { + + private DBConnector connector; + private String cognitoID; + + private final String LIST_CREATE = "INSERT INTO List (name, owner, lastUpdated) VALUES (?, ?, ?)"; + + public ListAdder(DBConnector connector, String cognitoID) { + this.connector = connector; + this.cognitoID = cognitoID; + } + + public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { + Connection connection = connector.getConnection(); + PreparedStatement statement = connection.prepareStatement(LIST_CREATE, Statement.RETURN_GENERATED_KEYS); + statement.setString(1, bodyMap.get("name").toString());//Needs safe checking + statement.setString(2, cognitoID); + statement.setTimestamp(3, Timestamp.from(Instant.now())); + System.out.println(statement); + statement.executeUpdate(); + ResultSet newIDRS = statement.getGeneratedKeys(); + newIDRS.first(); + Integer newID = newIDRS.getInt(1); + connection.commit(); + return newID; + } +} diff --git a/Lambdas/Lists/List/src/ListGET.java b/Lambdas/Lists/List/src/ListGET.java new file mode 100644 index 0000000..12a0889 --- /dev/null +++ b/Lambdas/Lists/List/src/ListGET.java @@ -0,0 +1,12 @@ +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; + +import java.util.Map; + +public class ListGET implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + return BasicHandler.handleRequest(inputMap, unfilled, ListGetter.class); + } + +} \ No newline at end of file diff --git a/Lambdas/Lists/List/src/ListGetter.java b/Lambdas/Lists/List/src/ListGetter.java new file mode 100644 index 0000000..e34366c --- /dev/null +++ b/Lambdas/Lists/List/src/ListGetter.java @@ -0,0 +1,58 @@ +import com.google.gson.Gson; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class ListGetter implements CallHandler{ + private final DBConnector connector; + private final String cognitoID; + + private final String GET_LIST = "SELECT * FROM List WHERE listID = ?;"; + private final String GET_LISTS = "SELECT listID FROM List WHERE owner = ?;"; + private final String GET_ENTRIES = "SELECT * FROM ListProduct WHERE listID = ?;"; + + public ListGetter(DBConnector connector, String cognitoID) { + this.connector = connector; + this.cognitoID = cognitoID; + } + + @Override + public Object conductAction(Map bodyMap, HashMap queryMap, String cognitoID) throws SQLException { + try (Connection connection = connector.getConnection()) { + Integer id = Integer.parseInt(queryMap.get("id")); + if (id == -1) { + PreparedStatement getLists = connection.prepareStatement(GET_LISTS); + getLists.setString(1, cognitoID); + System.out.println(getLists); + ResultSet getListsResults = getLists.executeQuery(); + System.out.println(getListsResults); + ArrayList listIds = new ArrayList<>(); + while (getListsResults.next()) { + listIds.add(getListsResults.getInt(1)); + } + return listIds; + } + PreparedStatement getList = connection.prepareStatement(GET_LIST); + getList.setInt(1, id); + System.out.println(getList); + ResultSet getListResults = getList.executeQuery(); + getListResults.first(); + System.out.println(getListResults); + List retrievedList = new List(getListResults); + System.out.println(retrievedList); + PreparedStatement getListEntries = connection.prepareStatement(GET_ENTRIES); + getListEntries.setInt(1, id); + ResultSet getEntryResults = getListEntries.executeQuery(); + while (getEntryResults.next()) { + retrievedList.addItemEntry(new ItemEntry(id, getEntryResults)); + } + System.out.println(retrievedList); + return retrievedList; + } + } +} diff --git a/Lambdas/Lists/List/src/ListPOST.java b/Lambdas/Lists/List/src/ListPOST.java new file mode 100644 index 0000000..4d47863 --- /dev/null +++ b/Lambdas/Lists/List/src/ListPOST.java @@ -0,0 +1,11 @@ +import java.util.Map; + +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; + +public class ListPOST implements RequestHandler, Object>{ + + public Object handleRequest(Map inputMap, Context unfilled) { + return BasicHandler.handleRequest(inputMap, unfilled, ListAdder.class); + } +} diff --git a/Lambdas/Lists/ListEntry/src/ListEntryAdder.java b/Lambdas/Lists/ListEntry/src/ListEntryAdder.java new file mode 100644 index 0000000..6154025 --- /dev/null +++ b/Lambdas/Lists/ListEntry/src/ListEntryAdder.java @@ -0,0 +1,39 @@ +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.ZoneOffset; +import java.util.HashMap; +import java.util.Map; + +public class ListEntryAdder implements CallHandler { + + private DBConnector connector; + private String cognitoID; + + private final String ITEM_TO_LIST = "INSERT INTO ListProduct (productID, listID, quantity, addedDate, purchased) VALUES (?, ?, ?, ?, ?)"; + + public ListEntryAdder(DBConnector connector, String cognitoID) { + this.connector = connector; + this.cognitoID = cognitoID; + } + + public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { + Connection connection = connector.getConnection(); + try { + PreparedStatement statement = connection.prepareStatement(ITEM_TO_LIST); + statement.setInt(1, (Integer) bodyMap.get("productID")); + statement.setInt(2, (Integer) bodyMap.get("listID")); + statement.setInt(3, (Integer) bodyMap.get("quantity")); + statement.setTimestamp(4, Timestamp.from(Instant.now())); + statement.setBoolean(5, (Boolean) bodyMap.get("purchased")); + System.out.println(statement); + statement.executeUpdate(); + connection.commit(); + } finally { + connection.close(); + } + return null; + } +} diff --git a/Lambdas/Lists/ListEntry/src/ListEntryDELETE.java b/Lambdas/Lists/ListEntry/src/ListEntryDELETE.java new file mode 100644 index 0000000..ad3045d --- /dev/null +++ b/Lambdas/Lists/ListEntry/src/ListEntryDELETE.java @@ -0,0 +1,11 @@ +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; + +import java.util.Map; + +public class ListEntryDELETE implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + return BasicHandler.handleRequest(inputMap, unfilled, ListEntryDeleter.class); + } +} \ No newline at end of file diff --git a/Lambdas/Lists/ListEntry/src/ListEntryDeleter.java b/Lambdas/Lists/ListEntry/src/ListEntryDeleter.java new file mode 100644 index 0000000..af074cd --- /dev/null +++ b/Lambdas/Lists/ListEntry/src/ListEntryDeleter.java @@ -0,0 +1,33 @@ +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +public class ListEntryDeleter implements CallHandler { + + private DBConnector connector; + private String cognitoID; + + private final String REMOVE_FROM_LIST = "DELETE FROM ListProduct WHERE (ProductID = ? AND ListID = ?);"; + + public ListEntryDeleter(DBConnector connector, String cognitoID) { + this.connector = connector; + this.cognitoID = cognitoID; + } + + public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { + Connection connection = connector.getConnection(); + try { + PreparedStatement statement = connection.prepareStatement(REMOVE_FROM_LIST); + statement.setInt(1, (Integer) bodyMap.get("ProductID")); + statement.setInt(2, (Integer) bodyMap.get("ListID")); + System.out.println(statement); + statement.executeUpdate(); + connection.commit(); + } finally { + connection.close(); + } + return null; + } +} diff --git a/Lambdas/Lists/ListEntry/src/ListEntryPOST.java b/Lambdas/Lists/ListEntry/src/ListEntryPOST.java new file mode 100644 index 0000000..828c43c --- /dev/null +++ b/Lambdas/Lists/ListEntry/src/ListEntryPOST.java @@ -0,0 +1,11 @@ +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; + +import java.util.Map; + +public class ListEntryPOST implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + return BasicHandler.handleRequest(inputMap, unfilled, ListEntryAdder.class); + } +} diff --git a/Lambdas/Lists/User/resources/cognitoProperties.json b/Lambdas/Lists/User/resources/cognitoProperties.json new file mode 100644 index 0000000..a01aefd --- /dev/null +++ b/Lambdas/Lists/User/resources/cognitoProperties.json @@ -0,0 +1,3 @@ +{ + "userPoolId": "us-east-2_MFgSVKQMd", +} \ No newline at end of file diff --git a/Lambdas/Lists/User/src/UserDELETE.java b/Lambdas/Lists/User/src/UserDELETE.java new file mode 100644 index 0000000..b1a7076 --- /dev/null +++ b/Lambdas/Lists/User/src/UserDELETE.java @@ -0,0 +1,11 @@ +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; + +import java.util.Map; + +public class UserDELETE implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + return BasicHandler.handleRequest(inputMap, unfilled, UserDeleter.class); + } +} \ No newline at end of file diff --git a/Lambdas/Lists/User/src/UserDeleter.java b/Lambdas/Lists/User/src/UserDeleter.java new file mode 100644 index 0000000..14f08ae --- /dev/null +++ b/Lambdas/Lists/User/src/UserDeleter.java @@ -0,0 +1,58 @@ +import com.amazonaws.services.cognitoidp.AWSCognitoIdentityProvider; +import com.amazonaws.services.cognitoidp.AWSCognitoIdentityProviderClientBuilder; +import com.amazonaws.services.cognitoidp.model.AdminDeleteUserRequest; +import com.amazonaws.services.cognitoidp.model.AdminUserGlobalSignOutRequest; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +public class UserDeleter implements CallHandler { + + private DBConnector connector; + private String cognitoID; + + //private final String REMOVE_FROM_LIST = "DELETE FROM ListProduct WHERE (ProductID = ? AND ListID = ?);"; + + public UserDeleter(DBConnector connector, String cognitoID) { + this.connector = connector; + this.cognitoID = cognitoID; + } + + public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { + AWSCognitoIdentityProvider awsCognitoIdentityProvider = AWSCognitoIdentityProviderClientBuilder.defaultClient(); + Properties cognitoProperties; + try { + cognitoProperties = DBConnector.loadProperties("cognitoProperties.json"); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + String userPoolId = cognitoProperties.get("userPoolId").toString(); + System.out.println(userPoolId); + AdminUserGlobalSignOutRequest adminUserGlobalSignOutRequest = new AdminUserGlobalSignOutRequest().withUserPoolId(userPoolId); + adminUserGlobalSignOutRequest.setUsername(cognitoID); + System.out.println(adminUserGlobalSignOutRequest); + awsCognitoIdentityProvider.adminUserGlobalSignOut(adminUserGlobalSignOutRequest); + AdminDeleteUserRequest adminDeleteUserRequest = new AdminDeleteUserRequest().withUserPoolId(userPoolId); + adminDeleteUserRequest.setUsername(cognitoID); + System.out.println(adminDeleteUserRequest); + awsCognitoIdentityProvider.adminDeleteUser(adminDeleteUserRequest); + return null; + + // Connection connection = connector.getConnection(); +// try { +// PreparedStatement statement = connection.prepareStatement(REMOVE_FROM_LIST); +// statement.setInt(1, (Integer) bodyMap.get("ProductID")); +// statement.setInt(2, (Integer) bodyMap.get("ListID")); +// System.out.println(statement); +// statement.executeUpdate(); +// connection.commit(); +// } finally { +// connection.close(); +// } +// return null; + } +} diff --git a/Lambdas/Lists/pom.xml b/Lambdas/Lists/pom.xml index 8d77579..9fb5565 100644 --- a/Lambdas/Lists/pom.xml +++ b/Lambdas/Lists/pom.xml @@ -39,6 +39,56 @@ mariadb-java-client 2.7.0 + + org.apache.httpcomponents + httpclient + 4.5.12 + + + com.google.code.gson + gson + 2.8.6 + + + com.amazonaws + aws-java-sdk-cognitoidentity + 1.11.875 + + + com.amazonaws + aws-java-sdk-cognitoidp + 1.11.875 + + + software.amazon.ion + ion-java + 1.5.1 + + + joda-time + joda-time + 2.10.6 + + + commons-logging + commons-logging + 1.2 + + + com.fasterxml.jackson.dataformat + jackson-dataformat-cbor + 2.11.3 + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + 2.8.5 + + + com.fasterxml.jackson.core + jackson-databind + 2.11.3 + 1.11 diff --git a/Lambdas/Lists/src/main/java/BasicHandler.java b/Lambdas/Lists/src/main/java/BasicHandler.java new file mode 100644 index 0000000..8c3e1d3 --- /dev/null +++ b/Lambdas/Lists/src/main/java/BasicHandler.java @@ -0,0 +1,31 @@ +import com.amazonaws.services.lambda.runtime.Context; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +public class BasicHandler { + public static Object handleRequest(Map inputMap, Context unfilled, Class toCall) { + String cognitoID = InputUtils.getCognitoIDFromBody(inputMap); + HashMap queryMap = InputUtils.getQueryParams(inputMap); + try { + DBConnector connector = new DBConnector(); + try { + Constructor constructor = toCall.getConstructor(DBConnector.class, String.class); + CallHandler callHandler = constructor.newInstance(connector, cognitoID); + return callHandler.conductAction(InputUtils.getBody(inputMap), queryMap, cognitoID); + } catch (SQLException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } finally { + connector.close(); + } + } catch (IOException |SQLException|ClassNotFoundException e) { + e.printStackTrace(); + throw new RuntimeException(e.getLocalizedMessage()); + } + return null; + } +} diff --git a/Lambdas/Lists/src/main/java/CallHandler.java b/Lambdas/Lists/src/main/java/CallHandler.java new file mode 100644 index 0000000..a637412 --- /dev/null +++ b/Lambdas/Lists/src/main/java/CallHandler.java @@ -0,0 +1,7 @@ +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +public interface CallHandler { + Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException; +} diff --git a/Lambdas/Lists/src/main/java/DBConnector.java b/Lambdas/Lists/src/main/java/DBConnector.java index 074f4de..798cfc3 100644 --- a/Lambdas/Lists/src/main/java/DBConnector.java +++ b/Lambdas/Lists/src/main/java/DBConnector.java @@ -12,11 +12,11 @@ public class DBConnector { Connection connection; - DBConnector() throws IOException, SQLException, ClassNotFoundException { + public DBConnector() throws IOException, SQLException, ClassNotFoundException { this(loadProperties("dbProperties.json")); } - DBConnector(Properties dbProperties) throws SQLException, ClassNotFoundException { + public DBConnector(Properties dbProperties) throws SQLException, ClassNotFoundException { Class.forName("org.mariadb.jdbc.Driver"); System.out.println(dbProperties); System.out.println(DBConnector.buildURL(dbProperties)); diff --git a/Lambdas/Lists/src/main/java/InputUtils.java b/Lambdas/Lists/src/main/java/InputUtils.java index 46a0694..2a4e8bc 100644 --- a/Lambdas/Lists/src/main/java/InputUtils.java +++ b/Lambdas/Lists/src/main/java/InputUtils.java @@ -1,3 +1,9 @@ +import org.apache.http.NameValuePair; +import org.apache.http.client.utils.URLEncodedUtils; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.List; import java.util.Map; public class InputUtils { @@ -19,6 +25,24 @@ public class InputUtils { return getMap(inputMap, "body"); } + private static String getQueryString(Map inputMap) { + return (String) (getMap(inputMap, "params").get("querystring")); + } + + public static HashMap getQueryParams(Map inputMap) { + return (HashMap) (getMap(inputMap, "params").get("querystring")); + +// String queryString = getQueryString(inputMap); +// List queryparams = URLEncodedUtils.parse(queryString, StandardCharsets.UTF_8); +// HashMap mappedParams = new HashMap<>(); +// for (NameValuePair param : queryparams) { +// mappedParams.put(param.getName(), param.getValue()); +// } +// return mappedParams; + } + + + public static Map getMap(Map parentMap, String childKey) { if ((parentMap.get(childKey) != null) && (parentMap.get(childKey) instanceof Map)) { return ((Map) parentMap.get(childKey)); diff --git a/Lambdas/Lists/src/main/java/ListAdder.java b/Lambdas/Lists/src/main/java/ListAdder.java deleted file mode 100644 index e1598b7..0000000 --- a/Lambdas/Lists/src/main/java/ListAdder.java +++ /dev/null @@ -1,27 +0,0 @@ -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.Map; - -public class ListAdder { - - private DBConnector connector; - private String cognitoID; - - private final String LIST_CREATE = "INSERT INTO Lists (Name, Owner) VALUES (?, ?)"; - - ListAdder(DBConnector connector, String cognitoID) { - this.connector = connector; - this.cognitoID = cognitoID; - } - - public void add(Map bodyMap) throws SQLException { - Connection connection = connector.getConnection(); - PreparedStatement statement = connection.prepareStatement(LIST_CREATE); - statement.setString(1, bodyMap.get("name").toString());//Needs safe checking - statement.setString(2, cognitoID); - System.out.println(statement); - statement.executeUpdate(); - connection.commit(); - } -} diff --git a/Lambdas/Lists/src/main/java/ListPOST.java b/Lambdas/Lists/src/main/java/ListPOST.java deleted file mode 100644 index c2fc63c..0000000 --- a/Lambdas/Lists/src/main/java/ListPOST.java +++ /dev/null @@ -1,28 +0,0 @@ -import java.io.IOException; -import java.sql.SQLException; -import java.util.Map; - -import com.amazonaws.services.lambda.runtime.Context; -import com.amazonaws.services.lambda.runtime.RequestHandler; - -public class ListPOST implements RequestHandler, String>{ - - - public String handleRequest(Map inputMap, Context unfilled) { - String cognitoID = InputUtils.getCognitoIDFromBody(inputMap); - try { - DBConnector connector = new DBConnector(); - try { - new ListAdder(connector, cognitoID).add(InputUtils.getBody(inputMap)); - } catch (SQLException e) { - e.printStackTrace(); - } finally { - connector.close(); - } - } catch (IOException|SQLException|ClassNotFoundException e) { - e.printStackTrace(); - throw new RuntimeException(e.getMessage()); - } - return null; - } -} diff --git a/Lambdas/Lists/target/Lists-1.0-SNAPSHOT.jar b/Lambdas/Lists/target/Lists-1.0-SNAPSHOT.jar new file mode 100644 index 0000000..a611fef Binary files /dev/null and b/Lambdas/Lists/target/Lists-1.0-SNAPSHOT.jar differ diff --git a/Lambdas/Lists/target/maven-archiver/pom.properties b/Lambdas/Lists/target/maven-archiver/pom.properties new file mode 100644 index 0000000..68bd418 --- /dev/null +++ b/Lambdas/Lists/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Mon Oct 05 10:19:24 EDT 2020 +groupId=groupId +artifactId=Lists +version=1.0-SNAPSHOT diff --git a/Lambdas/Lists/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/Lambdas/Lists/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..db1626f --- /dev/null +++ b/Lambdas/Lists/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,4 @@ +/Users/MNM/Documents/GitHub/Listify/Lambdas/Lists/src/main/java/CallHandler.java +/Users/MNM/Documents/GitHub/Listify/Lambdas/Lists/src/main/java/DBConnector.java +/Users/MNM/Documents/GitHub/Listify/Lambdas/Lists/src/main/java/BasicHandler.java +/Users/MNM/Documents/GitHub/Listify/Lambdas/Lists/src/main/java/InputUtils.java diff --git a/Listify/app/build.gradle b/Listify/app/build.gradle index 099077a..0ad5dc3 100644 --- a/Listify/app/build.gradle +++ b/Listify/app/build.gradle @@ -50,5 +50,6 @@ dependencies { implementation 'org.json:json:20200518' implementation 'com.github.bumptech.glide:glide:4.11.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' + implementation 'com.squareup.okhttp3:okhttp:4.8.1' } \ No newline at end of file diff --git a/Listify/app/src/main/AndroidManifest.xml b/Listify/app/src/main/AndroidManifest.xml index 9de69e3..cfa6d82 100644 --- a/Listify/app/src/main/AndroidManifest.xml +++ b/Listify/app/src/main/AndroidManifest.xml @@ -1,7 +1,8 @@ - + + - + - + + + + android:theme="@style/AppTheme.NoActionBar"> + - + + \ No newline at end of file diff --git a/Listify/app/src/main/java/com/example/listify/AuthManager.java b/Listify/app/src/main/java/com/example/listify/AuthManager.java index 4e67ed3..1248a05 100644 --- a/Listify/app/src/main/java/com/example/listify/AuthManager.java +++ b/Listify/app/src/main/java/com/example/listify/AuthManager.java @@ -8,6 +8,7 @@ import com.amplifyframework.auth.options.AuthSignUpOptions; import com.amplifyframework.auth.result.AuthSignInResult; import com.amplifyframework.auth.result.AuthSignUpResult; import com.amplifyframework.core.Amplify; +import com.example.listify.data.User; import org.json.JSONException; import org.json.JSONObject; @@ -44,6 +45,17 @@ public class AuthManager { } public String getUserToken() { + if (authSession == null) { + try { + fetchAuthSession(); + } catch (AuthException e) { + e.printStackTrace(); + return ""; + } + } + if (authSession.isSignedIn() == false) { + return ""; + } return authSession.getUserPoolTokens().getValue().getIdToken(); } @@ -78,6 +90,10 @@ public class AuthManager { waiting = false; } + public void signOutSuccess() { + waiting = false; + } + public void startSignUp(String email, String password) throws AuthException { this.email = email; this.password = password; @@ -117,7 +133,17 @@ public class AuthManager { throwIfAuthError(); } + public void deleteUser(Requestor requestor) throws AuthException { + requestor.deleteObject("N/A", User.class); + signOutUser(); + } + public void signOutUser() throws AuthException { + authSession = null; + waiting = true; + Amplify.Auth.signOut(this::signOutSuccess, error -> setAuthError(error)); + throwIfAuthError(); + } public static Properties loadProperties(Context context, String path) throws IOException, JSONException { Properties toReturn = new Properties(); diff --git a/Listify/app/src/main/java/com/example/listify/CreateListDialogFragment.java b/Listify/app/src/main/java/com/example/listify/CreateListDialogFragment.java new file mode 100644 index 0000000..00ff7ee --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/CreateListDialogFragment.java @@ -0,0 +1,68 @@ +package com.example.listify; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.DialogFragment; + + +public class CreateListDialogFragment extends DialogFragment { + + public interface OnNewListListener { + void sendNewListName(String name); + } + + public OnNewListListener onNewListListener; + + EditText etNewListName; + + public CreateListDialogFragment() {} + + + @Override + public Dialog onCreateDialog(final Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + // Get the layout inflater + LayoutInflater inflater = requireActivity().getLayoutInflater(); + + // Inflate and set the layout for the dialog + // Pass null as the parent view because its going in the dialog layout + View root = inflater.inflate(R.layout.dialog_create_list, null); + builder.setView(root) + // Add action buttons + .setPositiveButton("OK", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + onNewListListener.sendNewListName(etNewListName.getText().toString()); + } + }) + .setNegativeButton("cancel", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + CreateListDialogFragment.this.getDialog().cancel(); + } + }); + + etNewListName = (EditText) root.findViewById(R.id.et_new_list_name); + + + return builder.create(); + } + + // Required to extend DialogFragment + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + try { + onNewListListener = (OnNewListListener) getActivity(); + } catch (ClassCastException e) { + Log.e("CreateListDialogFragment", "onAttach: ClassCastException: " + e.getMessage()); + } + } +} diff --git a/Listify/app/src/main/java/com/example/listify/First2Fragment.java b/Listify/app/src/main/java/com/example/listify/First2Fragment.java deleted file mode 100644 index 3ca48ef..0000000 --- a/Listify/app/src/main/java/com/example/listify/First2Fragment.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.example.listify; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.navigation.fragment.NavHostFragment; - -public class First2Fragment extends Fragment { - - @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState - ) { - // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_first2, container, false); - } - - public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - NavHostFragment.findNavController(First2Fragment.this) - .navigate(R.id.action_First2Fragment_to_Second2Fragment); - } - }); - } -} \ No newline at end of file diff --git a/Listify/app/src/main/java/com/example/listify/FirstFragment.java b/Listify/app/src/main/java/com/example/listify/FirstFragment.java deleted file mode 100644 index 653c343..0000000 --- a/Listify/app/src/main/java/com/example/listify/FirstFragment.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.example.listify; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.navigation.fragment.NavHostFragment; - -public class FirstFragment extends Fragment { - - @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState - ) { - // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_first, container, false); - } - - public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - NavHostFragment.findNavController(FirstFragment.this) - .navigate(R.id.action_FirstFragment_to_SecondFragment); - } - }); - } -} \ No newline at end of file diff --git a/Listify/app/src/main/java/com/example/listify/ItemDetails.java b/Listify/app/src/main/java/com/example/listify/ItemDetails.java new file mode 100644 index 0000000..3af413b --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/ItemDetails.java @@ -0,0 +1,142 @@ +package com.example.listify; + +import android.os.Bundle; +import com.bumptech.glide.Glide; +import com.example.listify.model.Product; +import com.example.listify.model.ShoppingList; +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.widget.Toolbar; +import android.view.View; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import android.widget.Toast; +import java.util.ArrayList; + +public class ItemDetails extends AppCompatActivity implements ListPickerDialogFragment.OnListPickListener, CreateListDialogFragment.OnNewListListener { + private Product curProduct; + private LinearLayout linAddItem; + private LinearLayout linCreateList; + private TextView tvCreateNew; + private TextView tvAddItem; + private TextView tvItemName; + private TextView tvStoreName; + private ImageView itemImage; + private TextView tvItemPrice; + private TextView tvItemDesc; + private ImageButton backToSearchbutton; + + ArrayList shoppingLists = new ArrayList<>(); + + private boolean isFABOpen = false; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_item_details); + Toolbar toolbar = findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + // Load Product object from search results activity + curProduct = (Product) getIntent().getSerializableExtra("SelectedProduct"); + + // Set up floating action buttons + FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); + linAddItem = (LinearLayout) findViewById(R.id.lin_add_item); + linCreateList = (LinearLayout) findViewById(R.id.lin_create_list); + fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (!isFABOpen) { + showFABMenu(); + } else { + closeFABMenu(); + } + } + }); + + linAddItem.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + closeFABMenu(); + + // Hardcode shopping lists to demonstrate displaying lists + for (int i = 0; i < 10; i++) { + shoppingLists.add(new ShoppingList(Integer.toString(i))); + } + + ListPickerDialogFragment listPickerDialog = new ListPickerDialogFragment(shoppingLists); + listPickerDialog.show(getSupportFragmentManager(), "User Lists"); + } + }); + + linCreateList.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + closeFABMenu(); + + CreateListDialogFragment createListDialogFragment = new CreateListDialogFragment(); + createListDialogFragment.show(getSupportFragmentManager(), "Create New List"); + } + }); + + // Set data + tvItemName = (TextView) findViewById(R.id.item_name); + tvItemName.setText(curProduct.getItemName()); + + itemImage = (ImageView) findViewById(R.id.item_image); + Glide.with(this).load(curProduct.getImageUrl()).into(itemImage); + + tvStoreName = (TextView) findViewById(R.id.store_name); + tvStoreName.setText(curProduct.getChainName()); + + tvItemPrice = (TextView) findViewById(R.id.item_price); + tvItemPrice.setText(String.format("$%.2f", curProduct.getPrice())); + + tvItemDesc = (TextView) findViewById(R.id.item_desc); + tvItemDesc.setText(curProduct.getDescription()); + + tvCreateNew = (TextView) findViewById(R.id.create_new_list); + tvCreateNew.setVisibility(View.INVISIBLE); + + tvAddItem = (TextView) findViewById(R.id.add_item_to_list); + tvAddItem.setVisibility(View.INVISIBLE); + + backToSearchbutton = (ImageButton) findViewById(R.id.back_to_search_results_button); + backToSearchbutton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + } + + private void showFABMenu(){ + isFABOpen=true; + linAddItem.animate().translationY(-getResources().getDimension(R.dimen.standard_55)); + linCreateList.animate().translationY(-getResources().getDimension(R.dimen.standard_105)); + tvAddItem.setVisibility(View.VISIBLE); + tvCreateNew.setVisibility(View.VISIBLE); + } + + private void closeFABMenu(){ + isFABOpen=false; + linAddItem.animate().translationY(0); + linCreateList.animate().translationY(0); + tvAddItem.setVisibility(View.INVISIBLE); + tvCreateNew.setVisibility(View.INVISIBLE); + } + + + @Override + public void sendListSelection(int selectedListIndex, int quantity) { + Toast.makeText(this, String.format("%d of Item added to %s", quantity, shoppingLists.get(selectedListIndex).getName()), Toast.LENGTH_LONG).show(); + } + + @Override + public void sendNewListName(String name) { + Toast.makeText(this, String.format("%s created", name), Toast.LENGTH_LONG).show(); + } +} \ No newline at end of file diff --git a/Listify/app/src/main/java/com/example/listify/List.java b/Listify/app/src/main/java/com/example/listify/List.java index ae251ea..f011f96 100644 --- a/Listify/app/src/main/java/com/example/listify/List.java +++ b/Listify/app/src/main/java/com/example/listify/List.java @@ -1,15 +1,19 @@ package com.example.listify; import android.content.Context; +import android.content.Intent; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; +import android.widget.Button; +import android.widget.EditText; import android.widget.ImageView; import android.widget.ListView; import android.widget.TextView; +import java.util.ArrayList; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -17,40 +21,64 @@ import androidx.appcompat.app.AppCompatActivity; public class List extends AppCompatActivity { ListView listView; - String listName = "Sample List"; - String[] pNames = {"Half-gallon organic whole milk"}; - String[] pStores = {"Kroger"}; - String[] pPrices = {"$5.00"}; - int[] pImages = {R.drawable.milk}; + MyAdapter myAdapter; - //List(String name) { - // listName = name; - //} + Button incrQuan; + Button decrQuan; + Button removeItem; + + ArrayList pNames = new ArrayList<>(); //String[] pNames = {"Half-gallon organic whole milk"}; + ArrayList pStores = new ArrayList<>(); //String[] pStores = {"Kroger"}; + ArrayList pPrices = new ArrayList<>(); //String[] pPrices = {"$5.00"}; + ArrayList pQuantity = new ArrayList<>(); //String[] pQuantity = {"1"}; + ArrayList pImages = new ArrayList<>(); //int[] pImages = {R.drawable.milk}; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { + pNames.add("Half-gallon organic whole milk"); + pStores.add("Kroger"); + pPrices.add("$5.00"); + pQuantity.add("1"); + pImages.add(R.drawable.milk); + + pNames.add("5-bunch medium bananas"); + pStores.add("Kroger"); + pPrices.add("$3.00"); + pQuantity.add("1"); + pImages.add(R.drawable.bananas); + + pNames.add("JIF 40-oz creamy peanut butter"); + pStores.add("Kroger"); + pPrices.add("$7.00"); + pQuantity.add("1"); + pImages.add(R.drawable.peanutbutter); + + int currSize = pNames.size(); + super.onCreate(savedInstanceState); setContentView(R.layout.activity_list); listView = findViewById(R.id.listView); + myAdapter = new MyAdapter(this, pNames, pStores, pPrices, pQuantity, pImages); - MyAdapter myAdapter = new MyAdapter(this, pNames, pStores, pPrices, pImages); listView.setAdapter(myAdapter); } class MyAdapter extends ArrayAdapter { Context context; - String[] pNames; - String[] pStores; - String[] pPrices; - int[] pImages; + ArrayList pNames; //String[] pNames; + ArrayList pStores; //String[] pStores; + ArrayList pPrices; //String[] pPrices; + ArrayList pQuantity; //String[] pQuantity; + ArrayList pImages; //int[] pImages; - MyAdapter (Context c, String[] names, String[] stores, String[] prices, int[] images) { + MyAdapter (Context c, ArrayList names, ArrayList stores, ArrayList prices, ArrayList quantity, ArrayList images) { super(c, R.layout.listproduct, R.id.productView, names); context = c; pNames = names; pStores = stores; pPrices = prices; + pQuantity = quantity; pImages = images; } @@ -60,15 +88,65 @@ public class List extends AppCompatActivity { LayoutInflater layoutInflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); View listproduct = layoutInflater.inflate(R.layout.listproduct, parent,false); - ImageView image = listproduct.findViewById(R.id.imageView); + decrQuan = (Button) listproduct.findViewById(R.id.buttonDecr); + incrQuan = (Button) listproduct.findViewById(R.id.buttonIncr); + removeItem = (Button) listproduct.findViewById(R.id.buttonDel); + + decrQuan.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + int q = Integer.parseInt(pQuantity.get(position)) - 1; + pQuantity.set(position, Integer.toString(q)); + listView.setAdapter(myAdapter); + } + }); + if(Integer.parseInt(pQuantity.get(position)) <= 1) { + decrQuan.setEnabled(false); + } + if(Integer.parseInt(pQuantity.get(position)) < 10) { + incrQuan.setEnabled(true); + } + + incrQuan.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + int q = Integer.parseInt(pQuantity.get(position)) + 1; + pQuantity.set(position, Integer.toString(q)); + listView.setAdapter(myAdapter); + } + }); + if(Integer.parseInt(pQuantity.get(position)) > 1) { + decrQuan.setEnabled(true); + } + if(Integer.parseInt(pQuantity.get(position)) >= 10) { + incrQuan.setEnabled(false); + } + + removeItem.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + pNames.remove(position); + pStores.remove(position); + pPrices.remove(position); + pQuantity.remove(position); + pImages.remove(position); + listView.setAdapter(myAdapter); + } + }); + TextView name = listproduct.findViewById(R.id.productView); TextView store = listproduct.findViewById(R.id.storeView); TextView price = listproduct.findViewById(R.id.priceView); + TextView quantity = listproduct.findViewById(R.id.quantityView); + ImageView image = listproduct.findViewById(R.id.imageView); - image.setImageResource(pImages[position]); - name.setText(pNames[position]); - store.setText(pStores[position]); - price.setText(pPrices[position]); + 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)); + } return listproduct; } diff --git a/Listify/app/src/main/java/com/example/listify/ListPickerDialogFragment.java b/Listify/app/src/main/java/com/example/listify/ListPickerDialogFragment.java new file mode 100644 index 0000000..b9f7310 --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/ListPickerDialogFragment.java @@ -0,0 +1,121 @@ +package com.example.listify; +import android.app.Dialog; +import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Color; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.AdapterView; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ListView; +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.DialogFragment; +import com.example.listify.adapter.DisplayShoppingListsAdapter; +import com.example.listify.model.ShoppingList; +import java.util.ArrayList; + + +public class ListPickerDialogFragment extends DialogFragment { + + public interface OnListPickListener { + void sendListSelection(int selectedListIndex, int quantity); + } + + public OnListPickListener onListPickListener; + + ListView userListsView; + DisplayShoppingListsAdapter displayShoppingListsAdapter; + Button btnMinus; + Button btnPlus; + EditText etQuantity; + private ArrayList userLists; + private int selectedListIndex; + + public ListPickerDialogFragment(ArrayList userLists) { + this.userLists = userLists; + } + + + @Override + public Dialog onCreateDialog(final Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + // Get the layout inflater + LayoutInflater inflater = requireActivity().getLayoutInflater(); + + // Inflate and set the layout for the dialog + // Pass null as the parent view because its going in the dialog layout + View root = inflater.inflate(R.layout.dialog_add_to_list, null); + builder.setView(root) + // Add action buttons + .setPositiveButton("OK", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + onListPickListener.sendListSelection(selectedListIndex, Integer.parseInt(etQuantity.getText().toString())); + } + }) + .setNegativeButton("cancel", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + ListPickerDialogFragment.this.getDialog().cancel(); + } + }); + + // Display user's shopping lists + userListsView = (ListView) root.findViewById(R.id.user_lists); + displayShoppingListsAdapter = new DisplayShoppingListsAdapter(getActivity(), userLists); + userListsView.setAdapter(displayShoppingListsAdapter); + + userListsView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + for (int i = 0; i < parent.getChildCount(); i++) { + parent.getChildAt(i).setBackgroundColor(Color.TRANSPARENT); + } + + view.setBackgroundColor(Color.GREEN); + selectedListIndex = position; + } + }); + + // Set up quantity selection + etQuantity = (EditText) root.findViewById(R.id.et_quantity); + + btnMinus = (Button) root.findViewById(R.id.btn_minus); + btnMinus.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + int curQauntity = Integer.parseInt(etQuantity.getText().toString()); + if (curQauntity > 0) { + curQauntity--; + etQuantity.setText(String.format("%d", curQauntity)); + } + } + }); + + btnPlus = (Button) root.findViewById(R.id.btn_plus); + btnPlus.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + int curQauntity = Integer.parseInt(etQuantity.getText().toString()); + curQauntity++; + etQuantity.setText(String.format("%d", curQauntity)); + } + }); + + return builder.create(); + } + + // Required to extend DialogFragment + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + try { + onListPickListener = (OnListPickListener) getActivity(); + } catch (ClassCastException e) { + Log.e("ListPickerDialogFragment", "onAttach: ClassCastException: " + e.getMessage()); + } + } +} diff --git a/Listify/app/src/main/java/com/example/listify/MainActivity.java b/Listify/app/src/main/java/com/example/listify/MainActivity.java index 3cdd75b..c6a4c89 100644 --- a/Listify/app/src/main/java/com/example/listify/MainActivity.java +++ b/Listify/app/src/main/java/com/example/listify/MainActivity.java @@ -13,11 +13,18 @@ import androidx.navigation.Navigation; import androidx.navigation.ui.AppBarConfiguration; import androidx.navigation.ui.NavigationUI; import com.amplifyframework.auth.AuthException; +import com.example.listify.data.Item; +import com.example.listify.data.ItemSearch; +import com.example.listify.data.List; +import com.example.listify.data.ListEntry; import com.google.android.material.navigation.NavigationView; import org.json.JSONException; import java.io.IOException; +import java.time.Instant; +import java.util.Arrays; import java.util.Properties; +import java.util.Random; public class MainActivity extends AppCompatActivity { private AppBarConfiguration mAppBarConfiguration; @@ -25,42 +32,87 @@ public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + //------------------------------Auth Testing---------------------------------------------// - /*AuthManager authManager = new AuthManager(); - try { - authManager.signIn("merzn@purdue.edu", "Password123"); - Log.i("Authentication", authManager.getAuthSession().toString()); - Log.i("Token", authManager.getAuthSession().getUserPoolTokens().getValue().getIdToken()); - } - catch (AuthException e) { - Log.i("Authentication", "Login failed. User probably needs to register. Exact error: " + e.getMessage()); - try { - authManager.startSignUp("merzn@purdue.edu", "Password123"); - authManager.confirmSignUp("######"); - } catch (AuthException signUpError) { - Log.e("Authentication", "SignUp error: " + signUpError.getMessage()); - } - }*/ + boolean testAuth = false; + if (testAuth) { + + AuthManager authManager = new AuthManager(); + try { + authManager.signIn("merzn@purdue.edu", "Password123"); + Log.i("Authentication", authManager.getAuthSession().toString()); + Log.i("Token", authManager.getAuthSession().getUserPoolTokens().getValue().getIdToken()); + } catch (AuthException e) { + Log.i("Authentication", "Login failed. User probably needs to register. Exact error: " + e.getMessage()); + try { + authManager.startSignUp("merzn@purdue.edu", "Password123"); + authManager.confirmSignUp("######"); + } catch (AuthException signUpError) { + Log.e("Authentication", "SignUp error: " + signUpError.getMessage()); + } + } + } + //NOTE: deleteUser is slightly unusual in that it requires a Requestor. See below for building one + //authManager.deleteUser(requestor); + + //------------------------------------------------------------------------------------------// + + + boolean testAPI = false; //----------------------------------API Testing---------------------------------------------// - /*Properties configs = new Properties(); - try { - configs = AuthManager.loadProperties(this, "android.resource://" + getPackageName() + "/raw/auths.json"); - } - catch (IOException|JSONException e) { - e.printStackTrace(); - }*/ + if (testAPI) { + AuthManager authManager = new AuthManager(); + try { + authManager.signIn("merzn@purdue.edu", "Password123"); + } catch (AuthException e) { + e.printStackTrace(); + } + Properties configs = new Properties(); + try { + configs = AuthManager.loadProperties(this, "android.resource://" + getPackageName() + "/raw/auths.json"); + } catch (IOException | JSONException e) { + e.printStackTrace(); + } - /*Requestor requestor = new Requestor(this, authManager,configs.getProperty("apiKey")); - List testList = new List("IAmATestList"); - try { - requestor.postObject(testList); + Requestor requestor = new Requestor(authManager, configs.getProperty("apiKey")); + + + //The name is the only part of this that is used, the rest is generated by the Lambda. + List testList = new List(-1, "New List", "user filled by lambda", Instant.now().toEpochMilli()); + //Everything except addedDate is used for ItemEntry + ListEntry entry = new ListEntry(1, 4, Math.abs(new Random().nextInt()), Instant.now().toEpochMilli(),false); + SynchronousReceiver idReceiver = new SynchronousReceiver<>(); + try { + requestor.postObject(testList, idReceiver, idReceiver); + System.out.println(idReceiver.await()); + requestor.postObject(entry); + } catch (Exception e) { + e.printStackTrace(); + } + + SynchronousReceiver itemReceiver = new SynchronousReceiver<>(); + requestor.getObject("1", Item.class, itemReceiver, itemReceiver); + SynchronousReceiver listReceiver = new SynchronousReceiver<>(); + requestor.getObject("39", List.class, listReceiver, listReceiver); + SynchronousReceiver listIdsReceiver = new SynchronousReceiver<>(); + requestor.getListOfIds(List.class, listIdsReceiver, listIdsReceiver); + SynchronousReceiver itemSearchReceiver = new SynchronousReceiver<>(); + requestor.getObject("r", ItemSearch.class, itemSearchReceiver, itemSearchReceiver); + try { + System.out.println(itemReceiver.await()); + System.out.println(listReceiver.await()); + System.out.println(Arrays.toString(listIdsReceiver.await())); + System.out.println(itemSearchReceiver.await()); + } catch (Exception receiverError) { + receiverError.printStackTrace(); + } } - catch (JSONException e) { - e.printStackTrace(); - }*/ + //------------------------------------------------------------------------------------------// + setContentView(R.layout.activity_main); Toolbar toolbar = findViewById(R.id.toolbar); diff --git a/Listify/app/src/main/java/com/example/listify/Requestor.java b/Listify/app/src/main/java/com/example/listify/Requestor.java index 0c7b48d..84043f1 100644 --- a/Listify/app/src/main/java/com/example/listify/Requestor.java +++ b/Listify/app/src/main/java/com/example/listify/Requestor.java @@ -1,66 +1,130 @@ package com.example.listify; -import android.content.Context; -import com.android.volley.RequestQueue; -import com.android.volley.Response; -import com.android.volley.toolbox.JsonObjectRequest; -import com.android.volley.toolbox.Volley; +import android.util.Log; import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import okhttp3.*; +import org.jetbrains.annotations.NotNull; import org.json.JSONException; -import org.json.JSONObject; -import java.util.HashMap; -import java.util.Map; +import java.io.IOException; public class Requestor { private final String DEV_BASEURL = "https://datoh7woc9.execute-api.us-east-2.amazonaws.com/Development"; AuthManager authManager; - RequestQueue queue; String apiKey; + OkHttpClient client; - Requestor(Context context, AuthManager authManager, String apiKey) { - queue = Volley.newRequestQueue(context); + Requestor(AuthManager authManager, String apiKey) { this.authManager = authManager; this.apiKey = apiKey; + client = new OkHttpClient(); + } + + public void getListOfIds(Class ofType, Receiver successHandler, RequestErrorHandler failureHandler) { + String getURL = DEV_BASEURL + "/" + ofType.getSimpleName() + "?id=-1"; + Request postRequest = buildBaseRequest(getURL, "GET", null); + launchCall(postRequest, successHandler, Integer[].class, failureHandler); } public void getObject(String id, Class classType, Receiver receiver) { - String getURL = DEV_BASEURL + "/" + classType.getSimpleName() + "?id=" + id; + getObject(id, classType, receiver, null); } - public void postObject(Object toPost, Response.ErrorListener failureHandler) throws JSONException { - String postURL = DEV_BASEURL + "/" + toPost.getClass().getSimpleName(); - queue.add(buildRequest(postURL, toPost, null, failureHandler)); + public void getObject(String id, Class classType, Receiver successHandler, RequestErrorHandler failureHandler) { + String getURL = DEV_BASEURL + "/" + classType.getSimpleName() + "?id=" + id; + Request getRequest = buildBaseRequest(getURL, "GET", null); + launchCall(getRequest, successHandler, classType, failureHandler); + } + + public void deleteObject(String id, Class classType) { + deleteObject(id, classType, null); + } + + public void deleteObject(String id, Class classType, RequestErrorHandler failureHandler) { + String deleteURL = DEV_BASEURL + "/" + classType.getSimpleName() + "?id=" + id; + Request deleteRequest = buildBaseRequest(deleteURL, "DELETE", "{}"); + launchCall(deleteRequest, null, classType, failureHandler); } public void postObject(Object toPost) throws JSONException { - postObject(toPost, null); + postObject(toPost, (RequestErrorHandler) null); } - private JsonObjectRequest buildRequest(String url, Object toJSONify, Response.Listener successHandler, Response.ErrorListener failureHandler) throws JSONException { - return buildRequest(url, new JSONObject(new Gson().toJson(toJSONify)), successHandler, failureHandler); + public void postObject(Object toPost, RequestErrorHandler failureHandler) throws JSONException { + postObject(toPost, null, failureHandler); } - private JsonObjectRequest buildRequest(String url, JSONObject jsonBody, Response.Listener successHandler, Response.ErrorListener failureHandler) { - return new JsonObjectRequest(url, jsonBody, successHandler, failureHandler) { + public void postObject(Object toPost, Receiver idReceiver) throws JSONException { + postObject(toPost, idReceiver, null); + } + + public void postObject(Object toPost, Receiver idReceiver, RequestErrorHandler failureHandler) throws JSONException { + String postURL = DEV_BASEURL + "/" + toPost.getClass().getSimpleName(); + Request postRequest = buildBaseRequest(postURL, "POST", new Gson().toJson(toPost)); + launchCall(postRequest, idReceiver, Integer.class, failureHandler); + } + + private void launchCall(Request toLaunch, Receiver receiver, Class classType, RequestErrorHandler failureHandler) { + client.newCall(toLaunch).enqueue(new Callback() { @Override - public Map getHeaders() { - HashMap headers = new HashMap<>(); - System.out.println(authManager.getUserToken()); - headers.put("Authorization", authManager.getUserToken()); - headers.put("Content-Type", "application/json"); - headers.put("X-API-Key", apiKey); - return headers; + public void onResponse(@NotNull Call call, @NotNull okhttp3.Response response) throws IOException { + String responseString = response.body().string(); + if (receiver != null) { + if (classType == null) { + Log.e("Requestor Contract Error", "classType while receiver populated"); + } + try { + receiver.acceptDelivery(new Gson().fromJson(responseString, classType)); + } catch (JsonSyntaxException e) { + System.out.println(e); + Log.e("API response was not proper JSON", responseString); + if (failureHandler != null) { + failureHandler.acceptError(e); + } + //throw new JsonSyntaxException(e); + } + } + Log.d("API Response", responseString); } - }; + @Override + public void onFailure(@NotNull Call call, IOException e) { + if (failureHandler != null) { + failureHandler.acceptError(e); + } else { + Log.e("Network Error", e.getLocalizedMessage()); + } + } + }); } - public class Receiver { - public void acceptDelivery(T delivered) { + public static final MediaType JSON + = MediaType.parse("application/json; charset=utf-8"); + private Request buildBaseRequest(String url, String method, String bodyJSON) { + Request.Builder requestBase = addAuthHeaders(new Request.Builder().url(url)); + if (method == "GET") { + requestBase.get(); + } else { + requestBase.method(method, RequestBody.create(bodyJSON, JSON)); } + return requestBase.build(); + } + + private Request.Builder addAuthHeaders(Request.Builder toAuthorize) { + toAuthorize.addHeader("Authorization", authManager.getUserToken()); + toAuthorize.addHeader("X-API-Key", apiKey); + return toAuthorize; + } + + public interface Receiver { + void acceptDelivery(T delivered); + } + + public interface RequestErrorHandler { + void acceptError(Exception error); } } 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 28d6d8d..42908f4 100644 --- a/Listify/app/src/main/java/com/example/listify/SearchResults.java +++ b/Listify/app/src/main/java/com/example/listify/SearchResults.java @@ -1,4 +1,5 @@ package com.example.listify; +import android.content.Intent; import android.os.Bundle; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; @@ -77,7 +78,12 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { - Toast.makeText(SearchResults.this, resultsProductListSorted.get(position).getItemName(), Toast.LENGTH_SHORT).show(); +// Toast.makeText(SearchResults.this, resultsProductListSorted.get(position).getItemName(), Toast.LENGTH_SHORT).show(); + Intent itemDetailsPage = new Intent(SearchResults.this, ItemDetails.class); + + // Send the selected product + itemDetailsPage.putExtra("SelectedProduct", resultsProductListSorted.get(position)); + startActivity(itemDetailsPage); } }); @@ -129,6 +135,9 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme // TODO: Create a new Product Object for each result // TODO: Add each result to productList + // Clear the old search results + resultsProductList = new ArrayList<>(); + // Hardcode some search results... for (int i = 0; i < 2; i++) { Product a = new Product("Bottled Water", "0000", "Walmart", "0001", "0123456780", "Bro, it's water...", "Grocery", 13.37, "9/24/2020", "1", "http://3.bp.blogspot.com/-MfroPPQVDKo/UyhUZWqGvkI/AAAAAAAAB-I/DGk622onsvc/s1600/lettuce-b-kool-cat-meme.jpg"); @@ -136,8 +145,16 @@ public class SearchResults extends AppCompatActivity implements SortDialogFragme Product c = new Product("Lettuce", "0002", "Walmart", "0001", "0123456782", "Burger King foot lettuce", "Grocery", 0.60, "9/24/2020", "1", "https://www.cattitudedaily.com/wp-content/uploads/2019/12/white-cat-meme-feature.jpg"); Product d = new Product("Video Game", "0003", "Walmart", "0001", "0123456783", "Fun Vidya Gaemz", "Electronics", 60.00, "9/24/2020", "1", "https://i1.wp.com/bestlifeonline.com/wp-content/uploads/2018/06/cat-meme-67.jpg?resize=1024%2C1024&ssl=1"); Product e = new Product("Mountain Dew", "0004", "Walmart", "0001", "0123456784", "Gamer fuel", "Grocery", 5.87, "9/24/2020", "1", "https://memeguy.com/photos/images/gaming-cat-7680.png"); - Product f = new Product("Tire", "0005", "Walmart", "0001", "0123456785", "30 inch rims", "Automotive", 146.97, "9/24/2020", "1", "http://cdn.sheknows.com/articles/2013/05/pet5.jpg"); - Product g = new Product("Bottled Water", "0000", "Target", "0001", "0123456780", "Bro, it's water...", "Grocery", 13.37, "9/24/2020", "1", "http://3.bp.blogspot.com/-MfroPPQVDKo/UyhUZWqGvkI/AAAAAAAAB-I/DGk622onsvc/s1600/lettuce-b-kool-cat-meme.jpg"); + Product f = new Product("Tire", "0005", "Kroger", "0002", "0123456785", "30 inch rims", "Automotive", 146.97, "9/24/2020", "1", "http://cdn.sheknows.com/articles/2013/05/pet5.jpg"); + Product g = new Product("This is a test for a product that has a very long title to see if the text overflows", "0006", "Target", "0003", "0123456786", "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Elit ut aliquam purus sit amet luctus venenatis. Tellus orci ac auctor augue mauris augue neque gravida. Habitant morbi tristique senectus et netus. Dignissim diam quis enim lobortis. Suspendisse sed nisi lacus sed viverra tellus in. Viverra adipiscing at in tellus integer feugiat scelerisque. Volutpat consequat mauris nunc congue nisi vitae suscipit tellus. Habitant morbi tristique senectus et netus et malesuada. Quis enim lobortis scelerisque fermentum dui faucibus in ornare quam. Mattis pellentesque id nibh tortor id aliquet. Volutpat blandit aliquam etiam erat. Vestibulum lorem sed risus ultricies tristique nulla aliquet.\n" + + "\n" + + "Placerat orci nulla pellentesque dignissim. Quisque non tellus orci ac. Mattis enim ut tellus elementum sagittis vitae et. Interdum velit euismod in pellentesque massa placerat duis ultricies. Id nibh tortor id aliquet lectus. Massa placerat duis ultricies lacus sed. Convallis convallis tellus id interdum velit laoreet id donec. Amet luctus venenatis lectus magna fringilla urna porttitor rhoncus. Sodales ut eu sem integer vitae justo. Viverra ipsum nunc aliquet bibendum enim facilisis.\n" + + "\n" + + "Eget felis eget nunc lobortis mattis aliquam faucibus purus. Odio morbi quis commodo odio aenean sed adipiscing. Hac habitasse platea dictumst quisque sagittis purus sit. Nam libero justo laoreet sit. Et malesuada fames ac turpis egestas. Erat nam at lectus urna duis convallis convallis. Morbi tincidunt ornare massa eget egestas purus viverra accumsan in. Ut venenatis tellus in metus vulputate eu scelerisque felis imperdiet. At auctor urna nunc id cursus. Sed elementum tempus egestas sed. Lorem dolor sed viverra ipsum nunc aliquet bibendum. Orci eu lobortis elementum nibh tellus molestie. Porttitor leo a diam sollicitudin tempor. Adipiscing bibendum est ultricies integer quis auctor elit sed. Arcu cursus euismod quis viverra nibh. A diam sollicitudin tempor id eu nisl.\n" + + "\n" + + "Sapien eget mi proin sed libero enim sed faucibus turpis. Pharetra massa massa ultricies mi quis hendrerit dolor magna. Integer enim neque volutpat ac tincidunt vitae semper. Euismod lacinia at quis risus sed vulputate. Ut venenatis tellus in metus vulputate eu scelerisque. Etiam erat velit scelerisque in dictum non consectetur. Viverra nam libero justo laoreet sit amet cursus sit. Arcu non sodales neque sodales. Vivamus arcu felis bibendum ut tristique et egestas quis. Sed adipiscing diam donec adipiscing tristique risus. Sollicitudin tempor id eu nisl nunc mi ipsum faucibus vitae. Velit ut tortor pretium viverra suspendisse potenti nullam ac tortor. Non nisi est sit amet facilisis magna etiam. Tortor at risus viverra adipiscing. Donec ultrices tincidunt arcu non sodales neque sodales. Eget egestas purus viverra accumsan. Enim lobortis scelerisque fermentum dui faucibus in ornare. Porttitor massa id neque aliquam. Ut consequat semper viverra nam. Orci ac auctor augue mauris augue neque gravida.\n" + + "\n" + + "Lacus sed viverra tellus in hac habitasse platea dictumst. Nec ullamcorper sit amet risus nullam eget felis eget nunc. Semper feugiat nibh sed pulvinar. Consequat nisl vel pretium lectus quam id leo in. Volutpat maecenas volutpat blandit aliquam etiam erat velit scelerisque. Faucibus a pellentesque sit amet porttitor eget. Sed viverra tellus in hac habitasse platea dictumst vestibulum. Placerat vestibulum lectus mauris ultrices eros in cursus turpis. Sed tempus urna et pharetra pharetra massa massa ultricies mi. Ornare arcu odio ut sem. Ornare arcu dui vivamus arcu felis bibendum ut. Feugiat pretium nibh ipsum consequat. Consectetur adipiscing elit ut aliquam purus sit amet luctus venenatis. Felis eget velit aliquet sagittis id consectetur purus ut.", "Automotive", 45.22, "9/24/2020", "1", "http://cdn.sheknows.com/articles/2013/05/pet5.jpg"); Product h = new Product("Tin Foil", "0001", "Kroger", "0001", "0123456781", "Not aluminum foil", "Grocery", 1.00, "9/24/2020", "1", "https://i.ytimg.com/vi/q9N1doYMxR0/maxresdefault.jpg"); resultsProductList.add(a); resultsProductList.add(b); diff --git a/Listify/app/src/main/java/com/example/listify/Second2Fragment.java b/Listify/app/src/main/java/com/example/listify/Second2Fragment.java deleted file mode 100644 index 6e17432..0000000 --- a/Listify/app/src/main/java/com/example/listify/Second2Fragment.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.example.listify; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.navigation.fragment.NavHostFragment; - -public class Second2Fragment extends Fragment { - - @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState - ) { - // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_second2, container, false); - } - - public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - view.findViewById(R.id.button_second).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - NavHostFragment.findNavController(Second2Fragment.this) - .navigate(R.id.action_Second2Fragment_to_First2Fragment); - } - }); - } -} \ No newline at end of file diff --git a/Listify/app/src/main/java/com/example/listify/SecondFragment.java b/Listify/app/src/main/java/com/example/listify/SecondFragment.java deleted file mode 100644 index 609a036..0000000 --- a/Listify/app/src/main/java/com/example/listify/SecondFragment.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.example.listify; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.navigation.fragment.NavHostFragment; - -public class SecondFragment extends Fragment { - - @Override - public View onCreateView( - LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState - ) { - // Inflate the layout for this fragment - return inflater.inflate(R.layout.fragment_second, container, false); - } - - public void onViewCreated(@NonNull View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - view.findViewById(R.id.button_second).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - NavHostFragment.findNavController(SecondFragment.this) - .navigate(R.id.action_SecondFragment_to_FirstFragment); - } - }); - } -} \ No newline at end of file diff --git a/Listify/app/src/main/java/com/example/listify/SynchronousReceiver.java b/Listify/app/src/main/java/com/example/listify/SynchronousReceiver.java new file mode 100644 index 0000000..07e390b --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/SynchronousReceiver.java @@ -0,0 +1,37 @@ +package com.example.listify; + +public class SynchronousReceiver implements Requestor.Receiver, Requestor.RequestErrorHandler { + private volatile boolean waiting; + private volatile Exception error; + private T toReturn; + + public SynchronousReceiver() { + waiting = true; + error = null; + } + + public T await() throws Exception { + while (waiting) { + Thread.yield(); + } + waiting = true; + if (error != null) { + Exception toThrow = error; + error = null; + throw toThrow; + } + return toReturn; + } + + @Override + public void acceptDelivery(Object delivered) { + toReturn = (T) delivered; + waiting = false; + } + + @Override + public void acceptError(Exception error) { + waiting = false; + this.error = error; + } +} diff --git a/Listify/app/src/main/java/com/example/listify/adapter/DisplayShoppingListsAdapter.java b/Listify/app/src/main/java/com/example/listify/adapter/DisplayShoppingListsAdapter.java index 4de7e08..aed6342 100644 --- a/Listify/app/src/main/java/com/example/listify/adapter/DisplayShoppingListsAdapter.java +++ b/Listify/app/src/main/java/com/example/listify/adapter/DisplayShoppingListsAdapter.java @@ -9,7 +9,6 @@ import android.widget.BaseAdapter; import android.widget.TextView; import com.example.listify.R; import com.example.listify.model.ShoppingList; - import java.util.ArrayList; public class DisplayShoppingListsAdapter extends BaseAdapter { diff --git a/Listify/app/src/main/java/com/example/listify/adapter/SearchResultsListAdapter.java b/Listify/app/src/main/java/com/example/listify/adapter/SearchResultsListAdapter.java index 61f9473..cc4306c 100644 --- a/Listify/app/src/main/java/com/example/listify/adapter/SearchResultsListAdapter.java +++ b/Listify/app/src/main/java/com/example/listify/adapter/SearchResultsListAdapter.java @@ -57,7 +57,11 @@ public class SearchResultsListAdapter extends BaseAdapter { Product product = productList.get(position); // TODO: If image url is broken, display @drawable/ic_baseline_broken_image_600.xml Glide.with(activity).load(product.getImageUrl()).into(productImage); - itemName.setText(product.getItemName()); + if (product.getItemName().length() >= 35) { + itemName.setText(product.getItemName().substring(0, 35) + "..."); + } else { + itemName.setText(product.getItemName()); + } price.setText(String.format("$%.2f", product.getPrice())); itemStore.setText(product.getChainName()); diff --git a/Listify/app/src/main/java/com/example/listify/data/Item.java b/Listify/app/src/main/java/com/example/listify/data/Item.java new file mode 100644 index 0000000..12fbbb8 --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/data/Item.java @@ -0,0 +1,115 @@ +package com.example.listify.data; + +import java.math.BigDecimal; + +public class Item { + Integer productID; + Integer chainID; + String upc; + String description; + BigDecimal price; + String imageURL; + String department; + long retrievedDate; + Integer fetchCounts; + + public Item(Integer productID, Integer chainID, String upc, String description, BigDecimal price, + String imageURL, String department, long retrievedDate, Integer fetchCounts) { + this.productID = productID; + this.chainID = chainID; + this.upc = upc; + this.description = description; + this.price = price; + this.imageURL = imageURL; + this.department = department; + this.retrievedDate = retrievedDate; + this.fetchCounts = fetchCounts; + } + + @Override + public String toString() { + return "Item{" + + "productID=" + productID + + ", chainID=" + chainID + + ", upc='" + upc + '\'' + + ", description='" + description + '\'' + + ", price=" + price + + ", imageURL='" + imageURL + '\'' + + ", department='" + department + '\'' + + ", retrievedDate=" + retrievedDate + + ", fetchCounts=" + fetchCounts + + '}'; + } + + public Integer getProductID() { + return productID; + } + + public void setProductID(Integer productID) { + this.productID = productID; + } + + public Integer getChainID() { + return chainID; + } + + public void setChainID(Integer chainID) { + this.chainID = chainID; + } + + public String getUpc() { + return upc; + } + + public void setUpc(String upc) { + this.upc = upc; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public BigDecimal getPrice() { + return price; + } + + public void setPrice(BigDecimal price) { + this.price = price; + } + + public String getImageURL() { + return imageURL; + } + + public void setImageURL(String imageURL) { + this.imageURL = imageURL; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + public long getRetrievedDate() { + return retrievedDate; + } + + public void setRetrievedDate(long retrievedDate) { + this.retrievedDate = retrievedDate; + } + + public Integer getFetchCounts() { + return fetchCounts; + } + + public void setFetchCounts(Integer fetchCounts) { + this.fetchCounts = fetchCounts; + } +} diff --git a/Listify/app/src/main/java/com/example/listify/data/ItemSearch.java b/Listify/app/src/main/java/com/example/listify/data/ItemSearch.java new file mode 100644 index 0000000..8d7874d --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/data/ItemSearch.java @@ -0,0 +1,27 @@ +package com.example.listify.data; + +import java.util.ArrayList; + +public class ItemSearch { + ArrayList results; + + public ItemSearch(ArrayList results) { + this.results = results; + } + + @Override + public String toString() { + return "ItemSearch{" + + "results=" + results + + '}'; + } + + public ArrayList getResults() { + return results; + } + + public void setResults(ArrayList results) { + this.results = results; + } +} + diff --git a/Listify/app/src/main/java/com/example/listify/data/List.java b/Listify/app/src/main/java/com/example/listify/data/List.java new file mode 100644 index 0000000..23d77ea --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/data/List.java @@ -0,0 +1,70 @@ +package com.example.listify.data; + +import java.util.Arrays; + +public class List { + Integer itemID; + String name; + String owner; + long lastUpdated; + final ListEntry[] entries; + + public List(Integer itemID, String name, String owner, long lastUpdated, ListEntry[] entries) { + this.itemID = itemID; + this.name = name; + this.owner = owner; + this.lastUpdated = lastUpdated; + this.entries = entries; + } + + public List(Integer itemID, String name, String owner, long lastUpdated) { + this(itemID, name, owner, lastUpdated, null); + } + + @Override + public String toString() { + return "List{" + + "itemID=" + itemID + + ", name='" + name + '\'' + + ", owner='" + owner + '\'' + + ", lastUpdated=" + lastUpdated + + ", entries=" + Arrays.toString(entries) + + '}'; + } + + public Integer getItemID() { + return itemID; + } + + public void setItemID(Integer itemID) { + this.itemID = itemID; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getOwner() { + return owner; + } + + public void setOwner(String owner) { + this.owner = owner; + } + + public long getLastUpdated() { + return lastUpdated; + } + + public void setLastUpdated(long lastUpdated) { + this.lastUpdated = lastUpdated; + } + + public ListEntry[] getEntries() { + return entries; + } +} diff --git a/Listify/app/src/main/java/com/example/listify/data/ListEntry.java b/Listify/app/src/main/java/com/example/listify/data/ListEntry.java new file mode 100644 index 0000000..e482079 --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/data/ListEntry.java @@ -0,0 +1,68 @@ +package com.example.listify.data; + +public class ListEntry { + Integer listID; + Integer productID; + Integer quantity; + long addedDate; + Boolean purchased; + + public ListEntry(Integer listID, Integer productID, Integer quantity, long addedDate, Boolean purchased) { + this.listID = listID; + this.productID = productID; + this.quantity = quantity; + this.addedDate = addedDate; + this.purchased = purchased; + } + + @Override + public String toString() { + return "ListEntry{" + + "listID=" + listID + + ", productID=" + productID + + ", quantity=" + quantity + + ", addedDate=" + addedDate + + ", purchased=" + purchased + + '}'; + } + + public Integer getListID() { + return listID; + } + + public void setListID(Integer listID) { + this.listID = listID; + } + + public Integer getProductID() { + return productID; + } + + public void setProductID(Integer productID) { + this.productID = productID; + } + + public Integer getQuantity() { + return quantity; + } + + public void setQuantity(Integer quantity) { + this.quantity = quantity; + } + + public long getAddedDate() { + return addedDate; + } + + public void setAddedDate(long addedDate) { + this.addedDate = addedDate; + } + + public Boolean getPurchased() { + return purchased; + } + + public void setPurchased(Boolean purchased) { + this.purchased = purchased; + } +} diff --git a/Listify/app/src/main/java/com/example/listify/data/User.java b/Listify/app/src/main/java/com/example/listify/data/User.java new file mode 100644 index 0000000..65ba3e6 --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/data/User.java @@ -0,0 +1,4 @@ +package com.example.listify.data; + +public class User { +} diff --git a/Listify/app/src/main/java/com/example/listify/model/Product.java b/Listify/app/src/main/java/com/example/listify/model/Product.java index db52386..654ac6b 100644 --- a/Listify/app/src/main/java/com/example/listify/model/Product.java +++ b/Listify/app/src/main/java/com/example/listify/model/Product.java @@ -1,6 +1,8 @@ package com.example.listify.model; -public class Product { +import java.io.Serializable; + +public class Product implements Serializable { private String itemName; private String itemId; private String chainName; diff --git a/Listify/app/src/main/res/drawable/bananas.png b/Listify/app/src/main/res/drawable/bananas.png new file mode 100644 index 0000000..ff750c7 Binary files /dev/null and b/Listify/app/src/main/res/drawable/bananas.png differ diff --git a/Listify/app/src/main/res/drawable/ic_baseline_add_28.xml b/Listify/app/src/main/res/drawable/ic_baseline_add_28.xml new file mode 100644 index 0000000..f320e60 --- /dev/null +++ b/Listify/app/src/main/res/drawable/ic_baseline_add_28.xml @@ -0,0 +1,5 @@ + + + diff --git a/Listify/app/src/main/res/drawable/ic_baseline_create_28.xml b/Listify/app/src/main/res/drawable/ic_baseline_create_28.xml new file mode 100644 index 0000000..3740c94 --- /dev/null +++ b/Listify/app/src/main/res/drawable/ic_baseline_create_28.xml @@ -0,0 +1,5 @@ + + + diff --git a/Listify/app/src/main/res/drawable/ic_baseline_post_add_28.xml b/Listify/app/src/main/res/drawable/ic_baseline_post_add_28.xml new file mode 100644 index 0000000..4b9cc60 --- /dev/null +++ b/Listify/app/src/main/res/drawable/ic_baseline_post_add_28.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/Listify/app/src/main/res/drawable/peanutbutter.png b/Listify/app/src/main/res/drawable/peanutbutter.png new file mode 100644 index 0000000..74dff48 Binary files /dev/null and b/Listify/app/src/main/res/drawable/peanutbutter.png differ diff --git a/Listify/app/src/main/res/layout/activity_item_details.xml b/Listify/app/src/main/res/layout/activity_item_details.xml new file mode 100644 index 0000000..49f9f75 --- /dev/null +++ b/Listify/app/src/main/res/layout/activity_item_details.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Listify/app/src/main/res/layout/content_item_details.xml b/Listify/app/src/main/res/layout/content_item_details.xml new file mode 100644 index 0000000..0e98ba7 --- /dev/null +++ b/Listify/app/src/main/res/layout/content_item_details.xml @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Listify/app/src/main/res/layout/dialog_add_to_list.xml b/Listify/app/src/main/res/layout/dialog_add_to_list.xml new file mode 100644 index 0000000..8325780 --- /dev/null +++ b/Listify/app/src/main/res/layout/dialog_add_to_list.xml @@ -0,0 +1,50 @@ + + + + + + + + +