Browse Source

Update uploads to androidx, comment out retry stuff, Fix FAB disappearing

pull/63/head
Apostolos Fanakis 6 years ago
parent
commit
4709796b8a
  1. 3
      app/build.gradle
  2. 8
      app/src/main/AndroidManifest.xml
  3. 1
      app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java
  4. 68
      app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java
  5. 36
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
  6. 711
      app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java
  7. 342
      app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadFieldsBuilderActivity.java
  8. 176
      app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsHelper.java
  9. 192
      app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java
  10. 44
      app/src/main/java/gr/thmmy/mthmmy/model/UploadFile.java
  11. 223
      app/src/main/java/gr/thmmy/mthmmy/services/UploadsReceiver.java
  12. 97
      app/src/main/java/gr/thmmy/mthmmy/utils/FileUtils.java
  13. 18
      app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareFABBehavior.java
  14. 174
      app/src/main/java/gr/thmmy/mthmmy/utils/TakePhoto.java
  15. 4
      app/src/main/res/drawable/ic_attach_file_white_24dp.xml
  16. 4
      app/src/main/res/drawable/ic_cached_accent_24dp.xml
  17. 4
      app/src/main/res/drawable/ic_cancel_accent_24dp.xml
  18. 4
      app/src/main/res/drawable/ic_info_outline_warning_24dp.xml
  19. 15
      app/src/main/res/layout/activity_board.xml
  20. 4
      app/src/main/res/layout/activity_downloads.xml
  21. 4
      app/src/main/res/layout/activity_topic.xml
  22. 72
      app/src/main/res/layout/activity_upload.xml
  23. 2
      app/src/main/res/layout/activity_upload_fields_builder.xml
  24. 24
      app/src/main/res/layout/activity_upload_file_list_row.xml
  25. 10
      app/src/main/res/layout/activity_upload_filename_info_popup.xml
  26. 43
      app/src/main/res/layout/dialog_upload_progress.xml
  27. 37
      app/src/main/res/layout/editor_view_color_picker.xml
  28. 1
      app/src/main/res/values/colors.xml
  29. 12
      app/src/main/res/values/strings.xml
  30. 4
      app/src/main/res/xml/app_preferences_user.xml
  31. 2
      build.gradle
  32. 4
      gradle/wrapper/gradle-wrapper.properties

3
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'

8
app/src/main/AndroidManifest.xml

@ -160,6 +160,14 @@
</intent-filter>
</service>
<receiver
android:name=".services.UploadsReceiver"
android:exported="false">
<intent-filter>
<action android:name="gr.thmmy.mthmmy.uploadservice.broadcast.status" />
</intent-filter>
</receiver>
<activity
android:name=".activities.create_content.CreateContentActivity"
android:configChanges="orientation|screenSize"

1
app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java

