diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java index b5bb5b87..3470fe5e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java @@ -50,6 +50,7 @@ import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.model.UploadCategory; +import gr.thmmy.mthmmy.model.UploadFile; import gr.thmmy.mthmmy.utils.AppCompatSpinnerWithoutDefault; import gr.thmmy.mthmmy.utils.FileUtils; import gr.thmmy.mthmmy.utils.TakePhoto; @@ -84,10 +85,6 @@ public class UploadActivity extends BaseActivity { */ private static final int UPLOAD_REQUEST_CODE = 42; //Arbitrary, application specific - private static final int NO_UPLOAD_METHOD_SELECTED = 0; - private static final int SELECT_FILE_METHOD_SELECTED = 1; - private static final int TAKE_PHOTO_METHOD_SELECTED = 2; - private static final int MAX_FILE_SIZE_SUPPORTED = 45000000; private ArrayList uploadRootCategories = new ArrayList<>(); @@ -96,9 +93,7 @@ public class UploadActivity extends BaseActivity { private String categorySelected = "-1"; private String uploaderProfileIndex = "1"; - private int uploadMethodSelected = NO_UPLOAD_METHOD_SELECTED; - private Uri fileUri; - private File photoFileSelected = null; + private ArrayList filesList = new ArrayList<>(); private File photoFileCreated = null; private String fileIcon; @@ -110,6 +105,7 @@ public class UploadActivity extends BaseActivity { private EditText uploadFilename; private EditText uploadDescription; private AppCompatButton titleDescriptionBuilderButton; + private LinearLayout filesListView; @Override protected void onCreate(Bundle savedInstanceState) { @@ -247,21 +243,24 @@ public class UploadActivity extends BaseActivity { public void beforeTextChanged(CharSequence s, int start, int count, int after) { oldFilename = s.toString(); - if (fileUri != null) { - String uriExtension = FileUtils.getFileExtension(FileUtils. - filenameFromUri(getApplicationContext(), fileUri)); - - if (fileExtension == null || !fileExtension.equals(uriExtension)) { - //New file selected - //Changes the extension of the saved filename instance - oldFilename = FileUtils.getFilenameWithoutExtension(oldFilename) + - uriExtension; - } - - fileExtension = uriExtension; - } else { + String uriExtension; + if (filesList.isEmpty()) { fileExtension = null; + return; + } else if (filesList.size() == 1) { + uriExtension = FileUtils.getFileExtension(FileUtils. + filenameFromUri(getApplicationContext(), filesList.get(0).getFileUri())); + } else { + uriExtension = ".zip"; } + + if (fileExtension == null || !fileExtension.equals(uriExtension)) { + //New file selected + //Changes the extension of the saved filename instance + oldFilename = FileUtils.getFilenameWithoutExtension(oldFilename) + + uriExtension; + } + fileExtension = uriExtension; } @Override @@ -293,6 +292,8 @@ public class UploadActivity extends BaseActivity { } }); + filesListView = findViewById(R.id.upload_files_list); + AppCompatButton selectFileButton = findViewById(R.id.upload_select_file_button); Drawable selectStartDrawable = AppCompatResources.getDrawable(this, R.drawable.ic_insert_drive_file_white_24dp); selectFileButton.setCompoundDrawablesRelativeWithIntrinsicBounds(selectStartDrawable, null, null, null); @@ -335,7 +336,7 @@ public class UploadActivity extends BaseActivity { uploadTitle.setError("Required"); shouldReturn = true; } - if (fileUri == null) { + if (filesList.isEmpty()) { Toast.makeText(view.getContext(), "Please choose a file to upload or take a photo", Toast.LENGTH_LONG).show(); shouldReturn = true; } @@ -343,11 +344,18 @@ public class UploadActivity extends BaseActivity { Toast.makeText(view.getContext(), "Please choose category first", Toast.LENGTH_SHORT).show(); shouldReturn = true; } - if (fileUri != null && FileUtils.sizeFromUri(this, fileUri) > MAX_FILE_SIZE_SUPPORTED) { - Toast.makeText(view.getContext(), "Your files are too powerful for thmmy. Reduce size or split!", Toast.LENGTH_LONG).show(); - shouldReturn = true; + if (!filesList.isEmpty()) { + long totalFilesSize = 0; + for (UploadFile file : filesList) { + totalFilesSize += FileUtils.sizeFromUri(this, file.getFileUri()); + } + + if (totalFilesSize > MAX_FILE_SIZE_SUPPORTED) { + Toast.makeText(view.getContext(), "Your files are too powerful for thmmy. Reduce size or split!", Toast.LENGTH_LONG).show(); + shouldReturn = true; + } } - if (!editTextFilename.matches("(.+\\.)+.+")){ + if (!editTextFilename.matches("(.+\\.)+.+")) { uploadFilename.setError("Invalid filename"); shouldReturn = true; } @@ -363,42 +371,51 @@ public class UploadActivity extends BaseActivity { uploadDescriptionText += uploadedFromThmmyPromptHtml; } - //Checks if a file renaming is necessary Uri tempFileUri = null; - { - String selectedFileFilename = FileUtils.filenameFromUri(this, fileUri); + if (filesList.size() == 1) { + //Checks if the file needs renaming + UploadFile uploadFile = filesList.get(0); + String selectedFileFilename = FileUtils.filenameFromUri(this, uploadFile.getFileUri()); if (!editTextFilename.equals(selectedFileFilename)) { //File should be uploaded with a different name - switch (uploadMethodSelected) { - case SELECT_FILE_METHOD_SELECTED: - //Temporarily copies the file to a another location and renames it - tempFileUri = UploadsHelper.createTempFile(this, storage, fileUri, - FileUtils.getFilenameWithoutExtension(editTextFilename)); - break; - case TAKE_PHOTO_METHOD_SELECTED: - //Renames the photo taken - String photoPath = photoFileSelected.getPath(); - photoPath = photoPath.substring(0, photoPath.lastIndexOf(File.separator)); - String destinationFilename = photoPath + File.separator + - FileUtils.getFilenameWithoutExtension(editTextFilename) + ".jpg"; - - if (!storage.rename(photoFileSelected.getAbsolutePath(), destinationFilename)) { - //Something went wrong, abort - Toast.makeText(this, "Could not create temporary file for renaming", Toast.LENGTH_SHORT).show(); - progressBar.setVisibility(View.GONE); - return; - } + if (!uploadFile.isCameraPhoto()) { + //Temporarily copies the file to a another location and renames it + tempFileUri = UploadsHelper.createTempFile(this, storage, + uploadFile.getFileUri(), + FileUtils.getFilenameWithoutExtension(editTextFilename)); + } else { + //Renames the photo taken + String photoPath = uploadFile.getPhotoFile().getPath(); + photoPath = photoPath.substring(0, photoPath.lastIndexOf(File.separator)); + String destinationFilename = photoPath + File.separator + + FileUtils.getFilenameWithoutExtension(editTextFilename) + ".jpg"; + + if (!storage.rename(uploadFile.getPhotoFile().getAbsolutePath(), destinationFilename)) { + //Something went wrong, abort + Toast.makeText(this, "Could not create temporary file for renaming", Toast.LENGTH_SHORT).show(); + progressBar.setVisibility(View.GONE); + return; + } - //Points photoFile and fileUri to the new copied and renamed file - photoFileSelected = storage.getFile(destinationFilename); - fileUri = FileProvider.getUriForFile(this, getPackageName() + - ".provider", photoFileSelected); - break; - default: - break; + //Points photoFile and fileUri to the new copied and renamed file + uploadFile.setPhotoFile(storage.getFile(destinationFilename)); + uploadFile.setFileUri(FileProvider.getUriForFile(this, getPackageName() + + ".provider", uploadFile.getPhotoFile())); } } + } else { + Uri[] filesListArray = new Uri[filesList.size()]; + for (int i = 0; i < filesList.size(); ++i) { + filesListArray[i] = filesList.get(i).getFileUri(); + } + + File zipFile = UploadsHelper.createZipFile(this); + assert zipFile != null; + tempFileUri = FileProvider.getUriForFile(this, getPackageName() + + ".provider", zipFile); + + UploadsHelper.zip(this, filesListArray, tempFileUri); } try { @@ -408,7 +425,7 @@ public class UploadActivity extends BaseActivity { .addParameter("tp-dluploadcat", categorySelected) .addParameter("tp-dluploadtext", uploadDescriptionText) .addFileToUpload(tempFileUri == null - ? fileUri.toString() + ? filesList.get(0).getFileUri().toString() : tempFileUri.toString() , "tp-dluploadfile") .addParameter("tp_dluploadicon", fileIcon) @@ -434,15 +451,18 @@ public class UploadActivity extends BaseActivity { UploadsHelper.deleteTempFiles(); BaseApplication.getInstance().logFirebaseAnalyticsEvent("file_upload", null); - if (uploadMethodSelected == TAKE_PHOTO_METHOD_SELECTED) { - TakePhoto.galleryAddPic(context, photoFileSelected); + for (UploadFile file : filesList) { + if (file.isCameraPhoto()) { + TakePhoto.galleryAddPic(context, file.getPhotoFile()); + } } + uploadTitle.setText(null); uploadFilename.setText(null); uploadDescription.setText(null); - fileUri = null; + filesList.clear(); + filesListView.removeAllViews(); photoFileCreated = null; - photoFileSelected = null; progressBar.setVisibility(View.GONE); } @@ -497,9 +517,6 @@ public class UploadActivity extends BaseActivity { if (photoFileCreated != null) { storage.deleteFile(photoFileCreated.getAbsolutePath()); } - if (photoFileSelected != null) { - storage.deleteFile(photoFileSelected.getAbsolutePath()); - } } @Override @@ -509,62 +526,45 @@ public class UploadActivity extends BaseActivity { return; } - //Keeps the filename between different file selections if it has been modified - boolean hasCustomFilename = false; - { - String editTextFilename = FileUtils. - getFilenameWithoutExtension(uploadFilename.getText().toString()); - String previousFilename = ""; - if (fileUri != null) { - previousFilename = FileUtils. - getFilenameWithoutExtension(FileUtils.filenameFromUri(this, fileUri)); - } + Uri newFileUri = data.getData(); + if (newFileUri != null) { + String filename = FileUtils.filenameFromUri(this, newFileUri); - if (editTextFilename != null && !editTextFilename.isEmpty() && - !editTextFilename.equals(previousFilename)) { - hasCustomFilename = true; - } - } - - //Deletes any photo file previously created, as it is not going to be used - if (photoFileCreated != null) { - storage.deleteFile(photoFileCreated.getAbsolutePath()); - } - if (photoFileSelected != null) { - storage.deleteFile(photoFileSelected.getAbsolutePath()); - } - uploadMethodSelected = SELECT_FILE_METHOD_SELECTED; + if (filesList.isEmpty()) { + if (uploadFilename.getText().toString().isEmpty()) { + uploadFilename.setText(filename); + } - fileUri = data.getData(); - if (fileUri != null) { - String filename = FileUtils.filenameFromUri(this, fileUri); - if (!hasCustomFilename) { - uploadFilename.setText(filename); + filename = filename.toLowerCase(); + if (filename.endsWith(".jpg")) { + fileIcon = "jpg_image.gif"; + } else if (filename.endsWith(".gif")) { + fileIcon = "gif_image.gif"; + } else if (filename.endsWith(".png")) { + fileIcon = "png_image.gif"; + } else if (filename.endsWith(".html") || filename.endsWith(".htm")) { + fileIcon = "html_file.gif"; + } else if (filename.endsWith(".pdf") || filename.endsWith(".doc") || + filename.endsWith("djvu")) { + fileIcon = "text_file.gif"; + } else if (filename.endsWith(".zip") || filename.endsWith(".rar") || + filename.endsWith(".tar") || filename.endsWith(".tar.gz") || + filename.endsWith(".gz")) { + fileIcon = "archive.gif"; + } else { + fileIcon = "blank.gif"; + } } else { - //Causes the EditText watcher to detect the fileUri change in case the extension changed - String badHack = "stringThatIntentionallyInvalidatesFilename"; - uploadFilename.setText(badHack); - } - - filename = filename.toLowerCase(); - if (filename.endsWith(".jpg")) { - fileIcon = "jpg_image.gif"; - } else if (filename.endsWith(".gif")) { - fileIcon = "gif_image.gif"; - } else if (filename.endsWith(".png")) { - fileIcon = "png_image.gif"; - } else if (filename.endsWith(".html") || filename.endsWith(".htm")) { - fileIcon = "html_file.gif"; - } else if (filename.endsWith(".pdf") || filename.endsWith(".doc") || - filename.endsWith("djvu")) { - fileIcon = "text_file.gif"; - } else if (filename.endsWith(".zip") || filename.endsWith(".rar") || - filename.endsWith(".tar") || filename.endsWith(".tar.gz") || - filename.endsWith(".gz")) { fileIcon = "archive.gif"; - } else { - fileIcon = "blank.gif"; + + String currentFilename = uploadFilename.getText().toString(); + String newFilename = FileUtils.getFilenameWithoutExtension(currentFilename) + + ".zip"; + uploadFilename.setText(newFilename); } + + addFileViewToList(filename); + filesList.add(new UploadFile(false, newFileUri, null)); } } else if (requestCode == AFR_REQUEST_CODE_CAMERA) { if (resultCode == Activity.RESULT_CANCELED) { @@ -572,41 +572,27 @@ public class UploadActivity extends BaseActivity { storage.deleteFile(photoFileCreated.getAbsolutePath()); return; } - uploadMethodSelected = TAKE_PHOTO_METHOD_SELECTED; - - //Keeps the filename between different file selections if it has been modified - boolean hasCustomFilename = false; - { - String editTextFilename = FileUtils. - getFilenameWithoutExtension(uploadFilename.getText().toString()); - String previousFilename = ""; - if (fileUri != null) { - previousFilename = FileUtils. - getFilenameWithoutExtension(FileUtils.filenameFromUri(this, fileUri)); - } - if (editTextFilename != null && !editTextFilename.isEmpty() && - !editTextFilename.equals(previousFilename)) { - hasCustomFilename = true; + if (filesList.isEmpty()) { + if (uploadFilename.getText().toString().isEmpty()) { + uploadFilename.setText(photoFileCreated.getName()); } - } - - if (photoFileSelected != null) { - storage.deleteFile(photoFileSelected.getAbsolutePath()); - } - photoFileSelected = photoFileCreated; - fileUri = TakePhoto.processResult(this, photoFileSelected); - - if (!hasCustomFilename) { - uploadFilename.setText(photoFileSelected.getName()); + fileIcon = "jpg_image.gif"; } else { - //Causes the EditText watcher to detect the fileUri change in case the extension changed - String badHack = "stringThatIntentionallyInvalidatesFilename"; - uploadFilename.setText(badHack); + fileIcon = "archive.gif"; + + String currentFilename = uploadFilename.getText().toString(); + String newFilename = FileUtils.getFilenameWithoutExtension(currentFilename) + + ".zip"; + uploadFilename.setText(newFilename); } - fileIcon = "jpg_image.gif"; + UploadFile newFile = new UploadFile(true, TakePhoto.processResult(this, + photoFileCreated), photoFileCreated); + addFileViewToList(FileUtils.getFilenameWithoutExtension(FileUtils. + filenameFromUri(this, newFile.getFileUri()))); + filesList.add(newFile); } else if (requestCode == AFR_REQUEST_CODE_FIELDS_BUILDER) { if (resultCode == Activity.RESULT_CANCELED) { return; @@ -651,6 +637,30 @@ public class UploadActivity extends BaseActivity { } } + private void addFileViewToList(String filename) { + LayoutInflater layoutInflater = getLayoutInflater(); + LinearLayout newFileRow = (LinearLayout) layoutInflater. + inflate(R.layout.activity_upload_file_list_row, null); + + TextView itemText = newFileRow.findViewById(R.id.upload_file_item_text); + Drawable filenameDrawable = AppCompatResources.getDrawable(this, R.drawable.ic_attach_file_white_24dp); + itemText.setCompoundDrawablesRelativeWithIntrinsicBounds(filenameDrawable, null, null, null); + itemText.setText(filename); + + newFileRow.findViewById(R.id.upload_file_item_remove). + setOnClickListener(view -> { + int fileIndex = filesListView.indexOfChild(newFileRow); + filesListView.removeViewAt(fileIndex); + filesList.remove(fileIndex); + if (filesList.isEmpty()) { + filesListView.setVisibility(View.GONE); + } + }); + + filesListView.addView(newFileRow); + filesListView.setVisibility(View.VISIBLE); + } + private class CustomOnItemSelectedListener implements AdapterView.OnItemSelectedListener { private ArrayList parentCategories, childCategories; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsHelper.java b/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsHelper.java index a61fff6d..6a736566 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsHelper.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsHelper.java @@ -15,11 +15,19 @@ import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; import gr.thmmy.mthmmy.utils.FileUtils; import timber.log.Timber; class UploadsHelper { + private final static int BUFFER = 4096; + @SuppressWarnings("ResultOfMethodCallIgnored") @Nullable static Uri createTempFile(Context context, Storage storage, Uri fileUri, String newFilename) { @@ -70,6 +78,56 @@ class UploadsHelper { return FileProvider.getUriForFile(context, context.getPackageName() + ".provider", storage.getFile(destinationFilename)); + + } + + @Nullable + public static File createZipFile(Context context) { + // Create an image file name + String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.FRANCE).format(new Date()); + String zipFileName = "mThmmy_" + timeStamp + ".zip"; + + File zipFolder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS) + + File.separator + "mThmmy"); + + if (!zipFolder.exists()) { + if (!zipFolder.mkdirs()) { + Timber.w("Zip folder build returned false in %s", UploadsHelper.class.getSimpleName()); + Toast.makeText(context, "Couldn't create zip directory", Toast.LENGTH_SHORT).show(); + return null; + } + } + + return new File(zipFolder, zipFileName); + } + + public static void zip(Context context, Uri[] files, Uri zipFile) { + try { + BufferedInputStream origin; + OutputStream dest = context.getContentResolver().openOutputStream(zipFile); + assert dest != null; + ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest)); + byte data[] = new byte[BUFFER]; + + for (Uri file : files) { + InputStream inputStream = context.getContentResolver().openInputStream(file); + assert inputStream != null; + origin = new BufferedInputStream(inputStream, BUFFER); + + ZipEntry entry = new ZipEntry(FileUtils.filenameFromUri(context, file)); + out.putNextEntry(entry); + int count; + + while ((count = origin.read(data, 0, BUFFER)) != -1) { + out.write(data, 0, count); + } + origin.close(); + } + + out.close(); + } catch (Exception e) { + e.printStackTrace(); + } } @SuppressWarnings("ResultOfMethodCallIgnored") diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/UploadFile.java b/app/src/main/java/gr/thmmy/mthmmy/model/UploadFile.java new file mode 100644 index 00000000..41c21deb --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/model/UploadFile.java @@ -0,0 +1,44 @@ +package gr.thmmy.mthmmy.model; + +import android.net.Uri; +import android.support.annotation.Nullable; + +import java.io.File; + +public class UploadFile { + private final boolean isCameraPhoto; + private Uri fileUri; + private File photoFile; + + private UploadFile() { + isCameraPhoto = false; + fileUri = null; + photoFile = null; + } + + public UploadFile(boolean isCameraPhoto, Uri fileUri, @Nullable File photoFile) { + this.isCameraPhoto = isCameraPhoto; + this.fileUri = fileUri; + this.photoFile = photoFile; + } + + public boolean isCameraPhoto() { + return isCameraPhoto; + } + + public Uri getFileUri() { + return fileUri; + } + + public File getPhotoFile() { + return photoFile; + } + + public void setFileUri(Uri fileUri) { + this.fileUri = fileUri; + } + + public void setPhotoFile(File photoFile) { + this.photoFile = photoFile; + } +} diff --git a/app/src/main/res/drawable/ic_attach_file_white_24dp.xml b/app/src/main/res/drawable/ic_attach_file_white_24dp.xml new file mode 100644 index 00000000..4834305b --- /dev/null +++ b/app/src/main/res/drawable/ic_attach_file_white_24dp.xml @@ -0,0 +1,4 @@ + + + + diff --git a/app/src/main/res/layout/activity_upload.xml b/app/src/main/res/layout/activity_upload.xml index 1a12fecc..dcfc2df4 100644 --- a/app/src/main/res/layout/activity_upload.xml +++ b/app/src/main/res/layout/activity_upload.xml @@ -128,6 +128,15 @@ android:textAlignment="center" android:textColor="@color/accent" /> + + diff --git a/app/src/main/res/layout/activity_upload_file_list_row.xml b/app/src/main/res/layout/activity_upload_file_list_row.xml new file mode 100644 index 00000000..0a1f7e5c --- /dev/null +++ b/app/src/main/res/layout/activity_upload_file_list_row.xml @@ -0,0 +1,23 @@ + + + + + + + \ No newline at end of file