mirror of https://github.com/ThmmyNoLife/mTHMMY
oogee
5 years ago
94 changed files with 2801 additions and 1141 deletions
File diff suppressed because it is too large
@ -0,0 +1,79 @@ |
|||
package gr.thmmy.mthmmy.activities.upload; |
|||
|
|||
import android.os.Bundle; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
import java.util.regex.Matcher; |
|||
import java.util.regex.Pattern; |
|||
|
|||
import gr.thmmy.mthmmy.base.BaseApplication; |
|||
import timber.log.Timber; |
|||
|
|||
class UploadsCourse { |
|||
private String name; |
|||
private String minifiedName; |
|||
private String greeklishName; |
|||
|
|||
private UploadsCourse(String fullName, String minifiedName, String greeklishName) { |
|||
this.name = fullName; |
|||
this.minifiedName = minifiedName; |
|||
this.greeklishName = greeklishName; |
|||
} |
|||
|
|||
String getName() { |
|||
return name; |
|||
} |
|||
|
|||
String getMinifiedName() { |
|||
return minifiedName; |
|||
} |
|||
|
|||
String getGreeklishName() { |
|||
return greeklishName; |
|||
} |
|||
|
|||
static Map<String, UploadsCourse> generateUploadsCourses(String[] uploadsCoursesRes){ |
|||
Map<String, UploadsCourse> uploadsCourses = new HashMap<>(); |
|||
for(String uploadsCourseStr:uploadsCoursesRes) { |
|||
String[] split = uploadsCourseStr.split(":"); |
|||
UploadsCourse uploadsCourse = new UploadsCourse(split[0], split[1], split[2]); |
|||
uploadsCourses.put(uploadsCourse.getName(),uploadsCourse); |
|||
} |
|||
return uploadsCourses; |
|||
} |
|||
|
|||
static UploadsCourse findCourse(String retrievedCourse, |
|||
Map<String, UploadsCourse> uploadsCourses){ |
|||
retrievedCourse = normalizeGreekNumbers(retrievedCourse); |
|||
UploadsCourse uploadsCourse = uploadsCourses.get(retrievedCourse); |
|||
if(uploadsCourse != null) return uploadsCourse; |
|||
|
|||
String foundKey = null; |
|||
for (Map.Entry<String, UploadsCourse> entry : uploadsCourses.entrySet()) { |
|||
String key = entry.getKey(); |
|||
if ((key.contains(retrievedCourse) || retrievedCourse.contains(key)) |
|||
&& (foundKey==null || key.length()>foundKey.length())) |
|||
foundKey = key; |
|||
} |
|||
|
|||
if(foundKey==null){ |
|||
Timber.w("Couldn't find course that matches %s", retrievedCourse); |
|||
Bundle bundle = new Bundle(); |
|||
bundle.putString("course_name", retrievedCourse); |
|||
BaseApplication.getInstance().logFirebaseAnalyticsEvent("unsupported_uploads_course", bundle); |
|||
return null; |
|||
} |
|||
|
|||
return uploadsCourses.get(foundKey); |
|||
} |
|||
|
|||
private static String normalizeGreekNumbers(String stringWithGreekNumbers) { |
|||
StringBuilder normalizedStrBuilder = new StringBuilder(stringWithGreekNumbers); |
|||
Pattern pattern = Pattern.compile("(Ι+)(?:\\s|\\(|\\)|$)"); |
|||
Matcher matcher = pattern.matcher(stringWithGreekNumbers); |
|||
while (matcher.find()) |
|||
normalizedStrBuilder.replace(matcher.start(1), matcher.end(1), matcher.group(1).replaceAll("Ι", "I")); |
|||
return normalizedStrBuilder.toString(); |
|||
} |
|||
} |
@ -0,0 +1,8 @@ |
|||
package gr.thmmy.mthmmy.activities.upload.multipart; |
|||
|
|||
public class MultipartUploadException extends RuntimeException { |
|||
public MultipartUploadException(String message) { |
|||
super(message); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,99 @@ |
|||
package gr.thmmy.mthmmy.activities.upload.multipart; |
|||
|
|||
import android.content.Context; |
|||
import android.content.Intent; |
|||
|
|||
import net.gotev.uploadservice.HttpUploadRequest; |
|||
import net.gotev.uploadservice.Logger; |
|||
import net.gotev.uploadservice.UploadFile; |
|||
import net.gotev.uploadservice.UploadTask; |
|||
|
|||
import java.io.FileNotFoundException; |
|||
import java.net.MalformedURLException; |
|||
|
|||
/** |
|||
From MultipartUploadRequest gotev/android-upload-service in order to use the local custom |
|||
MultipartUploadTask. |
|||
*/ |
|||
public class MultipartUploadRequest extends HttpUploadRequest<MultipartUploadRequest> { |
|||
|
|||
private static final String LOG_TAG = MultipartUploadRequest.class.getSimpleName(); |
|||
private boolean isUtf8Charset = false; |
|||
|
|||
|
|||
public MultipartUploadRequest(final Context context, final String uploadId, final String serverUrl) |
|||
throws IllegalArgumentException, MalformedURLException { |
|||
super(context, uploadId, serverUrl); |
|||
} |
|||
|
|||
public MultipartUploadRequest(final Context context, final String serverUrl) |
|||
throws MalformedURLException, IllegalArgumentException { |
|||
this(context, null, serverUrl); |
|||
} |
|||
|
|||
@Override |
|||
protected void initializeIntent(Intent intent) { |
|||
super.initializeIntent(intent); |
|||
intent.putExtra(MultipartUploadTask.PARAM_UTF8_CHARSET, isUtf8Charset); |
|||
} |
|||
|
|||
@Override |
|||
protected Class<? extends UploadTask> getTaskClass() { |
|||
return MultipartUploadTask.class; |
|||
} |
|||
|
|||
public MultipartUploadRequest addFileToUpload(String filePath, |
|||
String parameterName, |
|||
String fileName, String contentType) |
|||
throws FileNotFoundException, IllegalArgumentException { |
|||
|
|||
UploadFile file = new UploadFile(filePath); |
|||
filePath = file.getPath(); |
|||
|
|||
if (parameterName == null || "".equals(parameterName)) { |
|||
throw new IllegalArgumentException("Please specify parameterName value for file: " |
|||
+ filePath); |
|||
} |
|||
|
|||
file.setProperty(MultipartUploadTask.PROPERTY_PARAM_NAME, parameterName); |
|||
|
|||
if (contentType == null || contentType.isEmpty()) { |
|||
contentType = file.getContentType(context); |
|||
Logger.debug(LOG_TAG, "Auto-detected MIME type for " + filePath |
|||
+ " is: " + contentType); |
|||
} else { |
|||
Logger.debug(LOG_TAG, "Content Type set for " + filePath |
|||
+ " is: " + contentType); |
|||
} |
|||
|
|||
file.setProperty(MultipartUploadTask.PROPERTY_CONTENT_TYPE, contentType); |
|||
|
|||
if (fileName == null || "".equals(fileName)) { |
|||
fileName = file.getName(context); |
|||
Logger.debug(LOG_TAG, "Using original file name: " + fileName); |
|||
} else { |
|||
Logger.debug(LOG_TAG, "Using custom file name: " + fileName); |
|||
} |
|||
|
|||
file.setProperty(MultipartUploadTask.PROPERTY_REMOTE_FILE_NAME, fileName); |
|||
|
|||
params.files.add(file); |
|||
return this; |
|||
} |
|||
|
|||
public MultipartUploadRequest addFileToUpload(final String path, final String parameterName, |
|||
final String fileName) |
|||
throws FileNotFoundException, IllegalArgumentException { |
|||
return addFileToUpload(path, parameterName, fileName, null); |
|||
} |
|||
|
|||
public MultipartUploadRequest addFileToUpload(final String path, final String parameterName) |
|||
throws FileNotFoundException, IllegalArgumentException { |
|||
return addFileToUpload(path, parameterName, null, null); |
|||
} |
|||
|
|||
public MultipartUploadRequest setUtf8Charset() { |
|||
isUtf8Charset = true; |
|||
return this; |
|||
} |
|||
} |
@ -0,0 +1,160 @@ |
|||
package gr.thmmy.mthmmy.activities.upload.multipart; |
|||
|
|||
import android.content.Intent; |
|||
|
|||
import net.gotev.uploadservice.HttpUploadTask; |
|||
import net.gotev.uploadservice.NameValue; |
|||
import net.gotev.uploadservice.UploadFile; |
|||
import net.gotev.uploadservice.UploadService; |
|||
import net.gotev.uploadservice.http.BodyWriter; |
|||
|
|||
import java.io.IOException; |
|||
import java.io.UnsupportedEncodingException; |
|||
import java.nio.charset.Charset; |
|||
|
|||
/** |
|||
Extended MultipartUploadTask from gotev/android-upload-service to include a fix for the parameter |
|||
tp_dluploadpic. Also changed Connection to keep-alive. |
|||
*/ |
|||
public class MultipartUploadTask extends HttpUploadTask { |
|||
|
|||
static final String PARAM_UTF8_CHARSET = "multipartUtf8Charset"; |
|||
|
|||
private static final String BOUNDARY_SIGNATURE = "-------AndroidUploadService"; |
|||
private static final Charset US_ASCII = Charset.forName("US-ASCII"); |
|||
private static final String NEW_LINE = "\r\n"; |
|||
private static final String TWO_HYPHENS = "--"; |
|||
|
|||
// properties associated to each file
|
|||
static final String PROPERTY_REMOTE_FILE_NAME = "httpRemoteFileName"; |
|||
static final String PROPERTY_CONTENT_TYPE = "httpContentType"; |
|||
static final String PROPERTY_PARAM_NAME = "httpParamName"; |
|||
|
|||
private byte[] boundaryBytes; |
|||
private byte[] trailerBytes; |
|||
private Charset charset; |
|||
|
|||
@Override |
|||
protected void init(UploadService service, Intent intent) throws IOException { |
|||
super.init(service, intent); |
|||
|
|||
String boundary = BOUNDARY_SIGNATURE + System.nanoTime(); |
|||
boundaryBytes = (TWO_HYPHENS + boundary + NEW_LINE).getBytes(US_ASCII); |
|||
trailerBytes = (TWO_HYPHENS + boundary + TWO_HYPHENS + NEW_LINE).getBytes(US_ASCII); |
|||
charset = intent.getBooleanExtra(PARAM_UTF8_CHARSET, false) ? |
|||
Charset.forName("UTF-8") : US_ASCII; |
|||
|
|||
httpParams.addHeader("Connection", "Keep-Alive"); |
|||
httpParams.addHeader("Content-Type", "multipart/form-data; boundary=" + boundary); |
|||
} |
|||
|
|||
@Override |
|||
protected long getBodyLength() throws UnsupportedEncodingException { |
|||
return (getRequestParametersLength() + getFilesLength() + trailerBytes.length); |
|||
} |
|||
|
|||
@Override |
|||
public void onBodyReady(BodyWriter bodyWriter) throws IOException { |
|||
//reset uploaded bytes when the body is ready to be written
|
|||
//because sometimes this gets invoked when network changes
|
|||
uploadedBytes = 0; |
|||
writeRequestParameters(bodyWriter); |
|||
writeFiles(bodyWriter); |
|||
bodyWriter.write(trailerBytes); |
|||
uploadedBytes += trailerBytes.length; |
|||
broadcastProgress(uploadedBytes, totalBytes); |
|||
} |
|||
|
|||
private long getFilesLength() throws UnsupportedEncodingException { |
|||
long total = 0; |
|||
|
|||
for (UploadFile file : params.files) { |
|||
total += getTotalMultipartBytes(file); |
|||
} |
|||
|
|||
return total; |
|||
} |
|||
|
|||
private long getRequestParametersLength() throws UnsupportedEncodingException { |
|||
long parametersBytes = 0; |
|||
|
|||
if (!httpParams.getRequestParameters().isEmpty()) { |
|||
for (final NameValue parameter : httpParams.getRequestParameters()) { |
|||
// the bytes needed for every parameter are the sum of the boundary bytes
|
|||
// and the bytes occupied by the parameter
|
|||
parametersBytes += boundaryBytes.length + getMultipartBytes(parameter).length; |
|||
} |
|||
} |
|||
|
|||
return parametersBytes; |
|||
} |
|||
|
|||
private byte[] getMultipartBytes(NameValue parameter) throws UnsupportedEncodingException { |
|||
if(parameter.getName().equals("tp_dluploadpic")){ |
|||
String header = "Content-Disposition: form-data; name=\"" + |
|||
parameter.getName() + "\"; filename=\"\"" + NEW_LINE + |
|||
"Content-Type: application/octet-stream" + NEW_LINE + NEW_LINE; |
|||
return header.getBytes(charset); |
|||
} |
|||
else |
|||
return ("Content-Disposition: form-data; name=\"" + parameter.getName() + "\"" |
|||
+ NEW_LINE + NEW_LINE + parameter.getValue() + NEW_LINE).getBytes(charset); |
|||
} |
|||
|
|||
private byte[] getMultipartHeader(UploadFile file) |
|||
throws UnsupportedEncodingException { |
|||
String header = "Content-Disposition: form-data; name=\"" + |
|||
file.getProperty(PROPERTY_PARAM_NAME) + "\"; filename=\"" + |
|||
file.getProperty(PROPERTY_REMOTE_FILE_NAME) + "\"" + NEW_LINE + |
|||
"Content-Type: " + file.getProperty(PROPERTY_CONTENT_TYPE) + |
|||
NEW_LINE + NEW_LINE; |
|||
|
|||
return header.getBytes(charset); |
|||
} |
|||
|
|||
private long getTotalMultipartBytes(UploadFile file) |
|||
throws UnsupportedEncodingException { |
|||
return boundaryBytes.length + getMultipartHeader(file).length + file.length(service) |
|||
+ NEW_LINE.getBytes(charset).length; |
|||
} |
|||
|
|||
private void writeRequestParameters(BodyWriter bodyWriter) throws IOException { |
|||
if (!httpParams.getRequestParameters().isEmpty()) { |
|||
for (final NameValue parameter : httpParams.getRequestParameters()) { |
|||
bodyWriter.write(boundaryBytes); |
|||
byte[] formItemBytes = getMultipartBytes(parameter); |
|||
bodyWriter.write(formItemBytes); |
|||
|
|||
uploadedBytes += boundaryBytes.length + formItemBytes.length; |
|||
broadcastProgress(uploadedBytes, totalBytes); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void writeFiles(BodyWriter bodyWriter) throws IOException { |
|||
for (UploadFile file : params.files) { |
|||
if (!shouldContinue) |
|||
break; |
|||
|
|||
bodyWriter.write(boundaryBytes); |
|||
byte[] headerBytes = getMultipartHeader(file); |
|||
bodyWriter.write(headerBytes); |
|||
|
|||
uploadedBytes += boundaryBytes.length + headerBytes.length; |
|||
broadcastProgress(uploadedBytes, totalBytes); |
|||
|
|||
bodyWriter.writeStream(file.getStream(service), this); |
|||
|
|||
byte[] newLineBytes = NEW_LINE.getBytes(charset); |
|||
bodyWriter.write(newLineBytes); |
|||
uploadedBytes += newLineBytes.length; |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected void onSuccessfulUpload() { |
|||
addAllFilesToSuccessfullyUploadedFiles(); |
|||
} |
|||
|
|||
} |
|||
|
@ -0,0 +1,45 @@ |
|||
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; |
|||
} |
|||
} |
@ -0,0 +1,233 @@ |
|||
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 android.view.View; |
|||
import android.view.Window; |
|||
import android.widget.Button; |
|||
import android.widget.TextView; |
|||
import android.widget.Toast; |
|||
|
|||
import androidx.appcompat.app.AlertDialog; |
|||
|
|||
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.activities.upload.multipart.MultipartUploadException; |
|||
import gr.thmmy.mthmmy.base.BaseApplication; |
|||
import me.zhanghai.android.materialprogressbar.MaterialProgressBar; |
|||
import timber.log.Timber; |
|||
|
|||
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); |
|||
Timber.d("Received ACTION_CANCEL_UPLOAD (id: %s)", uploadID); |
|||
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) { |
|||
Timber.i("Upload in progress (id: %s)",uploadInfo.getUploadId()); |
|||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && |
|||
uploadInfo.getUploadId().equals(dialogUploadID) && |
|||
uploadProgressDialog != null) { |
|||
Button alertDialogNeutral = uploadProgressDialog.getButton(AlertDialog.BUTTON_NEUTRAL); |
|||
alertDialogNeutral.setText(R.string.upload_resume_in_background); |
|||
alertDialogNeutral.setOnClickListener(v -> uploadProgressDialog.dismiss()); |
|||
|
|||
Button alertDialogNegative = uploadProgressDialog.getButton(AlertDialog.BUTTON_NEGATIVE); |
|||
alertDialogNegative.setText(R.string.cancel); |
|||
alertDialogNegative.setOnClickListener(v -> { |
|||
Timber.d("Cancelling upload (id: %s)", dialogUploadID); |
|||
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) { |
|||
Timber.i("Error while uploading (id: %s)",uploadInfo.getUploadId()); |
|||
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(R.string.cancel); |
|||
alertDialogNegative.setOnClickListener(v -> { |
|||
cancelNotification(context, 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(R.string.upload_failed); |
|||
} |
|||
|
|||
if (uploadInfo.getUploadedBytes() == uploadInfo.getTotalBytes()) { |
|||
uploadProgressDialog.dismiss(); |
|||
} |
|||
} |
|||
} else { |
|||
cancelNotification(context, 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(), R.string.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; |
|||
} |
|||
|
|||
String response = serverResponse.getBodyAsString(); |
|||
if(response.contains("Η προσθήκη του αρχείου ήταν επιτυχημένη.")||response.contains("The upload was successful.")){ |
|||
Timber.i("Upload completed successfully (id: %s)",uploadInfo.getUploadId()); |
|||
Toast.makeText(context.getApplicationContext(), "Upload completed successfully", Toast.LENGTH_SHORT).show(); |
|||
BaseApplication.getInstance().logFirebaseAnalyticsEvent("file_upload", null); |
|||
} |
|||
else { |
|||
MultipartUploadException multipartUploadException = new MultipartUploadException(response); |
|||
Timber.e(multipartUploadException); |
|||
onError(context,uploadInfo,serverResponse,multipartUploadException); |
|||
} |
|||
|
|||
if (storage == null) { |
|||
storage = new Storage(context.getApplicationContext()); |
|||
} |
|||
|
|||
UploadsHelper.deleteTempFiles(storage); |
|||
} |
|||
|
|||
@Override |
|||
public void onCancelled(Context context, UploadInfo uploadInfo) { |
|||
Timber.i("Upload cancelled (id: %s)", uploadInfo.getUploadId()); |
|||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { |
|||
uploadProgressDialog = null; |
|||
dialogUploadID = null; |
|||
} |
|||
|
|||
Toast.makeText(context.getApplicationContext(), R.string.upload_cancelled, Toast.LENGTH_SHORT).show(); |
|||
if (storage == null) |
|||
storage = new Storage(context.getApplicationContext()); |
|||
|
|||
//cancelNotification(context, uploadInfo.getNotificationID());
|
|||
UploadsHelper.deleteTempFiles(storage); |
|||
} |
|||
|
|||
public static void setDialogDisplay(AlertDialog uploadProgressDialog, String dialogUploadID, |
|||
Intent multipartUploadRetryIntent) { |
|||
UploadsReceiver.uploadProgressDialog = uploadProgressDialog; |
|||
UploadsReceiver.dialogUploadID = dialogUploadID; |
|||
//UploadsReceiver.multipartUploadRetryIntent = multipartUploadRetryIntent;
|
|||
} |
|||
|
|||
private void cancelNotification(Context context, int notificationId){ |
|||
NotificationManager notificationManager = (NotificationManager) context.getApplicationContext(). |
|||
getSystemService(Context.NOTIFICATION_SERVICE); |
|||
if (notificationManager != null) |
|||
notificationManager.cancel(notificationId); |
|||
} |
|||
} |
@ -0,0 +1,173 @@ |
|||
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.net.Uri; |
|||
import android.os.Environment; |
|||
import android.provider.MediaStore; |
|||
import android.widget.Toast; |
|||
|
|||
import androidx.annotation.NonNull; |
|||
import androidx.annotation.Nullable; |
|||
import androidx.core.content.FileProvider; |
|||
import androidx.exifinterface.media.ExifInterface; |
|||
|
|||
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()&&!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; |
|||
} |
|||
} |
@ -0,0 +1,27 @@ |
|||
package gr.thmmy.mthmmy.utils; |
|||
import android.content.Context; |
|||
import android.util.AttributeSet; |
|||
|
|||
import androidx.appcompat.widget.AppCompatButton; |
|||
|
|||
public class ToggledBackgroundButton extends AppCompatButton { |
|||
|
|||
public ToggledBackgroundButton(Context context) { |
|||
super(context); |
|||
} |
|||
|
|||
public ToggledBackgroundButton(Context context, AttributeSet attrs) { |
|||
super(context, attrs); |
|||
} |
|||
|
|||
public ToggledBackgroundButton(Context context, AttributeSet attrs, int defStyleAttr) { |
|||
super(context, attrs, defStyleAttr); |
|||
} |
|||
|
|||
@Override |
|||
public void setEnabled(boolean enabled) { |
|||
setAlpha(enabled ? 1 : 0.5f); |
|||
super.setEnabled(enabled); |
|||
} |
|||
} |
|||
|
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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" /> |
@ -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> |
@ -0,0 +1,158 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<resources> |
|||
<!--Format: Original:Minified:Greeklish--> |
|||
<string-array name="string_array_uploads_courses"> |
|||
<item>Ακουστική I:Ακουστική 1:Akoustiki_I</item> |
|||
<item>Ακουστική II:Ακουστική 2:Akoustiki_II</item> |
|||
<item>Ανάλυση Ηλεκτρικών Κυκλωμάτων με Υπολογιστή:Ανάλυση Ηλεκτρικ. Κυκλ. με Υπολογιστή:Analysi_Ilektr_Kykl</item> |
|||
<item>Ανάλυση Συστημάτων Ηλεκτρικής Ενέργειας:ΑΣΗΕ:ASHE</item> |
|||
<item>Ανάλυση Χρονοσειρών:Χρονοσειρές:Xronoseires</item> |
|||
<item>Ανάλυση και Σχεδίαση Αλγορίθμων:Αλγόριθμοι:Algorithms</item> |
|||
<item>Αναγνώριση Προτύπων:Αναγνώριση Προτύπων:protipa</item> |
|||
<item>Αναλογικές Τηλεπικοινωνίες (πρώην Τηλεπικοινωνιακά Συστήματα I):Αναλογικές Τηλεπ.:Anal_Tilep</item> |
|||
<item>Αντικειμενοστραφής Προγραμματισμός:Αντικειμενοστραφής:OOP</item> |
|||
<item>Αξιοπιστία Συστημάτων:Αξιοπιστία Συστημάτων:Aksiopistia_Systimaton</item> |
|||
<item>Αριθμητική Ανάλυση:Αριθμ. Ανάλυση:Arith_Anal</item> |
|||
<item>Αρχές Οικονομίας:Αρχές Οικονομίας:Arx_Oikonomias</item> |
|||
<item>Αρχές Παράλληλης Επεξεργασίας:Αρχές Παράλληλης Επεξεργασίας:Arxes_Parall_Epeksergasias</item> |
|||
<item>Αρχιτεκτονική Υπολογιστών:Αρχ. Υπολογιστών:Arx_Ypologiston</item> |
|||
<item>Ασαφή Συστήματα:Ασαφή:Asafi</item> |
|||
<item>Ασφάλεια Πληροφοριακών Συστημάτων:Ασφάλεια:Asfaleia</item> |
|||
<item>Ασύρματος Τηλεπικοινωνία I:Ασύρματος 1:Asyrmatos_I</item> |
|||
<item>Ασύρματος Τηλεπικοινωνία II:Ασύρματος 2:Asyrmatos_II</item> |
|||
<item>Βάσεις Δεδομένων:Βάσεις:Vaseis</item> |
|||
<item>Βιομηχανικά Ηλεκτρονικά:Βιομηχανικά Ηλεκτρονικά:Viomix_Ilektronika</item> |
|||
<item>Βιομηχανική Πληροφορική:Βιομηχανική Πληρ:Viomix_Plir</item> |
|||
<item>Βιοϊατρική Τεχνολογία:Βιοιατρική:Vioiatriki</item> |
|||
<item>Γεωηλεκτρομαγνητισμός:Γεωηλεκτρομαγνητισμός:Geoilektromagnitismos</item> |
|||
<item>Γραμμική Άλγεβρα:Γραμμ. Άλγεβρ.:Grammiki_Algevra</item> |
|||
<item>Γραφική με Υπολογιστές:Γραφική:Grafiki</item> |
|||
<item>Δίκτυα Τηλεπικοινωνιών:Δίκτυα Τηλέπ.:Diktya_Tilep</item> |
|||
<item>Δίκτυα Υπολογιστών I:Δίκτυα 1:Diktya_I</item> |
|||
<item>Δίκτυα Υπολογιστών II:Δίκτυα 2:Diktya_II</item> |
|||
<item>Διάδοση Η/Μ Κύματος II:Διάδοση 2:Diadosi_II</item> |
|||
<item>Διάδοση Ηλεκτρομαγνητικού Κύματος I (πρώην Πεδίο III):Διάδοση 1:Diadosi_I</item> |
|||
<item>Διακριτά Μαθηματικά:Διακριτά Μαθηματικά:Diakrita</item> |
|||
<item>Διακριτά μαθηματικά:Διακριτά Μαθηματικά:Diakrita</item> |
|||
<item>Διανεμημένη Παραγωγή:Διανεμημένη Παραγωγή:Dian_Paragogi</item> |
|||
<item>Διατάξεις Υψηλών Συχνοτήτων:ΔΥΣ:DYS</item> |
|||
<item>Διαφορικές Εξισώσεις:Διαφορικές:Diaforikes</item> |
|||
<item>Διαχείριση Συστημάτων Ηλεκτρικής Ενέργειας:ΔΣΗΕ:DSHE</item> |
|||
<item>Δομές Δεδομένων:Δομ. Δεδομ.:Domes_Dedomenon</item> |
|||
<item>Δομημένος Προγραμματισμός:Δομ. Προγραμμ.:C</item> |
|||
<item>Ειδικά Κεφάλαια Διαφορικών Εξισώσεων:Ειδικά Κεφάλαια Διαφορικών Εξισώσεων:Eidika_Kef_Diaf_Eksis</item> |
|||
<item>Ειδικά Κεφάλαια Ηλεκτρομαγνητικού Πεδίου I:Ειδικά Κεφάλαια Ηλεκτρομαγνητικού Πεδίου I:Eidika_Kef_HM_Pediou_I</item> |
|||
<item>Ειδικά Κεφάλαια Συστημάτων Ηλεκτρικής Ενέργειας:ΕΚΣΗΕ:EKSHE</item> |
|||
<item>Ειδικές Αρχιτεκτονικές Υπολογιστών:Ειδικές Αρχιτεκτονικές Υπολογιστών:Eidikes_Arx_Ypolog</item> |
|||
<item>Ειδικές Κεραίες, Σύνθεση Κεραιών:Ειδικές Κεραίες, Σύνθεση Κεραιών:Eidikes_Keraies</item> |
|||
<item>Εισαγωγή στην Ενεργειακή Τεχνολογία I:ΕΕΤ 1:EET_I</item> |
|||
<item>Εισαγωγή στην Ενεργειακή Τεχνολογία II:ΕΕΤ2:EET_II</item> |
|||
<item>Εισαγωγή στην Πολιτική Οικονομία:Πολιτική Οικονομία:Polit_Oik</item> |
|||
<item>Εισαγωγή στις εφαρμογές Πυρηνικής Τεχνολογίας:Εισ. Πυρηνικη Τεχν.:Intro_Pyriniki_Texn</item> |
|||
<item>Ενσωματωμένα Συστήματα Πραγματικού Χρόνου:Ενσωματωμένα:Enswmatwmena</item> |
|||
<item>Επιχειρησιακή Έρευνα:Επιχειρησιακή Έρευνα:Epixeirisiaki</item> |
|||
<item>Ευρυζωνικά Δίκτυα:Ευρυζωνικά:Evryzonika</item> |
|||
<item>Ευφυή Συστήματα Ρομπότ:Ευφυή:eufuh</item> |
|||
<item>Εφαρμογές Τηλεπικοινωνιακών Διατάξεων:Εφαρμογές Τηλεπ. Διατάξεων:Efarm_Tilep_Diatakseon</item> |
|||
<item>Εφαρμοσμένα Μαθηματικά I:Εφαρμοσμένα 1:Efarmosmena_Math_I</item> |
|||
<item>Εφαρμοσμένα Μαθηματικά II:Εφαρμοσμένα 2:Efarmosmena_Math_II</item> |
|||
<item>Εφαρμοσμένη Θερμοδυναμική:Θερμοδυναμική:Thermodynamiki</item> |
|||
<item>Ηλεκτρακουστική I:Ηλεκτρακουστική 1:Ilektrakoustiki_I</item> |
|||
<item>Ηλεκτρακουστική II:Ηλεκτρακουστική 2:Ilektrakoustiki_II</item> |
|||
<item>Ηλεκτρικά Κυκλώματα I:Κυκλώματα 1:Kyklomata_I</item> |
|||
<item>Ηλεκτρικά Κυκλώματα II:Κυκλώματα 2:Kyklomata_II</item> |
|||
<item>Ηλεκτρικά Κυκλώματα III:Κυκλώματα 3:Kyklomata_I</item> |
|||
<item>Ηλεκτρικές Μετρήσεις I:Μετρήσεις 1:Metriseis_I</item> |
|||
<item>Ηλεκτρικές Μετρήσεις II:Μετρήσεις 2:Metriseis_II</item> |
|||
<item>Ηλεκτρικές Μηχανές I:Μηχανές I:Mixanes_I</item> |
|||
<item>Ηλεκτρικές Μηχανές Α\':Μηχανές Α:Mixanes_A</item> |
|||
<item>Ηλεκτρικές Μηχανές Β\':Μηχανές Β:Mixanes_B</item> |
|||
<item>Ηλεκτρικές Μηχανές Γ\':Μηχανές Γ:Mixanes_C</item> |
|||
<item>Ηλεκτρική Οικονομία:Ηλεκτρική Οικονομία:Ilektr_Oikonomia</item> |
|||
<item>Ηλεκτρολογικά Υλικά:Ηλεκτρ. Υλικά:Ylika</item> |
|||
<item>Ηλεκτρομαγνητική Συμβατότητα:H/M Συμβατότητα:HM_Symvatotita</item> |
|||
<item>Ηλεκτρομαγνητικό Πεδίο I:Πεδίο 1:Pedio_I</item> |
|||
<item>Ηλεκτρομαγνητικό Πεδίο II:Πεδίο 2:Pedio_II</item> |
|||
<item>Ηλεκτρονικά Ισχύος I:Ισχύος 1:Isxyos_I</item> |
|||
<item>Ηλεκτρονικά Ισχύος II:Ισχύος 2:Isxyos_II</item> |
|||
<item>Ηλεκτρονικές Διατάξεις και Μετρήσεις:Ηλεκτρονικές Διατάξεις και Μετρήσεις:Ilektron_Diatakseis_Metriseis</item> |
|||
<item>Ηλεκτρονική I:Ηλεκτρονική 1:Ilektroniki_I</item> |
|||
<item>Ηλεκτρονική II:Ηλεκτρονική 2:Ilektroniki_II</item> |
|||
<item>Ηλεκτρονική III:Ηλεκτρονική 3:Ilektroniki_III</item> |
|||
<item>Ημιαγωγά Υλικά: Θεωρία-Διατάξεις:Ημιαγωγά Υλικά:Imiagoga_Ylika</item> |
|||
<item>Θεωρία Πιθανοτήτων και Στατιστική:Πιθανότητες:Pithanotites</item> |
|||
<item>Θεωρία Πληροφοριών:Θεωρία Πληρ.:Theoria_Plir</item> |
|||
<item>Θεωρία Σημάτων και Γραμμικών Συστημάτων:Σήματα & Συστήματα:Analog_Sima</item> |
|||
<item>Θεωρία Σκέδασης:Σκέδαση:Skedasi</item> |
|||
<item>Θεωρία Υπολογισμών και Αλγορίθμων:ΘΥΑ:THYA</item> |
|||
<item>Θεωρία και Τεχνολογία Πυρηνικών Αντιδραστήρων:Τεχνολογία Αντιδραστήρων:Texn_Antidrasthron</item> |
|||
<item>Κβαντική Φυσική:Κβαντική:Kvantiki</item> |
|||
<item>Κινητές και Δορυφορικές Επικοινωνίες:Κινητές & Δορυφορικές Επικοινωνίες:Kinites_Doryforikes_Epik</item> |
|||
<item>Λειτουργικά Συστήματα:Λειτουργικά:OS</item> |
|||
<item>Λογική Σχεδίαση:Λογική Σχεδίαση:Logiki_Sxediasi</item> |
|||
<item>Λογισμός I:Λογισμός 1:Logismos_I</item> |
|||
<item>Λογισμός II:Λογισμός 2:Logismos_II</item> |
|||
<item>Μετάδοση Θερμότητας:Μετάδοση Θερμ.:Metadosi_Therm</item> |
|||
<item>Μικροεπεξεργαστές και Περιφερειακά:Μίκρο 2:Mikro_II</item> |
|||
<item>Μικροκυματική Τηλεπισκόπηση:Τηλεπισκόπηση:Tilepiskopisi</item> |
|||
<item>Μικροκύματα I:Μικροκύματα 1:Mikrokymata_I</item> |
|||
<item>Μικροκύματα II:Μικροκύματα 2:Mikrokymata_II</item> |
|||
<item>Οπτικές Επικοινωνίες:Οπτικές Τηλεπ.:Optikes_Tilep</item> |
|||
<item>Οπτική I:Οπτική 1:Optiki_I</item> |
|||
<item>Οπτική II:Οπτική 2:Optiki_II</item> |
|||
<item>Οργάνωση Υπολογιστών:Οργάνωση Υπολ.:Org_Ypol</item> |
|||
<item>Οργάνωση και Διοίκηση Εργοστασίων:Οργάνωση και Διοίκηση Εργοστασίων:Organ_Dioik_Ergostasion</item> |
|||
<item>Παράλληλα και Κατανεμημένα Συστήματα:Παράλληλα:Parallila</item> |
|||
<item>Προγραμματιζόμενα Κυκλώματα ASIC:ASIC:ASIC</item> |
|||
<item>Προγραμματιστικές Τεχνικές:Προγραμματ. Τεχν.:CPP</item> |
|||
<item>Προηγμένες Τεχνικές Επεξεργασίας Σήματος:ΠΤΕΣ:PTES</item> |
|||
<item>Προσομοίωση και Μοντελοποίηση Συστημάτων:Μοντελοποίηση:Montelopoiisi</item> |
|||
<item>Ρομποτική:Ρομποτική:Robotiki</item> |
|||
<item>Σήματα και Συστήματα:Σήματα & Συστήματα:Analog_Sima</item> |
|||
<item>Σερβοκινητήρια Συστήματα:Σέρβο:Servo</item> |
|||
<item>Σταθμοί Παραγωγής Ηλεκτρικής Ενέργειας:ΣΠΗΕ:SPHE</item> |
|||
<item>Στοχαστικά Σήματα και Διαδικασίες:Στοχαστικό:Stochastic</item> |
|||
<item>Στοχαστικό Σήμα:Στοχαστικό:Stochastic</item> |
|||
<item>Συστήματα Αυτομάτου Ελέγχου I:ΣΑΕ 1:SAE_I</item> |
|||
<item>Συστήματα Αυτομάτου Ελέγχου II:ΣΑΕ 2:SAE_II</item> |
|||
<item>Συστήματα Αυτομάτου Ελέγχου III:ΣΑΕ 3:SAE_III</item> |
|||
<item>Συστήματα Ηλεκτρικής Ενέργειας I:ΣΗΕ 1:SHE_I</item> |
|||
<item>Συστήματα Ηλεκτρικής Ενέργειας II:ΣΗΕ 2:SHE_II</item> |
|||
<item>Συστήματα Ηλεκτρικής Ενέργειας III:ΣΗΕ 3:SHE_III</item> |
|||
<item>Συστήματα Ηλεκτροκίνησης:Ηλεκτροκίνηση:Ilektrokinisi</item> |
|||
<item>Συστήματα Μικροϋπολογιστών:Μίκρο 1:Mikro_I</item> |
|||
<item>Συστήματα Πολυμέσων και Εικονική Πραγματικότητα:Πολυμέσα:Polymesa</item> |
|||
<item>Συστήματα Υπολογιστών (Υπολογιστικά Συστήματα):Συσ. Υπολογιστών:Sys_Ypologiston</item> |
|||
<item>Σχεδίαση Συστημάτων VLSI:VLSI:VLSI</item> |
|||
<item>Σύνθεση Ενεργών και Παθητικών Κυκλωμάτων:Σύνθεση:Synthesi</item> |
|||
<item>Σύνθεση Τηλεπικοινωνιακών Διατάξεων:Σύνθεση Τηλεπ. Διατάξεων:Synth_Tilep_Diatakseon</item> |
|||
<item>Τεχνικές Βελτιστοποίησης:Βελτιστοποίηση:Veltistopoiisi</item> |
|||
<item>Τεχνικές Κωδικοποίησης:Τεχνικές Κωδικοποίησης:Texn_Kodikopoiisis</item> |
|||
<item>Τεχνικές Σχεδίασης με Η/Υ:Σχέδιο:sxedio</item> |
|||
<item>Τεχνικές μη Καταστρεπτικών Δοκιμών:Μη Καταστρεπτικές Δοκιμές:Non_Destructive_Tests</item> |
|||
<item>Τεχνική Μηχανική:Τεχν. Μηχαν.:Texn_Mixan</item> |
|||
<item>Τεχνολογία Ήχου και Εικόνας:Τεχνολογία Ήχου και Εικόνας:Texn_Ixou_Eikonas</item> |
|||
<item>Τεχνολογία Ηλεκτροτεχνικών Υλικών:Ηλεκτροτεχνικά Υλικά:Ilektrotexnika_Ylika</item> |
|||
<item>Τεχνολογία Λογισμικού:Τεχνολογία Λογισμικού:SE</item> |
|||
<item>Τηλεοπτικά Συστήματα:Τηλεοπτικά:Tileoptika</item> |
|||
<item>Τηλεπικοινωνιακά Συστήματα I:Τηλεπικοινωνιακά I:Tilepikoinoniaka_I</item> |
|||
<item>Τηλεπικοινωνιακά Συστήματα II:Τηλεπικοινωνιακά II:Tilepikoinoniaka_II</item> |
|||
<item>Τηλεπικοινωνιακή Ηλεκτρονική:Τηλεπ. Ηλεκτρ.:Tilep_Ilektr</item> |
|||
<item>Υπολογιστικές Μέθοδοι στα Ενεργειακά Συστήματα:ΥΜΕΣ:YMES</item> |
|||
<item>Υπολογιστικός Ηλεκτρομαγνητισμός:Υπολογιστικός Η/Μ:Ypologistikos_HM</item> |
|||
<item>Υψηλές Τάσεις I:Υψηλές 1:Ypsiles_I</item> |
|||
<item>Υψηλές Τάσεις II:Υψηλές 2:Ypsiles_II</item> |
|||
<item>Υψηλές Τάσεις III:Υψηλές 3:Ypsiles_III</item> |
|||
<item>Υψηλές Τάσεις 4:Υψηλές 4:Ypsiles_IV</item> |
|||
<item>Φυσική I:Φυσική 1:Fysiki_I</item> |
|||
<item>Φωτονική Τεχνολογία:Φωτονική:Fotoniki</item> |
|||
<item>Ψηφιακά Συστήματα I:Ψηφιακά 1:Psifiaka_I</item> |
|||
<item>Ψηφιακά Συστήματα II:Ψηφιακά 2:Psifiaka_II</item> |
|||
<item>Ψηφιακά Συστήματα III:Ψηφιακά 3:Psifiaka_III</item> |
|||
<item>Ψηφιακά Φίλτρα:Φίλτρα:Filtra</item> |
|||
<item>Ψηφιακές Τηλεπικοινωνίες I:Ψηφιακές Τηλεπ. 1:Psif_Tilep_I</item> |
|||
<item>Ψηφιακές Τηλεπικοινωνίες II:Ψηφιακές Τηλεπ. 2:Psif_Tilep_II</item> |
|||
<item>Ψηφιακή Επεξεργασία Εικόνας:ΨΕΕ:PSEE</item> |
|||
<item>Ψηφιακή Επεξεργασία Σήματος:ΨΕΣ:PSES</item> |
|||
</string-array> |
|||
</resources> |
@ -1,6 +1,6 @@ |
|||
#Sat Feb 09 12:35:50 EET 2019 |
|||
#Tue Sep 17 12:32:34 EEST 2019 |
|||
distributionBase=GRADLE_USER_HOME |
|||
distributionPath=wrapper/dists |
|||
zipStoreBase=GRADLE_USER_HOME |
|||
zipStorePath=wrapper/dists |
|||
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip |
|||
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip |
|||
|
Loading…
Reference in new issue