@ -100,6 +100,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
progressBar = findViewById(R.id.progressBar);
newTopicFAB = findViewById(R.id.board_fab);
newTopicFAB.setTag(true);
if (!sessionManager.isLoggedIn()) newTopicFAB.hide();
else {
newTopicFAB.setOnClickListener(view -> {

68
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;

36
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<RecyclerView.ViewHolder> {
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<RecyclerView.ViewHolder> {
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 <b>containing file's extension</b>
* @return FontAwesome character according to file's type
* @see <a href="http://fontawesome.io/">FontAwesome</a>
*/
@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);
}
}

711
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<UploadCategory> uploadRootCategories = new ArrayList<>();
private ParseUploadPageTask parseUploadPageTask;
private ArrayList<String> bundleCategory;
private String categorySelected = "-1";
private String uploaderProfileIndex = "1";
private String uploadFilename;
private Uri fileUri;
private ArrayList<UploadFile> 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<ResolveInfo> 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();
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 (fileUri == null) {
if (filesList.isEmpty()) {
Toast.makeText(view.getContext(), "Please choose a file to upload or take a photo", Toast.LENGTH_LONG).show();
shouldReturn = true;
}
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());
}
if (categorySelected.equals("-1") || uploadTitleText.equals("") || fileUri == null) {
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;
}
}
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 += uploadedFromThmmyPromptHtml;
uploadDescriptionText[0] += uploadedFromThmmyPromptHtml;
}
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) {
for (UploadFile file : filesList) {
if (file.isCameraPhoto()) {
TakePhoto.galleryAddPic(this, file.getPhotoFile());
}
}
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;
}
}
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) {
//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()));
}
@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);
}
} else {
Uri[] filesListArray = new Uri[filesList.size()];
for (int i = 0; i < filesList.size(); ++i) {
filesListArray[i] = filesList.get(i).getFileUri();
}
@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);
progressBar.setVisibility(View.GONE);
new ZipTask(this, editTextFilename, categorySelected,
uploadTitleText, uploadDescriptionText[0], fileIcon,
uploaderProfileIndex).execute(filesListArray);
finish();
return;
}
@Override
public void onCancelled(Context context, UploadInfo uploadInfo) {
Toast.makeText(context, "Upload canceled", Toast.LENGTH_SHORT).show();
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();
}
});
UploadsHelper.deleteTempFiles();
builder.setNegativeButton("NOPE", (dialog, which) -> {
progressBar.setVisibility(View.GONE);
}
})
.startUpload();
} catch (Exception exception) {
Timber.e(exception, "AndroidUploadService: %s", exception.getMessage());
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,12 +446,18 @@ 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
public void onActivityResult(int requestCode, int resultCode, Intent data) {
@ -369,11 +466,35 @@ 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);
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")) {
@ -394,46 +515,70 @@ public class UploadActivity extends BaseActivity {
} 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);
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 (filesList.isEmpty()) {
textWatcher.setFileExtension(FileUtils.getFileExtension(photoFileCreated.getName()));
try {
FileOutputStream out = new FileOutputStream(cacheImageFile);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
if (!hasModifiedFilename) {
uploadFilename.setText(photoFileCreated.getName());
hasModifiedFilename = false;
}
String newFilename = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.FRANCE).
format(new Date());
fileUri = Uri.parse(UploadsHelper.createTempFile(this, cacheFileUri, newFilename));
fileIcon = "jpg_image.gif";
} else {
fileIcon = "archive.gif";
textWatcher.setFileExtension(".zip");
newFilename += ".jpg";
filenameHolder.setText(newFilename);
filenameHolder.setVisibility(View.VISIBLE);
if (!hasModifiedFilename) {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.FRANCE).format(new Date());
String zipFilename = "mThmmy_" + timeStamp + ".zip";
uploadFilename.setText(zipFilename);
hasModifiedFilename = false;
}
}
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<String> 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<UploadCategory> 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<Uri, Void, Boolean> {
// Weak references will still allow the Activity to be garbage-collected
private final WeakReference<Activity> 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<String> 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;
@Override
protected Boolean doInBackground(Uri... filesToZip) {
if (weakActivity == null || zipFilename == null) {
return false;
}
++currentIndex;
File zipFile = UploadsHelper.createZipFile(zipFilename);
if (zipFile == null) {
return false;
}
zipFileUri = FileProvider.getUriForFile(weakActivity.get(),
weakActivity.get().getPackageName() +
".provider", zipFile);
if (bundleSelectionIndex != -1) {
rootCategorySpinner.setSelection(bundleSelectionIndex, true);
bundleCategory.remove(0);
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();
}
}
}

342
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;
}
}

