diff --git a/app/build.gradle b/app/build.gradle
index c2b07d75..337120bc 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -44,7 +44,7 @@ android {
tasks.whenTaskAdded { task ->
if (task.name.contains("assembleRelease")) {
task.getDependsOn().add({
- def inputFile = new File("app/google-services.json")
+ def inputFile = new File("google-services.json")
def json = new JsonSlurper().parseText(inputFile.text)
if (json.project_info.project_id != "mthmmy-release-3aef0")
throw new GradleException('Please supply the correct google-services.json for release (or manually change the id above)!')
@@ -73,6 +73,7 @@ dependencies {
implementation 'com.google.firebase:firebase-core:16.0.6'
implementation 'com.google.firebase:firebase-messaging:17.3.4'
implementation 'com.crashlytics.sdk.android:crashlytics:2.9.8'
+ implementation 'com.snatik:storage:2.1.0'
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
implementation 'com.squareup.picasso:picasso:2.5.2'
implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7620bcf7..1e8bf257 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -160,6 +160,14 @@
+
+
+
+
+
+
{
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java
index addccf35..e4c3676c 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java
@@ -1,8 +1,12 @@
package gr.thmmy.mthmmy.activities.downloads;
+import android.content.Intent;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
import android.widget.ProgressBar;
import android.widget.Toast;
@@ -16,7 +20,11 @@ import java.util.Objects;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+
import gr.thmmy.mthmmy.R;
+import gr.thmmy.mthmmy.activities.upload.UploadActivity;
import gr.thmmy.mthmmy.base.BaseActivity;
import gr.thmmy.mthmmy.base.BaseApplication;
import gr.thmmy.mthmmy.model.Download;
@@ -29,6 +37,8 @@ import okhttp3.Request;
import okhttp3.Response;
import timber.log.Timber;
+import static gr.thmmy.mthmmy.activities.upload.UploadActivity.BUNDLE_UPLOAD_CATEGORY;
+
public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.OnLoadMoreListener {
/**
* The key to use when putting download's url String to {@link DownloadsActivity}'s Bundle.
@@ -47,7 +57,7 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
private MaterialProgressBar progressBar;
private RecyclerView recyclerView;
private DownloadsAdapter downloadsAdapter;
- //private FloatingActionButton uploadFAB;
+ private FloatingActionButton uploadFAB;
private ParseDownloadPageTask parseDownloadPageTask;
private int numberOfPages = -1;
@@ -113,37 +123,37 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
}
});
-// uploadFAB = findViewById(R.id.upload_fab);
-// uploadFAB.setEnabled(false);
-// uploadFAB.hide();
+ uploadFAB = findViewById(R.id.upload_fab);
+ uploadFAB.setEnabled(false);
+ uploadFAB.hide();
parseDownloadPageTask = new ParseDownloadPageTask();
parseDownloadPageTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, downloadsUrl);
}
-// @Override
-// public boolean onCreateOptionsMenu(Menu menu) {
-// // Inflates the menu; this adds items to the action bar if it is present.
-// getMenuInflater().inflate(R.menu.downloads_menu, menu);
-// super.onCreateOptionsMenu(menu);
-// return true;
-// }
-//
-// @Override
-// public boolean onOptionsItemSelected(MenuItem item) {
-// // Handle presses on the action bar items
-// switch (item.getItemId()) {
-// case R.id.menu_upload:
-// Intent intent = new Intent(DownloadsActivity.this, UploadActivity.class);
-// Bundle extras = new Bundle();
-// extras.putString(BUNDLE_UPLOAD_CATEGORY, downloadsNav);
-// intent.putExtras(extras);
-// startActivity(intent);
-// return true;
-// default:
-// return super.onOptionsItemSelected(item);
-// }
-// }
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Inflates the menu; this adds items to the action bar if it is present.
+ getMenuInflater().inflate(R.menu.downloads_menu, menu);
+ super.onCreateOptionsMenu(menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ // Handle presses on the action bar items
+ switch (item.getItemId()) {
+ case R.id.menu_upload:
+ Intent intent = new Intent(DownloadsActivity.this, UploadActivity.class);
+ Bundle extras = new Bundle();
+ extras.putString(BUNDLE_UPLOAD_CATEGORY, downloadsNav);
+ intent.putExtras(extras);
+ startActivity(intent);
+ return true;
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
@Override
public void onLoadMore() {
@@ -198,7 +208,7 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
@Override
protected void onPreExecute() {
if (!isLoadingMore) progressBar.setVisibility(ProgressBar.VISIBLE);
- //if (uploadFAB.getVisibility() != View.GONE) uploadFAB.setEnabled(false);
+ if (uploadFAB.getVisibility() != View.GONE) uploadFAB.setEnabled(false);
}
@Override
@@ -296,7 +306,7 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
toolbar.setTitle(downloadsTitle);
++pagesLoaded;
- //if (uploadFAB.getVisibility() != View.GONE) uploadFAB.setEnabled(true);
+ if (uploadFAB.getVisibility() != View.GONE) uploadFAB.setEnabled(true);
progressBar.setVisibility(ProgressBar.INVISIBLE);
downloadsAdapter.notifyDataSetChanged();
isLoadingMore = false;
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
index dba15a45..5472a742 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
@@ -87,6 +87,7 @@ import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL;
import static gr.thmmy.mthmmy.activities.topic.TopicParser.USER_COLOR_WHITE;
import static gr.thmmy.mthmmy.activities.topic.TopicParser.USER_COLOR_YELLOW;
import static gr.thmmy.mthmmy.base.BaseActivity.getSessionManager;
+import static gr.thmmy.mthmmy.utils.FileUtils.faIconFromFilename;
/**
* Custom {@link RecyclerView.Adapter} used for topics.
@@ -392,7 +393,7 @@ class TopicAdapter extends RecyclerView.Adapter {
attached.setClickable(true);
attached.setTypeface(Typeface.createFromAsset(context.getAssets()
, "fonts/fontawesome-webfont.ttf"));
- attached.setText(faIconFromFilename(attachedFile.getFilename()) + " "
+ attached.setText(faIconFromFilename(context, attachedFile.getFilename()) + " "
+ attachedFile.getFilename() + attachedFile.getFileInfo());
attached.setTextColor(filesTextColor);
attached.setPadding(0, 3, 0, 3);
@@ -1035,37 +1036,4 @@ class TopicAdapter extends RecyclerView.Adapter {
public interface OnPostFocusChangeListener {
void onPostFocusChange(int position);
}
-
- /**
- * Returns a String with a single FontAwesome typeface character corresponding to this file's
- * extension.
- *
- * @param filename String with filename containing file's extension
- * @return FontAwesome character according to file's type
- * @see FontAwesome
- */
- @NonNull
- private String faIconFromFilename(String filename) {
- filename = filename.toLowerCase();
-
- if (filename.contains("jpg") || filename.contains("gif") || filename.contains("jpeg")
- || filename.contains("png"))
- return context.getResources().getString(R.string.fa_file_image_o);
- else if (filename.contains("pdf"))
- return context.getResources().getString(R.string.fa_file_pdf_o);
- else if (filename.contains("zip") || filename.contains("rar") || filename.contains("tar.gz"))
- return context.getResources().getString(R.string.fa_file_zip_o);
- else if (filename.contains("txt"))
- return context.getResources().getString(R.string.fa_file_text_o);
- else if (filename.contains("doc") || filename.contains("docx"))
- return context.getResources().getString(R.string.fa_file_word_o);
- else if (filename.contains("xls") || filename.contains("xlsx"))
- return context.getResources().getString(R.string.fa_file_excel_o);
- else if (filename.contains("pps"))
- return context.getResources().getString(R.string.fa_file_powerpoint_o);
- else if (filename.contains("mpg"))
- return context.getResources().getString(R.string.fa_file_video_o);
-
- return context.getResources().getString(R.string.fa_file);
- }
}
\ No newline at end of file
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 974b8b20..20fea00f 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
@@ -1,54 +1,68 @@
package gr.thmmy.mthmmy.activities.upload;
import android.app.Activity;
+import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.content.pm.ResolveInfo;
-import android.graphics.Bitmap;
+import android.content.pm.PackageManager;
+import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.Bundle;
-import android.provider.MediaStore;
+import androidx.annotation.NonNull;
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import androidx.core.content.FileProvider;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.content.res.AppCompatResources;
+import androidx.preference.PreferenceManager;
+import androidx.appcompat.widget.AppCompatButton;
+import androidx.appcompat.widget.AppCompatImageButton;
+import android.text.Editable;
+import android.text.Spannable;
+import android.text.TextWatcher;
+import android.text.method.LinkMovementMethod;
+import android.text.style.ForegroundColorSpan;
+import android.view.ContextThemeWrapper;
+import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.LinearLayout;
+import android.widget.PopupWindow;
import android.widget.ProgressBar;
+import android.widget.TextView;
import android.widget.Toast;
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
-
import net.gotev.uploadservice.MultipartUploadRequest;
-import net.gotev.uploadservice.ServerResponse;
-import net.gotev.uploadservice.UploadInfo;
+import net.gotev.uploadservice.UploadNotificationAction;
import net.gotev.uploadservice.UploadNotificationConfig;
-import net.gotev.uploadservice.UploadStatusDelegate;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.File;
-import java.io.FileOutputStream;
+import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
-import java.util.List;
import java.util.Locale;
+import java.util.UUID;
-import androidx.appcompat.content.res.AppCompatResources;
-import androidx.appcompat.widget.AppCompatButton;
-import androidx.appcompat.widget.AppCompatTextView;
-import androidx.preference.PreferenceManager;
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.services.UploadsReceiver;
import gr.thmmy.mthmmy.utils.AppCompatSpinnerWithoutDefault;
+import gr.thmmy.mthmmy.utils.FileUtils;
+import gr.thmmy.mthmmy.utils.TakePhoto;
import gr.thmmy.mthmmy.utils.parsing.ParseException;
import gr.thmmy.mthmmy.utils.parsing.ParseTask;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
@@ -60,6 +74,7 @@ import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.BUND
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.RESULT_DESCRIPTION;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.RESULT_FILENAME;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.RESULT_TITLE;
+import static gr.thmmy.mthmmy.utils.FileUtils.faIconFromFilename;
public class UploadActivity extends BaseActivity {
/**
@@ -71,27 +86,40 @@ public class UploadActivity extends BaseActivity {
/**
* Request codes used in activities for result (AFR) calls
*/
- private static final int AFR_REQUEST_CODE_CHOOSE_FILE = 8;
- private static final int AFR_REQUEST_CODE_CAMERA = 4;
- private static final int AFR_REQUEST_CODE_FIELDS_BUILDER = 74;
+ private static final int AFR_REQUEST_CODE_CHOOSE_FILE = 8; //Arbitrary, application specific
+ private static final int AFR_REQUEST_CODE_CAMERA = 4; //Arbitrary, application specific
+ private static final int AFR_REQUEST_CODE_FIELDS_BUILDER = 74; //Arbitrary, application specific
+
+ /**
+ * Request code to gain read/write permission
+ */
+ private static final int UPLOAD_REQUEST_CODE = 42; //Arbitrary, application specific
+
+ private static final int MAX_FILE_SIZE_SUPPORTED = 45000000;
+ //private UploadsReceiver uploadsReceiver = new UploadsReceiver();
private ArrayList uploadRootCategories = new ArrayList<>();
private ParseUploadPageTask parseUploadPageTask;
private ArrayList bundleCategory;
private String categorySelected = "-1";
private String uploaderProfileIndex = "1";
- private String uploadFilename;
- private Uri fileUri;
+
+ private ArrayList filesList = new ArrayList<>();
+ private File photoFileCreated = null;
private String fileIcon;
+ private AppCompatImageButton uploadFilenameInfo;
+ private CustomTextWatcher textWatcher;
+ private boolean hasModifiedFilename = false;
//UI elements
private MaterialProgressBar progressBar;
private LinearLayout categoriesSpinners;
private AppCompatSpinnerWithoutDefault rootCategorySpinner;
private EditText uploadTitle;
+ private EditText uploadFilename;
private EditText uploadDescription;
private AppCompatButton titleDescriptionBuilderButton;
- private AppCompatTextView filenameHolder;
+ private LinearLayout filesListView;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -197,9 +225,36 @@ public class UploadActivity extends BaseActivity {
uploadTitle = findViewById(R.id.upload_title);
uploadDescription = findViewById(R.id.upload_description);
- filenameHolder = findViewById(R.id.upload_filename);
- Drawable filenameDrawable = AppCompatResources.getDrawable(this, R.drawable.ic_attach_file_white_24dp);
- filenameHolder.setCompoundDrawablesRelativeWithIntrinsicBounds(filenameDrawable, null, null, null);
+ uploadFilenameInfo = findViewById(R.id.upload_filename_info);
+ uploadFilenameInfo.setOnClickListener(view -> {
+ //Inflates the popup menu content
+ LayoutInflater layoutInflater = (LayoutInflater) view.getContext().
+ getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ if (layoutInflater == null) {
+ return;
+ }
+
+ Context wrapper = new ContextThemeWrapper(this, R.style.PopupWindow);
+ View popUpContent = layoutInflater.inflate(R.layout.activity_upload_filename_info_popup, null);
+
+ //Creates the PopupWindow
+ PopupWindow popUp = new PopupWindow(wrapper);
+ popUp.setContentView(popUpContent);
+ popUp.setWidth(LinearLayout.LayoutParams.WRAP_CONTENT);
+ popUp.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
+ popUp.setFocusable(true);
+
+ ((TextView) popUpContent.findViewById(R.id.upload_filename_info_text)).
+ setMovementMethod(LinkMovementMethod.getInstance());
+ //Displays the popup
+ popUp.showAsDropDown(view);
+ });
+
+ uploadFilename = findViewById(R.id.upload_filename);
+ textWatcher = new CustomTextWatcher();
+ uploadFilename.addTextChangedListener(textWatcher);
+
+ 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);
@@ -212,7 +267,8 @@ public class UploadActivity extends BaseActivity {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT)
//.setType("*/*")
.setType("image/jpeg")
- .putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);
+ .putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes)
+ .putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
startActivityForResult(intent, AFR_REQUEST_CODE_CHOOSE_FILE);
});
@@ -221,118 +277,153 @@ public class UploadActivity extends BaseActivity {
Drawable takePhotoDrawable = AppCompatResources.getDrawable(this, R.drawable.ic_photo_camera_white_24dp);
takePhotoButton.setCompoundDrawablesRelativeWithIntrinsicBounds(takePhotoDrawable, null, null, null);
takePhotoButton.setOnClickListener(v -> {
- Intent takePhotoIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
- takePhotoIntent.putExtra("return-data", true);
- takePhotoIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(UploadsHelper.getCacheFile(this)));
-
- Intent targetedIntent = new Intent(takePhotoIntent);
- List resInfo = this.getPackageManager().queryIntentActivities(takePhotoIntent, 0);
- for (ResolveInfo resolveInfo : resInfo) {
- String packageName = resolveInfo.activityInfo.packageName;
- targetedIntent.setPackage(packageName);
- }
- startActivityForResult(takePhotoIntent, AFR_REQUEST_CODE_CAMERA);
+ if (checkPerms())
+ takePhoto();
+ else
+ requestPerms(UPLOAD_REQUEST_CODE);
});
FloatingActionButton uploadFAB = findViewById(R.id.upload_fab);
+ uploadFAB.setTag(true);
uploadFAB.setOnClickListener(view -> {
+ //Attempts upload
progressBar.setVisibility(View.VISIBLE);
String uploadTitleText = uploadTitle.getText().toString();
- String uploadDescriptionText = uploadDescription.getText().toString();
-
- if (uploadTitleText.equals("")) {
- uploadTitle.setError("Required");
- }
- if (fileUri == null) {
- Toast.makeText(view.getContext(), "Please choose a file to upload or take a photo", Toast.LENGTH_LONG).show();
- }
- if (categorySelected.equals("-1")) {
- Toast.makeText(view.getContext(), "Please choose category first", Toast.LENGTH_SHORT).show();
- }
-
- if (categorySelected.equals("-1") || uploadTitleText.equals("") || fileUri == null) {
- progressBar.setVisibility(View.GONE);
- return;
- }
-
- SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(view.getContext());
- if (sharedPrefs.getBoolean(UPLOADING_APP_SIGNATURE_ENABLE_KEY, true)) {
- uploadDescriptionText += uploadedFromThmmyPromptHtml;
- }
+ String editTextFilename = uploadFilename.getText().toString();
+ final String[] uploadDescriptionText = {uploadDescription.getText().toString()};
+
+ //Checks if all required fields are filled
+ {
+ boolean shouldReturn = false;
+ if (uploadTitleText.equals("")) {
+ uploadTitle.setError("Required");
+ shouldReturn = true;
+ }
+ if (filesList.isEmpty()) {
+ Toast.makeText(view.getContext(), "Please choose a file to upload or take a photo", Toast.LENGTH_LONG).show();
+ shouldReturn = true;
+ }
+ if (categorySelected.equals("-1")) {
+ Toast.makeText(view.getContext(), "Please choose category first", Toast.LENGTH_SHORT).show();
+ shouldReturn = true;
+ }
+ if (!filesList.isEmpty()) {
+ long totalFilesSize = 0;
+ for (UploadFile file : filesList) {
+ totalFilesSize += FileUtils.sizeFromUri(this, file.getFileUri());
+ }
- String tempFilePath = null;
- if (uploadFilename != null) {
- //File should be uploaded with a certain name. Temporarily copies the file and renames it
- tempFilePath = UploadsHelper.createTempFile(this, fileUri, uploadFilename);
- if (tempFilePath == null) {
- //Something went wrong, abort
- Toast.makeText(this, "Could not create temporary file for renaming", Toast.LENGTH_SHORT).show();
+ 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("(.+\\.)+.+") ||
+ !FileUtils.getFilenameWithoutExtension(editTextFilename).
+ matches("[0-9a-zA-Zα-ωΑ-Ω~!@#$%^&()_+=\\-`\\[\\]{};',.]+")) {
+ uploadFilename.setError("Invalid filename");
+ shouldReturn = true;
+ }
+ if (shouldReturn) {
progressBar.setVisibility(View.GONE);
return;
}
}
- try {
- new MultipartUploadRequest(view.getContext(), uploadIndexUrl)
- .setUtf8Charset()
- .addParameter("tp-dluploadtitle", uploadTitleText)
- .addParameter("tp-dluploadcat", categorySelected)
- .addParameter("tp-dluploadtext", uploadDescriptionText)
- .addFileToUpload(tempFilePath == null
- ? fileUri.toString()
- : tempFilePath
- , "tp-dluploadfile")
- .addParameter("tp_dluploadicon", fileIcon)
- .addParameter("tp-uploaduser", uploaderProfileIndex)
- .setNotificationConfig(new UploadNotificationConfig())
- .setMaxRetries(2)
- .setDelegate(new UploadStatusDelegate() {
- @Override
- public void onProgress(Context context, UploadInfo uploadInfo) {
- }
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle("Upload to thmmy");
+ builder.setMessage("Are you sure?");
+ builder.setPositiveButton("YES, FIRE AWAY", (dialog, which) -> {
+ //Checks settings and possibly adds "Uploaded from mTHMMY" string to description
+ SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(view.getContext());
+ if (sharedPrefs.getBoolean(UPLOADING_APP_SIGNATURE_ENABLE_KEY, true)) {
+ uploadDescriptionText[0] += uploadedFromThmmyPromptHtml;
+ }
- @Override
- public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse,
- Exception exception) {
- Toast.makeText(context, "Upload failed", Toast.LENGTH_SHORT).show();
- UploadsHelper.deleteTempFiles();
- progressBar.setVisibility(View.GONE);
- }
+ for (UploadFile file : filesList) {
+ if (file.isCameraPhoto()) {
+ TakePhoto.galleryAddPic(this, file.getPhotoFile());
+ }
+ }
- @Override
- public void onCompleted(Context context, UploadInfo uploadInfo, ServerResponse serverResponse) {
- Toast.makeText(context, "Upload completed successfully", Toast.LENGTH_SHORT).show();
- UploadsHelper.deleteTempFiles();
- BaseApplication.getInstance().logFirebaseAnalyticsEvent("file_upload", null);
-
- uploadTitle.setText(null);
- uploadDescription.setText(null);
- fileUri = null;
- filenameHolder.setText(null);
- filenameHolder.setVisibility(View.GONE);
+ Uri tempFileUri = null;
+ 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
+ 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;
}
- @Override
- public void onCancelled(Context context, UploadInfo uploadInfo) {
- Toast.makeText(context, "Upload canceled", Toast.LENGTH_SHORT).show();
+ //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();
+ }
+
+ new ZipTask(this, editTextFilename, categorySelected,
+ uploadTitleText, uploadDescriptionText[0], fileIcon,
+ uploaderProfileIndex).execute(filesListArray);
+ finish();
+ return;
+ }
- UploadsHelper.deleteTempFiles();
- progressBar.setVisibility(View.GONE);
- }
- })
- .startUpload();
- } catch (Exception exception) {
- Timber.e(exception, "AndroidUploadService: %s", exception.getMessage());
+ String uploadID = UUID.randomUUID().toString();
+ if (uploadFile(this, uploadID, getConfigForUpload(this, uploadID,
+ editTextFilename),
+ categorySelected, uploadTitleText,
+ uploadDescriptionText[0], fileIcon, uploaderProfileIndex,
+ tempFileUri == null
+ ? filesList.get(0).getFileUri()
+ : tempFileUri)) {
+ finish();
+ } else {
+ Toast.makeText(this, "Couldn't initiate upload.", Toast.LENGTH_SHORT).show();
+ }
+ });
+
+ builder.setNegativeButton("NOPE", (dialog, which) -> {
progressBar.setVisibility(View.GONE);
- }
+ dialog.dismiss();
+ });
+
+ AlertDialog alert = builder.create();
+ alert.setOnCancelListener(dialog -> {
+ progressBar.setVisibility(View.GONE);
+ dialog.dismiss();
+ });
+ alert.show();
});
if (uploadRootCategories.isEmpty()) {
//Parses the uploads page
parseUploadPageTask = new ParseUploadPageTask();
- parseUploadPageTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, uploadIndexUrl);
+ parseUploadPageTask.execute(uploadIndexUrl);
} else {
//Renders the already parsed data
updateUIElements();
@@ -355,11 +446,17 @@ public class UploadActivity extends BaseActivity {
super.onResume();
}
+ @Override
+ protected void onPause() {
+ super.onPause();
+ }
+
@Override
protected void onDestroy() {
super.onDestroy();
- if (parseUploadPageTask != null && parseUploadPageTask.getStatus() != AsyncTask.Status.RUNNING)
+ if (parseUploadPageTask != null && parseUploadPageTask.getStatus() != AsyncTask.Status.RUNNING) {
parseUploadPageTask.cancel(true);
+ }
}
@Override
@@ -369,71 +466,119 @@ public class UploadActivity extends BaseActivity {
return;
}
- fileUri = data.getData();
- if (fileUri != null) {
- String filename = UploadsHelper.filenameFromUri(this, fileUri);
- filenameHolder.setText(filename);
- filenameHolder.setVisibility(View.VISIBLE);
-
- 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";
+ if (data.getClipData() != null) {
+ fileIcon = "archive.gif";
+ textWatcher.setFileExtension(".zip");
+
+ if (!hasModifiedFilename) {
+ String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.FRANCE).format(new Date());
+ String zipFilename = "mThmmy_" + timeStamp + ".zip";
+ uploadFilename.setText(zipFilename);
+ hasModifiedFilename = false;
+ }
+
+ for (int fileIndex = 0; fileIndex < data.getClipData().getItemCount(); ++fileIndex) {
+ Uri newFileUri = data.getClipData().getItemAt(fileIndex).getUri();
+ String filename = FileUtils.filenameFromUri(this, newFileUri);
+ addFileViewToList(filename);
+ filesList.add(new UploadFile(false, newFileUri, null));
+ }
+ } else {
+ Uri newFileUri = data.getData();
+ if (newFileUri != null) {
+ String filename = FileUtils.filenameFromUri(this, newFileUri);
+
+ if (filesList.isEmpty()) {
+ textWatcher.setFileExtension(FileUtils.getFileExtension(filename));
+
+ if (!hasModifiedFilename) {
+ uploadFilename.setText(filename);
+ hasModifiedFilename = false;
+ }
+
+ 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 {
+ fileIcon = "archive.gif";
+ textWatcher.setFileExtension(".zip");
+
+ if (!hasModifiedFilename) {
+ String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.FRANCE).format(new Date());
+ String zipFilename = "mThmmy_" + timeStamp + ".zip";
+ uploadFilename.setText(zipFilename);
+ hasModifiedFilename = false;
+ }
+ }
+
+ addFileViewToList(filename);
+ filesList.add(new UploadFile(false, newFileUri, null));
}
}
} else if (requestCode == AFR_REQUEST_CODE_CAMERA) {
if (resultCode == Activity.RESULT_CANCELED) {
+ //Deletes image file
+ storage.deleteFile(photoFileCreated.getAbsolutePath());
return;
}
- Bitmap bitmap;
- File cacheImageFile = UploadsHelper.getCacheFile(this);
+ if (filesList.isEmpty()) {
+ textWatcher.setFileExtension(FileUtils.getFileExtension(photoFileCreated.getName()));
- Uri cacheFileUri = Uri.fromFile(cacheImageFile);
- fileIcon = "jpg_image.gif";
-
- bitmap = UploadsHelper.getImageResized(this, cacheFileUri);
- int rotation = UploadsHelper.getRotation(this, cacheFileUri);
- bitmap = UploadsHelper.rotate(bitmap, rotation);
+ if (!hasModifiedFilename) {
+ uploadFilename.setText(photoFileCreated.getName());
+ hasModifiedFilename = false;
+ }
- try {
- FileOutputStream out = new FileOutputStream(cacheImageFile);
- bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
- out.flush();
- out.close();
- } catch (Exception e) {
- e.printStackTrace();
+ fileIcon = "jpg_image.gif";
+ } else {
+ fileIcon = "archive.gif";
+ textWatcher.setFileExtension(".zip");
+
+ if (!hasModifiedFilename) {
+ String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.FRANCE).format(new Date());
+ String zipFilename = "mThmmy_" + timeStamp + ".zip";
+ uploadFilename.setText(zipFilename);
+ hasModifiedFilename = false;
+ }
}
- String newFilename = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.FRANCE).
- format(new Date());
- fileUri = Uri.parse(UploadsHelper.createTempFile(this, cacheFileUri, newFilename));
-
- newFilename += ".jpg";
- filenameHolder.setText(newFilename);
- filenameHolder.setVisibility(View.VISIBLE);
-
- UploadsHelper.deleteCacheFiles(this);
+ 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;
}
- uploadFilename = data.getStringExtra(RESULT_FILENAME);
+ String previousName = uploadFilename.getText().toString();
+ if (previousName.isEmpty()) {
+ uploadFilename.setText(data.getStringExtra(RESULT_FILENAME));
+ } else {
+ String filenameWithExtension = data.getStringExtra(RESULT_FILENAME) +
+ FileUtils.getFileExtension(previousName);
+ uploadFilename.setText(filenameWithExtension);
+ }
+ hasModifiedFilename = true;
+
uploadTitle.setText(data.getStringExtra(RESULT_TITLE));
uploadDescription.setText(data.getStringExtra(RESULT_DESCRIPTION));
} else {
@@ -441,6 +586,243 @@ public class UploadActivity extends BaseActivity {
}
}
+ @Override
+ public void onRequestPermissionsResult(int permsRequestCode, @NonNull String[] permissions
+ , @NonNull int[] grantResults) {
+ switch (permsRequestCode) {
+ case UPLOAD_REQUEST_CODE:
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
+ takePhoto();
+ break;
+ }
+ }
+
+ // Should only be called after making sure permissions are granted
+ private void takePhoto() {
+ // Create the File where the photo should go
+ photoFileCreated = TakePhoto.createImageFile(this);
+
+ // Continue only if the File was successfully created
+ if (photoFileCreated != null) {
+ startActivityForResult(TakePhoto.getIntent(this, photoFileCreated),
+ AFR_REQUEST_CODE_CAMERA);
+ }
+ }
+
+ private void updateUIElements() {
+ String[] tmpSpinnerArray = new String[uploadRootCategories.size()];
+ for (int i = 0; i < uploadRootCategories.size(); ++i) {
+ tmpSpinnerArray[i] = uploadRootCategories.get(i).getCategoryTitle();
+ }
+
+ ArrayAdapter spinnerArrayAdapter = new ArrayAdapter<>(BaseApplication.getInstance().getApplicationContext(),
+ R.layout.spinner_item, tmpSpinnerArray);
+ spinnerArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
+ rootCategorySpinner.setAdapter(spinnerArrayAdapter);
+
+ //Sets bundle selection
+ if (bundleCategory != null) {
+ int bundleSelectionIndex = -1, currentIndex = 0;
+
+ for (UploadCategory category : uploadRootCategories) {
+ if (bundleCategory.get(0).contains(category.getCategoryTitle())) {
+ bundleSelectionIndex = currentIndex;
+ break;
+ }
+ ++currentIndex;
+ }
+
+ if (bundleSelectionIndex != -1) {
+ rootCategorySpinner.setSelection(bundleSelectionIndex, true);
+ bundleCategory.remove(0);
+ }
+ }
+ }
+
+ 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);
+ itemText.setTypeface(Typeface.createFromAsset(this.getAssets()
+ , "fonts/fontawesome-webfont.ttf"));
+ String filenameWithIcon = faIconFromFilename(this, filename) + " " + filename;
+ itemText.setText(filenameWithIcon);
+
+ newFileRow.findViewById(R.id.upload_file_item_remove).setOnClickListener(view -> {
+ int fileIndex = filesListView.indexOfChild(newFileRow);
+ filesListView.removeViewAt(fileIndex);
+
+ if (filesList.get(fileIndex).isCameraPhoto()) {
+ storage.deleteFile(filesList.get(fileIndex).getPhotoFile().getAbsolutePath());
+ }
+ filesList.remove(fileIndex);
+ if (filesList.isEmpty()) {
+ filesListView.setVisibility(View.GONE);
+ } else if (filesList.size() == 1) {
+ textWatcher.setFileExtension(FileUtils.getFileExtension(FileUtils.
+ filenameFromUri(this, filesList.get(0).getFileUri())));
+ }
+ });
+
+ filesListView.addView(newFileRow);
+ filesListView.setVisibility(View.VISIBLE);
+ }
+
+ public static UploadNotificationConfig getConfigForUpload(Context context, String uploadID,
+ String filename) {
+ UploadNotificationConfig uploadNotificationConfig = new UploadNotificationConfig();
+ uploadNotificationConfig.setIconForAllStatuses(android.R.drawable.stat_sys_upload);
+ uploadNotificationConfig.setTitleForAllStatuses("Uploading " + filename);
+
+ uploadNotificationConfig.getProgress().iconResourceID = android.R.drawable.stat_sys_upload;
+ uploadNotificationConfig.getCompleted().iconResourceID = android.R.drawable.stat_sys_upload_done;
+ uploadNotificationConfig.getError().iconResourceID = android.R.drawable.stat_sys_upload_done;
+ uploadNotificationConfig.getError().iconColorResourceID = R.color.error_red;
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ uploadNotificationConfig.getError().message = "Error during upload. Click for options";
+ }
+ uploadNotificationConfig.getCancelled().iconColorResourceID = android.R.drawable.stat_sys_upload_done;
+ uploadNotificationConfig.getCancelled().autoClear = true;
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ Intent combinedActionsIntent = new Intent(UploadsReceiver.ACTION_COMBINED_UPLOAD);
+ combinedActionsIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ combinedActionsIntent.putExtra(UploadsReceiver.UPLOAD_ID_KEY, uploadID);
+
+ /*combinedActionsIntent.putExtra(UploadsReceiver.UPLOAD_RETRY_FILENAME, filename);
+ combinedActionsIntent.putExtra(UploadsReceiver.UPLOAD_RETRY_CATEGORY, retryCategory);
+ combinedActionsIntent.putExtra(UploadsReceiver.UPLOAD_RETRY_TITLE, retryTitleText);
+ combinedActionsIntent.putExtra(UploadsReceiver.UPLOAD_RETRY_DESCRIPTION, retryDescription);
+ combinedActionsIntent.putExtra(UploadsReceiver.UPLOAD_RETRY_ICON, retryIcon);
+ combinedActionsIntent.putExtra(UploadsReceiver.UPLOAD_RETRY_UPLOADER, retryUploaderProfile);
+ combinedActionsIntent.putExtra(UploadsReceiver.UPLOAD_RETRY_FILE_URI, retryFileUri);*/
+
+ uploadNotificationConfig.setClickIntentForAllStatuses(PendingIntent.getBroadcast(context,
+ 1, combinedActionsIntent, PendingIntent.FLAG_UPDATE_CURRENT));
+ }
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ Intent retryIntent = new Intent(context, UploadsReceiver.class);
+ retryIntent.setAction(UploadsReceiver.ACTION_RETRY_UPLOAD);
+ retryIntent.putExtra(UploadsReceiver.UPLOAD_ID_KEY, uploadID);
+
+ Intent cancelIntent = new Intent(context, UploadsReceiver.class);
+ cancelIntent.setAction(UploadsReceiver.ACTION_CANCEL_UPLOAD);
+ cancelIntent.putExtra(UploadsReceiver.UPLOAD_ID_KEY, uploadID);
+
+ uploadNotificationConfig.getProgress().actions.add(new UploadNotificationAction(
+ R.drawable.ic_cancel_accent_24dp,
+ context.getString(R.string.upload_notification_cancel),
+ PendingIntent.getBroadcast(context, 0, cancelIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT)
+ ));
+ uploadNotificationConfig.getError().actions.add(new UploadNotificationAction(
+ R.drawable.ic_notification,
+ context.getString(R.string.upload_notification_retry),
+ PendingIntent.getBroadcast(context, 0, retryIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT)
+ ));
+ }
+
+ return uploadNotificationConfig;
+ }
+
+ public static boolean uploadFile(Context context, String uploadID,
+ UploadNotificationConfig uploadNotificationConfig,
+ String categorySelected, String uploadTitleText,
+ String uploadDescriptionText, String fileIcon,
+ String uploaderProfileIndex, Uri fileUri) {
+ try {
+ new MultipartUploadRequest(context, uploadID, uploadIndexUrl)
+ .setUtf8Charset()
+ .setNotificationConfig(uploadNotificationConfig)
+ .addParameter("tp-dluploadtitle", uploadTitleText)
+ .addParameter("tp-dluploadcat", categorySelected)
+ .addParameter("tp-dluploadtext", uploadDescriptionText)
+ .addFileToUpload(fileUri.toString()
+ , "tp-dluploadfile")
+ .addParameter("tp_dluploadicon", fileIcon)
+ .addParameter("tp-uploaduser", uploaderProfileIndex)
+ .setNotificationConfig(uploadNotificationConfig)
+ .setMaxRetries(2)
+ .startUpload();
+
+ Toast.makeText(context, "Uploading files in the background.", Toast.LENGTH_SHORT).show();
+ return true;
+ } catch (Exception exception) {
+ Timber.e(exception, "AndroidUploadService: %s", exception.getMessage());
+ return false;
+ }
+ }
+
+ private class CustomTextWatcher implements TextWatcher {
+ String oldFilename, fileExtension;
+
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ //Saves an instance of the filename before changing
+ oldFilename = s.toString();
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ //Warns user for bad filenames
+ String filenameWithoutExtension = FileUtils.getFilenameWithoutExtension(s.toString());
+ if (filenameWithoutExtension != null && !filenameWithoutExtension.isEmpty() &&
+ !filenameWithoutExtension.matches("[0-9a-zA-Z~!@#$%^&()_+=\\-`\\[\\]{};',.]+")) {
+ uploadFilenameInfo.setImageResource(R.drawable.ic_info_outline_warning_24dp);
+ } else {
+ uploadFilenameInfo.setImageResource(R.drawable.ic_info_outline_white_24dp);
+ }
+
+ if (fileExtension == null) {
+ hasModifiedFilename = !s.toString().isEmpty();
+ return;
+ }
+
+ if (!s.toString().endsWith(fileExtension)) {
+ //User tried to alter the extension
+ //Prevents the change
+ uploadFilename.setText(oldFilename);
+ return;
+ }
+
+ //User has modified the filename
+ hasModifiedFilename = true;
+ if (s.toString().isEmpty() || (filesList.size() == 1 && s.toString().equals(FileUtils.
+ filenameFromUri(getApplicationContext(), filesList.get(0).getFileUri())))) {
+ //After modification the filename falls back to the original
+ hasModifiedFilename = false;
+ }
+
+ //Adds the grey colored span to the extension
+ s.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.secondary_text)),
+ s.length() - fileExtension.length(), s.length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+
+ void setFileExtension(String extension) {
+ boolean oldHasModifiedFilename = hasModifiedFilename;
+ oldFilename = uploadFilename.getText().toString();
+ fileExtension = extension;
+ String newFilename;
+
+ if (!oldFilename.isEmpty()) {
+ newFilename = FileUtils.getFilenameWithoutExtension(oldFilename) + extension;
+ } else {
+ newFilename = extension;
+ }
+
+ uploadFilename.setText(newFilename);
+ hasModifiedFilename = oldHasModifiedFilename;
+ }
+ }
+
private class CustomOnItemSelectedListener implements AdapterView.OnItemSelectedListener {
private ArrayList parentCategories, childCategories;
@@ -574,32 +956,79 @@ public class UploadActivity extends BaseActivity {
}
}
- private void updateUIElements() {
- String[] tmpSpinnerArray = new String[uploadRootCategories.size()];
- for (int i = 0; i < uploadRootCategories.size(); ++i) {
- tmpSpinnerArray[i] = uploadRootCategories.get(i).getCategoryTitle();
+ public static class ZipTask extends AsyncTask {
+ // Weak references will still allow the Activity to be garbage-collected
+ private final WeakReference weakActivity;
+ final String zipFilename, categorySelected, uploadTitleText, uploadDescriptionText,
+ fileIcon, uploaderProfileIndex;
+ Uri zipFileUri;
+
+ // Suppresses default constructor
+ @SuppressWarnings("unused")
+ private ZipTask() {
+ weakActivity = null;
+ this.zipFilename = null;
+ this.categorySelected = null;
+ this.uploadTitleText = null;
+ this.uploadDescriptionText = null;
+ this.fileIcon = null;
+ this.uploaderProfileIndex = null;
}
- ArrayAdapter spinnerArrayAdapter = new ArrayAdapter<>(BaseApplication.getInstance().getApplicationContext(),
- R.layout.spinner_item, tmpSpinnerArray);
- spinnerArrayAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
- rootCategorySpinner.setAdapter(spinnerArrayAdapter);
+ ZipTask(Activity uploadsActivity, @NonNull String zipFilename,
+ @NonNull String categorySelected, @NonNull String uploadTitleText,
+ @NonNull String uploadDescriptionText, @NonNull String fileIcon,
+ @NonNull String uploaderProfileIndex) {
+ weakActivity = new WeakReference<>(uploadsActivity);
+ this.zipFilename = zipFilename;
+ this.categorySelected = categorySelected;
+ this.uploadTitleText = uploadTitleText;
+ this.uploadDescriptionText = uploadDescriptionText;
+ this.fileIcon = fileIcon;
+ this.uploaderProfileIndex = uploaderProfileIndex;
+ }
- //Sets bundle selection
- if (bundleCategory != null) {
- int bundleSelectionIndex = -1, currentIndex = 0;
+ @Override
+ protected void onPreExecute() {
+ assert weakActivity != null;
+ Toast.makeText(weakActivity.get(), "Zipping files", Toast.LENGTH_SHORT).show();
+ }
- for (UploadCategory category : uploadRootCategories) {
- if (bundleCategory.get(0).contains(category.getCategoryTitle())) {
- bundleSelectionIndex = currentIndex;
- break;
- }
- ++currentIndex;
+ @Override
+ protected Boolean doInBackground(Uri... filesToZip) {
+ if (weakActivity == null || zipFilename == null) {
+ return false;
}
+ File zipFile = UploadsHelper.createZipFile(zipFilename);
- if (bundleSelectionIndex != -1) {
- rootCategorySpinner.setSelection(bundleSelectionIndex, true);
- bundleCategory.remove(0);
+ if (zipFile == null) {
+ return false;
+ }
+ zipFileUri = FileProvider.getUriForFile(weakActivity.get(),
+ weakActivity.get().getPackageName() +
+ ".provider", zipFile);
+
+ UploadsHelper.zip(weakActivity.get(), filesToZip, zipFileUri);
+ return true;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ if (weakActivity == null) {
+ return;
+ }
+
+ if (!result) {
+ Toast.makeText(weakActivity.get(), "Couldn't create zip!", Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ String uploadID = UUID.randomUUID().toString();
+ if (!uploadFile(weakActivity.get(), uploadID,
+ getConfigForUpload(weakActivity.get(), uploadID, zipFilename), categorySelected,
+ uploadTitleText, uploadDescriptionText, fileIcon, uploaderProfileIndex,
+ zipFileUri)) {
+ Toast.makeText(weakActivity.get(), "Couldn't initiate upload.", Toast.LENGTH_SHORT).show();
}
}
}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadFieldsBuilderActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadFieldsBuilderActivity.java
index f9fd9407..e89fda41 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadFieldsBuilderActivity.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadFieldsBuilderActivity.java
@@ -3,6 +3,7 @@ package gr.thmmy.mthmmy.activities.upload;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
+import androidx.annotation.Nullable;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
@@ -12,14 +13,14 @@ import android.widget.RadioGroup;
import android.widget.Toast;
import java.util.Calendar;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
-import androidx.annotation.Nullable;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
import gr.thmmy.mthmmy.R;
+import gr.thmmy.mthmmy.base.BaseActivity;
import timber.log.Timber;
-public class UploadFieldsBuilderActivity extends AppCompatActivity {
+public class UploadFieldsBuilderActivity extends BaseActivity {
static final String BUNDLE_UPLOAD_FIELD_BUILDER_COURSE = "UPLOAD_FIELD_BUILDER_COURSE";
static final String BUNDLE_UPLOAD_FIELD_BUILDER_SEMESTER = "UPLOAD_FIELD_BUILDER_SEMESTER";
@@ -28,6 +29,7 @@ public class UploadFieldsBuilderActivity extends AppCompatActivity {
static final String RESULT_DESCRIPTION = "RESULT_DESCRIPTION";
private String course, semester;
+ private boolean isValidYear;
private LinearLayout semesterChooserLinear;
private RadioGroup typeRadio, semesterRadio;
@@ -38,18 +40,17 @@ public class UploadFieldsBuilderActivity extends AppCompatActivity {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String working = s.toString();
- boolean isValid;
if (working.length() == 4) {
int currentYear = Calendar.getInstance().get(Calendar.YEAR);
int inputYear = Integer.parseInt(working);
- isValid = inputYear <= currentYear && inputYear > 2000;
+ isValidYear = inputYear <= currentYear && inputYear > 1980;
} else {
- isValid = false;
+ isValidYear = false;
}
- if (!isValid) {
+ if (!isValidYear) {
year.setError("Please enter a valid year");
} else {
year.setError(null);
@@ -86,7 +87,7 @@ public class UploadFieldsBuilderActivity extends AppCompatActivity {
}
//Initialize toolbar
- Toolbar toolbar = findViewById(R.id.toolbar);
+ toolbar = findViewById(R.id.toolbar);
toolbar.setTitle(R.string.upload_fields_builder_toolbar_title);
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) {
@@ -94,6 +95,9 @@ public class UploadFieldsBuilderActivity extends AppCompatActivity {
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
+ createDrawer();
+ drawer.setSelection(UPLOAD_ID, false);
+
semesterChooserLinear = findViewById(R.id.upload_fields_builder_choose_semester);
semesterRadio = findViewById(R.id.upload_fields_builder_semester_radio_group);
semesterRadio.check(Integer.parseInt(semester) % 2 == 0
@@ -121,8 +125,8 @@ public class UploadFieldsBuilderActivity extends AppCompatActivity {
} else if (semesterChooserLinear.getVisibility() == View.VISIBLE && semesterId == -1) {
Toast.makeText(view.getContext(), "Please choose a semester for the upload", Toast.LENGTH_SHORT).show();
return;
- } else if (year.getText().toString().isEmpty()) {
- Toast.makeText(view.getContext(), "Please choose a year for the upload", Toast.LENGTH_SHORT).show();
+ } else if (year.getText().toString().isEmpty() || !isValidYear) {
+ Toast.makeText(view.getContext(), "Please choose a valid year for the upload", Toast.LENGTH_SHORT).show();
return;
}
@@ -212,304 +216,324 @@ public class UploadFieldsBuilderActivity extends AppCompatActivity {
return getGreeklishOrMinifiedCourseName(false);
}
+ private String normalizeLatinNumbers(String stringWithLatinNumbers) {
+ String greekLatinOne = "Ι", englishLatinOne = "I";
+ String normalisedString;
+
+ //Separates the latin number suffix from the course name
+ final String regex = "(.+)\\ ([IΙ]+)";
+ final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
+ final Matcher matcher = pattern.matcher(stringWithLatinNumbers);
+
+ if (matcher.matches() && matcher.groupCount() == 2) {
+ normalisedString = matcher.group(1) + " " + matcher.group(2).replaceAll(greekLatinOne, englishLatinOne);
+ } else {
+ normalisedString = stringWithLatinNumbers;
+ }
+
+ return normalisedString;
+ }
@Nullable
private String getGreeklishOrMinifiedCourseName(boolean greeklish) {
- if (course.contains("Ψηφιακή Επεξεργασία Σήματος")) {
+ String normalisedCourse = normalizeLatinNumbers(course);
+
+ if (normalisedCourse.contains(("Ψηφιακή Επεξεργασία Σήματος"))) {
return greeklish ? "PSES" : "ΨΕΣ";
- } else if (course.contains("Ψηφιακή Επεξεργασία Εικόνας")) {
+ } else if (normalisedCourse.contains(("Ψηφιακή Επεξεργασία Εικόνας"))) {
return greeklish ? "psee" : "ΨΕΕ";
- } else if (course.contains("Ψηφιακές Τηλεπικοινωνίες ΙΙ")) {
+ } else if (normalisedCourse.contains(("Ψηφιακές Τηλεπικοινωνίες II"))) {
return greeklish ? "pshf_thlep_II" : "Ψηφιακές Τηλεπ. 2";
- } else if (course.contains("Ψηφιακές Τηλεπικοινωνίες Ι")) {
+ } else if (normalisedCourse.contains(("Ψηφιακές Τηλεπικοινωνίες I"))) {
return greeklish ? "pshf_thlep_I" : "Ψηφιακές Τηλεπ. 1";
- } else if (course.contains("Ψηφιακά Φίλτρα")) {
+ } else if (normalisedCourse.contains(("Ψηφιακά Φίλτρα"))) {
return greeklish ? "filtra" : "Φίλτρα";
- } else if (course.contains("Ψηφιακά Συστήματα ΙΙΙ")) {
+ } else if (normalisedCourse.contains(("Ψηφιακά Συστήματα III"))) {
return greeklish ? "pshfiaka_III" : "Ψηφιακά 3";
- } else if (course.contains("Ψηφιακά Συστήματα ΙΙ")) {
+ } else if (normalisedCourse.contains(("Ψηφιακά Συστήματα II"))) {
return greeklish ? "pshfiaka_II" : "Ψηφιακά 2";
- } else if (course.contains("Ψηφιακά Συστήματα Ι")) {
+ } else if (normalisedCourse.contains(("Ψηφιακά Συστήματα I"))) {
return greeklish ? "pshfiaka_I" : "Ψηφιακά 1";
- } else if (course.contains("Φωτονική Τεχνολογία")) {
+ } else if (normalisedCourse.contains(("Φωτονική Τεχνολογία"))) {
return greeklish ? "fwtonikh" : "Φωτονική";
- } else if (course.contains("Φυσική Ι")) {
+ } else if (normalisedCourse.contains(("Φυσική I"))) {
return greeklish ? "fysikh_I" : "Φυσική 1";
- } else if (course.contains("Υψηλές Τάσεις ΙΙΙ")) {
+ } else if (normalisedCourse.contains(("Υψηλές Τάσεις III"))) {
return greeklish ? "ypshles_III" : "Υψηλές 3";
- } else if (course.contains("Υψηλές Τάσεις ΙΙ")) {
+ } else if (normalisedCourse.contains(("Υψηλές Τάσεις II"))) {
return greeklish ? "ypshles_II" : "Υψηλές 2";
- } else if (course.contains("Υψηλές Τάσεις Ι")) {
+ } else if (normalisedCourse.contains(("Υψηλές Τάσεις I"))) {
return greeklish ? "ypshles_I" : "Υψηλές 1";
- } else if (course.contains("Υψηλές Τάσεις 4")) {
+ } else if (normalisedCourse.contains(("Υψηλές Τάσεις 4"))) {
return greeklish ? "ypshles_IV" : "Υψηλές 4";
- } else if (course.contains("Υπολογιστικός Ηλεκτρομαγνητισμός")) {
+ } else if (normalisedCourse.contains(("Υπολογιστικός Ηλεκτρομαγνητισμός"))) {
return greeklish ? "ypologistikos_HM" : "Υπολογιστικός Η/Μ";
- } else if (course.contains("Υπολογιστικές Μέθοδοι στα Ενεργειακά Συστήματα")) {
+ } else if (normalisedCourse.contains(("Υπολογιστικές Μέθοδοι στα Ενεργειακά Συστήματα"))) {
return greeklish ? "ymes" : "ΥΜΕΣ";
- } else if (course.contains("Τηλεπικοινωνιακή Ηλεκτρονική")) {
+ } else if (normalisedCourse.contains(("Τηλεπικοινωνιακή Ηλεκτρονική"))) {
return greeklish ? "tilep_ilektr" : "Τηλεπ. Ηλεκτρ.";
- } else if (course.contains("Τηλεοπτικά Συστήματα")) {
+ } else if (normalisedCourse.contains(("Τηλεοπτικά Συστήματα"))) {
return greeklish ? "tileoptika" : "Τηλεοπτικά";
- } else if (course.contains("Τεχνολογία Λογισμικού")) {
+ } else if (normalisedCourse.contains(("Τεχνολογία Λογισμικού"))) {
return greeklish ? "SE" : "Τεχνολογία Λογισμικού";
- } else if (course.contains("Τεχνολογία Ηλεκτροτεχνικών Υλικών")) {
+ } else if (normalisedCourse.contains(("Τεχνολογία Ηλεκτροτεχνικών Υλικών"))) {
return greeklish ? "Hlektrotexnika_Ylika" : "Ηλεκτροτεχνικά Υλικά";
- } else if (course.contains("Τεχνολογία Ήχου και Εικόνας")) {
+ } else if (normalisedCourse.contains(("Τεχνολογία Ήχου και Εικόνας"))) {
return greeklish ? "texn_hxoy_eikonas" : "Τεχνολογία Ήχου και Εικόνας";
- } else if (course.contains("Τεχνική Μηχανική")) {
+ } else if (normalisedCourse.contains(("Τεχνική Μηχανική"))) {
return greeklish ? "texn_mhxan" : "Τεχν. Μηχαν.";
- } else if (course.contains("Τεχνικές μη Καταστρεπτικών Δοκιμών")) {
+ } else if (normalisedCourse.contains(("Τεχνικές μη Καταστρεπτικών Δοκιμών"))) {
return greeklish ? "non_destructive_tests" : "Μη Καταστρεπτικές Δοκιμές";
- } else if (course.contains("Τεχνικές Σχεδίασης με Η/Υ")) {
+ } else if (normalisedCourse.contains(("Τεχνικές Σχεδίασης με Η/Υ"))) {
return greeklish ? "sxedio" : "Σχέδιο";
- } else if (course.contains("Τεχνικές Κωδικοποίησης")) {
+ } else if (normalisedCourse.contains(("Τεχνικές Κωδικοποίησης"))) {
return greeklish ? "texn_kwdikopoihshs" : "Τεχνικές Κωδικοποίησης";
- } else if (course.contains("Τεχνικές Βελτιστοποίησης")) {
+ } else if (normalisedCourse.contains(("Τεχνικές Βελτιστοποίησης"))) {
return greeklish ? "veltistopoihsh" : "Βελτιστοποίηση";
- } else if (course.contains("Σύνθεση Τηλεπικοινωνιακών Διατάξεων")) {
+ } else if (normalisedCourse.contains(("Σύνθεση Τηλεπικοινωνιακών Διατάξεων"))) {
return greeklish ? "synth_thlep_diataksewn" : "Σύνθεση Τηλεπ. Διατάξεων";
- } else if (course.contains("Σύνθεση Ενεργών και Παθητικών Κυκλωμάτων")) {
+ } else if (normalisedCourse.contains(("Σύνθεση Ενεργών και Παθητικών Κυκλωμάτων"))) {
return greeklish ? "synthesh" : "Σύνθεση";
- } else if (course.contains("Σχεδίαση Συστημάτων VLSI")) {
+ } else if (normalisedCourse.contains(("Σχεδίαση Συστημάτων VLSI"))) {
return greeklish ? "VLSI" : "VLSI";
- } else if (course.contains("Συστήματα Υπολογιστών (Υπολογιστικά Συστήματα)")) {
+ } else if (normalisedCourse.contains(("Συστήματα Υπολογιστών (Υπολογιστικά Συστήματα)"))) {
return greeklish ? "sys_ypologistwn" : "Συσ. Υπολογιστών";
- } else if (course.contains("Συστήματα Πολυμέσων και Εικονική Πραγματικότητα")) {
+ } else if (normalisedCourse.contains(("Συστήματα Πολυμέσων και Εικονική Πραγματικότητα"))) {
return greeklish ? "polymesa" : "Πολυμέσα";
- } else if (course.contains("Συστήματα Μικροϋπολογιστών")) {
+ } else if (normalisedCourse.contains(("Συστήματα Μικροϋπολογιστών"))) {
return greeklish ? "mikro_I" : "Μίκρο 1";
- } else if (course.contains("Συστήματα Ηλεκτροκίνησης")) {
+ } else if (normalisedCourse.contains(("Συστήματα Ηλεκτροκίνησης"))) {
return greeklish ? "hlektrokinhsh" : "Ηλεκτροκίνηση";
- } else if (course.contains("Συστήματα Ηλεκτρικής Ενέργειας ΙΙΙ")) {
+ } else if (normalisedCourse.contains(("Συστήματα Ηλεκτρικής Ενέργειας III"))) {
return greeklish ? "SHE_III" : "ΣΗΕ 3";
- } else if (course.contains("Συστήματα Ηλεκτρικής Ενέργειας ΙΙ")) {
+ } else if (normalisedCourse.contains(("Συστήματα Ηλεκτρικής Ενέργειας II"))) {
return greeklish ? "SHE_II" : "ΣΗΕ 2";
- } else if (course.contains("Συστήματα Ηλεκτρικής Ενέργειας Ι")) {
+ } else if (normalisedCourse.contains(("Συστήματα Ηλεκτρικής Ενέργειας I"))) {
return greeklish ? "SHE_I" : "ΣΗΕ 1";
- } else if (course.contains("Συστήματα Αυτομάτου Ελέγχου ΙΙI")) {
+ } else if (normalisedCourse.contains(("Συστήματα Αυτομάτου Ελέγχου III"))) {
return greeklish ? "SAE_III" : "ΣΑΕ 3";
- } else if (course.contains("Συστήματα Αυτομάτου Ελέγχου ΙΙ")) {
+ } else if (normalisedCourse.contains(("Συστήματα Αυτομάτου Ελέγχου II"))) {
return greeklish ? "SAE_II" : "ΣΑΕ 2";
- } else if (course.contains("Συστήματα Αυτομάτου Ελέγχου Ι")) {
+ } else if (normalisedCourse.contains(("Συστήματα Αυτομάτου Ελέγχου I"))) {
return greeklish ? "SAE_1" : "ΣΑΕ 1";
- } else if (course.contains("Στοχαστικό Σήμα")) {
+ } else if (normalisedCourse.contains(("Στοχαστικό Σήμα"))) {
return greeklish ? "stox_shma" : "Στοχ. Σήμα";
- } else if (course.contains("Σταθμοί Παραγωγής Ηλεκτρικής Ενέργειας")) {
+ } else if (normalisedCourse.contains(("Σταθμοί Παραγωγής Ηλεκτρικής Ενέργειας"))) {
return greeklish ? "SPHE" : "ΣΠΗΕ";
- } else if (course.contains("Σερβοκινητήρια Συστήματα")) {
+ } else if (normalisedCourse.contains(("Σερβοκινητήρια Συστήματα"))) {
return greeklish ? "servo" : "Σέρβο";
- } else if (course.contains("Σήματα και Συστήματα")) {
+ } else if (normalisedCourse.contains(("Σήματα και Συστήματα"))) {
return greeklish ? "analog_shma" : "Σύματα & Συστήματα";
- } else if (course.contains("Ρομποτική")) {
+ } else if (normalisedCourse.contains(("Ρομποτική"))) {
return greeklish ? "rompotikh" : "Ρομποτική";
- } else if (course.contains("Προσομοίωση και Μοντελοποίηση Συστημάτων")) {
+ } else if (normalisedCourse.contains(("Προσομοίωση και Μοντελοποίηση Συστημάτων"))) {
return greeklish ? "montelopoihsh" : "Μοντελοποίηση";
- } else if (course.contains("Προηγμένες Τεχνικές Επεξεργασίας Σήματος")) {
+ } else if (normalisedCourse.contains(("Προηγμένες Τεχνικές Επεξεργασίας Σήματος"))) {
return greeklish ? "ptes" : "ΠΤΕΣ";
- } else if (course.contains("Προγραμματιστικές Τεχνικές")) {
+ } else if (normalisedCourse.contains(("Προγραμματιστικές Τεχνικές"))) {
return greeklish ? "cpp" : "Προγραμματ. Τεχν.";
- } else if (course.contains("Προγραμματιζόμενα Κυκλώματα ASIC")) {
+ } else if (normalisedCourse.contains(("Προγραμματιζόμενα Κυκλώματα ASIC"))) {
return greeklish ? "asic" : "ASIC";
- } else if (course.contains("Παράλληλα και Κατανεμημένα Συστήματα")) {
+ } else if (normalisedCourse.contains(("Παράλληλα και Κατανεμημένα Συστήματα"))) {
return greeklish ? "parallhla" : "Παράλληλα";
- } else if (course.contains("Οργάνωση και Διοίκηση Εργοστασίων")) {
+ } else if (normalisedCourse.contains(("Οργάνωση και Διοίκηση Εργοστασίων"))) {
return greeklish ? "organ_dioik_ergostasiwn" : "Οργάνωση και Διοίκηση Εργοστασίων";
- } else if (course.contains("Οργάνωση Υπολογιστών")) {
+ } else if (normalisedCourse.contains(("Οργάνωση Υπολογιστών"))) {
return greeklish ? "org_ypol" : "Οργάνωση Υπολ.";
- } else if (course.contains("Οπτική ΙΙ")) {
+ } else if (normalisedCourse.contains(("Οπτική II"))) {
return greeklish ? "optikh_II" : "Οπτική 2";
- } else if (course.contains("Οπτική Ι")) {
+ } else if (normalisedCourse.contains(("Οπτική I"))) {
return greeklish ? "optikh_I" : "Οπτική 1";
- } else if (course.contains("Οπτικές Επικοινωνίες")) {
+ } else if (normalisedCourse.contains(("Οπτικές Επικοινωνίες"))) {
return greeklish ? "optikes_thlep" : "Οπτικές Τηλεπ.";
- } else if (course.contains("Μικροκύματα II")) {
+ } else if (normalisedCourse.contains(("Μικροκύματα II"))) {
return greeklish ? "mikrokymata_II" : "Μικροκύματα 2";
- } else if (course.contains("Μικροκύματα I")) {
+ } else if (normalisedCourse.contains(("Μικροκύματα I"))) {
return greeklish ? "mikrokymata_I" : "Μικροκύματα 1";
- } else if (course.contains("Μικροκυματική Τηλεπισκόπηση")) {
+ } else if (normalisedCourse.contains(("Μικροκυματική Τηλεπισκόπηση"))) {
return greeklish ? "thlepiskophsh" : "Τηλεπισκόπηση";
- } else if (course.contains("Μικροεπεξεργαστές και Περιφερειακά")) {
+ } else if (normalisedCourse.contains(("Μικροεπεξεργαστές και Περιφερειακά"))) {
return greeklish ? "mikro_II" : "Μίκρο 2";
- } else if (course.contains("Μετάδοση Θερμότητας")) {
+ } else if (normalisedCourse.contains(("Μετάδοση Θερμότητας"))) {
return greeklish ? "metadosi_therm" : "Μετάδοση Θερμ.";
- } else if (course.contains("Λογισμός ΙΙ")) {
+ } else if (normalisedCourse.contains(("Λογισμός II"))) {
return greeklish ? "logismos_II" : "Λογισμός 2";
- } else if (course.contains("Λογισμός Ι")) {
+ } else if (normalisedCourse.contains(("Λογισμός I"))) {
return greeklish ? "logismos_I" : "Λογισμός 1";
- } else if (course.contains("Λογική Σχεδίαση")) {
+ } else if (normalisedCourse.contains(("Λογική Σχεδίαση"))) {
return greeklish ? "logiki_sxediash" : "Λογική Σχεδίαση";
- } else if (course.contains("Λειτουργικά Συστήματα")) {
+ } else if (normalisedCourse.contains(("Λειτουργικά Συστήματα"))) {
return greeklish ? "OS" : "Λειτουργικά";
- } else if (course.contains("Κινητές και Δορυφορικές Επικοινωνίες")) {
+ } else if (normalisedCourse.contains(("Κινητές και Δορυφορικές Επικοινωνίες"))) {
return greeklish ? "kinhtes_doryforikes_epik" : "Κινητές & Δορυφορικές Επικοινωνίες";
- } else if (course.contains("Κβαντική Φυσική")) {
+ } else if (normalisedCourse.contains(("Κβαντική Φυσική"))) {
return greeklish ? "kvantikh" : "Κβαντική";
- } else if (course.contains("Θεωρία και Τεχνολογία Πυρηνικών Αντιδραστήρων")) {
+ } else if (normalisedCourse.contains(("Θεωρία και Τεχνολογία Πυρηνικών Αντιδραστήρων"))) {
return greeklish ? "texn_antidrasthrwn" : "Τεχνολογία Αντιδραστήρων";
- } else if (course.contains("Θεωρία Υπολογισμών και Αλγορίθμων")) {
+ } else if (normalisedCourse.contains(("Θεωρία Υπολογισμών και Αλγορίθμων"))) {
return greeklish ? "thya" : "ΘΥΑ";
- } else if (course.contains("Θεωρία Σκέδασης")) {
+ } else if (normalisedCourse.contains(("Θεωρία Σκέδασης"))) {
return greeklish ? "skedash" : "Σκέδαση";
- } else if (course.contains("Θεωρία Σημάτων και Γραμμικών Συστημάτων")) {
+ } else if (normalisedCourse.contains(("Θεωρία Σημάτων και Γραμμικών Συστημάτων"))) {
return greeklish ? "analog_shma" : "Σύματα & Συστήματα";
- } else if (course.contains("Θεωρία Πληροφοριών")) {
+ } else if (normalisedCourse.contains(("Θεωρία Πληροφοριών"))) {
return greeklish ? "theoria_plir" : "Θεωρία Πληρ.";
- } else if (course.contains("Θεωρία Πιθανοτήτων και Στατιστική")) {
+ } else if (normalisedCourse.contains(("Θεωρία Πιθανοτήτων και Στατιστική"))) {
return greeklish ? "pithanothtes" : "Πιθανότητες";
- } else if (course.contains("Ημιαγωγά Υλικά: Θεωρία-Διατάξεις")) {
+ } else if (normalisedCourse.contains(("Ημιαγωγά Υλικά: Θεωρία-Διατάξεις"))) {
return greeklish ? "Hmiagwga_Ylika" : "Ημιαγωγά Υλικά";
- } else if (course.contains("Ηλεκτρονική ΙΙΙ")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρονική III"))) {
return greeklish ? "hlektronikh_III" : "Ηλεκτρονική 3";
- } else if (course.contains("Ηλεκτρονική ΙΙ")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρονική II"))) {
return greeklish ? "hlektronikh_2" : "Ηλεκτρονική 2";
- } else if (course.contains("Ηλεκτρονική Ι")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρονική I"))) {
return greeklish ? "hlektronikh_1" : "Ηλεκτρονική 1";
- } else if (course.contains("Ηλεκτρονικές Διατάξεις και Μετρήσεις")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρονικές Διατάξεις και Μετρήσεις"))) {
return greeklish ? "hlektron_diatakseis_metrhseis" : "Ηλεκτρονικές Διατάξεις και Μετρήσεις";
- } else if (course.contains("Ηλεκτρονικά Ισχύος ΙΙ")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρονικά Iσχύος II"))) {
return greeklish ? "isxyos_II" : "Ισχύος 2";
- } else if (course.contains("Ηλεκτρονικά Ισχύος Ι")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρονικά Iσχύος I"))) {
return greeklish ? "isxyos_I" : "Ισχύος 1";
- } else if (course.contains("Ηλεκτρομαγνητικό Πεδίο ΙΙ")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρομαγνητικό Πεδίο II"))) {
return greeklish ? "pedio_II" : "Πεδίο 2";
- } else if (course.contains("Ηλεκτρομαγνητικό Πεδίο Ι")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρομαγνητικό Πεδίο I"))) {
return greeklish ? "pedio_I" : "Πεδίο 1";
- } else if (course.contains("Ηλεκτρομαγνητική Συμβατότητα")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρομαγνητική Συμβατότητα"))) {
return greeklish ? "HM_symvatothta" : "H/M Συμβατότητα";
- } else if (course.contains("Ηλεκτρολογικά Υλικά")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρολογικά Υλικά"))) {
return greeklish ? "ylika" : "Ηλεκτρ. Υλικά";
- } else if (course.contains("Ηλεκτρική Οικονομία")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρική Οικονομία"))) {
return greeklish ? "hlektr_oikonomia" : "Ηλεκτρική Οικονομία";
- } else if (course.contains("Ηλεκτρικές Μηχανές Γ'")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρικές Μηχανές Γ'"))) {
return greeklish ? "mhxanes_C" : "Μηχανές Γ";
- } else if (course.contains("Ηλεκτρικές Μηχανές Β'")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρικές Μηχανές Β'"))) {
return greeklish ? "mhxanes_B" : "Μηχανές Β";
- } else if (course.contains("Ηλεκτρικές Μηχανές Α'")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρικές Μηχανές Α'"))) {
return greeklish ? "mhxanes_A" : "Μηχανές Α";
- } else if (course.contains("Ηλεκτρικές Μετρήσεις ΙΙ")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρικές Μετρήσεις II"))) {
return greeklish ? "metrhseis_II" : "Μετρήσεις 2";
- } else if (course.contains("Ηλεκτρικές Μετρήσεις Ι")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρικές Μετρήσεις I"))) {
return greeklish ? "metrhseis_1" : "Μετρήσεις 1";
- } else if (course.contains("Ηλεκτρικά Κυκλώματα ΙΙΙ")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρικά Κυκλώματα III"))) {
return greeklish ? "kyklwmata_I" : "Κυκλώματα 3";
- } else if (course.contains("Ηλεκτρικά Κυκλώματα ΙΙ")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρικά Κυκλώματα II"))) {
return greeklish ? "kyklwmata_II" : "Κυκλώματα 2";
- } else if (course.contains("Ηλεκτρικά Κυκλώματα Ι")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρικά Κυκλώματα I"))) {
return greeklish ? "kyklwmata_I" : "Κυκλώματα 1";
- } else if (course.contains("Ηλεκτρακουστική ΙΙ")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρακουστική II"))) {
return greeklish ? "hlektroakoystikh_II" : "Ηλεκτροακουστική 2";
- } else if (course.contains("Ηλεκτρακουστική Ι")) {
+ } else if (normalisedCourse.contains(("Ηλεκτρακουστική I"))) {
return greeklish ? "hlektroakoystikh_I" : "Ηλεκτροακουστική 1";
- } else if (course.contains("Εφαρμοσμένη Θερμοδυναμική")) {
+ } else if (normalisedCourse.contains(("Εφαρμοσμένη Θερμοδυναμική"))) {
return greeklish ? "thermodynamikh" : "Θερμοδυναμική";
- } else if (course.contains("Εφαρμοσμένα Μαθηματικά ΙΙ")) {
+ } else if (normalisedCourse.contains(("Εφαρμοσμένα Μαθηματικά II"))) {
return greeklish ? "efarmosmena_math_II" : "Εφαρμοσμένα 2";
- } else if (course.contains("Εφαρμοσμένα Μαθηματικά Ι")) {
+ } else if (normalisedCourse.contains(("Εφαρμοσμένα Μαθηματικά I"))) {
return greeklish ? "efarmosmena_math_I" : "Εφαρμοσμένα 1";
- } else if (course.contains("Εφαρμογές Τηλεπικοινωνιακών Διατάξεων")) {
+ } else if (normalisedCourse.contains(("Εφαρμογές Τηλεπικοινωνιακών Διατάξεων"))) {
return greeklish ? "efarm_thlep_diataksewn" : "Εφαρμογές Τηλεπ. Διατάξεων";
- } else if (course.contains("Ευφυή Συστήματα Ρομπότ")) {
+ } else if (normalisedCourse.contains(("Ευφυή Συστήματα Ρομπότ"))) {
return greeklish ? "eufuh" : "Ευφυή";
- } else if (course.contains("Ευρυζωνικά Δίκτυα")) {
+ } else if (normalisedCourse.contains(("Ευρυζωνικά Δίκτυα"))) {
return greeklish ? "eyryzwnika" : "Ευρυζωνικά";
- } else if (course.contains("Επιχειρησιακή Έρευνα")) {
+ } else if (normalisedCourse.contains(("Επιχειρησιακή Έρευνα"))) {
return greeklish ? "epixeirisiaki" : "Επιχειρησιακή Έρευνα";
- } else if (course.contains("Ενσωματωμένα Συστήματα Πραγματικού Χρόνου")) {
+ } else if (normalisedCourse.contains(("Ενσωματωμένα Συστήματα Πραγματικού Χρόνου"))) {
return greeklish ? "enswmatwmena" : "Ενσωματωμένα";
- } else if (course.contains("Εισαγωγή στις εφαρμογές Πυρηνικής Τεχνολογίας")) {
+ } else if (normalisedCourse.contains(("Εισαγωγή στις εφαρμογές Πυρηνικής Τεχνολογίας"))) {
return greeklish ? "Intro_Purhnikh_Texn" : "Εισ. Πυρηνικη Τεχν.";
- } else if (course.contains("Εισαγωγή στην Πολιτική Οικονομία")) {
+ } else if (normalisedCourse.contains(("Εισαγωγή στην Πολιτική Οικονομία"))) {
return greeklish ? "polit_oik" : "Πολιτική Οικονομία";
- } else if (course.contains("Εισαγωγή στην Ενεργειακή Τεχνολογία ΙΙ")) {
+ } else if (normalisedCourse.contains(("Εισαγωγή στην Ενεργειακή Τεχνολογία II"))) {
return greeklish ? "EET_2" : "ΕΕΤ2";
- } else if (course.contains("Εισαγωγή στην Ενεργειακή Τεχνολογία Ι")) {
+ } else if (normalisedCourse.contains(("Εισαγωγή στην Ενεργειακή Τεχνολογία I"))) {
return greeklish ? "EET_I" : "ΕΕΤ 1";
- } else if (course.contains("Ειδικές Κεραίες, Σύνθεση Κεραιών")) {
+ } else if (normalisedCourse.contains(("Ειδικές Κεραίες, Σύνθεση Κεραιών"))) {
return greeklish ? "eidikes_keraies" : "Ειδικές Κεραίες, Σύνθεση Κεραιών";
- } else if (course.contains("Ειδικές Αρχιτεκτονικές Υπολογιστών")) {
+ } else if (normalisedCourse.contains(("Ειδικές Αρχιτεκτονικές Υπολογιστών"))) {
return greeklish ? "eidikes_arx_ypolog" : "Ειδικές Αρχιτεκτονικές Υπολογιστών";
- } else if (course.contains("Ειδικά Κεφάλαια Συστημάτων Ηλεκτρικής Ενέργειας")) {
+ } else if (normalisedCourse.contains(("Ειδικά Κεφάλαια Συστημάτων Ηλεκτρικής Ενέργειας"))) {
return greeklish ? "ekshe" : "ΕΚΣΗΕ";
- } else if (course.contains("Ειδικά Κεφάλαια Ηλεκτρομαγνητικού Πεδίου Ι")) {
- return greeklish ? "eidika_kef_HM_pedioy_I" : "Ειδικά Κεφάλαια Ηλεκτρομαγνητικού Πεδίου Ι";
- } else if (course.contains("Ειδικά Κεφάλαια Διαφορικών Εξισώσεων")) {
+ } else if (normalisedCourse.contains(("Ειδικά Κεφάλαια Ηλεκτρομαγνητικού Πεδίου I"))) {
+ return greeklish ? "eidika_kef_HM_pedioy_I" : "Ειδικά Κεφάλαια Ηλεκτρομαγνητικού Πεδίου I";
+ } else if (normalisedCourse.contains(("Ειδικά Κεφάλαια Διαφορικών Εξισώσεων"))) {
return greeklish ? "eidika_kef_diaf_eksis" : "Ειδικά Κεφάλαια Διαφορικών Εξισώσεων";
- } else if (course.contains("Δομημένος Προγραμματισμός")) {
+ } else if (normalisedCourse.contains(("Δομημένος Προγραμματισμός"))) {
return greeklish ? "C" : "Δομ. Προγραμμ.";
- } else if (course.contains("Δομές Δεδομένων")) {
+ } else if (normalisedCourse.contains(("Δομές Δεδομένων"))) {
return greeklish ? "dom_dedomenwn" : "Δομ. Δεδομ.";
- } else if (course.contains("Διαχείριση Συστημάτων Ηλεκτρικής Ενέργειας")) {
+ } else if (normalisedCourse.contains(("Διαχείριση Συστημάτων Ηλεκτρικής Ενέργειας"))) {
return greeklish ? "dshe" : "ΔΣΗΕ";
- } else if (course.contains("Διαφορικές Εξισώσεις")) {
+ } else if (normalisedCourse.contains(("Διαφορικές Εξισώσεις"))) {
return greeklish ? "diaforikes" : "Διαφορικές";
- } else if (course.contains("Διανεμημένη Παραγωγή")) {
+ } else if (normalisedCourse.contains(("Διανεμημένη Παραγωγή"))) {
return greeklish ? "dian_paragwgh" : "Διανεμημένη Παραγωγή";
- } else if (course.contains("Διακριτά μαθηματικά")) {
+ } else if (normalisedCourse.contains(("Διακριτά μαθηματικά"))) {
return greeklish ? "diakrita" : "Διακριτά Μαθηματικά";
- } else if (course.contains("Διακριτά Μαθηματικά")) {
+ } else if (normalisedCourse.contains(("Διακριτά Μαθηματικά"))) {
return greeklish ? "diakrita" : "Διακριτά Μαθηματικά";
- } else if (course.contains("Διάδοση Ηλεκτρομαγνητικού Κύματος Ι (πρώην Πεδίο ΙΙΙ)")) {
+ } else if (normalisedCourse.contains(("Διάδοση Ηλεκτρομαγνητικού Κύματος I (πρώην Πεδίο III)"))) {
return greeklish ? "diadosi_1" : "Διάδοση 1";
- } else if (course.contains("Διάδοση Η/Μ Κύματος ΙΙ")) {
+ } else if (normalisedCourse.contains(("Διάδοση Η/Μ Κύματος II"))) {
return greeklish ? "diadosi_II" : "Διάδοση 2";
- } else if (course.contains("Δίκτυα Υπολογιστών ΙΙ")) {
+ } else if (normalisedCourse.contains(("Δίκτυα Υπολογιστών II"))) {
return greeklish ? "diktya_II" : "Δίκτυα 2";
- } else if (course.contains("Δίκτυα Υπολογιστών Ι")) {
+ } else if (normalisedCourse.contains(("Δίκτυα Υπολογιστών I"))) {
return greeklish ? "diktya_I" : "Δίκτυα 1";
- } else if (course.contains("Δίκτυα Τηλεπικοινωνιών")) {
+ } else if (normalisedCourse.contains(("Δίκτυα Τηλεπικοινωνιών"))) {
return greeklish ? "diktya_thlep" : "Δίκτυα Τηλέπ.";
- } else if (course.contains("Γραφική με Υπολογιστές")) {
+ } else if (normalisedCourse.contains(("Γραφική με Υπολογιστές"))) {
return greeklish ? "grafikh" : "Γραφική";
- } else if (course.contains("Γραμμική Άλγεβρα")) {
+ } else if (normalisedCourse.contains(("Γραμμική Άλγεβρα"))) {
return greeklish ? "grammikh_algebra" : "Γραμμ. Άλγεβρ.";
- } else if (course.contains("Γεωηλεκτρομαγνητισμός")) {
+ } else if (normalisedCourse.contains(("Γεωηλεκτρομαγνητισμός"))) {
return greeklish ? "geohlektromagnitismos" : "Γεωηλεκτρομαγνητισμός";
- } else if (course.contains("Βιοϊατρική Τεχνολογία")) {
+ } else if (normalisedCourse.contains(("Βιοϊατρική Τεχνολογία"))) {
return greeklish ? "vioiatriki" : "Βιοιατρική";
- } else if (course.contains("Βιομηχανική Πληροφορική")) {
+ } else if (normalisedCourse.contains(("Βιομηχανική Πληροφορική"))) {
return greeklish ? "viomix_plir" : "Βιομηχανική Πληρ";
- } else if (course.contains("Βιομηχανικά Ηλεκτρονικά")) {
+ } else if (normalisedCourse.contains(("Βιομηχανικά Ηλεκτρονικά"))) {
return greeklish ? "bhomix_hlektronika" : "Βιομηχανικά Ηλεκτρονικά";
- } else if (course.contains("Βάσεις Δεδομένων")) {
+ } else if (normalisedCourse.contains(("Βάσεις Δεδομένων"))) {
return greeklish ? "vaseis" : "Βάσεις";
- } else if (course.contains("Ασύρματος Τηλεπικοινωνία ΙΙ")) {
+ } else if (normalisedCourse.contains(("Ασύρματος Τηλεπικοινωνία II"))) {
return greeklish ? "asyrmatos_II" : "Ασύρματος 2";
- } else if (course.contains("Ασύρματος Τηλεπικοινωνία Ι")) {
+ } else if (normalisedCourse.contains(("Ασύρματος Τηλεπικοινωνία I"))) {
return greeklish ? "asyrmatos_I" : "Ασύρματος 1";
- } else if (course.contains("Ασφάλεια Πληροφοριακών Συστημάτων")) {
+ } else if (normalisedCourse.contains(("Ασφάλεια Πληροφοριακών Συστημάτων"))) {
return greeklish ? "asfaleia" : "Ασφάλεια";
- } else if (course.contains("Ασαφή Συστήματα")) {
+ } else if (normalisedCourse.contains(("Ασαφή Συστήματα"))) {
return greeklish ? "asafh" : "Ασαφή";
- } else if (course.contains("Αρχιτεκτονική Υπολογιστών")) {
+ } else if (normalisedCourse.contains(("Αρχιτεκτονική Υπολογιστών"))) {
return greeklish ? "arx_ypologistwn" : "Αρχ. Υπολογιστών";
- } else if (course.contains("Αρχές Παράλληλης Επεξεργασίας")) {
+ } else if (normalisedCourse.contains(("Αρχές Παράλληλης Επεξεργασίας"))) {
return greeklish ? "arxes_parall_epeksergasias" : "Αρχές Παράλληλης Επεξεργασίας";
- } else if (course.contains("Αρχές Οικονομίας")) {
+ } else if (normalisedCourse.contains(("Αρχές Οικονομίας"))) {
return greeklish ? "arx_oikonomias" : "Αρχές Οικονομίας";
- } else if (course.contains("Αριθμητική Ανάλυση")) {
+ } else if (normalisedCourse.contains(("Αριθμητική Ανάλυση"))) {
return greeklish ? "arith_anal" : "Αριθμ. Ανάλυση";
- } else if (course.contains("Αξιοπιστία Συστημάτων")) {
+ } else if (normalisedCourse.contains(("Αξιοπιστία Συστημάτων"))) {
return greeklish ? "aksiopistia_systhmatwn" : "Αξιοπιστία Συστημάτων";
- } else if (course.contains("Αντικειμενοστραφής Προγραμματισμός")) {
+ } else if (normalisedCourse.contains(("Αντικειμενοστραφής Προγραμματισμός"))) {
return greeklish ? "OOP" : "Αντικειμενοστραφής";
- } else if (course.contains("Αναλογικές Τηλεπικοινωνίες (πρώην Τηλεπικοινωνιακά Συστήματα Ι)")) {
+ } else if (normalisedCourse.contains(("Αναλογικές Τηλεπικοινωνίες (πρώην Τηλεπικοινωνιακά Συστήματα I)"))) {
return greeklish ? "anal_thlep" : "Αναλογικές Τηλεπ.";
- } else if (course.contains("Αναγνώριση Προτύπων")) {
+ } else if (normalisedCourse.contains(("Αναγνώριση Προτύπων"))) {
return greeklish ? "protipa" : "Αναγνώριση Προτύπων";
- } else if (course.contains("Ανάλυση και Σχεδίαση Αλγορίθμων")) {
+ } else if (normalisedCourse.contains(("Ανάλυση και Σχεδίαση Αλγορίθμων"))) {
return greeklish ? "algorithms" : "Αλγόριθμοι";
- } else if (course.contains("Ανάλυση Χρονοσειρών")) {
+ } else if (normalisedCourse.contains(("Ανάλυση Χρονοσειρών"))) {
return greeklish ? "xronoseires" : "Χρονοσειρές";
- } else if (course.contains("Ανάλυση Συστημάτων Ηλεκτρικής Ενέργειας")) {
+ } else if (normalisedCourse.contains(("Ανάλυση Συστημάτων Ηλεκτρικής Ενέργειας"))) {
return greeklish ? "ASHE" : "ΑΣΗΕ";
- } else if (course.contains("Ανάλυση Ηλεκτρικών Κυκλωμάτων με Υπολογιστή")) {
+ } else if (normalisedCourse.contains(("Ανάλυση Ηλεκτρικών Κυκλωμάτων με Υπολογιστή"))) {
return greeklish ? "analysh_hlektr_kykl" : "Ανάλυση Ηλεκτρικ. Κυκλ. με Υπολογιστή";
- } else if (course.contains("Ακουστική ΙΙ")) {
+ } else if (normalisedCourse.contains(("Ακουστική II"))) {
return greeklish ? "akoystikh_II" : "Ακουστική 2";
- } else if (course.contains("Ακουστική Ι")) {
+ } else if (normalisedCourse.contains(("Ακουστική I"))) {
return greeklish ? "akoystikh_I" : "Ακουστική 1";
} else {
+ Timber.wtf("Unrecognised course came in the upload fields generator! Course string = %s", course);
return null;
}
}
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 e5f5301b..1bb45c84 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
@@ -1,64 +1,44 @@
package gr.thmmy.mthmmy.activities.upload;
import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.database.Cursor;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Matrix;
-import android.media.ExifInterface;
import android.net.Uri;
import android.os.Environment;
-import android.provider.OpenableColumns;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.content.FileProvider;
+
+import android.util.Log;
import android.widget.Toast;
+import com.snatik.storage.Storage;
+
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
+import gr.thmmy.mthmmy.utils.FileUtils;
import timber.log.Timber;
-class UploadsHelper {
- private static final int DEFAULT_MIN_WIDTH_QUALITY = 400;
- private static final String CACHE_IMAGE_NAME = "tempUploadFile.jpg";
-
- @NonNull
- static String filenameFromUri(Context context, Uri uri) {
- String filename = null;
- if (uri.getScheme().equals("content")) {
- try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
- if (cursor != null && cursor.moveToFirst()) {
- filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
- }
- }
- }
- if (filename == null) {
- filename = uri.getPath();
- int cut = filename.lastIndexOf('/');
- if (cut != -1) {
- filename = filename.substring(cut + 1);
- }
- }
-
- return filename;
- }
+public class UploadsHelper {
+ private final static int BUFFER = 4096;
+ private static final String TEMP_FILES_DIRECTORY = "~tmp_mThmmy_uploads";
@SuppressWarnings("ResultOfMethodCallIgnored")
@Nullable
- static String createTempFile(Context context, Uri fileUri, String newFilename) {
- String oldFilename = filenameFromUri(context, fileUri);
+ static Uri createTempFile(Context context, Storage storage, Uri fileUri, String newFilename) {
+ String oldFilename = FileUtils.filenameFromUri(context, fileUri);
String fileExtension = oldFilename.substring(oldFilename.indexOf("."));
String destinationFilename = Environment.getExternalStorageDirectory().getPath() +
- File.separatorChar + "~tmp_mThmmy_uploads" + File.separatorChar + newFilename + fileExtension;
+ File.separatorChar + TEMP_FILES_DIRECTORY + File.separatorChar + newFilename + fileExtension;
File tempDirectory = new File(android.os.Environment.getExternalStorageDirectory().getPath() +
- File.separatorChar + "~tmp_mThmmy_uploads");
+ File.separatorChar + TEMP_FILES_DIRECTORY);
if (!tempDirectory.exists()) {
if (!tempDirectory.mkdirs()) {
@@ -97,103 +77,65 @@ class UploadsHelper {
}
}
- return destinationFilename;
- }
+ return FileProvider.getUriForFile(context, context.getPackageName() +
+ ".provider", storage.getFile(destinationFilename));
- static File getCacheFile(Context context) {
- File imageFile = new File(context.getExternalCacheDir(), CACHE_IMAGE_NAME);
- //noinspection ResultOfMethodCallIgnored
- imageFile.getParentFile().mkdirs();
- return imageFile;
}
- @SuppressWarnings("ResultOfMethodCallIgnored")
- static void deleteTempFiles() {
- File tempFilesDirectory = new File(Environment.getExternalStorageDirectory().getPath() +
- File.separatorChar + "~tmp_mThmmy_uploads");
-
- if (tempFilesDirectory.isDirectory()) {
- String[] tempFilesArray = tempFilesDirectory.list();
- for (String tempFile : tempFilesArray) {
- new File(tempFilesDirectory, tempFile).delete();
+ @Nullable
+ public static File createZipFile(@NonNull String zipFilename) {
+ // Create a zip file name
+ 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());
+ return null;
}
- tempFilesDirectory.delete();
- }
- }
-
- @SuppressWarnings("ResultOfMethodCallIgnored")
- static void deleteCacheFiles(Context context) {
- File cacheFilesDirectory = context.getExternalCacheDir();
- assert cacheFilesDirectory != null;
- String[] tempFilesArray = cacheFilesDirectory.list();
- for (String tempFile : tempFilesArray) {
- new File(cacheFilesDirectory, tempFile).delete();
- }
- }
-
- /**
- * Resize to avoid using too much memory loading big images (e.g.: 2560*1920)
- **/
- static Bitmap getImageResized(Context context, Uri selectedImage) {
- Bitmap bm;
- int[] sampleSizes = new int[]{5, 3, 2, 1};
- int i = 0;
- do {
- bm = decodeBitmap(context, selectedImage, sampleSizes[i]);
- i++;
- } while (bm.getWidth() < DEFAULT_MIN_WIDTH_QUALITY && i < sampleSizes.length);
- return bm;
- }
-
- private static Bitmap decodeBitmap(Context context, Uri theUri, int sampleSize) {
- BitmapFactory.Options options = new BitmapFactory.Options();
- options.inSampleSize = sampleSize;
-
- AssetFileDescriptor fileDescriptor = null;
- try {
- fileDescriptor = context.getContentResolver().openAssetFileDescriptor(theUri, "r");
- } catch (FileNotFoundException e) {
- e.printStackTrace();
}
- assert fileDescriptor != null;
- return BitmapFactory.decodeFileDescriptor(
- fileDescriptor.getFileDescriptor(), null, options);
+ return new File(zipFolder, zipFilename);
}
- static int getRotation(Context context, Uri imageUri) {
- int rotation = 0;
+ public static void zip(Context context, Uri[] files, Uri zipFile) {
try {
-
- context.getContentResolver().notifyChange(imageUri, null);
- ExifInterface exif = new ExifInterface(imageUri.getPath());
- int orientation = exif.getAttributeInt(
- ExifInterface.TAG_ORIENTATION,
- ExifInterface.ORIENTATION_NORMAL);
-
- switch (orientation) {
- case ExifInterface.ORIENTATION_ROTATE_270:
- rotation = 270;
- break;
- case ExifInterface.ORIENTATION_ROTATE_180:
- rotation = 180;
- break;
- case ExifInterface.ORIENTATION_ROTATE_90:
- rotation = 90;
- break;
+ 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();
}
- return rotation;
}
- static Bitmap rotate(Bitmap bm, int rotation) {
- if (rotation != 0) {
- Matrix matrix = new Matrix();
- matrix.postRotate(rotation);
- return Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
+ public static void deleteTempFiles(Storage storage) {
+ File tempFilesDirectory = new File(Environment.getExternalStorageDirectory().getPath() +
+ File.separatorChar + TEMP_FILES_DIRECTORY);
+
+ if (storage.isDirectoryExists(tempFilesDirectory.getAbsolutePath())) {
+ for (File tempFile : storage.getFiles(tempFilesDirectory.getAbsolutePath())) {
+ storage.deleteFile(tempFile.getAbsolutePath());
+ }
+ storage.deleteDirectory(tempFilesDirectory.getAbsolutePath());
}
- return bm;
}
}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java
index d8019545..0671b7e3 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java
@@ -2,21 +2,34 @@ package gr.thmmy.mthmmy.base;
import android.Manifest;
import android.app.ProgressDialog;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
+import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
+import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.appcompat.widget.Toolbar;
+import androidx.core.content.ContextCompat;
+import androidx.core.content.FileProvider;
+import androidx.lifecycle.ViewModelProviders;
+import androidx.preference.PreferenceManager;
+
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.google.firebase.messaging.FirebaseMessaging;
import com.mikepenz.fontawesome_typeface_library.FontAwesome;
@@ -28,6 +41,9 @@ import com.mikepenz.materialdrawer.Drawer;
import com.mikepenz.materialdrawer.DrawerBuilder;
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem;
import com.mikepenz.materialdrawer.model.ProfileDrawerItem;
+import com.snatik.storage.Storage;
+
+import net.gotev.uploadservice.UploadService;
import java.io.BufferedReader;
import java.io.File;
@@ -35,14 +51,6 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
-import androidx.appcompat.app.AppCompatActivity;
-import androidx.appcompat.widget.Toolbar;
-import androidx.core.content.ContextCompat;
-import androidx.core.content.FileProvider;
-import androidx.lifecycle.ViewModelProviders;
-import androidx.preference.PreferenceManager;
import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.activities.AboutActivity;
import gr.thmmy.mthmmy.activities.LoginActivity;
@@ -52,12 +60,15 @@ import gr.thmmy.mthmmy.activities.main.MainActivity;
import gr.thmmy.mthmmy.activities.profile.ProfileActivity;
import gr.thmmy.mthmmy.activities.settings.SettingsActivity;
import gr.thmmy.mthmmy.activities.shoutbox.ShoutboxActivity;
+import gr.thmmy.mthmmy.activities.upload.UploadActivity;
import gr.thmmy.mthmmy.model.Bookmark;
import gr.thmmy.mthmmy.model.ThmmyFile;
import gr.thmmy.mthmmy.services.DownloadHelper;
+import gr.thmmy.mthmmy.services.UploadsReceiver;
import gr.thmmy.mthmmy.session.SessionManager;
import gr.thmmy.mthmmy.utils.FileUtils;
import gr.thmmy.mthmmy.viewmodel.BaseViewModel;
+import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import okhttp3.OkHttpClient;
import ru.noties.markwon.LinkResolverDef;
import ru.noties.markwon.Markwon;
@@ -72,6 +83,7 @@ import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DEFAULT_HOME_TAB;
import static gr.thmmy.mthmmy.services.DownloadHelper.SAVE_DIR;
+import static gr.thmmy.mthmmy.services.UploadsReceiver.UPLOAD_ID_KEY;
import static gr.thmmy.mthmmy.session.SessionManager.SUCCESS;
import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType;
@@ -82,6 +94,9 @@ public abstract class BaseActivity extends AppCompatActivity {
//SessionManager
protected static SessionManager sessionManager;
+ //Storage manager
+ protected Storage storage;
+
//Bookmarks
public static final String BOOKMARKS_SHARED_PREFS = "bookmarksSharedPrefs";
public static final String BOOKMARKED_TOPICS_KEY = "bookmarkedTopicsKey";
@@ -96,6 +111,9 @@ public abstract class BaseActivity extends AppCompatActivity {
//Common UI elements
protected Toolbar toolbar;
protected Drawer drawer;
+ //Uploads progress dialog
+ UploadsShowDialogReceiver uploadsShowDialogReceiver;
+ AlertDialog uploadsProgressDialog;
private MainActivity mainActivity;
private boolean isMainActivity;
@@ -123,16 +141,25 @@ public abstract class BaseActivity extends AppCompatActivity {
BaseViewModel baseViewModel = ViewModelProviders.of(this).get(BaseViewModel.class);
baseViewModel.getCurrentPageBookmark().observe(this, thisPageBookmark -> setTopicBookmark(thisPageBookmarkMenuButton));
+
+ storage = new Storage(getApplicationContext());
}
@Override
protected void onResume() {
super.onResume();
updateDrawer();
- if (!sharedPreferences.getBoolean(getString(R.string.user_consent_shared_preference_key), false) && !isUserConsentDialogShown){
- isUserConsentDialogShown=true;
+ if (!sharedPreferences.getBoolean(getString(R.string.user_consent_shared_preference_key), false) && !isUserConsentDialogShown) {
+ isUserConsentDialogShown = true;
showUserConsentDialog();
}
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ if (uploadsShowDialogReceiver == null) {
+ uploadsShowDialogReceiver = new UploadsShowDialogReceiver(this);
+ }
+ this.registerReceiver(uploadsShowDialogReceiver, new IntentFilter(UploadsReceiver.ACTION_COMBINED_UPLOAD));
+ }
}
@Override
@@ -140,6 +167,10 @@ public abstract class BaseActivity extends AppCompatActivity {
super.onPause();
if (drawer != null) //close drawer animation after returning to activity
drawer.closeDrawer();
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && uploadsShowDialogReceiver != null) {
+ this.unregisterReceiver(uploadsShowDialogReceiver);
+ }
}
@@ -151,6 +182,10 @@ public abstract class BaseActivity extends AppCompatActivity {
return sessionManager;
}
+ public Storage getStorage() {
+ return storage;
+ }
+
//TODO: move stuff below (?)
//------------------------------------------DRAWER STUFF----------------------------------------
protected static final int HOME_ID = 0;
@@ -254,14 +289,15 @@ public abstract class BaseActivity extends AppCompatActivity {
.withName(R.string.downloads)
.withIcon(downloadsIcon)
.withSelectedIcon(downloadsIconSelected);
-// uploadItem = new PrimaryDrawerItem()
-// .withTextColor(primaryColor)
-// .withSelectedColor(selectedPrimaryColor)
-// .withSelectedTextColor(selectedSecondaryColor)
-// .withIdentifier(UPLOAD_ID)
-// .withName(R.string.upload)
-// .withIcon(uploadIcon)
-// .withSelectedIcon(uploadIconSelected);
+
+ uploadItem = new PrimaryDrawerItem()
+ .withTextColor(primaryColor)
+ .withSelectedColor(selectedPrimaryColor)
+ .withSelectedTextColor(selectedSecondaryColor)
+ .withIdentifier(UPLOAD_ID)
+ .withName(R.string.upload)
+ .withIcon(uploadIcon)
+ .withSelectedIcon(uploadIconSelected);
shoutboxItem = new PrimaryDrawerItem()
.withTextColor(primaryColor)
@@ -377,11 +413,11 @@ public abstract class BaseActivity extends AppCompatActivity {
intent.putExtras(extras);
startActivity(intent);
}
-// } else if (drawerItem.equals(UPLOAD_ID)) {
-// if (!(BaseActivity.this instanceof UploadActivity)) {
-// Intent intent = new Intent(BaseActivity.this, UploadActivity.class);
-// startActivity(intent);
-// }
+ } else if (drawerItem.equals(UPLOAD_ID)) {
+ if (!(BaseActivity.this instanceof UploadActivity)) {
+ Intent intent = new Intent(BaseActivity.this, UploadActivity.class);
+ startActivity(intent);
+ }
} else if (drawerItem.equals(BOOKMARKS_ID)) {
if (!(BaseActivity.this instanceof BookmarksActivity)) {
Intent intent = new Intent(BaseActivity.this, BookmarksActivity.class);
@@ -432,7 +468,7 @@ public abstract class BaseActivity extends AppCompatActivity {
if (!sessionManager.isLoggedIn()) //When logged out or if user is guest
{
drawer.removeItem(DOWNLOADS_ID);
-// drawer.removeItem(UPLOAD_ID);
+ drawer.removeItem(UPLOAD_ID);
loginLogoutItem.withName(R.string.login).withIcon(loginIcon); //Swap logout with login
profileDrawerItem.withName(sessionManager.getUsername());
setDefaultAvatar();
@@ -440,9 +476,9 @@ public abstract class BaseActivity extends AppCompatActivity {
if (!drawer.getDrawerItems().contains(downloadsItem)) {
drawer.addItemAtPosition(downloadsItem, 4);
}
-// if (!drawer.getDrawerItems().contains(uploadItem)) {
-// drawer.addItemAtPosition(uploadItem, 5);
-// }
+ if (!drawer.getDrawerItems().contains(uploadItem)) {
+ drawer.addItemAtPosition(uploadItem, 5);
+ }
loginLogoutItem.withName(R.string.logout).withIcon(logoutIcon); //Swap login with logout
profileDrawerItem.withName(sessionManager.getUsername());
if (sessionManager.hasAvatar())
@@ -667,10 +703,10 @@ public abstract class BaseActivity extends AppCompatActivity {
//-------------------------------------------BOOKMARKS END------------------------------------------
//-------PERMS---------
- private static final int PERMISSIONS_REQUEST_CODE = 69;
+ private static final int DOWNLOAD_REQUEST_CODE = 69; //Arbitrary, application specific
//True if permissions are OK
- private boolean checkPerms() {
+ protected boolean checkPerms() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
@@ -683,13 +719,13 @@ public abstract class BaseActivity extends AppCompatActivity {
}
//Display popup for user to grant permission
- private void requestPerms() { //Runtime permissions request for devices with API >= 23
+ protected void requestPerms(int code) { //Runtime permissions request for devices with API >= 23
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE};
- requestPermissions(PERMISSIONS_STORAGE, PERMISSIONS_REQUEST_CODE);
+ requestPermissions(PERMISSIONS_STORAGE, code);
}
}
@@ -698,8 +734,9 @@ public abstract class BaseActivity extends AppCompatActivity {
public void onRequestPermissionsResult(int permsRequestCode, @NonNull String[] permissions
, @NonNull int[] grantResults) {
switch (permsRequestCode) {
- case PERMISSIONS_REQUEST_CODE:
- downloadFile();
+ case DOWNLOAD_REQUEST_CODE:
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED)
+ prepareDownload(tempThmmyFile);
break;
}
}
@@ -713,7 +750,7 @@ public abstract class BaseActivity extends AppCompatActivity {
prepareDownload(thmmyFile);
else {
tempThmmyFile = thmmyFile;
- requestPerms();
+ requestPerms(DOWNLOAD_REQUEST_CODE);
}
}
@@ -835,6 +872,93 @@ public abstract class BaseActivity extends AppCompatActivity {
editor.putBoolean(getString(R.string.pref_privacy_analytics_enable_key), enabled).apply();
}
+ //------------------------------------------ UPLOADS -------------------------------------------
+ private class UploadsShowDialogReceiver extends BroadcastReceiver {
+ private final Context activityContext;
+
+ UploadsShowDialogReceiver(Context activityContext) {
+ this.activityContext = activityContext;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Bundle intentBundle = intent.getExtras();
+ if (intentBundle == null) {
+ return;
+ }
+
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ String dialogUploadID = intentBundle.getString(UPLOAD_ID_KEY);
+
+ /*String retryFilename = intentBundle.getString(UPLOAD_RETRY_FILENAME);
+ String retryCategory = intentBundle.getString(UPLOAD_RETRY_CATEGORY);
+ String retryTitleText = intentBundle.getString(UPLOAD_RETRY_TITLE);
+ String retryDescription = intentBundle.getString(UPLOAD_RETRY_DESCRIPTION);
+ String retryIcon = intentBundle.getString(UPLOAD_RETRY_ICON);
+ String retryUploaderProfile = intentBundle.getString(UPLOAD_RETRY_UPLOADER);
+ Uri retryFileUri = (Uri) intentBundle.get(UPLOAD_RETRY_FILE_URI);
+
+ Intent retryIntent = new Intent(context, UploadsReceiver.class);
+ retryIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ retryIntent.setAction(UploadsReceiver.ACTION_RETRY_UPLOAD);
+
+ retryIntent.putExtra(UPLOAD_RETRY_FILENAME, retryFilename);
+ retryIntent.putExtra(UPLOAD_RETRY_CATEGORY, retryCategory);
+ retryIntent.putExtra(UPLOAD_RETRY_TITLE, retryTitleText);
+ retryIntent.putExtra(UPLOAD_RETRY_DESCRIPTION, retryDescription);
+ retryIntent.putExtra(UPLOAD_RETRY_ICON, retryIcon);
+ retryIntent.putExtra(UPLOAD_RETRY_UPLOADER, retryUploaderProfile);
+ retryIntent.putExtra(UPLOAD_RETRY_FILE_URI, retryFileUri);*/
+
+ if (uploadsProgressDialog == null) {
+ AlertDialog.Builder progressDialogBuilder = new AlertDialog.Builder(activityContext);
+ LayoutInflater inflater = LayoutInflater.from(activityContext);
+ LinearLayout progressDialogLayout = (LinearLayout) inflater.inflate(R.layout.dialog_upload_progress, null);
+
+ MaterialProgressBar dialogProgressBar = progressDialogLayout.findViewById(R.id.dialogProgressBar);
+ dialogProgressBar.setMax(100);
+
+ progressDialogBuilder.setView(progressDialogLayout);
+
+ uploadsProgressDialog = progressDialogBuilder.create();
+ if (!UploadService.getTaskList().contains("" + dialogUploadID)) {
+ //Upload probably failed at this point
+ uploadsProgressDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "Retry", (progressDialog, progressWhich) -> {
+ /*LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context.getApplicationContext());
+ localBroadcastManager.sendBroadcast(multipartUploadRetryIntent);*/
+ uploadsProgressDialog.dismiss();
+
+ //context.sendBroadcast(retryIntent);
+ });
+ uploadsProgressDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "Cancel", (progressDialog, progressWhich) -> {
+ uploadsProgressDialog.dismiss();
+ });
+
+ TextView dialogProgressText = progressDialogLayout.findViewById(R.id.dialog_upload_progress_text);
+ dialogProgressBar.setVisibility(View.GONE);
+ dialogProgressText.setText("Upload failed.");
+
+ uploadsProgressDialog.show();
+ } else {
+ //Empty buttons are needed, they are updated with correct values in the receiver
+ uploadsProgressDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "placeholder", (progressDialog, progressWhich) -> {
+ });
+ uploadsProgressDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "placeholder", (progressDialog, progressWhich) -> {
+ });
+
+ UploadsReceiver.setDialogDisplay(uploadsProgressDialog, dialogUploadID, null);
+ //UploadsReceiver.setDialogDisplay(uploadsProgressDialog, dialogUploadID, retryIntent);
+ uploadsProgressDialog.show();
+ }
+ } else {
+ UploadsReceiver.setDialogDisplay(uploadsProgressDialog, dialogUploadID, null);
+ //UploadsReceiver.setDialogDisplay(uploadsProgressDialog, dialogUploadID, retryIntent);
+ uploadsProgressDialog.show();
+ }
+ }
+ }
+ }
+
//----------------------------------MISC----------------------
protected void setMainActivity(MainActivity mainActivity) {
this.mainActivity = mainActivity;
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..c1bdb539
--- /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 androidx.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/java/gr/thmmy/mthmmy/services/UploadsReceiver.java b/app/src/main/java/gr/thmmy/mthmmy/services/UploadsReceiver.java
new file mode 100644
index 00000000..c7c56e86
--- /dev/null
+++ b/app/src/main/java/gr/thmmy/mthmmy/services/UploadsReceiver.java
@@ -0,0 +1,223 @@
+package gr.thmmy.mthmmy.services;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Build;
+import android.os.Bundle;
+import androidx.appcompat.app.AlertDialog;
+
+import android.view.View;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.snatik.storage.Storage;
+
+import net.gotev.uploadservice.ServerResponse;
+import net.gotev.uploadservice.UploadInfo;
+import net.gotev.uploadservice.UploadService;
+import net.gotev.uploadservice.UploadServiceBroadcastReceiver;
+
+import gr.thmmy.mthmmy.R;
+import gr.thmmy.mthmmy.activities.upload.UploadsHelper;
+import gr.thmmy.mthmmy.base.BaseApplication;
+import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
+
+public class UploadsReceiver extends UploadServiceBroadcastReceiver {
+ public static final String UPLOAD_ID_KEY = "UPLOAD_ID_KEY";
+
+ public static final String ACTION_COMBINED_UPLOAD = "ACTION_COMBINED_UPLOAD";
+ public static final String ACTION_CANCEL_UPLOAD = "ACTION_CANCEL_UPLOAD";
+ public static final String ACTION_RETRY_UPLOAD = "ACTION_RETRY_UPLOAD";
+
+ /*public static final String UPLOAD_RETRY_FILENAME = "UPLOAD_RETRY_FILENAME";
+ public static final String UPLOAD_RETRY_CATEGORY = "UPLOAD_RETRY_CATEGORY";
+ public static final String UPLOAD_RETRY_TITLE = "UPLOAD_RETRY_TITLE";
+ public static final String UPLOAD_RETRY_DESCRIPTION = "UPLOAD_RETRY_DESCRIPTION";
+ public static final String UPLOAD_RETRY_ICON = "UPLOAD_RETRY_ICON";
+ public static final String UPLOAD_RETRY_UPLOADER = "UPLOAD_RETRY_UPLOADER";
+ public static final String UPLOAD_RETRY_FILE_URI = "UPLOAD_RETRY_FILE_URI";*/
+
+ private Storage storage;
+ private static AlertDialog uploadProgressDialog;
+ private static String dialogUploadID;
+ //private static Intent multipartUploadRetryIntent;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String intentAction = intent.getAction();
+ Bundle intentBundle = intent.getExtras();
+ if (intentAction == null || intentBundle == null) {
+ super.onReceive(context, intent);
+ return;
+ }
+
+ switch (intentAction) {
+ case ACTION_CANCEL_UPLOAD:
+ String uploadID = intentBundle.getString(UPLOAD_ID_KEY);
+ UploadService.stopUpload(uploadID);
+ break;
+ /*case ACTION_RETRY_UPLOAD:
+ String retryFilename = intentBundle.getString(UPLOAD_RETRY_FILENAME);
+ String retryCategory = intentBundle.getString(UPLOAD_RETRY_CATEGORY);
+ String retryTitleText = intentBundle.getString(UPLOAD_RETRY_TITLE);
+ String retryDescription = intentBundle.getString(UPLOAD_RETRY_DESCRIPTION);
+ String retryIcon = intentBundle.getString(UPLOAD_RETRY_ICON);
+ String retryUploaderProfile = intentBundle.getString(UPLOAD_RETRY_UPLOADER);
+ Uri retryFileUri = (Uri) intentBundle.get(UPLOAD_RETRY_FILE_URI);
+ String retryUploadID = UUID.randomUUID().toString();
+
+ UploadActivity.uploadFile(context, retryUploadID,
+ UploadActivity.getConfigForUpload(context, retryUploadID, retryFilename, retryCategory,
+ retryTitleText, retryDescription, retryIcon, retryUploaderProfile, retryFileUri),
+ retryCategory, retryTitleText, retryDescription, retryIcon,
+ retryUploaderProfile, retryFileUri);
+
+ break;*/
+ default:
+ super.onReceive(context, intent);
+ break;
+ }
+ }
+
+ @Override
+ public void onProgress(Context context, UploadInfo uploadInfo) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP &&
+ uploadInfo.getUploadId().equals(dialogUploadID) &&
+ uploadProgressDialog != null) {
+ Button alertDialogNeutral = uploadProgressDialog.getButton(AlertDialog.BUTTON_NEUTRAL);
+ alertDialogNeutral.setText("Resume on background");
+ alertDialogNeutral.setOnClickListener(v -> uploadProgressDialog.dismiss());
+
+ Button alertDialogNegative = uploadProgressDialog.getButton(AlertDialog.BUTTON_NEGATIVE);
+ alertDialogNegative.setText("Cancel");
+ alertDialogNegative.setOnClickListener(v -> {
+ UploadService.stopUpload(dialogUploadID);
+ uploadProgressDialog.dismiss();
+ });
+
+ if (uploadProgressDialog.isShowing()) {
+ Window progressWindow = uploadProgressDialog.getWindow();
+ if (progressWindow != null) {
+ MaterialProgressBar dialogProgressBar = progressWindow.findViewById(R.id.dialogProgressBar);
+ TextView dialogProgressText = progressWindow.findViewById(R.id.dialog_upload_progress_text);
+
+ dialogProgressBar.setProgress(uploadInfo.getProgressPercent());
+ dialogProgressText.setText(context.getResources().getString(
+ R.string.upload_progress_dialog_bytes_uploaded,
+ (float) uploadInfo.getUploadRate(),
+ (int) uploadInfo.getUploadedBytes() / 1000,
+ (int) uploadInfo.getTotalBytes() / 1000));
+ }
+
+ if (uploadInfo.getUploadedBytes() == uploadInfo.getTotalBytes()) {
+ uploadProgressDialog.dismiss();
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse,
+ Exception exception) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP &&
+ uploadInfo.getUploadId().equals(dialogUploadID) &&
+ uploadProgressDialog != null) {
+ /*Button alertDialogNeutral = uploadProgressDialog.getButton(AlertDialog.BUTTON_NEUTRAL);
+ alertDialogNeutral.setText("Retry");
+ alertDialogNeutral.setOnClickListener(v -> {
+ if (multipartUploadRetryIntent != null) {
+ context.sendBroadcast(multipartUploadRetryIntent);
+ }
+ uploadProgressDialog.dismiss();
+ });*/
+
+ Button alertDialogNegative = uploadProgressDialog.getButton(AlertDialog.BUTTON_NEGATIVE);
+ alertDialogNegative.setText("Cancel");
+ alertDialogNegative.setOnClickListener(v -> {
+ NotificationManager notificationManager = (NotificationManager) context.getApplicationContext().
+ getSystemService(Context.NOTIFICATION_SERVICE);
+ if (notificationManager != null) {
+ notificationManager.cancel(uploadInfo.getNotificationID());
+ }
+ UploadsHelper.deleteTempFiles(storage);
+ uploadProgressDialog.dismiss();
+ });
+
+ if (uploadProgressDialog.isShowing()) {
+ Window progressWindow = uploadProgressDialog.getWindow();
+ if (progressWindow != null) {
+ MaterialProgressBar dialogProgressBar = progressWindow.findViewById(R.id.dialogProgressBar);
+ TextView dialogProgressText = progressWindow.findViewById(R.id.dialog_upload_progress_text);
+
+ dialogProgressBar.setVisibility(View.GONE);
+ dialogProgressText.setText("Upload failed.");
+ }
+
+ if (uploadInfo.getUploadedBytes() == uploadInfo.getTotalBytes()) {
+ uploadProgressDialog.dismiss();
+ }
+ }
+ } else {
+ NotificationManager notificationManager = (NotificationManager) context.getApplicationContext().
+ getSystemService(Context.NOTIFICATION_SERVICE);
+ if (notificationManager != null) {
+ notificationManager.cancel(uploadInfo.getNotificationID());
+ }
+
+ Intent combinedActionsIntent = new Intent(UploadsReceiver.ACTION_COMBINED_UPLOAD);
+ combinedActionsIntent.putExtra(UploadsReceiver.UPLOAD_ID_KEY, uploadInfo.getUploadId());
+ context.sendBroadcast(combinedActionsIntent);
+ }
+
+ Toast.makeText(context.getApplicationContext(), "Upload failed", Toast.LENGTH_SHORT).show();
+ if (storage == null) {
+ storage = new Storage(context.getApplicationContext());
+ }
+ }
+
+ @Override
+ public void onCompleted(Context context, UploadInfo uploadInfo, ServerResponse serverResponse) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ uploadProgressDialog = null;
+ dialogUploadID = null;
+ }
+
+ Toast.makeText(context.getApplicationContext(), "Upload completed successfully", Toast.LENGTH_SHORT).show();
+ if (storage == null) {
+ storage = new Storage(context.getApplicationContext());
+ }
+
+ BaseApplication.getInstance().logFirebaseAnalyticsEvent("file_upload", null);
+ UploadsHelper.deleteTempFiles(storage);
+ }
+
+ @Override
+ public void onCancelled(Context context, UploadInfo uploadInfo) {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
+ uploadProgressDialog = null;
+ dialogUploadID = null;
+ }
+
+ Toast.makeText(context.getApplicationContext(), "Upload canceled", Toast.LENGTH_SHORT).show();
+ if (storage == null) {
+ storage = new Storage(context.getApplicationContext());
+ }
+
+ /*NotificationManager notificationManager = (NotificationManager) context.getApplicationContext().
+ getSystemService(Context.NOTIFICATION_SERVICE);
+ if (notificationManager != null) {
+ notificationManager.cancel(uploadInfo.getNotificationID());
+ }*/
+ UploadsHelper.deleteTempFiles(storage);
+ }
+
+ public static void setDialogDisplay(AlertDialog uploadProgressDialog, String dialogUploadID,
+ Intent multipartUploadRetryIntent) {
+ UploadsReceiver.uploadProgressDialog = uploadProgressDialog;
+ UploadsReceiver.dialogUploadID = dialogUploadID;
+ //UploadsReceiver.multipartUploadRetryIntent = multipartUploadRetryIntent;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/FileUtils.java b/app/src/main/java/gr/thmmy/mthmmy/utils/FileUtils.java
index 1c8eb0b0..7beffeb6 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/utils/FileUtils.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/utils/FileUtils.java
@@ -1,10 +1,16 @@
package gr.thmmy.mthmmy.utils;
+import android.content.Context;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.OpenableColumns;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.webkit.MimeTypeMap;
import java.io.File;
-import androidx.annotation.NonNull;
+import gr.thmmy.mthmmy.R;
import static gr.thmmy.mthmmy.services.DownloadHelper.SAVE_DIR;
@@ -21,7 +27,94 @@ public class FileUtils {
return type;
}
- public static boolean fileNameExists (String fileName) {
+ public static boolean fileNameExists(String fileName) {
return fileName != null && (new File(SAVE_DIR.getAbsolutePath(), fileName)).isFile();
}
+
+ @Nullable
+ public static String getFileExtension(@NonNull String filename) {
+ String fileExtension;
+
+ if (!filename.contains(".")) {
+ return null;
+ }
+ if (filename.toLowerCase().endsWith(".tar.gz")) {
+ fileExtension = filename.substring(filename.length() - 7);
+ } else {
+ fileExtension = filename.substring(filename.lastIndexOf("."));
+ }
+
+ return fileExtension;
+ }
+
+ public static String getFilenameWithoutExtension(String filename) {
+ String fileExtension = getFileExtension(filename);
+
+ return fileExtension == null
+ ? filename
+ : filename.substring(0, filename.indexOf(fileExtension));
+ }
+
+ @NonNull
+ public static String filenameFromUri(Context context, Uri uri) {
+ String filename = null;
+ if (uri.getScheme().equals("content")) {
+ try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
+ if (cursor != null && cursor.moveToFirst()) {
+ filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
+ }
+ }
+ }
+ if (filename == null) {
+ filename = uri.getPath();
+ int cut = filename.lastIndexOf('/');
+ if (cut != -1) {
+ filename = filename.substring(cut + 1);
+ }
+ }
+
+ return filename;
+ }
+
+ public static long sizeFromUri(Context context, @NonNull Uri uri) {
+ try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
+ if (cursor != null && cursor.moveToFirst()) {
+ return cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE));
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns a String with a single FontAwesome typeface character corresponding to this file's
+ * extension.
+ *
+ * @param filename String with filename containing file's extension
+ * @return FontAwesome character according to file's type
+ * @see FontAwesome
+ */
+ @NonNull
+ public static String faIconFromFilename(Context context, String filename) {
+ filename = filename.toLowerCase();
+
+ if (filename.contains("jpg") || filename.contains("gif") || filename.contains("jpeg")
+ || filename.contains("png"))
+ return context.getResources().getString(R.string.fa_file_image_o);
+ else if (filename.contains("pdf"))
+ return context.getResources().getString(R.string.fa_file_pdf_o);
+ else if (filename.contains("zip") || filename.contains("rar") || filename.contains("tar.gz"))
+ return context.getResources().getString(R.string.fa_file_zip_o);
+ else if (filename.contains("txt"))
+ return context.getResources().getString(R.string.fa_file_text_o);
+ else if (filename.contains("doc") || filename.contains("docx"))
+ return context.getResources().getString(R.string.fa_file_word_o);
+ else if (filename.contains("xls") || filename.contains("xlsx"))
+ return context.getResources().getString(R.string.fa_file_excel_o);
+ else if (filename.contains("pps"))
+ return context.getResources().getString(R.string.fa_file_powerpoint_o);
+ else if (filename.contains("mpg"))
+ return context.getResources().getString(R.string.fa_file_video_o);
+
+ return context.getResources().getString(R.string.fa_file);
+ }
}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareFABBehavior.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareFABBehavior.java
index a45e1a3f..06a355f2 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareFABBehavior.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareFABBehavior.java
@@ -2,15 +2,16 @@ package gr.thmmy.mthmmy.utils;
import android.content.Context;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import com.google.android.material.snackbar.Snackbar;
-
import androidx.annotation.NonNull;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.view.ViewCompat;
+import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import com.google.android.material.snackbar.Snackbar;
+
/**
* Extends FloatingActionButton's behavior so the button will hide when scrolling down and show
* otherwise. It also lifts the {@link FloatingActionButton} when a {@link Snackbar} is shown.
@@ -37,7 +38,9 @@ public class ScrollAwareFABBehavior extends CoordinatorLayout.Behavior 0 || (!target.canScrollVertically(-1) && dyConsumed == 0 && dyUnconsumed > 50)) {
+ Log.d("THISSSS", "GOT_HIDE");
child.hide(new FloatingActionButton.OnVisibilityChangedListener() {
@Override
public void onHidden(FloatingActionButton fab) {
@@ -47,7 +50,14 @@ public class ScrollAwareFABBehavior extends CoordinatorLayout.Behavior resInfoList = context.getPackageManager().
+ queryIntentActivities(takePictureIntent, PackageManager.MATCH_DEFAULT_ONLY);
+ for (ResolveInfo resolveInfo : resInfoList) {
+ String packageName = resolveInfo.activityInfo.packageName;
+ context.grantUriPermission(packageName, photoURI,
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION |
+ Intent.FLAG_GRANT_READ_URI_PERMISSION);
+ }
+ return takePictureIntent;
+ }
+ return null;
+ }
+
+ public static Uri processResult(Context context, File photoFile) {
+ Bitmap bitmap;
+ Uri fileUri = FileProvider.getUriForFile(context, context.getPackageName() + ".provider", photoFile);
+
+ bitmap = getImageResized(context, fileUri);
+ int rotation = getRotation(context, fileUri);
+ bitmap = rotate(bitmap, rotation);
+
+ try {
+ FileOutputStream out = new FileOutputStream(photoFile);
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
+ out.flush();
+ out.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return fileUri;
+ }
+
+ @Nullable
+ public static File createImageFile(Context context) {
+ // Create an image file name
+ String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.FRANCE).format(new Date());
+ String imageFileName = "mThmmy_" + timeStamp + ".jpg";
+
+ File imageFolder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) +
+ File.separator + "mThmmy");
+
+ if (!imageFolder.exists()) {
+ if (!imageFolder.mkdirs()) {
+ Timber.w("Photos folder build returned false in %s", TakePhoto.class.getSimpleName());
+ Toast.makeText(context, "Couldn't create photos directory", Toast.LENGTH_SHORT).show();
+ return null;
+ }
+ }
+
+ return new File(imageFolder, imageFileName);
+ }
+
+ public static void galleryAddPic(Context context, File photoFile) {
+ ContentValues values = new ContentValues();
+ values.put(MediaStore.Images.Media.TITLE, photoFile.getName());
+ values.put(MediaStore.Images.Media.DESCRIPTION, IMAGE_CONTENT_DESCRIPTION);
+ values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
+ values.put(MediaStore.Images.ImageColumns.BUCKET_ID, photoFile.toString().toLowerCase(Locale.US).hashCode());
+ values.put(MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME, photoFile.getName().toLowerCase(Locale.US));
+ values.put("_data", photoFile.getAbsolutePath());
+
+ ContentResolver cr = context.getContentResolver();
+ cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
+ }
+
+ private static Bitmap getImageResized(Context context, Uri selectedImage) {
+ Bitmap bm;
+ int[] sampleSizes = new int[]{5, 3, 2, 1};
+ int i = 0;
+ do {
+ bm = decodeBitmap(context, selectedImage, sampleSizes[i]);
+ i++;
+ } while (bm.getWidth() < DEFAULT_MIN_WIDTH_QUALITY && i < sampleSizes.length);
+ return bm;
+ }
+
+ private static Bitmap decodeBitmap(Context context, Uri theUri, int sampleSize) {
+ BitmapFactory.Options options = new BitmapFactory.Options();
+ options.inSampleSize = sampleSize;
+
+ AssetFileDescriptor fileDescriptor = null;
+ try {
+ fileDescriptor = context.getContentResolver().openAssetFileDescriptor(theUri, "r");
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ assert fileDescriptor != null;
+ return BitmapFactory.decodeFileDescriptor(
+ fileDescriptor.getFileDescriptor(), null, options);
+ }
+
+ private static int getRotation(Context context, Uri imageUri) {
+ int rotation = 0;
+ try {
+
+ context.getContentResolver().notifyChange(imageUri, null);
+ ExifInterface exif = new ExifInterface(imageUri.getPath());
+ int orientation = exif.getAttributeInt(
+ ExifInterface.TAG_ORIENTATION,
+ ExifInterface.ORIENTATION_NORMAL);
+
+ switch (orientation) {
+ case ExifInterface.ORIENTATION_ROTATE_270:
+ rotation = 270;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_180:
+ rotation = 180;
+ break;
+ case ExifInterface.ORIENTATION_ROTATE_90:
+ rotation = 90;
+ break;
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return rotation;
+ }
+
+ private static Bitmap rotate(Bitmap bm, int rotation) {
+ if (rotation != 0) {
+ Matrix matrix = new Matrix();
+ matrix.postRotate(rotation);
+ return Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true);
+ }
+ return bm;
+ }
+}
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
deleted file mode 100644
index 4834305b..00000000
--- a/app/src/main/res/drawable/ic_attach_file_white_24dp.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/drawable/ic_cached_accent_24dp.xml b/app/src/main/res/drawable/ic_cached_accent_24dp.xml
new file mode 100644
index 00000000..b4f3f7dd
--- /dev/null
+++ b/app/src/main/res/drawable/ic_cached_accent_24dp.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_cancel_accent_24dp.xml b/app/src/main/res/drawable/ic_cancel_accent_24dp.xml
new file mode 100644
index 00000000..4c1d6837
--- /dev/null
+++ b/app/src/main/res/drawable/ic_cancel_accent_24dp.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_info_outline_warning_24dp.xml b/app/src/main/res/drawable/ic_info_outline_warning_24dp.xml
new file mode 100644
index 00000000..1c3b206c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_info_outline_warning_24dp.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/app/src/main/res/layout/activity_board.xml b/app/src/main/res/layout/activity_board.xml
index 9a51aa92..5ac81b3a 100644
--- a/app/src/main/res/layout/activity_board.xml
+++ b/app/src/main/res/layout/activity_board.xml
@@ -1,6 +1,5 @@
-
+ app:srcCompat="@drawable/ic_bookmark_false_accent_24dp" />
@@ -43,8 +42,8 @@
android:layout_marginTop="64dp"
android:background="@color/background"
android:scrollbars="none"
- tools:context="gr.thmmy.mthmmy.activities.topic.TopicActivity">
-
+ app:layout_behavior="@string/appbar_scrolling_view_behavior"
+ tools:context="gr.thmmy.mthmmy.activities.topic.TopicActivity" />
+ app:mpb_progressStyle="horizontal" />
+ app:srcCompat="@drawable/ic_add_fab" />
-
-
diff --git a/app/src/main/res/layout/activity_downloads.xml b/app/src/main/res/layout/activity_downloads.xml
index dc92a274..97e0afbc 100644
--- a/app/src/main/res/layout/activity_downloads.xml
+++ b/app/src/main/res/layout/activity_downloads.xml
@@ -48,7 +48,7 @@
app:mpb_indeterminateTint="@color/accent"
app:mpb_progressStyle="horizontal"/>
-
+ app:srcCompat="@drawable/ic_file_upload_white_24dp"/>
diff --git a/app/src/main/res/layout/activity_topic.xml b/app/src/main/res/layout/activity_topic.xml
index aaa13e4b..b61c41cf 100644
--- a/app/src/main/res/layout/activity_topic.xml
+++ b/app/src/main/res/layout/activity_topic.xml
@@ -45,8 +45,8 @@
android:layout_below="@id/appbar"
android:layout_gravity="top|start"
android:clipToPadding="false"
- android:paddingBottom="4dp"
android:paddingTop="4dp"
+ android:paddingBottom="4dp"
android:scrollbars="none"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="gr.thmmy.mthmmy.activities.topic.TopicActivity" />
@@ -146,8 +146,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
- android:layout_marginBottom="50dp"
android:layout_marginEnd="@dimen/fab_margins"
+ android:layout_marginBottom="50dp"
app:layout_behavior="gr.thmmy.mthmmy.utils.ScrollAwareFABBehavior"
app:srcCompat="@drawable/ic_reply" />
diff --git a/app/src/main/res/layout/activity_upload.xml b/app/src/main/res/layout/activity_upload.xml
index 8639fd8c..fb985454 100644
--- a/app/src/main/res/layout/activity_upload.xml
+++ b/app/src/main/res/layout/activity_upload.xml
@@ -28,16 +28,16 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top|start"
- android:background="@color/background"
- android:paddingEnd="@dimen/activity_horizontal_margin"
+ android:background="@color/primary_light"
android:paddingStart="@dimen/activity_horizontal_margin"
+ android:paddingEnd="@dimen/activity_horizontal_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="gr.thmmy.mthmmy.activities.upload.UploadActivity">
@@ -45,15 +45,16 @@
android:id="@+id/upload_spinners"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:background="@color/background"
+ android:layout_marginTop="8dp"
+ android:background="@color/primary_light"
android:orientation="vertical">
@@ -61,8 +62,8 @@
+ android:layout_marginTop="6dp"
+ android:layout_marginBottom="6dp">
+
+
+
+
+
+
+
+
+
+
+ android:layout_marginTop="6dp"
+ android:layout_marginBottom="6dp">
-
-
-
+
+
@@ -165,8 +193,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
- android:layout_marginBottom="@dimen/fab_margins"
android:layout_marginEnd="@dimen/fab_margins"
+ android:layout_marginBottom="@dimen/fab_margins"
app:layout_behavior="gr.thmmy.mthmmy.utils.ScrollAwareFABBehavior"
app:srcCompat="@drawable/ic_file_upload_white_24dp" />
diff --git a/app/src/main/res/layout/activity_upload_fields_builder.xml b/app/src/main/res/layout/activity_upload_fields_builder.xml
index 0583b601..601cdeeb 100644
--- a/app/src/main/res/layout/activity_upload_fields_builder.xml
+++ b/app/src/main/res/layout/activity_upload_fields_builder.xml
@@ -27,7 +27,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top|start"
- android:background="@color/background"
+ android:background="@color/primary_light"
android:paddingEnd="@dimen/activity_horizontal_margin"
android:paddingStart="@dimen/activity_horizontal_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
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..08b74a4a
--- /dev/null
+++ b/app/src/main/res/layout/activity_upload_file_list_row.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_upload_filename_info_popup.xml b/app/src/main/res/layout/activity_upload_filename_info_popup.xml
new file mode 100644
index 00000000..bb6a9704
--- /dev/null
+++ b/app/src/main/res/layout/activity_upload_filename_info_popup.xml
@@ -0,0 +1,10 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_upload_progress.xml b/app/src/main/res/layout/dialog_upload_progress.xml
new file mode 100644
index 00000000..18444cb4
--- /dev/null
+++ b/app/src/main/res/layout/dialog_upload_progress.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/editor_view_color_picker.xml b/app/src/main/res/layout/editor_view_color_picker.xml
index b71214e1..be1ce295 100644
--- a/app/src/main/res/layout/editor_view_color_picker.xml
+++ b/app/src/main/res/layout/editor_view_color_picker.xml
@@ -1,11 +1,10 @@
-
+ android:layout_height="wrap_content"
+ android:background="@color/card_background">
-
@@ -14,84 +13,84 @@
android:id="@+id/black"
style="@style/PopupMenuItem.TopItem"
android:text="@string/black"
- android:textColor="@color/black"/>
+ android:textColor="@color/black" />
+ android:textColor="@color/red" />
+ android:textColor="@color/yellow" />
+ android:textColor="@color/pink" />
+ android:textColor="@color/green" />
+ android:textColor="@color/orange" />
+ android:textColor="@color/purple" />
+ android:textColor="@color/blue" />
+ android:textColor="@color/beige" />
+ android:textColor="@color/brown" />
+ android:textColor="@color/teal" />
+ android:textColor="@color/navy" />
+ android:textColor="@color/maroon" />
+ android:textColor="@color/lime_green" />
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index f2209027..6a76e274 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -18,6 +18,7 @@
#8B8B8B
#FF9800
#FAA61A
+ #890d0d
#FFFFFF
#CCCCCC
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index bf3d9e5f..5d856f19 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -132,12 +132,20 @@
Upload
- Generate title and description
+ Generate fields
Title
+ Upload as (filename)
Description
- Select file
+ Add files
Take photo
Select a category
+ Please follow the filename rules as\ndescribed
+ in this topic.\n
+ \nThis does not rename your local files.
+ Uploading
+ Uploading: %1$.2f Kbit/s, %2$d/%3$d KBytes
+ "Cancel"
+ "Retry"
Select type of upload
diff --git a/app/src/main/res/xml/app_preferences_user.xml b/app/src/main/res/xml/app_preferences_user.xml
index 2599df44..0ea00d34 100644
--- a/app/src/main/res/xml/app_preferences_user.xml
+++ b/app/src/main/res/xml/app_preferences_user.xml
@@ -49,7 +49,7 @@
app:iconSpaceReserved="false" />
-
+