diff --git a/Lambdas/Lists/List/src/List.java b/Lambdas/Lists/List/src/List.java index 26abc71..659a212 100644 --- a/Lambdas/Lists/List/src/List.java +++ b/Lambdas/Lists/List/src/List.java @@ -89,11 +89,9 @@ public class List { public ItemEntry[] getEntries() { return entries.toArray(new ItemEntry[entries.size()]); - //return; } public void addItemEntry(ItemEntry entry) { entries.add(entry); - //return; } } diff --git a/Lambdas/Lists/List/src/ListGetter.java b/Lambdas/Lists/List/src/ListGetter.java index e29267c..98fbc5c 100644 --- a/Lambdas/Lists/List/src/ListGetter.java +++ b/Lambdas/Lists/List/src/ListGetter.java @@ -12,7 +12,7 @@ public class ListGetter implements CallHandler{ private final String cognitoID; private final String GET_LIST = "SELECT * FROM List WHERE listID = ?;"; - private final String GET_LISTS = "SELECT listID FROM ListSharee WHERE userID = ? ORDER BY uiPosition;"; + private final String GET_LISTS = "SELECT listID, permissionLevel FROM ListSharee WHERE userID = ? ORDER BY uiPosition;"; private final String SHARE_CHECK = "SELECT * FROM ListSharee WHERE listID = ?;"; private final String GET_ENTRIES = "SELECT * FROM ListProduct WHERE listID = ?;"; @@ -32,7 +32,10 @@ public class ListGetter implements CallHandler{ System.out.println(getListsResults); ArrayList listIds = new ArrayList<>(); while (getListsResults.next()) { - listIds.add(getListsResults.getInt(1)); + Integer permissionLevel = getListsResults.getInt("permissionLevel"); + if (ListPermissions.hasPermission(permissionLevel, "Read")) { + listIds.add(getListsResults.getInt("listID")); + } } return listIds; } @@ -43,7 +46,7 @@ public class ListGetter implements CallHandler{ int sharees = 0; boolean verifiedAccess = false; int uiPosition = 1; - while ((sharees < 2 && accessResults.next()) || !verifiedAccess) { + while (accessResults.next() && (sharees < 2 || !verifiedAccess )) { int permissionLevel = accessResults.getInt("permissionLevel"); if (accessResults.getString("userID").equals(cognitoID)) { verifiedAccess = true; @@ -56,6 +59,9 @@ public class ListGetter implements CallHandler{ sharees++; } } + if (!verifiedAccess) { + throw new AccessControlException("User " + cognitoID + " does not have ant permission for list " + id); + } boolean shared = false; if (sharees > 1) { shared = true; diff --git a/Lambdas/Lists/List/src/ListPermissions.java b/Lambdas/Lists/List/src/ListPermissions.java index 7405191..e448894 100644 --- a/Lambdas/Lists/List/src/ListPermissions.java +++ b/Lambdas/Lists/List/src/ListPermissions.java @@ -24,7 +24,7 @@ public class ListPermissions { } public static boolean hasPermission(Integer level, String permission) { - return level % getKeyForPermission(permission) == 0; + return (level % getKeyForPermission(permission) == 0 && level != 0); } public static Integer getKeyForPermission(String permissionRaw) { diff --git a/Lambdas/Lists/ListShare/src/ListShare.java b/Lambdas/Lists/ListShare/src/ListShare.java index 151d842..9e4ea56 100644 --- a/Lambdas/Lists/ListShare/src/ListShare.java +++ b/Lambdas/Lists/ListShare/src/ListShare.java @@ -1,16 +1,57 @@ -package com.example.listify.data; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; public class ListShare { Integer listID; String shareWithEmail; + Integer permissionLevel; + Integer uiPosition; ArrayList other; - public ListShare(ResultSet listRow) throws SQLException { + public ListShare(ResultSet listRow, String shareWithEmail) throws SQLException { this.listID = listRow.getInt("listID"); - this.shareWithEmail = listRow.getString("userID"); + this.shareWithEmail = shareWithEmail; + this.permissionLevel = listRow.getInt("permissionLevel"); + this.uiPosition = listRow.getInt("uiPosition"); other = new ArrayList<>(); } + @Override + public String toString() { + return "ListShare{" + + "listID=" + listID + + ", shareWithEmail='" + shareWithEmail + '\'' + + ", permissionLevel=" + permissionLevel + + ", uiPosition=" + uiPosition + + ", other=" + other + + '}'; + } + + public Integer getPermissionLevel() { + return permissionLevel; + } + + public void setPermissionLevel(Integer permissionLevel) { + this.permissionLevel = permissionLevel; + } + + public Integer getUiPosition() { + return uiPosition; + } + + public void setUiPosition(Integer uiPosition) { + this.uiPosition = uiPosition; + } + + public ArrayList getOther() { + return other; + } + + public void setOther(ArrayList other) { + this.other = other; + } + public Integer getListID() { return listID; } diff --git a/Lambdas/Lists/ListShare/src/ListShareDeleter.java b/Lambdas/Lists/ListShare/src/ListShareDeleter.java deleted file mode 100644 index 7ec0076..0000000 --- a/Lambdas/Lists/ListShare/src/ListShareDeleter.java +++ /dev/null @@ -1,65 +0,0 @@ -import java.security.AccessControlException; -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 ListShareDeleter implements CallHandler { - private final Connection connection; - private final String cognitoID; - - private final String GET_LIST_ACCESS = "SELECT * FROM List WHERE (owner = ? AND listID = ?);"; - private final String REMOVE_SHAREE = "DELETE FROM ListSharee WHERE listID = ? AND user = ?;"; - - public ListShareDeleter(Connection connection, String cognitoID) { - this.connection = connection; - this.cognitoID = cognitoID; - } - - @Override - public Object conductAction(Map bodyMap, HashMap queryMap, String cognitoID) throws SQLException { - Integer listID = Integer.parseInt(queryMap.get("id")); - - InvokeRequest invokeRequest = new InvokeRequest(); - invokeRequest.setFunctionName("UserGET"); - invokeRequest.setPayload("{" + - " \"body\": {" + - " \"emailToCheck\": \"" + bodyMap.get("shareWithEmail").toString() + "\"" + - " }," + - " \"params\": {" + - " \"querystring\": {" + - " }" + - " }," + - " \"context\": {" + - " \"sub\": \"not used\"" + - " }" + - "}"); - InvokeResult invokeResult = AWSLambdaClientBuilder.defaultClient().invoke(invokeRequest); - - String shareeID = new String(invokeResult.getPayload().array()).replace("\"", ""); - - //Ensure that the user who is unsharing a list is the owner of that list - PreparedStatement accessCheck = connection.prepareStatement(GET_LIST_ACCESS); - accessCheck.setString(1, cognitoID); - accessCheck.setInt(2, listID); - - ResultSet userLists = accessCheck.executeQuery(); - - //User does not own the list; unshare attempt fails - if (!userLists.next()) { - throw new AccessControlException("User does not have access to list"); - } - - //Unshare the list with the specified sharee - PreparedStatement unshareList = connection.prepareStatement(REMOVE_SHAREE); - unshareList.setInt(1, listID); - unshareList.setInt(2, shareeID); - - cleanAccess.executeUpdate(); - connection.commit(); - - return null; - } -} diff --git a/Lambdas/Lists/ListShare/src/ListShareGetter.java b/Lambdas/Lists/ListShare/src/ListShareGetter.java index 009f0d6..70bbc0a 100644 --- a/Lambdas/Lists/ListShare/src/ListShareGetter.java +++ b/Lambdas/Lists/ListShare/src/ListShareGetter.java @@ -1,9 +1,14 @@ +import com.amazonaws.services.lambda.AWSLambdaClientBuilder; +import com.amazonaws.services.lambda.model.InvokeRequest; +import com.amazonaws.services.lambda.model.InvokeResult; +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.InputMismatchException; import java.util.Map; public class ListShareGetter implements CallHandler{ @@ -21,18 +26,67 @@ public class ListShareGetter implements CallHandler{ public Object conductAction(Map bodyMap, HashMap queryMap, String cognitoID) throws SQLException { Integer listID = Integer.parseInt(queryMap.get("id")); - PreparedStatement getList = connection.prepareStatement(GET_LIST); + PreparedStatement getList = connection.prepareStatement(GET_LISTS); getList.setInt(1, listID); ResultSet getListResults = getList.executeQuery(); - getListResults.first(); + System.out.println(getListResults); + + ListShare first = null; + while (getListResults.next() && first == null) { + InvokeRequest invokeRequest = new InvokeRequest(); + invokeRequest.setFunctionName("UserGET"); + invokeRequest.setPayload("{" + + " \"body\": {" + + " }," + + " \"params\": {" + + " \"querystring\": {" + + " \"id\": \"" + getListResults.getString("userID") + "\"" + + " }" + + " }," + + " \"context\": {" + + " \"sub\": \"not used\"" + + " }" + + "}"); + InvokeResult invokeResult = AWSLambdaClientBuilder.defaultClient().invoke(invokeRequest); + if (invokeResult.getStatusCode() != 200) { + throw new InputMismatchException("Could not find specified user to share with"); + } + String shareWithEmail = new Gson().fromJson(new String(invokeResult.getPayload().array()), User.class).email; + first = new ListShare(getListResults, shareWithEmail); + if (first.permissionLevel == 0 || first.permissionLevel == 1) { + first = null; + } + } + - //ListShare object to hold the data values of the first row retrived - ListShare first = new ListShare(getListResults); //Insert the ListShare objects to hold the data of the remaining rows into first's ListShare list while (getListResults.next()) { - first.addtoList(new ListShare(getListResults)); + InvokeRequest invokeRequest = new InvokeRequest(); + invokeRequest.setFunctionName("UserGET"); + invokeRequest.setPayload("{" + + " \"body\": {" + + " }," + + " \"params\": {" + + " \"querystring\": {" + + " \"id\": \"" + getListResults.getString("userID") + "\"" + + " }" + + " }," + + " \"context\": {" + + " \"sub\": \"not used\"" + + " }" + + "}"); + InvokeResult invokeResult = AWSLambdaClientBuilder.defaultClient().invoke(invokeRequest); + if (invokeResult.getStatusCode() != 200) { + throw new InputMismatchException("Could not find specified user to share with"); + } + String shareWithEmail = new Gson().fromJson(new String(invokeResult.getPayload().array()), User.class).email; + ListShare newShare = new ListShare(getListResults, shareWithEmail); + System.out.println(newShare); + if (newShare.permissionLevel != 0 && newShare.permissionLevel != 1) { + first.addtoList(newShare); + } } return first; diff --git a/Lambdas/Lists/ListShare/src/ListSharer.java b/Lambdas/Lists/ListShare/src/ListSharer.java index a80d0d8..2273399 100644 --- a/Lambdas/Lists/ListShare/src/ListSharer.java +++ b/Lambdas/Lists/ListShare/src/ListSharer.java @@ -1,6 +1,7 @@ import com.amazonaws.services.lambda.AWSLambdaClientBuilder; import com.amazonaws.services.lambda.model.InvokeRequest; import com.amazonaws.services.lambda.model.InvokeResult; +import com.google.gson.Gson; import java.security.AccessControlException; import java.sql.Connection; @@ -56,7 +57,7 @@ public class ListSharer implements CallHandler { if (invokeResult.getStatusCode() != 200) { throw new InputMismatchException("Could not find specified user to share with"); } - String shareWithSub = new String(invokeResult.getPayload().array()).replace("\"", ""); + String shareWithSub = new Gson().fromJson(new String(invokeResult.getPayload().array()), User.class).cognitoID; // checkAccess.setString(2, shareWithSub); // checkAccessRS = checkAccess.executeQuery(); // if (checkAccessRS.next()) { diff --git a/Lambdas/Lists/Picture/src/Picture.java b/Lambdas/Lists/Picture/src/Picture.java new file mode 100644 index 0000000..f4e5fae --- /dev/null +++ b/Lambdas/Lists/Picture/src/Picture.java @@ -0,0 +1,34 @@ +import java.sql.ResultSet; +import java.sql.SQLException; + +public class Picture { + String base64EncodedImage; + + public Picture(ResultSet rs) { + try { + this.base64EncodedImage = rs.getString("base64image"); + } catch (SQLException throwables) { + throwables.printStackTrace(); + this.base64EncodedImage = null; + } + } + + public Picture(String base64EncodedImage) { + this.base64EncodedImage = base64EncodedImage; + } + + @Override + public String toString() { + return "Picture{" + + "base64EncodedImage='" + base64EncodedImage + '\'' + + '}'; + } + + public String getBase64EncodedImage() { + return base64EncodedImage; + } + + public void setBase64EncodedImage(String base64EncodedImage) { + this.base64EncodedImage = base64EncodedImage; + } +} diff --git a/Lambdas/Lists/Picture/src/PictureGET.java b/Lambdas/Lists/Picture/src/PictureGET.java new file mode 100644 index 0000000..e5787dd --- /dev/null +++ b/Lambdas/Lists/Picture/src/PictureGET.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 PictureGET implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + return BasicHandler.handleRequest(inputMap, unfilled, PictureGetter.class); + } + +} \ No newline at end of file diff --git a/Lambdas/Lists/Picture/src/PictureGetter.java b/Lambdas/Lists/Picture/src/PictureGetter.java new file mode 100644 index 0000000..136e926 --- /dev/null +++ b/Lambdas/Lists/Picture/src/PictureGetter.java @@ -0,0 +1,34 @@ +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 PictureGetter implements CallHandler { + private final Connection connection; + private final String cognitoID; + + private final String GET_ITEM = "SELECT * FROM Pictures WHERE cognitoID = ?;"; + + public PictureGetter(Connection connection, String cognitoID) { + this.connection = connection; + this.cognitoID = cognitoID; + } + + @Override + public Object conductAction(Map bodyMap, HashMap queryMap, String cognitoID) throws SQLException { + PreparedStatement statement = connection.prepareStatement(GET_ITEM); + if (!queryMap.get("id").toString().equals("profile")) { + throw new IllegalArgumentException("Only profile pictures are currently supported."); + } + statement.setString(1, cognitoID); + System.out.println(statement); + ResultSet queryResults = statement.executeQuery(); + queryResults.first(); + System.out.println(queryResults); + Picture retrievedPicture = new Picture(queryResults); +// System.out.println(retrievedPicture); + return retrievedPicture; + } +} \ No newline at end of file diff --git a/Lambdas/Lists/ListShare/src/ListShareDELETE.java b/Lambdas/Lists/Picture/src/PicturePUT.java similarity index 57% rename from Lambdas/Lists/ListShare/src/ListShareDELETE.java rename to Lambdas/Lists/Picture/src/PicturePUT.java index 784a725..43fc914 100644 --- a/Lambdas/Lists/ListShare/src/ListShareDELETE.java +++ b/Lambdas/Lists/Picture/src/PicturePUT.java @@ -3,10 +3,9 @@ import com.amazonaws.services.lambda.runtime.RequestHandler; import java.util.Map; -public class ListShareDELETE implements RequestHandler, Object> { +public class PicturePUT implements RequestHandler, Object> { public Object handleRequest(Map inputMap, Context unfilled) { - return BasicHandler.handleRequest(inputMap, unfilled, ListShareDeleter.class); + return BasicHandler.handleRequest(inputMap, unfilled, PicturePutter.class); } - } diff --git a/Lambdas/Lists/Picture/src/PicturePutter.java b/Lambdas/Lists/Picture/src/PicturePutter.java new file mode 100644 index 0000000..fadff15 --- /dev/null +++ b/Lambdas/Lists/Picture/src/PicturePutter.java @@ -0,0 +1,28 @@ +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +public class PicturePutter implements CallHandler { + + private Connection connection; + private String cognitoID; + + public PicturePutter(Connection connection, String cognitoID) { + this.connection = connection; + this.cognitoID = cognitoID; + } + + final private String STORE_PICTURE_SQL = "REPLACE INTO Pictures(cognitoID, base64image) VALUES(?, ?);"; + + public Object conductAction(Map bodyMap, HashMap queryString, String cognitoID) throws SQLException { + PreparedStatement storePicture = connection.prepareStatement(STORE_PICTURE_SQL); + storePicture.setString(1, cognitoID); + storePicture.setString(2, bodyMap.get("base64EncodedImage").toString()); + System.out.println(storePicture); + storePicture.executeUpdate(); + connection.commit(); + return null; + } +} \ No newline at end of file diff --git a/Lambdas/Lists/User/src/User.java b/Lambdas/Lists/User/src/User.java new file mode 100644 index 0000000..e3ceb43 --- /dev/null +++ b/Lambdas/Lists/User/src/User.java @@ -0,0 +1,26 @@ + +public class User { + String cognitoID; + String email; + + public User(String cognitoID, String email) { + this.cognitoID = cognitoID; + this.email = email; + } + + public String getCognitoID() { + return cognitoID; + } + + public void setCognitoID(String cognitoID) { + this.cognitoID = cognitoID; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/Lambdas/Lists/User/src/UserGetter.java b/Lambdas/Lists/User/src/UserGetter.java index 42d7422..5f00ef2 100644 --- a/Lambdas/Lists/User/src/UserGetter.java +++ b/Lambdas/Lists/User/src/UserGetter.java @@ -34,15 +34,14 @@ public class UserGetter implements CallHandler { } else { try { String id = queryMap.get("id"); + attributeToGet = "email"; + checkRequest.setFilter("sub=\"" + cognitoID + "\""); if ((id != null) && (!id.equals(""))) { - attributeToGet = "email"; - checkRequest.setFilter("sub=\"" + cognitoID + "\""); - } else { - return cognitoID; + checkRequest.setFilter("sub=\"" + id + "\""); } } catch (Exception e) { System.out.println(e); - return cognitoID; + return new User(cognitoID, null); } } System.out.println(checkRequest); @@ -52,9 +51,9 @@ public class UserGetter implements CallHandler { if (foundUsers.size() != 1) { System.out.println(foundUsers); if (foundUsers.size() == 0) { - throw new InputMismatchException("Not user with given email"); + throw new InputMismatchException("No user with given attribute when searching for (" + attributeToGet + ")"); } - throw new InputMismatchException("Found more than one user with supposedly unique email"); + throw new InputMismatchException("Found more than one user with supposedly unique attribute (" + attributeToGet + ")"); } UserType foundUser = foundUsers.get(0); System.out.println(foundUser.getAttributes()); @@ -66,6 +65,11 @@ public class UserGetter implements CallHandler { } System.out.println(attribute.getName() + ": " + attribute.getValue()); } - return attributeToReturn; + if (attributeToGet.equals("email")) { + return new User(cognitoID, attributeToReturn); + } else if (attributeToGet.equals("sub")) { + return new User(attributeToReturn, emailObject.toString()); + } + return null; } } diff --git a/Listify/app/build.gradle b/Listify/app/build.gradle index a14ee50..7038265 100644 --- a/Listify/app/build.gradle +++ b/Listify/app/build.gradle @@ -53,4 +53,6 @@ dependencies { implementation 'com.squareup.okhttp3:okhttp:4.8.1' implementation 'com.crystal:crystalrangeseekbar:1.1.3' implementation 'com.chauthai.swipereveallayout:swipe-reveal-layout:1.4.1' + implementation "androidx.cardview:cardview:1.0.0" + } \ No newline at end of file diff --git a/Listify/app/src/main/AndroidManifest.xml b/Listify/app/src/main/AndroidManifest.xml index 7389dd5..2dabe96 100644 --- a/Listify/app/src/main/AndroidManifest.xml +++ b/Listify/app/src/main/AndroidManifest.xml @@ -3,6 +3,9 @@ package="com.example.listify"> + + + + + + + + + + \ 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 48a2f4a..2573157 100644 --- a/Listify/app/src/main/java/com/example/listify/AuthManager.java +++ b/Listify/app/src/main/java/com/example/listify/AuthManager.java @@ -9,6 +9,7 @@ import com.amplifyframework.auth.result.AuthResetPasswordResult; import com.amplifyframework.auth.result.AuthSignInResult; import com.amplifyframework.auth.result.AuthSignUpResult; import com.amplifyframework.core.Amplify; +import com.example.listify.data.ListShare; import com.example.listify.data.User; import org.json.JSONException; import org.json.JSONObject; @@ -60,7 +61,21 @@ public class AuthManager { return authSession.getUserPoolTokens().getValue().getIdToken(); } - public String getEmail() { + public String getEmail(Requestor requestor) { + if (email == null) { + try { + requestor.putObject(new ListShare(285, "nmerz@icloud.com", 210, -1, null)); + } catch (JSONException jsonException) { + jsonException.printStackTrace(); + } + SynchronousReceiver userSynchronousReceiver = new SynchronousReceiver<>(); + requestor.getObject("", User.class, userSynchronousReceiver); + try { + email = userSynchronousReceiver.await().getEmail(); + } catch (Exception e) { + return email; + } + } return email; } 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 783924d..2d658a3 100644 --- a/Listify/app/src/main/java/com/example/listify/ListPage.java +++ b/Listify/app/src/main/java/com/example/listify/ListPage.java @@ -1,15 +1,17 @@ package com.example.listify; -import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.graphics.Color; import android.os.Bundle; +import android.text.Editable; import android.util.Log; import android.view.*; import android.widget.*; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; @@ -27,7 +29,7 @@ import java.util.Properties; import static com.example.listify.MainActivity.am; -public class ListPage extends AppCompatActivity implements Requestor.Receiver { +public class ListPage extends AppCompatActivity implements Requestor.Receiver, RenameListDialogFragment.OnRenameListListener { ListView listView; MyAdapter myAdapter; Requestor requestor; @@ -59,15 +61,15 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { Map storeHeaderIndex = new HashMap<>(); DecimalFormat df = new DecimalFormat("0.00"); + List selectedList; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_list); - final int LIST_ID = (int) getIntent().getSerializableExtra("listID"); - final String LIST_NAME = (String) getIntent().getSerializableExtra("listName"); - setTitle(LIST_NAME); + selectedList = (List) getIntent().getSerializableExtra("selectedList"); + setTitle(selectedList.getName()); Properties configs = new Properties(); try { @@ -76,7 +78,7 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { e.printStackTrace(); } requestor = new Requestor(am, configs.getProperty("apiKey")); - requestor.getObject(Integer.toString(LIST_ID), List.class, this); + requestor.getObject(Integer.toString(selectedList.getListID()), List.class, this); listView = findViewById(R.id.listView); myAdapter = new MyAdapter(this, pNames, pStores, pPrices, pQuantity, pImages); @@ -158,7 +160,7 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { } requestor = new Requestor(am, configs.getProperty("apiKey")); - requestor.getObject(Integer.toString(LIST_ID), List.class, ListPage.this); + requestor.getObject(Integer.toString(selectedList.getListID()), List.class, ListPage.this); } }); } @@ -166,16 +168,16 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { @Override public boolean onCreateOptionsMenu(Menu menu) { //Inflate the menu; this adds items to the action bar if it is present. - getMenuInflater().inflate(R.menu.list, menu); - - //return super.onCreateOptionsMenu(menu); + + MenuItem renameItem = menu.findItem(R.id.action_rename_list); renameItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { - Toast.makeText(ListPage.this, "Rename List", Toast.LENGTH_SHORT).show(); + RenameListDialogFragment renameListDialog = new RenameListDialogFragment(); + renameListDialog.show(getSupportFragmentManager(), "Rename List"); return false; } }); @@ -193,7 +195,24 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { duplicateItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { - Toast.makeText(ListPage.this, "Duplicate List", Toast.LENGTH_SHORT).show(); + + ListDuplicate duplicate = new ListDuplicate(selectedList.getListID(), String.format("%s copy", selectedList.getName())); + + Properties configs = new Properties(); + try { + configs = AuthManager.loadProperties(ListPage.this, "android.resource://" + getPackageName() + "/raw/auths.json"); + } catch (IOException | JSONException e) { + e.printStackTrace(); + } + + requestor = new Requestor(am, configs.getProperty("apiKey")); + try { + requestor.postObject(duplicate); + } catch (JSONException e) { + e.printStackTrace(); + } + + Toast.makeText(ListPage.this, "List duplicated", Toast.LENGTH_SHORT).show(); return false; } }); @@ -202,6 +221,24 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { exportItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { + StringBuilder listContents = new StringBuilder(); + + for (int i = 0; i < pNames.size(); i++) { + if (Integer.parseInt(pQuantity.get(i)) == -1) { + listContents.append(String.format("\n%s\n", pNames.get(i))); + } else { + listContents.append(String.format(" %s of %s\n", pQuantity.get(i), pNames.get(i))); + } + } + + Intent sendIntent = new Intent(); + sendIntent.setAction(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_TEXT, listContents.toString()); + sendIntent.setType("text/plain"); + + Intent shareIntent = Intent.createChooser(sendIntent, null); + startActivity(shareIntent); + Toast.makeText(ListPage.this, "Export List", Toast.LENGTH_SHORT).show(); return false; } @@ -213,22 +250,16 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { @Override public void acceptDelivery(Object delivered) { // Clear out old values - runOnUiThread(new Runnable() { - @Override - public void run() { - pNames.clear(); - pStores.clear(); - pPrices.clear(); - pQuantity.clear(); - pImages.clear(); - totalPriceByStore.clear(); - storeID2Name.clear(); - storeHeaderIndex.clear(); - pListItemPair.clear(); - totalPrice = 0; - tvTotalPrice.setText(String.format("$%.2f", totalPrice)); - } - }); + pNames.clear(); + pStores.clear(); + pPrices.clear(); + pQuantity.clear(); + pImages.clear(); + totalPriceByStore.clear(); + storeID2Name.clear(); + storeHeaderIndex.clear(); + pListItemPair.clear(); + totalPrice = 0; List list = (List) delivered; @@ -326,9 +357,44 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { }); } + runOnUiThread(new Runnable() { + @Override + public void run() { + tvTotalPrice.setText(String.format("$%.2f", totalPrice)); + } + }); + refreshList.setRefreshing(false); } + @Override + public void sendRenameListName(String name) { + selectedList.setName(name); + + Properties configs = new Properties(); + try { + configs = AuthManager.loadProperties(ListPage.this, "android.resource://" + getPackageName() + "/raw/auths.json"); + } catch (IOException | JSONException e) { + e.printStackTrace(); + } + + requestor = new Requestor(am, configs.getProperty("apiKey")); + try { + requestor.putObject(selectedList); + } catch (Exception e) { + e.printStackTrace(); + } + + + runOnUiThread(new Runnable() { + @Override + public void run() { + setTitle(name); + Toast.makeText(ListPage.this, "List Renamed", Toast.LENGTH_SHORT).show(); + } + }); + } + class MyAdapter extends ArrayAdapter { Context context; ArrayList pNames; diff --git a/Listify/app/src/main/java/com/example/listify/ListSharees.java b/Listify/app/src/main/java/com/example/listify/ListSharees.java index c7527a8..0393b0d 100644 --- a/Listify/app/src/main/java/com/example/listify/ListSharees.java +++ b/Listify/app/src/main/java/com/example/listify/ListSharees.java @@ -1,54 +1,34 @@ package com.example.listify; -import android.app.AlertDialog; 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.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.EditText; -import android.widget.ImageView; -import android.widget.ListView; -import android.widget.ProgressBar; -import android.widget.TextView; - -import com.bumptech.glide.Glide; -import com.example.listify.adapter.ShareeSwipeableAdapter; -import com.example.listify.adapter.ShoppingListsSwipeableAdapter; -import com.example.listify.data.Chain; -import com.example.listify.data.Item; -import com.example.listify.data.List; -import com.example.listify.data.ListEntry; -import com.example.listify.data.ListShare; - -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 android.widget.*; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; +import com.example.listify.data.ListShare; +import org.json.JSONException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Properties; import static com.example.listify.MainActivity.am; public class ListSharees extends AppCompatActivity implements Requestor.Receiver { - ShareeSwipeableAdapter myAdapter; + ListView listView; + MyAdapter myAdapter; Requestor requestor; - ProgressBar loadingListItems; + Button shareList; + Button removeSharee; - DecimalFormat df = new DecimalFormat("0.00"); + ArrayList lShareeEntries = new ArrayList<>(); + ArrayList lShareeEmails = new ArrayList<>(); - // TODO: Display a message if their list is empty @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -65,8 +45,26 @@ public class ListSharees extends AppCompatActivity implements Requestor.Receiver requestor = new Requestor(am, configs.getProperty("apiKey")); requestor.getObject(Integer.toString(listID), ListShare.class, this); - loadingListItems = findViewById(R.id.progress_loading_list_items); - loadingListItems.setVisibility(View.VISIBLE); + listView = findViewById(R.id.listOfSharees); + myAdapter = new MyAdapter(this, lShareeEmails); + listView.setAdapter(myAdapter); + + shareList = (Button) findViewById(R.id.buttonShare); + shareList.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + EditText sharedEmailText = (EditText) findViewById(R.id.editTextShareeEmail); + String sharedEmail = sharedEmailText.getText().toString(); + + ListShare listShare = new ListShare(listID, sharedEmail, "Read, Write, Delete, Share", null); + try { + requestor.putObject(listShare); + } + catch(Exception e) { + e.printStackTrace(); + } + } + }); } @Override @@ -74,29 +72,69 @@ public class ListSharees extends AppCompatActivity implements Requestor.Receiver ListShare sharee = (ListShare) delivered; if(sharee != null) { - SynchronousReceiver listShareReceiver = new SynchronousReceiver<>(); - requestor.getObject(Integer.toString(sharee.getListID()), ListShare.class, listShareReceiver, listShareReceiver); + lShareeEmails.add(sharee.getShareWithEmail()); - ArrayList resultList = new ArrayList<>(); - ListShare result; - - try { - result = listShareReceiver.await(); - } - catch (Exception e) { - e.printStackTrace(); - result = null; - } - - if(result != null) { - resultList.add(result); - - for(ListShare r : result.getEntries()) { - resultList.add(r); + if(sharee.getEntries() != null) { + for(ListShare ls : sharee.getEntries()) { + lShareeEntries.add(ls); + lShareeEmails.add(ls.getShareWithEmail()); } - - myAdapter = new ShareeSwipeableAdapter(this, resultList); } + + runOnUiThread(new Runnable() { + @Override + public void run() { + myAdapter.notifyDataSetChanged(); + } + }); + } + } + + class MyAdapter extends ArrayAdapter { + Context context; + ArrayList lShareeEmails; + + MyAdapter (Context c, ArrayList shareeEmails) { + super(c, R.layout.shopping_list_sharee_entry, R.id.textView14, shareeEmails); + context = c; + lShareeEmails = shareeEmails; + } + + @NonNull + @Override + public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { + LayoutInflater layoutInflater = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View listproduct = layoutInflater.inflate(R.layout.shopping_list_sharee_entry, parent,false); + + TextView shareeEmail = listproduct.findViewById(R.id.textView14); + if(!lShareeEmails.isEmpty()) { + shareeEmail.setText(lShareeEmails.get(position)); + } + + removeSharee = (Button) listproduct.findViewById(R.id.button4); + removeSharee.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + try { + lShareeEntries.get(position).setPermissionLevel(0); + ListShare toRemove = lShareeEntries.remove(position); + System.out.println(toRemove); + requestor.putObject(toRemove); + myAdapter.notifyDataSetChanged(); + } + catch(Exception e) { + e.printStackTrace(); + } + } + }); + + //No need to show owner + if(position == 0) { + shareeEmail.setVisibility(View.GONE); + removeSharee.setVisibility(View.GONE); + } + + return listproduct; } } } 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 8053dd0..096db85 100644 --- a/Listify/app/src/main/java/com/example/listify/MainActivity.java +++ b/Listify/app/src/main/java/com/example/listify/MainActivity.java @@ -1,15 +1,26 @@ package com.example.listify; +import android.app.AlertDialog; +import android.content.Context; import android.content.Intent; +import android.database.Cursor; +import android.net.Uri; import android.os.Bundle; +import android.os.Environment; import android.os.Handler; +import android.provider.MediaStore; +import android.util.Base64; +import android.util.Base64OutputStream; import android.util.Log; import android.view.MenuItem; import android.view.View; import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; +import androidx.core.content.FileProvider; import androidx.drawerlayout.widget.DrawerLayout; import androidx.navigation.NavController; import androidx.navigation.Navigation; @@ -17,15 +28,15 @@ import androidx.navigation.ui.AppBarConfiguration; import androidx.navigation.ui.NavigationUI; import com.amplifyframework.auth.AuthException; import com.example.listify.data.List; -import com.example.listify.data.ListDuplicate; -import com.example.listify.data.ListReposition; -import com.example.listify.data.SearchHistory; +import com.example.listify.data.Picture; import com.example.listify.ui.LoginPage; import com.google.android.material.navigation.NavigationView; import org.json.JSONException; -import java.io.IOException; +import java.io.*; +import java.text.SimpleDateFormat; import java.time.Instant; +import java.util.Date; import java.util.Properties; import static com.example.listify.SplashActivity.showSplash; @@ -33,6 +44,9 @@ import static com.example.listify.SplashActivity.showSplash; public class MainActivity extends AppCompatActivity implements CreateListDialogFragment.OnNewListListener { private AppBarConfiguration mAppBarConfiguration; public static AuthManager am = new AuthManager(); + private File newImageFileLocation = null; + private final int CAMERA_CAPTURE = 1; + private final int IMAGE_SELECT = 2; @Override public void onBackPressed() { @@ -151,12 +165,62 @@ public class MainActivity extends AppCompatActivity implements CreateListDialogF } //------------------------------------------------------------------------------------------// - setContentView(R.layout.activity_main); Toolbar toolbar = findViewById(R.id.toolbar); setSupportActionBar(toolbar); DrawerLayout drawer = findViewById(R.id.drawer_layout); NavigationView navigationView = findViewById(R.id.nav_view); + + 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(am, configs.getProperty("apiKey")); + TextView emailView = navigationView.getHeaderView(0).findViewById(R.id.textViewEmailSidebar); + emailView.setText(am.getEmail(requestor)); + SynchronousReceiver profilePictureReceiver = new SynchronousReceiver<>(); + ImageView profilePictureView = navigationView.getHeaderView(0).findViewById(R.id.imageViewProfilePicture); + try { + requestor.getObject("profile", Picture.class, profilePictureReceiver); + profilePictureView.setImageURI(Uri.fromFile(saveImage(profilePictureReceiver.await().getBase64EncodedImage()))); + } catch (Exception e) { + e.printStackTrace(); + } + profilePictureView.setOnClickListener(new View.OnClickListener() { + + @Override + public void onClick(View v) { + AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); +// builder.setView(navigationView.getHeaderView(0)); + builder.setTitle("Change picture"); + builder.setMessage("Please select a method to add a new profile picture."); + builder.setCancelable(true); + builder.setPositiveButton("Take picture", (dialog, which) -> { + Intent takePicture = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + File imageFileLocation = getOutputImageFile(); + Log.i("Profile Picture", "New image file at " + imageFileLocation.getAbsolutePath()); + newImageFileLocation = imageFileLocation; + Uri imageUri = FileProvider.getUriForFile( + MainActivity.this, + BuildConfig.APPLICATION_ID + ".provider", + imageFileLocation); + takePicture.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); + startActivityForResult(takePicture, CAMERA_CAPTURE); + }); + builder.setNegativeButton("Select picture", (dialog, which) -> { + Intent pickPhoto = new Intent(Intent.ACTION_PICK, + MediaStore.Images.Media.EXTERNAL_CONTENT_URI); + startActivityForResult(pickPhoto, IMAGE_SELECT); + }); + builder.setNeutralButton("Cancel", (dialog, which) -> { + }); + AlertDialog dialog = builder.create(); + dialog.show(); + } + }); + mAppBarConfiguration = new AppBarConfiguration.Builder( R.id.nav_home, R.id.nav_profile, R.id.nav_logout) .setDrawerLayout(drawer) @@ -176,6 +240,144 @@ public class MainActivity extends AppCompatActivity implements CreateListDialogF }); } + //From: https://stackoverflow.com/questions/30005815/convert-encoded-base64-image-to-file-object-in-android + private File saveImage(final String imageData) throws IOException { + final byte[] imgBytesData = android.util.Base64.decode(imageData, + android.util.Base64.DEFAULT); + + final File file = File.createTempFile("profilePicture", null, this.getCacheDir()); + final FileOutputStream fileOutputStream; + try { + fileOutputStream = new FileOutputStream(file); + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } + + final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream( + fileOutputStream); + try { + bufferedOutputStream.write(imgBytesData); + } catch (IOException e) { + e.printStackTrace(); + return null; + } finally { + try { + bufferedOutputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return file; + } + + protected void onActivityResult (int requestCode, + int resultCode, + Intent data) { + Uri selectedImage = null; + 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(am, configs.getProperty("apiKey")); + switch (requestCode){ + case CAMERA_CAPTURE: + Log.i("Profile Picture", "Pulling image file at " + this.newImageFileLocation.getAbsolutePath()); + selectedImage = Uri.fromFile(this.newImageFileLocation); + try { + requestor.putObject(new Picture(fileToString(this.newImageFileLocation))); + } catch (JSONException | IOException jsonException) { + jsonException.printStackTrace(); + } + + break; + case IMAGE_SELECT: + if ((data == null) || (data.getData() == null)) { + return; + } + selectedImage = data.getData(); + try { + requestor.putObject(new Picture(fileToString(new File(getRealPathFromUri(this, selectedImage))))); + } catch (JSONException | IOException exception) { + exception.printStackTrace(); + } + break; + } + + MainActivity.super.onActivityResult(requestCode, resultCode, data); + if (selectedImage == null) { + return; + } + NavigationView navigationView = findViewById(R.id.nav_view); + + ImageView profilePicture = navigationView.getHeaderView(0).findViewById(R.id.imageViewProfilePicture); + profilePicture.setImageURI(selectedImage); + + } + + //From: https://stackoverflow.com/questions/20028319/how-to-convert-content-media-external-images-media-y-to-file-storage-sdc + private static String getRealPathFromUri(Context context, Uri contentUri) { + Cursor cursor = null; + try { + String[] proj = { MediaStore.Images.Media.DATA }; + cursor = context.getContentResolver().query(contentUri, proj, null, null, null); + int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); + cursor.moveToFirst(); + return cursor.getString(column_index); + } finally { + if (cursor != null) { + cursor.close(); + } + } + } + + //From: https://stackoverflow.com/questions/27784230/convert-a-file-100mo-in-base64-on-android + private String fileToString(File toStringify) throws IOException { + InputStream inputStream = new FileInputStream(toStringify.getAbsolutePath()); + byte[] buffer = new byte[8192]; + int bytesRead; + ByteArrayOutputStream output = new ByteArrayOutputStream(); + Base64OutputStream output64 = new Base64OutputStream(output, Base64.DEFAULT); + try { + while ((bytesRead = inputStream.read(buffer)) != -1) { + output64.write(buffer, 0, bytesRead); + } + } catch (IOException e) { + e.printStackTrace(); + } + output64.close(); + + return output.toString(); + } + + //getOutputImageFile from https://developer.android.com/guide/topics/media/camera + private static File getOutputImageFile(){ + // To be safe, you should check that the SDCard is mounted + // using Environment.getExternalStorageState() before doing this. + + File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory( + Environment.DIRECTORY_PICTURES), "MyCameraApp"); + // This location works best if you want the created images to be shared + // between applications and persist after your app has been uninstalled. + + // Create the storage directory if it does not exist + if (! mediaStorageDir.exists()){ + if (! mediaStorageDir.mkdirs()){ + Log.d("File creation", "failed to create directory"); + return null; + } + } + + // Create a media file name + String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); + File mediaFile = new File(mediaStorageDir.getPath() + File.separator + + "IMG_"+ timeStamp + ".jpg"); + Log.i("File creation", mediaFile.toString()); + return mediaFile; + } + @Override public boolean onSupportNavigateUp() { NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); @@ -214,5 +416,8 @@ public class MainActivity extends AppCompatActivity implements CreateListDialogF Toast.makeText(this, "An error occurred", Toast.LENGTH_LONG).show(); e.printStackTrace(); } + } + + } \ No newline at end of file diff --git a/Listify/app/src/main/java/com/example/listify/RenameListDialogFragment.java b/Listify/app/src/main/java/com/example/listify/RenameListDialogFragment.java new file mode 100644 index 0000000..1b82b6d --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/RenameListDialogFragment.java @@ -0,0 +1,71 @@ +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 RenameListDialogFragment extends DialogFragment { + + public interface OnRenameListListener { + void sendRenameListName(String name); + } + + public OnRenameListListener onRenameListListener; + + EditText etRenameListName; + + public RenameListDialogFragment() {} + + + @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_rename_list, null); + builder.setView(root) + // Add action buttons + .setPositiveButton("OK", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + onRenameListListener.sendRenameListName(etRenameListName.getText().toString()); + } + }) + .setNegativeButton("cancel", new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + RenameListDialogFragment.this.getDialog().cancel(); + } + }); + + etRenameListName = (EditText) root.findViewById(R.id.et_renamed_list_name); + + return builder.create(); + } + + // Required to extend DialogFragment + @Override + public void onAttach(@NonNull Context context) { + super.onAttach(context); + try { + onRenameListListener = (OnRenameListListener) getTargetFragment(); + if (onRenameListListener == null) { + onRenameListListener = (OnRenameListListener) getActivity(); + } + } catch (ClassCastException e) { + Log.e("CreateListDialogFragment", "onAttach: ClassCastException: " + e.getMessage()); + } + } +} diff --git a/Listify/app/src/main/java/com/example/listify/adapter/ShareeSwipeableAdapter.java b/Listify/app/src/main/java/com/example/listify/adapter/ShareeSwipeableAdapter.java index ac8ee0e..0c5327b 100644 --- a/Listify/app/src/main/java/com/example/listify/adapter/ShareeSwipeableAdapter.java +++ b/Listify/app/src/main/java/com/example/listify/adapter/ShareeSwipeableAdapter.java @@ -79,7 +79,7 @@ public class ShareeSwipeableAdapter extends BaseAdapter { holder.swipeLayout = (SwipeRevealLayout)convertView.findViewById(R.id.swipe_layout); holder.frontView = convertView.findViewById(R.id.front_layout); holder.deleteList = convertView.findViewById(R.id.delete_list); - holder.shareList = convertView.findViewById(R.id.share_list); +// holder.shareList = convertView.findViewById(R.id.share_list); holder.textView = (TextView) convertView.findViewById(R.id.shopping_list_name); convertView.setTag(holder); @@ -101,12 +101,12 @@ public class ShareeSwipeableAdapter extends BaseAdapter { } }); - holder.shareList.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - - } - }); +// holder.shareList.setOnClickListener(new View.OnClickListener() { +// @Override +// public void onClick(View v) { +// +// } +// }); holder.frontView.setOnClickListener(new View.OnClickListener() { @Override diff --git a/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsAdapter.java b/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsAdapter.java index f7a9c6a..fa986a5 100644 --- a/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsAdapter.java +++ b/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsAdapter.java @@ -49,7 +49,7 @@ public class ShoppingListsAdapter extends BaseAdapter { TextView tvListName = (TextView) convertView.findViewById(R.id.shopping_list_name); if(curList.isShared()) { - tvListName.setText(curList.getName() + " (shared)"); + tvListName.setText(curList.getName() + " (shared by " + curList.getOwner() + ")"); } else { tvListName.setText(curList.getName()); diff --git a/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java b/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java index fbdf493..1ad6d5e 100644 --- a/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java +++ b/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java @@ -17,6 +17,7 @@ import com.chauthai.swipereveallayout.SwipeRevealLayout; import com.chauthai.swipereveallayout.ViewBinderHelper; import com.example.listify.AuthManager; import com.example.listify.ListPage; +import com.example.listify.ListSharees; import com.example.listify.R; import com.example.listify.Requestor; import com.example.listify.data.List; @@ -94,13 +95,17 @@ public class ShoppingListsSwipeableAdapter extends BaseAdapter { binderHelper.bind(holder.swipeLayout, Integer.toString(curList.getListID())); if(curList.isShared()) { - holder.listName.setText(curList.getName() + " (shared)"); + holder.listName.setText(curList.getName() + " (shared by " + curList.getOwner() + ")"); } else { holder.listName.setText(curList.getName()); } - holder.itemCount.setText(String.format("%d items", curList.getEntries().length)); + if (curList.getEntries() != null) { + holder.itemCount.setText(String.format("%d items", curList.getEntries().length)); + } else { + holder.itemCount.setText("0 items"); + } holder.deleteList.setOnClickListener(new View.OnClickListener() { @Override @@ -123,36 +128,12 @@ public class ShoppingListsSwipeableAdapter extends BaseAdapter { holder.shareList.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - View codeView = inflater.inflate(R.layout.activity_sharedemail, null); - AlertDialog.Builder builder = new AlertDialog.Builder(activity); - builder.setView(codeView); - builder.setTitle("Share list"); - builder.setMessage("Please enter the email of the user who you want to share the list with."); - builder.setPositiveButton("Submit", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - EditText sharedEmailText = (EditText) codeView.findViewById(R.id.editTextTextSharedEmail); - String sharedEmail = sharedEmailText.getText().toString(); - ListShare listShare = new ListShare(curList.getListID(), sharedEmail, "Read, Write, Delete, Share", null); - try { - requestor.putObject(listShare); - } - catch(Exception e) { - e.printStackTrace(); - } - } - }); - builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) {} - }); - AlertDialog dialog = builder.create(); - dialog.show(); + Intent listSharees = new Intent(activity, ListSharees.class); - Toast.makeText(activity, String.format("Share %s", curList.getName()), Toast.LENGTH_SHORT).show(); + // Send the list ID and list name + listSharees.putExtra("listID", curList.getListID()); - // Close the layout - binderHelper.closeLayout(Integer.toString(curList.getListID())); + activity.startActivity(listSharees); } }); @@ -161,9 +142,8 @@ public class ShoppingListsSwipeableAdapter extends BaseAdapter { public void onClick(View v) { Intent listPage = new Intent(activity, ListPage.class); - // Send the list ID and list name - listPage.putExtra("listID", curList.getListID()); - listPage.putExtra("listName", curList.getName()); + // Send the selected list + listPage.putExtra("selectedList", curList); activity.startActivity(listPage); } 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 index 47f3971..79fc8d1 100644 --- a/Listify/app/src/main/java/com/example/listify/data/List.java +++ b/Listify/app/src/main/java/com/example/listify/data/List.java @@ -1,8 +1,9 @@ package com.example.listify.data; +import java.io.Serializable; import java.util.Arrays; -public class List { +public class List implements Serializable { Integer listID; String name; String owner; 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 index e482079..66720e8 100644 --- a/Listify/app/src/main/java/com/example/listify/data/ListEntry.java +++ b/Listify/app/src/main/java/com/example/listify/data/ListEntry.java @@ -1,6 +1,8 @@ package com.example.listify.data; -public class ListEntry { +import java.io.Serializable; + +public class ListEntry implements Serializable { Integer listID; Integer productID; Integer quantity; diff --git a/Listify/app/src/main/java/com/example/listify/data/ListShare.java b/Listify/app/src/main/java/com/example/listify/data/ListShare.java index 50765cb..aac2142 100644 --- a/Listify/app/src/main/java/com/example/listify/data/ListShare.java +++ b/Listify/app/src/main/java/com/example/listify/data/ListShare.java @@ -11,6 +11,7 @@ public class ListShare { String shareWithEmail; final ListShare[] other; Integer permissionLevel; + Integer uiPosition; private static final Map keysToPerms; static { @@ -24,11 +25,17 @@ public class ListShare { keysToPerms = Collections.unmodifiableMap(keysToPermsTemp); } - public ListShare(Integer listID, String shareWithEmail, Integer permissionLevel, ListShare[] other) { + public ListShare(Integer listID, String shareWithEmail, Integer permissionLevel, Integer uiPosition, ListShare[] other) { this.listID = listID; this.shareWithEmail = shareWithEmail; this.permissionLevel = permissionLevel; this.other = other; + this.uiPosition = uiPosition; + } + + public ListShare(Integer listID, String shareWithEmail, String permissionsRaw, Integer uiPosition, ListShare[] other) { + this(listID, shareWithEmail, permissionsRaw, other); + this.uiPosition = uiPosition; } public ListShare(Integer listID, String shareWithEmail, String permissionsRaw, ListShare[] other) { @@ -42,6 +49,7 @@ public class ListShare { permissionLevel *= keytoPermEntry.getKey(); } } + this.uiPosition = -1; } @Override @@ -53,14 +61,16 @@ public class ListShare { " [Permissions: "); int permissionLevelCopy = permissionLevel; - for (Integer permissionObject : keysToPerms.keySet()) { - Integer permissionInteger = permissionObject; - if (permissionLevelCopy % permissionInteger == 0) { - permissionLevelCopy /= permissionInteger; - toReturn.append(keysToPerms.get(permissionInteger)).append(","); + if (permissionLevel > 0) { + for (Integer permissionObject : keysToPerms.keySet()) { + Integer permissionInteger = permissionObject; + if (permissionLevelCopy % permissionInteger == 0) { + permissionLevelCopy /= permissionInteger; + toReturn.append(keysToPerms.get(permissionInteger)).append(","); + } } } - if (BuildConfig.DEBUG && permissionLevelCopy != 1) { + if (BuildConfig.DEBUG && (permissionLevelCopy != 1 && permissionLevelCopy != 0)) { throw new AssertionError("Assertion failed"); } toReturn.append("]}"); diff --git a/Listify/app/src/main/java/com/example/listify/data/Picture.java b/Listify/app/src/main/java/com/example/listify/data/Picture.java new file mode 100644 index 0000000..59578cb --- /dev/null +++ b/Listify/app/src/main/java/com/example/listify/data/Picture.java @@ -0,0 +1,24 @@ +package com.example.listify.data; + +public class Picture { + String base64EncodedImage; + + public Picture(String base64EncodedImage) { + this.base64EncodedImage = base64EncodedImage; + } + + @Override + public String toString() { + return "Picture{" + + "base64EncodedImage='" + base64EncodedImage + '\'' + + '}'; + } + + public String getBase64EncodedImage() { + return base64EncodedImage; + } + + public void setBase64EncodedImage(String base64EncodedImage) { + this.base64EncodedImage = base64EncodedImage; + } +} 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 index 65ba3e6..e12952d 100644 --- a/Listify/app/src/main/java/com/example/listify/data/User.java +++ b/Listify/app/src/main/java/com/example/listify/data/User.java @@ -1,4 +1,27 @@ package com.example.listify.data; public class User { + String cognitoID; + String email; + + public User(String cognitoID, String email) { + this.cognitoID = cognitoID; + this.email = email; + } + + public String getCognitoID() { + return cognitoID; + } + + public void setCognitoID(String cognitoID) { + this.cognitoID = cognitoID; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } } 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 3a93463..eb65496 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 @@ -6,24 +6,15 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ListView; import android.widget.ProgressBar; -import android.widget.RelativeLayout; import android.widget.TextView; import android.widget.Toast; - import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; - -import com.example.listify.AuthManager; -import com.example.listify.CreateListDialogFragment; -import com.example.listify.LoadingCircleDialog; -import com.example.listify.R; -import com.example.listify.Requestor; -import com.example.listify.SynchronousReceiver; +import com.example.listify.*; import com.example.listify.adapter.ShoppingListsSwipeableAdapter; import com.example.listify.data.List; import com.google.android.material.floatingactionbutton.FloatingActionButton; - import org.json.JSONException; import java.io.IOException; @@ -157,6 +148,9 @@ public class HomeFragment extends Fragment implements CreateListDialogFragment.O Integer[] listIds = (Integer[]) delivered; // Create threads and add them to a list + if (listIds == null) { + return; + } Thread[] threads = new Thread[listIds.length]; List[] results = new List[listIds.length]; for (int i = 0; i < listIds.length; i++) { diff --git a/Listify/app/src/main/java/com/example/listify/ui/profile/ProfileFragment.java b/Listify/app/src/main/java/com/example/listify/ui/profile/ProfileFragment.java index 546d78d..42f5201 100644 --- a/Listify/app/src/main/java/com/example/listify/ui/profile/ProfileFragment.java +++ b/Listify/app/src/main/java/com/example/listify/ui/profile/ProfileFragment.java @@ -33,7 +33,14 @@ public class ProfileFragment extends Fragment { View root = inflater.inflate(R.layout.fragment_profile, container, false); TextView emailText = (TextView) root.findViewById(R.id.textViewEmail); - emailText.setText(am.getEmail()); + Properties configs = new Properties(); + try { + configs = AuthManager.loadProperties(getContext(), "android.resource://" + getActivity().getPackageName() + "/raw/auths.json"); + } catch (IOException | JSONException e) { + e.printStackTrace(); + } + Requestor requestor = new Requestor(am, configs.getProperty("apiKey")); + emailText.setText(am.getEmail(requestor)); toDeleteAccountPage = (Button) root.findViewById(R.id.button); toDeleteAccountPage.setOnClickListener(new View.OnClickListener() { diff --git a/Listify/app/src/main/res/layout/activity_listofsharees.xml b/Listify/app/src/main/res/layout/activity_listofsharees.xml index 58747d3..53fd6c3 100644 --- a/Listify/app/src/main/res/layout/activity_listofsharees.xml +++ b/Listify/app/src/main/res/layout/activity_listofsharees.xml @@ -3,20 +3,36 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - + android:text="Enter the email of the user you want to share the list with." + android:layout_marginTop="10dp" + android:layout_marginLeft="13dp"/> + + + +