176
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();
}
tempFilesDirectory.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;
}
}
@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;
return new File(zipFolder, zipFilename);
}
private static Bitmap decodeBitmap(Context context, Uri theUri, int sampleSize) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = sampleSize;
AssetFileDescriptor fileDescriptor = null;
public static void zip(Context context, Uri[] files, Uri zipFile) {
try {
fileDescriptor = context.getContentResolver().openAssetFileDescriptor(theUri, "r");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
BufferedInputStream origin;
OutputStream dest = context.getContentResolver().openOutputStream(zipFile);
assert dest != null;
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(dest));
byte data[] = new byte[BUFFER];
assert fileDescriptor != null;
return BitmapFactory.decodeFileDescriptor(
fileDescriptor.getFileDescriptor(), null, options);
}
for (Uri file : files) {
InputStream inputStream = context.getContentResolver().openInputStream(file);
assert inputStream != null;
origin = new BufferedInputStream(inputStream, BUFFER);
static int getRotation(Context context, Uri imageUri) {
int rotation = 0;
try {
ZipEntry entry = new ZipEntry(FileUtils.filenameFromUri(context, file));
out.putNextEntry(entry);
int count;
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;
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;
}
}

192
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;

44
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;
}
}

223
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;
}
}

97
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 <b>containing file's extension</b>
* @return FontAwesome character according to file's type
* @see <a href="http://fontawesome.io/">FontAwesome</a>
*/
@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);
}
}

18
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<FloatingA
final int dxUnconsumed, final int dyUnconsumed, int type) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed,
dyUnconsumed, type);
Log.d("THISSSS", "GOT");
if (dyConsumed > 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<FloatingA
});
} else if (child.getTag() != null && (boolean) child.getTag() && (dyConsumed < 0 ||
!target.canScrollVertically(-1) && dyUnconsumed < -50)) {
child.show();
Log.d("THISSSS", "GOT_SHOW");
child.show(new FloatingActionButton.OnVisibilityChangedListener() {
@Override
public void onShown(FloatingActionButton fab) {
super.onShown(fab);
fab.setVisibility(View.VISIBLE);
}
});
}
}

174
app/src/main/java/gr/thmmy/mthmmy/utils/TakePhoto.java

@ -0,0 +1,174 @@
package gr.thmmy.mthmmy.utils;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.AssetFileDescriptor;
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.MediaStore;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.FileProvider;
import android.widget.Toast;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import timber.log.Timber;
public class TakePhoto {
private static final int DEFAULT_MIN_WIDTH_QUALITY = 400;
private static final String IMAGE_CONTENT_DESCRIPTION = "mThmmy uploads image";
@Nullable
public static Intent getIntent(Context context, @NonNull File photoFile) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
//Ensures that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(context.getPackageManager()) != null) {
Uri photoURI = FileProvider.getUriForFile(context, context.getPackageName() +
".provider", photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
//Grants necessary permissions for Gallery to use the Uri
List<ResolveInfo> 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;
}
}

4
app/src/main/res/drawable/ic_attach_file_white_24dp.xml

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
<path android:fillColor="#FFFFFF" android:pathData="M16.5,6v11.5c0,2.21 -1.79,4 -4,4s-4,-1.79 -4,-4V5c0,-1.38 1.12,-2.5 2.5,-2.5s2.5,1.12 2.5,2.5v10.5c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V6H10v9.5c0,1.38 1.12,2.5 2.5,2.5s2.5,-1.12 2.5,-2.5V5c0,-2.21 -1.79,-4 -4,-4S7,2.79 7,5v12.5c0,3.04 2.46,5.5 5.5,5.5s5.5,-2.46 5.5,-5.5V6h-1.5z"/>
</vector>

4
app/src/main/res/drawable/ic_cached_accent_24dp.xml

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
<path android:fillColor="#26A69A" android:pathData="M19,8l-4,4h3c0,3.31 -2.69,6 -6,6 -1.01,0 -1.97,-0.25 -2.8,-0.7l-1.46,1.46C8.97,19.54 10.43,20 12,20c4.42,0 8,-3.58 8,-8h3l-4,-4zM6,12c0,-3.31 2.69,-6 6,-6 1.01,0 1.97,0.25 2.8,0.7l1.46,-1.46C15.03,4.46 13.57,4 12,4c-4.42,0 -8,3.58 -8,8H1l4,4 4,-4H6z"/>
</vector>

