From 0550ae4faf0ad07b7169a4223e325fb5a4cea399 Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Fri, 27 Nov 2020 15:08:21 -0500 Subject: [PATCH 01/10] duplicate lists functionality --- .../java/com/example/listify/ListPage.java | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) 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..b695e23 100644 --- a/Listify/app/src/main/java/com/example/listify/ListPage.java +++ b/Listify/app/src/main/java/com/example/listify/ListPage.java @@ -59,14 +59,16 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { Map storeHeaderIndex = new HashMap<>(); DecimalFormat df = new DecimalFormat("0.00"); + int LIST_ID; + String LIST_NAME; @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"); + LIST_ID = (int) getIntent().getSerializableExtra("listID"); + LIST_NAME = (String) getIntent().getSerializableExtra("listName"); setTitle(LIST_NAME); Properties configs = new Properties(); @@ -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(LIST_ID, String.format("%s copy", LIST_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.postObject(duplicate); + } catch (JSONException e) { + e.printStackTrace(); + } + + Toast.makeText(ListPage.this, "List duplicated", Toast.LENGTH_SHORT).show(); return false; } }); From b81f3b3fd6b04af736ea66e171d1a084abb4c2a5 Mon Sep 17 00:00:00 2001 From: NMerz Date: Fri, 27 Nov 2020 17:35:17 -0500 Subject: [PATCH 02/10] Add profile picture on client Display and allow for selection of profile picture --- Listify/app/build.gradle | 2 + Listify/app/src/main/AndroidManifest.xml | 15 +++ .../com/example/listify/MainActivity.java | 107 +++++++++++++++++- .../src/main/res/layout/nav_header_main.xml | 44 +++---- .../src/main/res/raw/ic_launcher_round.png | Bin 0 -> 16570 bytes Listify/app/src/main/res/xml/file_paths.xml | 4 + 6 files changed, 149 insertions(+), 23 deletions(-) create mode 100644 Listify/app/src/main/res/raw/ic_launcher_round.png create mode 100644 Listify/app/src/main/res/xml/file_paths.xml 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..cf117a8 100644 --- a/Listify/app/src/main/AndroidManifest.xml +++ b/Listify/app/src/main/AndroidManifest.xml @@ -3,6 +3,9 @@ package="com.example.listify"> + + + + + + + + + { + 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.setNeutralButton("Select picture", (dialog, which) -> { + Intent pickPhoto = new Intent(Intent.ACTION_PICK, + MediaStore.Images.Media.EXTERNAL_CONTENT_URI); + startActivityForResult(pickPhoto, IMAGE_SELECT); + }); + builder.setNegativeButton("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 +223,55 @@ public class MainActivity extends AppCompatActivity implements CreateListDialogF }); } + protected void onActivityResult (int requestCode, + int resultCode, + Intent data) { + Uri selectedImage = null; + switch (requestCode){ + case CAMERA_CAPTURE: + Log.i("Profile Picture", "Pulling image file at " + this.newImageFileLocation.getAbsolutePath()); + selectedImage = Uri.fromFile(this.newImageFileLocation); + break; + case IMAGE_SELECT: + if ((data == null) || (data.getData() == null)) { + return; + } + selectedImage = data.getData(); + break; + } + + MainActivity.super.onActivityResult(requestCode, resultCode, data); + NavigationView navigationView = findViewById(R.id.nav_view); + ImageView profilePicture = navigationView.getHeaderView(0).findViewById(R.id.imageViewProfilePicture); + profilePicture.setImageURI(selectedImage); + } + + //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 +310,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/res/layout/nav_header_main.xml b/Listify/app/src/main/res/layout/nav_header_main.xml index 3f4a0fa..4014ebb 100644 --- a/Listify/app/src/main/res/layout/nav_header_main.xml +++ b/Listify/app/src/main/res/layout/nav_header_main.xml @@ -1,8 +1,9 @@ - - - - - - - - - - - - - + + + - - - - - + + \ No newline at end of file diff --git a/Listify/app/src/main/res/raw/ic_launcher_round.png b/Listify/app/src/main/res/raw/ic_launcher_round.png new file mode 100644 index 0000000000000000000000000000000000000000..e96783ccce844001359f968f5cd9d85b341bd3fb GIT binary patch literal 16570 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 literal 0 HcmV?d00001 diff --git a/Listify/app/src/main/res/xml/file_paths.xml b/Listify/app/src/main/res/xml/file_paths.xml new file mode 100644 index 0000000..3197349 --- /dev/null +++ b/Listify/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file From c0a93e3684cbba0ff737819b66436cf3efdf3a9c Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Fri, 27 Nov 2020 18:13:37 -0500 Subject: [PATCH 03/10] Rename list functionality --- .../java/com/example/listify/ListPage.java | 55 ++++++++++---- .../listify/RenameListDialogFragment.java | 71 +++++++++++++++++++ .../ShoppingListsSwipeableAdapter.java | 11 +-- .../java/com/example/listify/data/List.java | 3 +- .../com/example/listify/data/ListEntry.java | 4 +- .../main/res/layout/dialog_rename_list.xml | 22 ++++++ 6 files changed, 146 insertions(+), 20 deletions(-) create mode 100644 Listify/app/src/main/java/com/example/listify/RenameListDialogFragment.java create mode 100644 Listify/app/src/main/res/layout/dialog_rename_list.xml 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 b695e23..86bbdee 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,16 @@ package com.example.listify; -import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; 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 +28,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,17 +60,15 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { Map storeHeaderIndex = new HashMap<>(); DecimalFormat df = new DecimalFormat("0.00"); - int LIST_ID; - String LIST_NAME; + List selectedList; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_list); - LIST_ID = (int) getIntent().getSerializableExtra("listID"); - LIST_NAME = (String) getIntent().getSerializableExtra("listName"); - setTitle(LIST_NAME); + selectedList = (List) getIntent().getSerializableExtra("selectedList"); + setTitle(selectedList.getName()); Properties configs = new Properties(); try { @@ -78,7 +77,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); @@ -160,7 +159,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); } }); } @@ -168,16 +167,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; } }); @@ -196,7 +195,7 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { @Override public boolean onMenuItemClick(MenuItem item) { - ListDuplicate duplicate = new ListDuplicate(LIST_ID, String.format("%s copy", LIST_NAME)); + ListDuplicate duplicate = new ListDuplicate(selectedList.getListID(), String.format("%s copy", selectedList.getName())); Properties configs = new Properties(); try { @@ -348,6 +347,34 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { 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/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/ShoppingListsSwipeableAdapter.java b/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java index fbdf493..dc2bd72 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 @@ -100,7 +100,11 @@ public class ShoppingListsSwipeableAdapter extends BaseAdapter { 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 @@ -161,9 +165,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/res/layout/dialog_rename_list.xml b/Listify/app/src/main/res/layout/dialog_rename_list.xml new file mode 100644 index 0000000..55ca2e1 --- /dev/null +++ b/Listify/app/src/main/res/layout/dialog_rename_list.xml @@ -0,0 +1,22 @@ + + + + + + + \ No newline at end of file From cf4791badc1352142cedf4697dbc8ff26e05d594 Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Fri, 27 Nov 2020 18:21:26 -0500 Subject: [PATCH 04/10] Removed share button from sliding lists --- .../adapter/ShareeSwipeableAdapter.java | 14 ++-- .../ShoppingListsSwipeableAdapter.java | 74 +++++++++---------- .../shopping_lists_swipeable_name_item.xml | 12 +-- 3 files changed, 50 insertions(+), 50 deletions(-) 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/ShoppingListsSwipeableAdapter.java b/Listify/app/src/main/java/com/example/listify/adapter/ShoppingListsSwipeableAdapter.java index dc2bd72..3f5d7a7 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 @@ -79,7 +79,7 @@ public class ShoppingListsSwipeableAdapter 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.listName = (TextView) convertView.findViewById(R.id.shopping_list_name); holder.itemCount = (TextView) convertView.findViewById(R.id.shopping_list_item_count); @@ -124,41 +124,41 @@ 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(); - - Toast.makeText(activity, String.format("Share %s", curList.getName()), Toast.LENGTH_SHORT).show(); - - // Close the layout - binderHelper.closeLayout(Integer.toString(curList.getListID())); - } - }); +// 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(); +// +// Toast.makeText(activity, String.format("Share %s", curList.getName()), Toast.LENGTH_SHORT).show(); +// +// // Close the layout +// binderHelper.closeLayout(Integer.toString(curList.getListID())); +// } +// }); holder.frontView.setOnClickListener(new View.OnClickListener() { @Override @@ -179,7 +179,7 @@ public class ShoppingListsSwipeableAdapter extends BaseAdapter { SwipeRevealLayout swipeLayout; View frontView; View deleteList; - View shareList; +// View shareList; TextView listName; TextView itemCount; } diff --git a/Listify/app/src/main/res/layout/shopping_lists_swipeable_name_item.xml b/Listify/app/src/main/res/layout/shopping_lists_swipeable_name_item.xml index 9ecf6db..df2c9e7 100644 --- a/Listify/app/src/main/res/layout/shopping_lists_swipeable_name_item.xml +++ b/Listify/app/src/main/res/layout/shopping_lists_swipeable_name_item.xml @@ -17,12 +17,12 @@ android:layout_width="wrap_content" android:layout_height="wrap_content"> - + + + + + + Date: Sat, 28 Nov 2020 21:14:57 -0500 Subject: [PATCH 05/10] Finished pull-to-refresh on list activity --- .../java/com/example/listify/ListPage.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) 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 fd6c3fe..1cfeb24 100644 --- a/Listify/app/src/main/java/com/example/listify/ListPage.java +++ b/Listify/app/src/main/java/com/example/listify/ListPage.java @@ -205,19 +205,20 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { @Override public void acceptDelivery(Object delivered) { // Clear out old values + pNames.clear(); + pStores.clear(); + pPrices.clear(); + pQuantity.clear(); + pImages.clear(); + totalPriceByStore.clear(); + storeID2Name.clear(); + storeHeaderIndex.clear(); + pListItemPair.clear(); + totalPrice = 0; + 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)); } }); From b12509cf5b97dcff3d27694592fe0e5afd3e1f6d Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Sun, 29 Nov 2020 12:55:30 -0500 Subject: [PATCH 06/10] Display android sharesheet --- .../java/com/example/listify/ListPage.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) 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 1cfeb24..ef5a684 100644 --- a/Listify/app/src/main/java/com/example/listify/ListPage.java +++ b/Listify/app/src/main/java/com/example/listify/ListPage.java @@ -3,6 +3,7 @@ package com.example.listify; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; +import android.content.Intent; import android.os.Bundle; import android.util.Log; import android.view.*; @@ -194,6 +195,17 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { exportItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { + String listContent = ""; + + + Intent sendIntent = new Intent(); + sendIntent.setAction(Intent.ACTION_SEND); + sendIntent.putExtra(Intent.EXTRA_TEXT, "this is my text test"); + sendIntent.setType("text/plain"); + + Intent shareIntent = Intent.createChooser(sendIntent, null); + startActivity(shareIntent); + Toast.makeText(ListPage.this, "Export List", Toast.LENGTH_SHORT).show(); return false; } @@ -215,13 +227,6 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { storeHeaderIndex.clear(); pListItemPair.clear(); totalPrice = 0; - - runOnUiThread(new Runnable() { - @Override - public void run() { - tvTotalPrice.setText(String.format("$%.2f", totalPrice)); - } - }); List list = (List) delivered; @@ -313,6 +318,13 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver { }); } + runOnUiThread(new Runnable() { + @Override + public void run() { + tvTotalPrice.setText(String.format("$%.2f", totalPrice)); + } + }); + refreshList.setRefreshing(false); } From d9dbe45d7b00d730dfa96174ef04954804e3949e Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Sun, 29 Nov 2020 13:40:46 -0500 Subject: [PATCH 07/10] Export lists to other apps --- .../src/main/java/com/example/listify/ListPage.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) 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 c882416..2d658a3 100644 --- a/Listify/app/src/main/java/com/example/listify/ListPage.java +++ b/Listify/app/src/main/java/com/example/listify/ListPage.java @@ -221,12 +221,19 @@ public class ListPage extends AppCompatActivity implements Requestor.Receiver, R exportItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { - String listContent = ""; + 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, "this is my text test"); + sendIntent.putExtra(Intent.EXTRA_TEXT, listContents.toString()); sendIntent.setType("text/plain"); Intent shareIntent = Intent.createChooser(sendIntent, null); From bede2fc1a09b5c74475195031445685b57a64bc3 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sun, 29 Nov 2020 14:06:02 -0500 Subject: [PATCH 08/10] ListShare compiling Make ListShare compile again --- Lambdas/Lists/List/src/List.java | 3 - Lambdas/Lists/ListShare/src/ListShare.java | 4 +- .../Lists/ListShare/src/ListShareDELETE.java | 12 ---- .../Lists/ListShare/src/ListShareDeleter.java | 65 ------------------- .../Lists/ListShare/src/ListShareGetter.java | 3 +- .../com/example/listify/MainActivity.java | 4 +- 6 files changed, 6 insertions(+), 85 deletions(-) delete mode 100644 Lambdas/Lists/ListShare/src/ListShareDELETE.java delete mode 100644 Lambdas/Lists/ListShare/src/ListShareDeleter.java diff --git a/Lambdas/Lists/List/src/List.java b/Lambdas/Lists/List/src/List.java index fd73808..30cd7da 100644 --- a/Lambdas/Lists/List/src/List.java +++ b/Lambdas/Lists/List/src/List.java @@ -85,9 +85,6 @@ public class List { public void setUiPosition(Integer uiPosition) { this.uiPosition = uiPosition; - - public ItemEntry[] getEntries() { - return entries.toArray(new ItemEntry[entries.size()]); } public void addItemEntry(ItemEntry entry) { diff --git a/Lambdas/Lists/ListShare/src/ListShare.java b/Lambdas/Lists/ListShare/src/ListShare.java index 151d842..d73368d 100644 --- a/Lambdas/Lists/ListShare/src/ListShare.java +++ b/Lambdas/Lists/ListShare/src/ListShare.java @@ -1,4 +1,6 @@ -package com.example.listify.data; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; public class ListShare { Integer listID; diff --git a/Lambdas/Lists/ListShare/src/ListShareDELETE.java b/Lambdas/Lists/ListShare/src/ListShareDELETE.java deleted file mode 100644 index 784a725..0000000 --- a/Lambdas/Lists/ListShare/src/ListShareDELETE.java +++ /dev/null @@ -1,12 +0,0 @@ -import com.amazonaws.services.lambda.runtime.Context; -import com.amazonaws.services.lambda.runtime.RequestHandler; - -import java.util.Map; - -public class ListShareDELETE implements RequestHandler, Object> { - - public Object handleRequest(Map inputMap, Context unfilled) { - return BasicHandler.handleRequest(inputMap, unfilled, ListShareDeleter.class); - } - -} 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..273b8cd 100644 --- a/Lambdas/Lists/ListShare/src/ListShareGetter.java +++ b/Lambdas/Lists/ListShare/src/ListShareGetter.java @@ -2,7 +2,6 @@ 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; @@ -21,7 +20,7 @@ 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(); 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 83f8d7c..e19570d 100644 --- a/Listify/app/src/main/java/com/example/listify/MainActivity.java +++ b/Listify/app/src/main/java/com/example/listify/MainActivity.java @@ -192,12 +192,12 @@ public class MainActivity extends AppCompatActivity implements CreateListDialogF takePicture.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(takePicture, CAMERA_CAPTURE); }); - builder.setNeutralButton("Select picture", (dialog, which) -> { + builder.setNegativeButton("Select picture", (dialog, which) -> { Intent pickPhoto = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(pickPhoto, IMAGE_SELECT); }); - builder.setNegativeButton("Cancel", (dialog, which) -> { + builder.setNeutralButton("Cancel", (dialog, which) -> { }); AlertDialog dialog = builder.create(); dialog.show(); From 70195632f87cd8fb2bc547653c4c57e7c7a97525 Mon Sep 17 00:00:00 2001 From: NMerz Date: Sun, 29 Nov 2020 15:19:10 -0500 Subject: [PATCH 09/10] Store Profile Picture on AWS Save the profile picture to AWS so that the user need not retrieve it every time. --- Lambdas/Lists/Picture/src/Picture.java | 34 +++++ Lambdas/Lists/Picture/src/PictureGET.java | 12 ++ Lambdas/Lists/Picture/src/PictureGetter.java | 34 +++++ Lambdas/Lists/Picture/src/PicturePUT.java | 11 ++ Lambdas/Lists/Picture/src/PicturePutter.java | 28 +++++ .../com/example/listify/MainActivity.java | 116 +++++++++++++++++- .../com/example/listify/data/Picture.java | 24 ++++ 7 files changed, 254 insertions(+), 5 deletions(-) create mode 100644 Lambdas/Lists/Picture/src/Picture.java create mode 100644 Lambdas/Lists/Picture/src/PictureGET.java create mode 100644 Lambdas/Lists/Picture/src/PictureGetter.java create mode 100644 Lambdas/Lists/Picture/src/PicturePUT.java create mode 100644 Lambdas/Lists/Picture/src/PicturePutter.java create mode 100644 Listify/app/src/main/java/com/example/listify/data/Picture.java 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/Picture/src/PicturePUT.java b/Lambdas/Lists/Picture/src/PicturePUT.java new file mode 100644 index 0000000..43fc914 --- /dev/null +++ b/Lambdas/Lists/Picture/src/PicturePUT.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 PicturePUT implements RequestHandler, Object> { + + public Object handleRequest(Map inputMap, Context unfilled) { + 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/Listify/app/src/main/java/com/example/listify/MainActivity.java b/Listify/app/src/main/java/com/example/listify/MainActivity.java index e19570d..7bbaf0c 100644 --- a/Listify/app/src/main/java/com/example/listify/MainActivity.java +++ b/Listify/app/src/main/java/com/example/listify/MainActivity.java @@ -1,12 +1,16 @@ 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; @@ -24,12 +28,12 @@ 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.Picture; import com.example.listify.ui.LoginPage; import com.google.android.material.navigation.NavigationView; import org.json.JSONException; -import java.io.File; -import java.io.IOException; +import java.io.*; import java.text.SimpleDateFormat; import java.time.Instant; import java.util.Date; @@ -169,9 +173,22 @@ public class MainActivity extends AppCompatActivity implements CreateListDialogF TextView emailView = navigationView.getHeaderView(0).findViewById(R.id.textViewEmailSidebar); emailView.setText(am.getEmail()); - - ImageView profilePicture = navigationView.getHeaderView(0).findViewById(R.id.imageViewProfilePicture); - profilePicture.setOnClickListener(new View.OnClickListener() { + 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")); + 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) { @@ -223,27 +240,116 @@ 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 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; + } +} From 8ecee59da91e8e73949482c45915bd04670a24bc Mon Sep 17 00:00:00 2001 From: NMerz Date: Sun, 29 Nov 2020 15:45:08 -0500 Subject: [PATCH 10/10] Make ListShareGET work Fix absolute functionality-breaking bugs. There is still a fair amount of funkiness and lack of polish (such as having other and entried in the Lambda return). In addition, the NULL uiPositions that got put in the database may need cleaning up manually. --- Lambdas/Lists/ListShare/src/ListShare.java | 39 +++++++++++++++++++ .../com/example/listify/data/ListShare.java | 10 ++++- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Lambdas/Lists/ListShare/src/ListShare.java b/Lambdas/Lists/ListShare/src/ListShare.java index d73368d..60e3fde 100644 --- a/Lambdas/Lists/ListShare/src/ListShare.java +++ b/Lambdas/Lists/ListShare/src/ListShare.java @@ -5,14 +5,53 @@ import java.util.ArrayList; public class ListShare { Integer listID; String shareWithEmail; + Integer permissionLevel; + Integer uiPosition; ArrayList other; public ListShare(ResultSet listRow) throws SQLException { this.listID = listRow.getInt("listID"); this.shareWithEmail = listRow.getString("userID"); + 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/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..3958df8 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