diff --git a/app/build.gradle b/app/build.gradle index 21fe081..1f99868 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -44,6 +44,7 @@ dependencies { implementation 'com.google.firebase:firebase-auth:19.4.0' implementation 'com.github.addisonelliott:SegmentedButton:3.1.9' implementation 'com.google.firebase:firebase-firestore:21.6.0' + implementation 'com.google.firebase:firebase-storage:19.2.1' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index cf8367b..7b89ce3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,16 +2,26 @@ + + + + + + + + android:theme="@style/Theme.StormWaterUtilityAndroid" android:requestLegacyExternalStorage="true"> @@ -27,12 +37,21 @@ + + + + + + + + + diff --git a/app/src/main/java/com/sf/stormwaterutilityandroid/ConstructionFormData.java b/app/src/main/java/com/sf/stormwaterutilityandroid/ConstructionFormData.java index bef4f17..8c1b45f 100644 --- a/app/src/main/java/com/sf/stormwaterutilityandroid/ConstructionFormData.java +++ b/app/src/main/java/com/sf/stormwaterutilityandroid/ConstructionFormData.java @@ -22,6 +22,17 @@ public class ConstructionFormData implements Serializable { List answers; List imgLink; + + public ConstructionFormData(String contact, String date, String inspector, + String location, List answers, List imgLinks) { + data = new HashMap<>(); + data.put("contact", contact); + data.put("date", date); + data.put("inspector", inspector); + data.put("location", location); + data.put("answers", answers); + data.put("imgLinks", imgLinks); + public ConstructionFormData(String contact, String date, String inspector, Date timestamp, String location, GeoPoint geoPoint, List answers, List imgLinks) { this.contact = contact; @@ -119,6 +130,7 @@ public List getImgLink() { public void setImgLink(List imgLink) { this.imgLink = imgLink; + } public Map getMap() { diff --git a/app/src/main/java/com/sf/stormwaterutilityandroid/ImageAttachForm.java b/app/src/main/java/com/sf/stormwaterutilityandroid/ImageAttachForm.java new file mode 100644 index 0000000..f64bfc2 --- /dev/null +++ b/app/src/main/java/com/sf/stormwaterutilityandroid/ImageAttachForm.java @@ -0,0 +1,200 @@ +package com.sf.stormwaterutilityandroid; + +import android.Manifest; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.provider.MediaStore; +import android.widget.Button; +import android.widget.ImageView; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.core.app.ActivityCompat; +import androidx.core.content.ContextCompat; + +import java.io.ByteArrayOutputStream; +import java.io.Serializable; +import java.util.ArrayList; + +import javax.annotation.Nullable; + +public class ImageAttachForm extends AppCompatActivity { + private static final int OPEN_GALLERY_REQUEST = 2; + private static final int OPEN_CAMERA_REQUEST = 3; + + private Button uploadCameraImageBtn; + private Button uploadGalleryImageBtn; + private Button uploadImageBackBtn; + + + private ArrayList imageURIs; + + private ArrayList imageViews; + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_image_attach_form); + + this.uploadCameraImageBtn = findViewById(R.id.uploadCameraImageBtn); + this.uploadGalleryImageBtn = findViewById(R.id.uploadGalleryImageBtn); + this.uploadImageBackBtn = findViewById(R.id.uploadImageBackBtn); + + // this.imageView = findViewById(R.id.ImageView1); + + + // this.imageUri = null; + + this.imageURIs = new ArrayList<>(3); + + imageViews = new ArrayList<>(); + + this.imageViews.add(findViewById(R.id.ImageView1)); + this.imageViews.add(findViewById(R.id.ImageView2)); + this.imageViews.add(findViewById(R.id.ImageView3)); + + initActionListeners(); + } + + private void initActionListeners() { + + uploadImageBackBtn.setOnClickListener(view -> { + if (imageURIs == null) { + setResult(RESULT_CANCELED); + finish(); + } + + Intent data = new Intent(); + // data.putExtra("imageURIs", imageURIs.toArray()); + Bundle args = new Bundle(); + args.putSerializable("IMAGEURIS", (Serializable) imageURIs); + data.putExtra("BUNDLE", args); + setResult(RESULT_OK, data); + finish(); + }); + + + // pick from gallery + uploadGalleryImageBtn.setOnClickListener(view -> { + chooseGalleryImage(); + }); + + // pick from camera + uploadCameraImageBtn.setOnClickListener(view -> { + // request camera permission if not granted already + if (ContextCompat.checkSelfPermission(ImageAttachForm.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + ActivityCompat.requestPermissions(ImageAttachForm.this, + new String[]{ + Manifest.permission.CAMERA + }, + 100); + } + + chooseCameraImage(); + }); + + imageViews.get(0).setOnClickListener(view -> { + imageURIs.remove(0); + updateImageViews(); + }); + + imageViews.get(1).setOnClickListener(view -> { + imageURIs.remove(1); + updateImageViews(); + }); + + imageViews.get(2).setOnClickListener(view -> { + imageURIs.remove(2); + updateImageViews(); + }); + } + + private void chooseCameraImage() { + Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); + startActivityForResult(intent, OPEN_CAMERA_REQUEST); + } + + + private void chooseGalleryImage() { + Intent intent = new Intent(); + intent.setType("image/*"); + intent.setAction(Intent.ACTION_GET_CONTENT); + startActivityForResult(intent, OPEN_GALLERY_REQUEST); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + if (requestCode == OPEN_GALLERY_REQUEST && resultCode == RESULT_OK && data != null && data.getData() != null) { + Uri newImageUri = data.getData(); + //this.imageView.setImageURI(imageUri); + addImage(newImageUri); + + // uploadPicture(); + } else if (requestCode == OPEN_CAMERA_REQUEST && resultCode == RESULT_OK && data != null && data.getExtras() != null) { + Bundle extras = data.getExtras(); + Bitmap imageBitmap = (Bitmap) extras.get("data"); + + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + imageBitmap.compress(Bitmap.CompressFormat.JPEG, 100, bytes); + String path = MediaStore.Images.Media.insertImage(getContentResolver(), imageBitmap, "Title", null); +// this.imageUri = Uri.parse(path); + Uri newImageUri = Uri.parse(path); + addImage(newImageUri); + + + // uploadPicture(); + } + } + +// private void uploadPicture() { +// final String randomKey = UUID.randomUUID().toString(); +// StorageReference storageRef = storageReference.child("images/" + randomKey); +// storageRef.putFile(imageUri) +// .addOnSuccessListener(new OnSuccessListener() { +// @Override +// public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { +// System.out.println("SUCCESSS!!!"); +// Task downloadUri = taskSnapshot.getStorage().getDownloadUrl(); +// System.out.println("downloadUri: " + downloadUri); +// } +// }) +// .addOnFailureListener(new OnFailureListener() { +// @Override +// public void onFailure(@NonNull Exception e) { +// System.out.println("FAILEDDD"); +// } +// }); +// } + + // adds image to imageURIs list and to the recycle view of displayed images + private void addImage(Uri newImageUri) { + System.out.println("Image URI HEREEE!!!: " + newImageUri); + + + if (imageURIs.size() == 3) { + // send message to remove 1 + System.out.println("EARLY RETURN !!!!!"); + return; + } + + this.imageURIs.add(newImageUri); + + System.out.println("ImageURIs:\n" + imageURIs); + updateImageViews(); + } + + private void updateImageViews() { + // set images to first views + int i = 0; + for (i = 0; i < imageURIs.size(); i++) { + imageViews.get(i).setImageURI(imageURIs.get(i)); + } + + // set the rest to invisible + while (i < 3) imageViews.get(i++).setImageURI(null); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/sf/stormwaterutilityandroid/InspectionForm.java b/app/src/main/java/com/sf/stormwaterutilityandroid/InspectionForm.java index 35c17db..296a7c5 100644 --- a/app/src/main/java/com/sf/stormwaterutilityandroid/InspectionForm.java +++ b/app/src/main/java/com/sf/stormwaterutilityandroid/InspectionForm.java @@ -1,16 +1,28 @@ package com.sf.stormwaterutilityandroid; +import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.widget.Button; +import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.recyclerview.widget.RecyclerView; +import com.google.android.gms.tasks.OnFailureListener; +import com.google.android.gms.tasks.OnSuccessListener; +import com.google.android.gms.tasks.Task; import com.google.firebase.firestore.FirebaseFirestore; +import com.google.firebase.storage.FirebaseStorage; +import com.google.firebase.storage.StorageReference; +import com.google.firebase.storage.UploadTask; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.UUID; + +import javax.annotation.Nullable; import me.riddhimanadib.formmaster.FormBuilder; import me.riddhimanadib.formmaster.model.BaseFormElement; @@ -23,27 +35,37 @@ import me.riddhimanadib.formmaster.model.FormHeader; public class InspectionForm extends AppCompatActivity { + private final int UPLOAD_IMAGE_REQUEST = 1; + private RecyclerView recyclerView; + private Button submitButton; + private Button uploadImageBtn; + + private FirebaseStorage storage; + private StorageReference storageReference; + + private ArrayList imageURIs; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_sample_fordm); + recyclerView = findViewById(R.id.recyclerView2); + + this.submitButton = findViewById(R.id.submitButton); + this.uploadImageBtn = findViewById(R.id.uploadImageBtn); + // submitButton = findViewById(R.id.submitButton); - setupForm(); - } - private void uploadToFirestore(ConstructionFormData constructionFormData) { - FirebaseFirestore db = FirebaseFirestore.getInstance(); - db.collection("ConstructionSiteForm") - .add(constructionFormData.getMap()) - .addOnSuccessListener(documentReference -> System.out.println("SUCCESSFUL - FIRESTORE")) - .addOnFailureListener(e -> System.out.println("FAILED - FIRESTORE: " + e)); + this.storage = FirebaseStorage.getInstance(); + this.storageReference = storage.getReference(); + + setupForm(); } private void setupForm() { @@ -81,7 +103,7 @@ private void setupForm() { FormElementSwitch correctiveAction4Switch = FormElementSwitch.createInstance().setTitle("Individual Building Lot(s)").setSwitchTexts("Yes", "No"); FormHeader correctiveAction5Header = FormHeader.createInstance(""); - List correctiveAction5Options= new ArrayList<>(Arrays.asList("Repair", "Install properly"," Replace", "Add (areas prone to sheet-flow erosion)")); + List correctiveAction5Options = new ArrayList<>(Arrays.asList("Repair", "Install properly", " Replace", "Add (areas prone to sheet-flow erosion)")); FormElementPickerMulti correctiveAction5Multi = FormElementPickerMulti.createInstance().setTitle("Address silt fence issues which includes one or more of the following: Repair, install properly, Replace, Add (areas prone to sheet-flow erosion)").setOptions(correctiveAction5Options).setPickerTitle("Address silt fence issues which includes one or more of the following:"); FormElementSwitch correctiveAction6Switch = FormElementSwitch.createInstance().setTitle("Install erosions and sediment control for individual building lot(s) as specified in the approved SWP3").setSwitchTexts("Yes", "No"); @@ -90,7 +112,7 @@ private void setupForm() { FormElementSwitch correctiveAction9Switch = FormElementSwitch.createInstance().setTitle("Individual Building Lot(s)").setSwitchTexts("Yes", "No"); FormHeader correctiveAction10Header = FormHeader.createInstance(""); - List correctiveAction10Options= new ArrayList<>(Arrays.asList("sediment traps", "behind check dams", "around storm drain inlets or/and other")); + List correctiveAction10Options = new ArrayList<>(Arrays.asList("sediment traps", "behind check dams", "around storm drain inlets or/and other")); FormElementPickerMulti correctiveAction10Multi = FormElementPickerMulti.createInstance().setTitle("Remove sediment from one or more of the following: sediment traps, behind check dams, around storm drain inlets or/and other").setOptions(correctiveAction10Options).setPickerTitle("Pick corrective action"); @@ -158,6 +180,12 @@ private void setupForm() { // populate formBuilder with items formBuilder.addFormElements(formItems); + uploadImageBtn.setOnClickListener(view -> { + Intent intent = new Intent(getApplicationContext(), ImageAttachForm.class); + startActivityForResult(intent, UPLOAD_IMAGE_REQUEST); + }); + + // onSubmit submitButton.setOnClickListener(view -> { @@ -215,12 +243,15 @@ private void setupForm() { List enforcementAction = enforcementActionPickerSingle.getOptionsSelected(); answersList.addAll(enforcementAction); - List imgLink = new ArrayList<>(); - imgLink.add(evidenceTextField.getValue()); - - // ConstructionFormData constructionFormData = new ConstructionFormData(contact, date, inspector, location, answersList, imgLink); + List imgLinks = new ArrayList<>(); + for (Uri imageUri : imageURIs) { + imgLinks.add(uploadPicture(imageUri)); + } + System.out.println(imgLinks); + ConstructionFormData constructionFormData = new ConstructionFormData(contact, date, inspector, location, answersList, imgLinks); + System.out.println(constructionFormData); // submit data to firestore // uploadToFirestore(constructionFormData); }); @@ -228,9 +259,56 @@ private void setupForm() { } + // result of getting added images + @Override + protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { + super.onActivityResult(requestCode, resultCode, data); + + if (requestCode == UPLOAD_IMAGE_REQUEST && resultCode == RESULT_OK && data != null && data.getExtras() != null) { + System.out.println("IM HERE!\n"); + Bundle args = data.getBundleExtra("BUNDLE"); + this.imageURIs = (ArrayList) args.getSerializable("IMAGEURIS"); + System.out.println(imageURIs); + } + } + + private void uploadToFirestore(ConstructionFormData constructionFormData) { + FirebaseFirestore db = FirebaseFirestore.getInstance(); + db.collection("ConstructionSiteForm") + .add(constructionFormData.getMap()) + .addOnSuccessListener(documentReference -> System.out.println("SUCCESSFUL - FIRESTORE")) + .addOnFailureListener(e -> System.out.println("FAILED - FIRESTORE: " + e)); + } + private String getSwitchBool(FormElementSwitch switchElement) { if (switchElement.getValue().equals("Yes")) return "true"; return "false"; } + private String uploadPicture(Uri imageUri) { + final String[] imageLink = {null}; + + final String randomKey = UUID.randomUUID().toString(); + StorageReference storageRef = storageReference.child("images/" + randomKey); + storageRef.putFile(imageUri) + .addOnSuccessListener(new OnSuccessListener() { + @Override + public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) { + System.out.println("SUCCESSS!!!"); + Task downloadUri = taskSnapshot.getStorage().getDownloadUrl(); + System.out.println("downloadUri: " + downloadUri); + imageLink[0] = downloadUri.toString(); + } + }) + .addOnFailureListener(new OnFailureListener() { + @Override + public void onFailure(@NonNull Exception e) { + System.out.println("FAILEDDD"); + } + }); + + return imageLink[0]; + } + + } diff --git a/app/src/main/res/layout/activity_image_attach_form.xml b/app/src/main/res/layout/activity_image_attach_form.xml new file mode 100644 index 0000000..e7741d4 --- /dev/null +++ b/app/src/main/res/layout/activity_image_attach_form.xml @@ -0,0 +1,76 @@ + + + + + + + +