4
app/src/main/res/drawable/ic_cancel_accent_24dp.xml

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
<path android:fillColor="#26A69A" android:pathData="M12,2C6.47,2 2,6.47 2,12s4.47,10 10,10 10,-4.47 10,-10S17.53,2 12,2zM17,15.59L15.59,17 12,13.41 8.41,17 7,15.59 10.59,12 7,8.41 8.41,7 12,10.59 15.59,7 17,8.41 13.41,12 17,15.59z"/>
</vector>

4
app/src/main/res/drawable/ic_info_outline_warning_24dp.xml

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24.0" android:viewportWidth="24.0" android:width="24dp">
<path android:fillColor="#FF9800" android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/>
</vector>

15
app/src/main/res/layout/activity_board.xml

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_content"
@ -31,7 +30,7 @@
android:layout_marginEnd="19dp"
android:background="@null"
android:contentDescription="@string/bookmark"
app:srcCompat="@drawable/ic_bookmark_false_accent_24dp"/>
app:srcCompat="@drawable/ic_bookmark_false_accent_24dp" />
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
@ -43,8 +42,8 @@
android:layout_marginTop="64dp"
android:background="@color/background"
android:scrollbars="none"
tools:context="gr.thmmy.mthmmy.activities.topic.TopicActivity">
</androidx.recyclerview.widget.RecyclerView>
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="gr.thmmy.mthmmy.activities.topic.TopicActivity" />
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="@+id/progressBar"
@ -56,7 +55,7 @@
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|center"
app:mpb_indeterminateTint="@color/accent"
app:mpb_progressStyle="horizontal"/>
app:mpb_progressStyle="horizontal" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/board_fab"
@ -65,7 +64,5 @@
android:layout_gravity="bottom|end"
android:layout_margin="@dimen/fab_margins"
app:layout_behavior="gr.thmmy.mthmmy.utils.ScrollAwareFABBehavior"
app:srcCompat="@drawable/ic_add_fab"/>
app:srcCompat="@drawable/ic_add_fab" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

4
app/src/main/res/layout/activity_downloads.xml

@ -48,7 +48,7 @@
app:mpb_indeterminateTint="@color/accent"
app:mpb_progressStyle="horizontal"/>
<!--<com.google.android.material.floatingactionbutton.FloatingActionButton
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/upload_fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@ -56,5 +56,5 @@
android:layout_marginBottom="@dimen/fab_margins"
android:layout_marginEnd="@dimen/fab_margins"
app:layout_behavior="gr.thmmy.mthmmy.utils.ScrollAwareFABBehavior"
app:srcCompat="@drawable/ic_file_upload_white_24dp"/>-->
app:srcCompat="@drawable/ic_file_upload_white_24dp"/>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

4
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" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

72
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">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/background"
android:background="@color/primary_light"
android:focusableInTouchMode="true"
android:orientation="vertical">
@ -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">
<gr.thmmy.mthmmy.utils.AppCompatSpinnerWithoutDefault
android:id="@+id/upload_spinner_category_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:popupBackground="@color/primary"
android:prompt="@string/upload_spinners_hint" />
</LinearLayout>
@ -61,8 +62,8 @@
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:layout_marginTop="6dp">
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp">
<EditText
android:id="@+id/upload_title"
@ -73,11 +74,41 @@
android:maxLength="500" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.textfield.TextInputLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp"
android:layout_marginTop="6dp">
android:layout_weight="1">
<EditText
android:id="@+id/upload_filename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/upload_filename"
android:inputType="textNoSuggestions"
android:maxLength="500" />
</com.google.android.material.textfield.TextInputLayout>
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/upload_filename_info"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="12dp"
android:theme="@style/LightBackgroundColoredButton"
app:srcCompat="@drawable/ic_info_outline_white_24dp" />
</LinearLayout>
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:layout_marginBottom="6dp">
<EditText
android:id="@+id/upload_description"
@ -97,16 +128,13 @@
android:textAlignment="center"
android:textColor="@color/accent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/upload_filename"
<LinearLayout
android:id="@+id/upload_files_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:layout_marginTop="6dp"
android:drawablePadding="5dp"
android:ellipsize="marquee"
android:singleLine="true"
android:textColor="@color/primary_text"
android:layout_marginBottom="6dp"
android:orientation="vertical"
android:visibility="gone" />
<LinearLayout
@ -129,11 +157,6 @@
android:text="@string/upload_select_file"
android:textColor="@color/primary_text" />
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/upload_take_photo_button"
android:layout_width="wrap_content"
@ -144,6 +167,11 @@
android:gravity="center_vertical"
android:text="@string/upload_take_photo"
android:textColor="@color/primary_text" />
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
@ -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" />

2
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"

24
app/src/main/res/layout/activity_upload_file_list_row.xml

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/upload_file_item_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:ellipsize="marquee"
android:singleLine="true"
android:textColor="@color/primary_text" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/upload_file_item_remove"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:theme="@style/LightBackgroundColoredButton"
app:srcCompat="@drawable/ic_delete_accent_24dp" />
</LinearLayout>

10
app/src/main/res/layout/activity_upload_filename_info_popup.xml

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/upload_filename_info_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/primary_light"
android:linksClickable="true"
android:padding="8dp"
android:text="@string/upload_filename_info"
android:textColor="@color/primary_text" />

43
app/src/main/res/layout/dialog_upload_progress.xml

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingEnd="24dp"
android:paddingStart="24dp">
<TextView
android:id="@+id/dialog_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginBottom="5dp"
android:text="@string/upload_progress_dialog_title"
android:textColor="@color/accent"
android:textSize="20sp" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginBottom="15dp"
android:background="@color/secondary_text" />
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="@+id/dialogProgressBar"
style="@style/Widget.MaterialProgressBar.ProgressBar.Horizontal.NoPadding"
android:layout_width="match_parent"
android:layout_height="@dimen/progress_bar_height"
android:indeterminate="false"
app:mpb_progressStyle="horizontal"
app:mpb_progressTint="@color/accent" />
<TextView
android:id="@+id/dialog_upload_progress_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:layout_marginTop="12dp"
android:minEms="64"
android:textColor="@color/white" />
</LinearLayout>

37
app/src/main/res/layout/editor_view_color_picker.xml

@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:background="@color/card_background">
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
@ -14,84 +13,84 @@
android:id="@+id/black"
style="@style/PopupMenuItem.TopItem"
android:text="@string/black"
android:textColor="@color/black"/>
android:textColor="@color/black" />
<TextView
android:id="@+id/red"
style="@style/PopupMenuItem"
android:text="@string/red"
android:textColor="@color/red"/>
android:textColor="@color/red" />
<TextView
android:id="@+id/yellow"
style="@style/PopupMenuItem"
android:text="@string/yellow"
android:textColor="@color/yellow"/>
android:textColor="@color/yellow" />
<TextView
android:id="@+id/pink"
style="@style/PopupMenuItem"
android:text="@string/pink"
android:textColor="@color/pink"/>
android:textColor="@color/pink" />
<TextView
android:id="@+id/green"
style="@style/PopupMenuItem"
android:text="@string/green"
android:textColor="@color/green"/>
android:textColor="@color/green" />
<TextView
android:id="@+id/orange"
style="@style/PopupMenuItem"
android:text="@string/orange"
android:textColor="@color/orange"/>
android:textColor="@color/orange" />
<TextView
android:id="@+id/purple"
style="@style/PopupMenuItem"
android:text="@string/purple"
android:textColor="@color/purple"/>
android:textColor="@color/purple" />
<TextView
android:id="@+id/blue"
style="@style/PopupMenuItem"
android:text="@string/blue"
android:textColor="@color/blue"/>
android:textColor="@color/blue" />
<TextView
android:id="@+id/beige"
style="@style/PopupMenuItem"
android:text="@string/beige"
android:textColor="@color/beige"/>
android:textColor="@color/beige" />
<TextView
android:id="@+id/brown"
style="@style/PopupMenuItem"
android:text="@string/brown"
android:textColor="@color/brown"/>
android:textColor="@color/brown" />
<TextView
android:id="@+id/teal"
style="@style/PopupMenuItem"
android:text="@string/teal"
android:textColor="@color/teal"/>
android:textColor="@color/teal" />
<TextView
android:id="@+id/navy"
style="@style/PopupMenuItem"
android:text="@string/navy"
android:textColor="@color/navy"/>
android:textColor="@color/navy" />
<TextView
android:id="@+id/maroon"
style="@style/PopupMenuItem"
android:text="@string/maroon"
android:textColor="@color/maroon"/>
android:textColor="@color/maroon" />
<TextView
android:id="@+id/lime_green"
style="@style/PopupMenuItem.BottomItem"
android:text="@string/lime_green"
android:textColor="@color/lime_green"/>
android:textColor="@color/lime_green" />
</LinearLayout>
</ScrollView>

1
app/src/main/res/values/colors.xml

@ -18,6 +18,7 @@
<color name="divider">#8B8B8B</color>
<color name="link_color">#FF9800</color>
<color name="mention_color">#FAA61A</color>
<color name="error_red">#890d0d</color>
<color name="white">#FFFFFF</color>
<color name="iron">#CCCCCC</color>

12
app/src/main/res/values/strings.xml

@ -132,12 +132,20 @@
<string name="upload_button">Upload</string>
<!--Upload Activity-->
<string name="upload_title_description_builder">Generate title and description</string>
<string name="upload_title_description_builder">Generate fields</string>
<string name="upload_title_hint">Title</string>
<string name="upload_filename">Upload as (filename)</string>
<string name="upload_description_hint">Description</string>
<string name="upload_select_file">Select file</string>
<string name="upload_select_file">Add files</string>
<string name="upload_take_photo">Take photo</string>
<string name="upload_spinners_hint">Select a category</string>
<string name="upload_filename_info">Please follow the filename rules as\ndescribed
in&#160;<a href="https://www.thmmy.gr/smf/index.php?topic=34294.0">this topic</a>.\n
\nThis does not rename your local files.</string>
<string name="upload_progress_dialog_title">Uploading</string>
<string name="upload_progress_dialog_bytes_uploaded">Uploading: %1$.2f Kbit/s, %2$d/%3$d KBytes</string>
<string name="upload_notification_cancel">"Cancel"</string>
<string name="upload_notification_retry">"Retry"</string>
<!--Upload Fields Builder Activity-->
<string name="upload_fields_builder_type_radio_buttons_title">Select type of upload</string>

4
app/src/main/res/xml/app_preferences_user.xml

@ -49,7 +49,7 @@
app:iconSpaceReserved="false" />
</androidx.preference.PreferenceCategory>
<!--<androidx.preference.PreferenceCategory
<androidx.preference.PreferenceCategory
android:key="pref_category_uploading_key"
android:title="@string/pref_category_uploading"
app:iconSpaceReserved="false">
@ -59,7 +59,7 @@
android:title="@string/pref_title_uploading_app_signature_enable"
android:summary="@string/pref_summary_uploading_app_signature_enable"
app:iconSpaceReserved="false" />
</androidx.preference.PreferenceCategory>-->
</androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory
android:key="pref_category_privacy_key"

2
build.gradle

@ -8,7 +8,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
classpath 'com.android.tools.build:gradle:3.4.1'
classpath 'com.google.gms:google-services:4.2.0'
classpath 'io.fabric.tools:gradle:1.26.1'
classpath 'org.ajoberstar.grgit:grgit-core:3.0.0' // Also change in app/gradle/grgit.gradle

4
gradle/wrapper/gradle-wrapper.properties

@ -1,6 +1,6 @@
#Fri Sep 28 13:21:54 EEST 2018
#Sat Jun 15 18:56:13 EEST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip

Loading…
Cancel
Save