diff --git a/README.md b/README.md
index 598072af..7d0fd105 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# mTHMMY
[![GitHub release](https://img.shields.io/github/release/ThmmyNoLife/mTHMMY.svg?color=orange)](https://github.com/ThmmyNoLife/mTHMMY/releases)
-[![API](https://img.shields.io/badge/API-19%2B-blue.svg?style=flat)](https://android-arsenal.com/api?level=19)
+[![API](https://img.shields.io/badge/API-21%2B-blue.svg?style=flat)](https://android-arsenal.com/api?level=21)
[![Discord Channel](https://img.shields.io/discord/252539000571559947?style=flat&color=738bd7&label=discord)][discord-server]
![Last Commit](https://img.shields.io/github/last-commit/ThmmyNoLife/mTHMMY/develop.svg?style=flat)
@@ -11,7 +11,7 @@ A mobile app for [thmmy.gr](https://www.thmmy.gr).
## Requirements
-mTHMMY can be installed on any smartphone with Android 4.4 KitKat or newer.
+mTHMMY can be installed on any smartphone with Android 5.0 Lollipop or newer.
## Download
diff --git a/app/build.gradle b/app/build.gradle
index 7405e986..29faec1f 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -7,16 +7,15 @@ apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'
android {
- compileSdkVersion 29
- buildToolsVersion = '29.0.3'
+ compileSdkVersion 30
+ buildToolsVersion = '30.0.2'
defaultConfig {
- vectorDrawables.useSupportLibrary = true //TODO: Remove when minSdkVersion >= 21
applicationId "gr.thmmy.mthmmy"
- minSdkVersion 19
- targetSdkVersion 29
- versionCode 29
- versionName "1.9.0"
+ minSdkVersion 21
+ targetSdkVersion 30
+ versionCode 30
+ versionName "2.0.0"
archivesBaseName = "mTHMMY-v$versionName"
buildConfigField "String", "CURRENT_BRANCH", "\"" + getCurrentBranch() + "\""
buildConfigField "String", "COMMIT_HASH", "\"" + getCommitHash() + "\""
@@ -25,14 +24,11 @@ android {
buildTypes {
release {
- multiDexEnabled true //TODO: Remove when minSdkVersion >= 21
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- multiDexKeepProguard file('proguard-rules.pro') //TODO: Remove when minSdkVersion >= 21
}
debug {
- multiDexEnabled true //TODO: Remove when minSdkVersion >= 21
def date = new Date().format('ddMMyy_HHmmss')
archivesBaseName = archivesBaseName + "-$date"
firebaseCrashlytics {
@@ -41,6 +37,10 @@ android {
}
}
+ sourceSets {
+ test.resources.srcDirs += 'src/main/res/raw'
+ }
+
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
@@ -76,27 +76,26 @@ tasks.whenTaskAdded { task ->
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(":emojis")
- implementation 'androidx.appcompat:appcompat:1.3.0-alpha02'
+ implementation 'androidx.appcompat:appcompat:1.4.0-alpha03'
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.legacy:legacy-preference-v14:1.0.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
- implementation 'androidx.recyclerview:recyclerview:1.1.0'
+ implementation 'androidx.recyclerview:recyclerview:1.2.1'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
- implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
- implementation 'androidx.exifinterface:exifinterface:1.2.0'
- implementation 'androidx.multidex:multidex:2.0.1' //TODO: Remove when minSdkVersion >= 21
- implementation 'com.google.android.material:material:1.1.0'
- implementation 'com.google.firebase:firebase-analytics:17.4.4'
- implementation 'com.google.firebase:firebase-crashlytics:17.3.0'
- implementation 'com.google.firebase:firebase-messaging:21.0.0'
+ implementation 'androidx.constraintlayout:constraintlayout:2.1.0'
+ implementation 'androidx.exifinterface:exifinterface:1.3.3'
+ implementation 'com.google.android.material:material:1.4.0'
+ implementation platform('com.google.firebase:firebase-bom:28.4.0')
+ implementation 'com.google.firebase:firebase-analytics'
+ implementation 'com.google.firebase:firebase-config'
+ implementation 'com.google.firebase:firebase-crashlytics'
+ implementation 'com.google.firebase:firebase-messaging'
+ implementation 'com.google.code.gson:gson:2.8.8'
implementation 'com.snatik:storage:2.1.0'
- implementation('com.squareup.okhttp3:okhttp:3.12.12') {
- //TODO: Warning: OkHttp has dropped support for Android 19 since OkHttp 3.13!
- force = true //TODO: Remove when minSdkVersion >= 21
- }
- implementation 'org.jsoup:jsoup:1.13.1'
- implementation 'joda-time:joda-time:2.10.4'
+ implementation 'com.squareup.okhttp3:okhttp:3.14.9'
+ implementation 'org.jsoup:jsoup:1.14.2'
+ implementation 'joda-time:joda-time:2.10.10'
implementation 'com.github.franmontiel:PersistentCookieJar:1.0.1'
implementation 'com.github.PhilJay:MPAndroidChart:3.0.3'
implementation 'com.mikepenz:materialdrawer:6.1.1'
@@ -108,15 +107,15 @@ dependencies {
implementation 'com.jakewharton.timber:timber:4.7.1'
implementation 'ru.noties:markwon:2.0.2'
implementation 'net.gotev:uploadservice:3.5.2'
- implementation 'net.gotev:uploadservice-okhttp:3.4.2'
- //TODO: Warning: v.3.5 depends on okhttp 3.13!
- implementation 'com.itkacher.okhttpprofiler:okhttpprofiler:1.0.7'
+ implementation 'net.gotev:uploadservice-okhttp:3.5.2'
+ implementation 'com.localebro:okhttpprofiler:1.0.8'
//Plugin: https://plugins.jetbrains.com/plugin/11249-okhttp-profiler
- implementation 'com.github.bumptech.glide:glide:4.11.0'
+ implementation 'com.github.bumptech.glide:glide:4.12.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
testImplementation 'junit:junit:4.12'
testImplementation 'org.powermock:powermock-core:2.0.2'
testImplementation 'org.powermock:powermock-module-junit4:2.0.2'
testImplementation 'org.powermock:powermock-api-mockito2:2.0.2'
testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1'
+ testImplementation 'org.json:json:20210307'
}
diff --git a/app/src/main/assets/apache_libraries.html b/app/src/main/assets/apache_libraries.html
index 2d6e23cb..b3b983b4 100644
--- a/app/src/main/assets/apache_libraries.html
+++ b/app/src/main/assets/apache_libraries.html
@@ -6,7 +6,7 @@
-
-
OkHttp v3.12.12 (Copyright ©2019
+ OkHttp v3.14.9 (Copyright ©2019
Square, Inc.)
-
@@ -40,7 +40,7 @@
-
Android Upload Service v3.5.2
- (Copyright ©2013-2019 Aleksandar Gotev)
+ (Copyright ©2013-2021 Aleksandar Gotev)
-
Markwon v2.0.2 (Copyright ©2017
@@ -51,8 +51,8 @@
Andrew Oberstar)
-
-
Joda-Time v2.10.4 (Copyright
- ©2002-2019 Joda.org)
+ Joda-Time v2.10.10 (Copyright
+ ©2002-2021 Joda.org)
-
@@ -61,7 +61,7 @@
-
-
+
diff --git a/app/src/main/assets/mit_libraries.html b/app/src/main/assets/mit_libraries.html
index 59344819..c775905d 100644
--- a/app/src/main/assets/mit_libraries.html
+++ b/app/src/main/assets/mit_libraries.html
@@ -6,7 +6,7 @@
-
-
jsoup v1.13.1 (Copyright ©2009-2020, Jonathan
+ jsoup v1.14.2 (Copyright ©2009-2021, Jonathan
Hedley <jonathan@hedley.net>)
-
diff --git a/app/src/main/assets/other_libraries.html b/app/src/main/assets/other_libraries.html
index 53cfb0bf..75a57c89 100644
--- a/app/src/main/assets/other_libraries.html
+++ b/app/src/main/assets/other_libraries.html
@@ -6,7 +6,7 @@
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java
index 70316810..4fb4805b 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java
@@ -133,7 +133,7 @@ public class AboutActivity extends BaseActivity {
@Override
public void onBackPressed() {
- if (easterEggImage.getVisibility() == View.INVISIBLE)
+ if (easterEggImage.getVisibility() == View.GONE)
super.onBackPressed();
else
hideEasterEgg();
@@ -184,9 +184,9 @@ public class AboutActivity extends BaseActivity {
@SuppressLint("SourceLockedOrientationActivity")
private void showEasterEgg() {
if (getResources().getConfiguration().orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
- setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); //TODO: why?
- appBar.setVisibility(View.INVISIBLE);
- mainContent.setVisibility(View.INVISIBLE);
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ appBar.setVisibility(View.GONE);
+ mainContent.setVisibility(View.GONE);
easterEggImage.setVisibility(View.VISIBLE);
drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
@@ -195,7 +195,7 @@ public class AboutActivity extends BaseActivity {
private void hideEasterEgg() {
appBar.setVisibility(View.VISIBLE);
mainContent.setVisibility(View.VISIBLE);
- easterEggImage.setVisibility(View.INVISIBLE);
+ easterEggImage.setVisibility(View.GONE);
drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_UNDEFINED);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java
index 12b70d89..50ecb812 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java
@@ -2,7 +2,6 @@ package gr.thmmy.mthmmy.activities.bookmarks;
import android.app.Activity;
import android.graphics.drawable.Drawable;
-import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -13,7 +12,6 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
-import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
import java.util.ArrayList;
@@ -85,15 +83,10 @@ public class BookmarksFragment extends Fragment {
}
}
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
- notificationsEnabledButtonImage = getResources().getDrawable(R.drawable.ic_notification_on, null);
- else
- notificationsEnabledButtonImage = VectorDrawableCompat.create(getResources(), R.drawable.ic_notification_on, null);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
- notificationsDisabledButtonImage = getResources().getDrawable(R.drawable.ic_notification_off, null);
- else
- notificationsDisabledButtonImage = VectorDrawableCompat.create(getResources(), R.drawable.ic_notification_off, null);
+ notificationsEnabledButtonImage = getResources().getDrawable(R.drawable.ic_notification_on, null);
+ notificationsDisabledButtonImage = getResources().getDrawable(R.drawable.ic_notification_off, null);
+
}
@Override
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java
index 1b2ed6cc..34ddfc59 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java
@@ -3,13 +3,11 @@ package gr.thmmy.mthmmy.activities.main;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Toast;
-import androidx.appcompat.app.AppCompatDelegate;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
@@ -59,13 +57,6 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
private TabLayout tabLayout;
private boolean displayCompactTabs;
- //Fix for vector drawables on android <21
- static {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
- AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
- }
- }
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -263,6 +254,7 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
private void redirectToActivityFromIntent(Intent intent) {
if (intent != null) {
Uri uri = intent.getData();
+ Bundle extras = intent.getExtras();
if (uri != null) {
ThmmyPage.PageCategory page = ThmmyPage.resolvePageCategory(uri);
if (!page.is(ThmmyPage.PageCategory.NOT_THMMY)) {
@@ -299,6 +291,16 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "This is not thmmy.", Toast.LENGTH_LONG).show();
}
}
+ else if(extras!=null){
+ String topicTitle = extras.getString(BUNDLE_TOPIC_TITLE);
+ String topicPageUrl = extras.getString(BUNDLE_TOPIC_URL);
+ if(topicTitle!=null && topicPageUrl!=null){
+ Intent redirectIntent = new Intent(MainActivity.this, TopicActivity.class);
+ redirectIntent.putExtra(BUNDLE_TOPIC_URL, topicPageUrl);
+ redirectIntent.putExtra(BUNDLE_TOPIC_TITLE, topicTitle);
+ startActivity(redirectIntent);
+ }
+ }
}
}
}
\ No newline at end of file
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java
index 75b7073f..7af974d8 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java
@@ -5,7 +5,6 @@ import android.graphics.Color;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.Bundle;
import android.text.Spannable;
import android.text.SpannableString;
@@ -19,7 +18,6 @@ import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
-import androidx.appcompat.app.AppCompatDelegate;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
@@ -98,13 +96,6 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
private String username;
private int tabSelect;
- //Fix for vector drawables on android <21
- static {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
- AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
- }
- }
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java
index 49e60a63..698e2492 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java
@@ -260,12 +260,7 @@ public class StatsFragment extends Fragment {
LineDataSet postingActivityByTimeDataSet = new LineDataSet(postingActivityByTime, null);
if (isAdded()) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- postingActivityByTimeDataSet.setFillDrawable(getResources().getDrawable(R.drawable.line_chart_gradient, null));
- }
- else
- //noinspection deprecation
- postingActivityByTimeDataSet.setFillDrawable(getResources().getDrawable(R.drawable.line_chart_gradient));
+ postingActivityByTimeDataSet.setFillDrawable(getResources().getDrawable(R.drawable.line_chart_gradient, null));
}
postingActivityByTimeDataSet.setDrawFilled(true);
postingActivityByTimeDataSet.setDrawCircles(false);
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java
index 16979c00..b2bdff0a 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java
@@ -1,11 +1,9 @@
package gr.thmmy.mthmmy.activities.shoutbox;
-import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@@ -99,8 +97,6 @@ public class ShoutAdapter extends CustomRecyclerView.Adapter {
holder.stars.setVisibility(View.GONE);
if (currentPost.isUserMentionedInPost()) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- holder.cardChildLinear.setBackground(context.getResources().
- getDrawable(R.drawable.mention_card, null));
- }
- else
- holder.cardChildLinear.setBackground(context.getResources().
- getDrawable(R.drawable.mention_card));
+ holder.cardChildLinear.setBackground(context.getResources().
+ getDrawable(R.drawable.mention_card, null));
}
else if (mUserColor == TopicParser.USER_COLOR_PINK) {
//Special card for special member of the month!
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- holder.cardChildLinear.setBackground(context.getResources().
- getDrawable(R.drawable.member_of_the_month_card, null));
- }
- else
- holder.cardChildLinear.setBackground(context.getResources().
- getDrawable(R.drawable.member_of_the_month_card));
+ holder.cardChildLinear.setBackground(context.getResources().
+ getDrawable(R.drawable.member_of_the_month_card, null));
}
else holder.cardChildLinear.setBackground(null);
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java
index fd98fba0..e0b5b986 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java
@@ -6,12 +6,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
-import android.content.res.Resources;
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.text.Editable;
import android.text.Spannable;
@@ -39,10 +37,13 @@ import androidx.core.content.FileProvider;
import androidx.preference.PreferenceManager;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
+import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
import net.gotev.uploadservice.UploadNotificationAction;
import net.gotev.uploadservice.UploadNotificationConfig;
+import org.json.JSONException;
+import org.json.JSONObject;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
@@ -87,6 +88,8 @@ public class UploadActivity extends BaseActivity {
* The key to use when putting upload's category String to {@link UploadActivity}'s Bundle.
*/
public static final String BUNDLE_UPLOAD_CATEGORY = "UPLOAD_CATEGORY";
+ public static final String firebaseConfigUploadsCoursesKey = "uploads_courses";
+
private static final String uploadIndexUrl = "https://www.thmmy.gr/smf/index.php?action=tpmod;dl=upload";
private static final String uploadedFromTHMMYPromptHtml = "
uploaded from mTHMMY";
/**
@@ -104,7 +107,7 @@ public class UploadActivity extends BaseActivity {
private static final int MAX_FILE_SIZE_SUPPORTED = 45000000;
- private HashMap
uploadsCourses;
+ private HashMap uploadsCourses;
private ArrayList uploadRootCategories = new ArrayList<>();
private ParseUploadPageTask parseUploadPageTask;
@@ -417,10 +420,16 @@ public class UploadActivity extends BaseActivity {
updateUIElements();
generateFieldsButton.setEnabled(true);
}
-
- Resources res = getResources();
- uploadsCourses = new HashMap<>(UploadsCourse
- .generateUploadsCourses(res.getStringArray(R.array.string_array_uploads_courses)));
+ FirebaseRemoteConfig firebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
+ String uploadsCoursesString = firebaseRemoteConfig.getValue(firebaseConfigUploadsCoursesKey).asString();
+ JSONObject uploadsCoursesJSON;
+ try {
+ uploadsCoursesJSON = new JSONObject(uploadsCoursesString);
+ uploadsCourses = UploadsCourse.generateCoursesFromJSON(uploadsCoursesJSON);
+ } catch (JSONException e) {
+ uploadsCourses = new HashMap<>();
+ Timber.e(e, "JSONException in uploads courses.");
+ }
}
@Override
@@ -603,6 +612,8 @@ public class UploadActivity extends BaseActivity {
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Please retry uploading.", Toast.LENGTH_SHORT).show();
}
break;
+ default:
+ super.onRequestPermissionsResult(permsRequestCode, permissions, grantResults);
}
}
@@ -697,50 +708,30 @@ public class UploadActivity extends BaseActivity {
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));
- }
- else {
- 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.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_retry),
- PendingIntent.getBroadcast(context, 0, retryIntent,
- PendingIntent.FLAG_UPDATE_CURRENT)
- ));
- }
+ 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.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_retry),
+ PendingIntent.getBroadcast(context, 0, retryIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT)
+ ));
return uploadNotificationConfig;
}
@@ -958,13 +949,19 @@ public class UploadActivity extends BaseActivity {
.trim();
if (!retrievedCourse.isEmpty()) {
- UploadsCourse foundUploadsCourse = UploadsCourse.findCourse(retrievedCourse, uploadsCourses);
-
- if (foundUploadsCourse != null) {
- uploadsCourse = foundUploadsCourse;
- semester = maybeSemester.replaceAll("-", "").trim().substring(0, 1);
- Timber.d("Selected course: %s, semester: %s", uploadsCourse.getName(), semester);
- generateFieldsButton.setEnabled(true);
+ try {
+ int categoryValue = Integer.parseInt(categorySelected);
+ if(uploadsCourses.containsKey(categoryValue)){
+ UploadsCourse foundUploadsCourse = uploadsCourses.get(categoryValue);
+ if (foundUploadsCourse != null) {
+ uploadsCourse = foundUploadsCourse;
+ semester = maybeSemester.replaceAll("-", "").trim().substring(0, 1);
+ Timber.d("Selected course: %s, semester: %s", uploadsCourse.getName(), semester);
+ generateFieldsButton.setEnabled(true);
+ }
+ }
+ } catch (final NumberFormatException e) {
+ Timber.e(e, "Invalid category value!");
}
}
}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsCourse.java b/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsCourse.java
index 5a0fd8fe..7c2877a9 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsCourse.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsCourse.java
@@ -1,79 +1,64 @@
package gr.thmmy.mthmmy.activities.upload;
-import android.os.Bundle;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
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;
+public class UploadsCourse {
+ private final int id;
+ private final String name, minifiedName, greeklishName;
- private UploadsCourse(String fullName, String minifiedName, String greeklishName) {
- this.name = fullName;
+ private UploadsCourse(int id, String name, String minifiedName, String greeklishName) {
+ this.id = id;
+ this.name = name;
this.minifiedName = minifiedName;
this.greeklishName = greeklishName;
}
- String getName() {
+ public int getId() {
+ return id;
+ }
+
+ public String getName() {
return name;
}
- String getMinifiedName() {
+ public String getMinifiedName() {
return minifiedName;
}
- String getGreeklishName() {
+ public String getGreeklishName() {
return greeklishName;
}
- static Map generateUploadsCourses(String[] uploadsCoursesRes) {
- Map 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 uploadsCourses) {
- retrievedCourse = normalizeGreekNumbers(retrievedCourse);
- UploadsCourse uploadsCourse = uploadsCourses.get(retrievedCourse);
- if (uploadsCourse != null) return uploadsCourse;
-
- String foundKey = null;
- for (Map.Entry entry : uploadsCourses.entrySet()) {
- String key = entry.getKey();
- if ((key.contains(retrievedCourse) || retrievedCourse.contains(key))
- && (foundKey == null || key.length() > foundKey.length()))
- foundKey = key;
+ public static HashMap generateCoursesFromJSON(JSONObject json) throws JSONException {
+ HashMap coursesHashMap = new HashMap<>();
+ if(json.has("courses")){
+ JSONArray coursesArray = json.getJSONArray("courses");
+ for(int i=0, size = coursesArray.length(); i {
- /*LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(context.getApplicationContext());
- localBroadcastManager.sendBroadcast(multipartUploadRetryIntent);*/
- //uploadsProgressDialog.dismiss();
-
- //context.sendBroadcast(retryIntent);
- });
- uploadsProgressDialog.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.cancel), (progressDialog, progressWhich) -> {
- uploadsProgressDialog.dismiss();
- });
-
- TextView dialogProgressText = progressDialogLayout.findViewById(R.id.dialog_upload_progress_text);
- dialogProgressBar.setVisibility(View.GONE);
- dialogProgressText.setText(getString(R.string.upload_failed));
-
- uploadsProgressDialog.show();
- }
- else {
- //Empty buttons are needed, they are updated with correct values in the receiver
- uploadsProgressDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "placeholder", (progressDialog, progressWhich) -> {
- });
- uploadsProgressDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "placeholder", (progressDialog, progressWhich) -> {
- });
-
- UploadsReceiver.setDialogDisplay(uploadsProgressDialog, dialogUploadID, null);
- //UploadsReceiver.setDialogDisplay(uploadsProgressDialog, dialogUploadID, retryIntent);
- uploadsProgressDialog.show();
- }
- }
- else {
- UploadsReceiver.setDialogDisplay(uploadsProgressDialog, dialogUploadID, null);
- //UploadsReceiver.setDialogDisplay(uploadsProgressDialog, dialogUploadID, retryIntent);
- uploadsProgressDialog.show();
- }
- }
- }
- }
-
//----------------------------------MISC----------------------
protected void setMainActivity(MainActivity mainActivity) {
this.mainActivity = mainActivity;
diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java
index 41f3d803..e9293dd2 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java
@@ -1,16 +1,15 @@
package gr.thmmy.mthmmy.base;
+import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.drawable.Drawable;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.widget.ImageView;
import androidx.core.content.ContextCompat;
-import androidx.multidex.MultiDexApplication;
import androidx.preference.PreferenceManager;
import com.bumptech.glide.Glide;
@@ -20,27 +19,26 @@ import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersisto
import com.google.firebase.FirebaseApp;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.google.firebase.crashlytics.FirebaseCrashlytics;
-import com.itkacher.okhttpprofiler.OkHttpProfilerInterceptor;
-import com.mikepenz.fontawesome_typeface_library.FontAwesome;
-import com.mikepenz.iconics.IconicsDrawable;
+import com.google.firebase.remoteconfig.FirebaseRemoteConfig;
+import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings;
+import com.localebro.okhttpprofiler.OkHttpProfilerInterceptor;
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader;
import com.mikepenz.materialdrawer.util.DrawerImageLoader;
import net.gotev.uploadservice.UploadService;
import net.gotev.uploadservice.okhttp.OkHttpStack;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import gr.thmmy.mthmmy.BuildConfig;
import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.session.SessionManager;
import gr.thmmy.mthmmy.utils.crashreporting.CrashReportingTree;
-import okhttp3.CipherSuite;
-import okhttp3.ConnectionSpec;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.Request;
@@ -48,9 +46,10 @@ import timber.log.Timber;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DISPLAY_COMPACT_TABS;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DISPLAY_RELATIVE_TIME;
+import static gr.thmmy.mthmmy.activities.upload.UploadActivity.firebaseConfigUploadsCoursesKey;
+import static gr.thmmy.mthmmy.utils.io.ResourceUtils.readJSONResourceToString;
-// TODO: Replace MultiDexApplication with Application after KitKat support is dropped
-public class BaseApplication extends MultiDexApplication {
+public class BaseApplication extends Application implements Executor{
private static BaseApplication baseApplication; //BaseApplication singleton
private CrashReportingTree crashReportingTree;
@@ -58,6 +57,7 @@ public class BaseApplication extends MultiDexApplication {
//Firebase
private static String firebaseProjectId;
private FirebaseAnalytics firebaseAnalytics;
+ private FirebaseRemoteConfig firebaseRemoteConfig;
//Client & SessionManager
private OkHttpClient client;
@@ -128,6 +128,27 @@ public class BaseApplication extends MultiDexApplication {
Timber.i("Starting app with Firebase Analytics enabled.");
else
Timber.i("Starting app with Firebase Analytics disabled.");
+
+ // Firebase Remote Config (uploads courses)
+ InputStream inputStream = getApplicationContext().getResources().openRawResource(R.raw.uploads_courses);
+ String uploadsCourses = readJSONResourceToString(inputStream);
+ Map uploadsCoursesMap = new HashMap<>();
+ uploadsCoursesMap.put(firebaseConfigUploadsCoursesKey, uploadsCourses);
+
+ firebaseRemoteConfig = FirebaseRemoteConfig.getInstance();
+ FirebaseRemoteConfigSettings configSettings = new FirebaseRemoteConfigSettings.Builder()
+ .setMinimumFetchIntervalInSeconds(3600)
+ .build();
+ firebaseRemoteConfig.setConfigSettingsAsync(configSettings);
+ firebaseRemoteConfig.setDefaultsAsync(uploadsCoursesMap);
+ firebaseRemoteConfig.fetchAndActivate()
+ .addOnCompleteListener(this, task -> {
+ if (task.isSuccessful()) {
+ boolean updated = task.getResult();
+ Timber.i("Firebase remote config params updated: %s", updated);
+ } else
+ Timber.e("Fetching Firebase remote config params failed!");
+ });
}
private void initOkHttp(PersistentCookieJar cookieJar) {
@@ -148,20 +169,6 @@ public class BaseApplication extends MultiDexApplication {
.writeTimeout(40, TimeUnit.SECONDS)
.readTimeout(40, TimeUnit.SECONDS);
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // Just for KitKats
- // Necessary because our servers don't have the right cipher suites.
- // https://github.com/square/okhttp/issues/4053
- List cipherSuites = new ArrayList<>(ConnectionSpec.MODERN_TLS.cipherSuites());
- cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA);
- cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA);
-
- ConnectionSpec legacyTls = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
- .cipherSuites(cipherSuites.toArray(new CipherSuite[0]))
- .build();
-
- builder.connectionSpecs(Arrays.asList(legacyTls, ConnectionSpec.CLEARTEXT));
- }
-
if (BuildConfig.DEBUG)
builder.addInterceptor(new OkHttpProfilerInterceptor());
@@ -183,14 +190,7 @@ public class BaseApplication extends MultiDexApplication {
@Override
public Drawable placeholder(Context ctx, String tag) {
if (DrawerImageLoader.Tags.PROFILE.name().equals(tag)) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
- return ContextCompat.getDrawable(BaseApplication.getInstance(), R.drawable.ic_default_user_avatar);
- else { // Just for KitKats
- return new IconicsDrawable(ctx).icon(FontAwesome.Icon.faw_user)
- .paddingDp(10)
- .color(ContextCompat.getColor(ctx, R.color.iron))
- .backgroundColor(ContextCompat.getColor(ctx, R.color.primary_lighter));
- }
+ return ContextCompat.getDrawable(BaseApplication.getInstance(), R.drawable.ic_default_user_avatar);
}
return super.placeholder(ctx, tag);
}
@@ -277,4 +277,10 @@ public class BaseApplication extends MultiDexApplication {
public static String getFirebaseProjectId() {
return firebaseProjectId;
}
+
+ // Implement Executor (for Firebase remote config)
+ @Override
+ public void execute(Runnable runnable) {
+ runnable.run();
+ }
}
diff --git a/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java b/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java
index 0ea4527f..b271e39f 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java
@@ -28,7 +28,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import gr.thmmy.mthmmy.R;
-import gr.thmmy.mthmmy.activities.topic.TopicActivity;
+import gr.thmmy.mthmmy.activities.main.MainActivity;
import gr.thmmy.mthmmy.base.BaseApplication;
import gr.thmmy.mthmmy.model.Bookmark;
import gr.thmmy.mthmmy.model.PostNotification;
@@ -172,7 +172,7 @@ public class NotificationService extends FirebaseMessagingService {
//Builds notification
String topicUrl = "https://www.thmmy.gr/smf/index.php?topic=" + postNotification.getTopicId() + "." + postNotification.getPostId();
- Intent intent = new Intent(this, TopicActivity.class);
+ Intent intent = new Intent(this, MainActivity.class);
Bundle extras = new Bundle();
extras.putString(BUNDLE_TOPIC_URL, topicUrl);
extras.putString(BUNDLE_TOPIC_TITLE, postNotification.getTopicTitle());
diff --git a/app/src/main/java/gr/thmmy/mthmmy/services/UploadsReceiver.java b/app/src/main/java/gr/thmmy/mthmmy/services/UploadsReceiver.java
index 650727f1..9823d3d3 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/services/UploadsReceiver.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/services/UploadsReceiver.java
@@ -3,12 +3,7 @@ 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;
@@ -24,7 +19,6 @@ 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 {
@@ -88,87 +82,17 @@ public class UploadsReceiver extends UploadServiceBroadcastReceiver {
@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);
- }
+
+ 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) {
@@ -178,11 +102,6 @@ public class UploadsReceiver extends UploadServiceBroadcastReceiver {
@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());
@@ -205,10 +124,6 @@ public class UploadsReceiver extends UploadServiceBroadcastReceiver {
@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)
diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/io/ResourceUtils.java b/app/src/main/java/gr/thmmy/mthmmy/utils/io/ResourceUtils.java
new file mode 100644
index 00000000..479d288e
--- /dev/null
+++ b/app/src/main/java/gr/thmmy/mthmmy/utils/io/ResourceUtils.java
@@ -0,0 +1,46 @@
+package gr.thmmy.mthmmy.utils.io;
+
+import android.content.res.Resources;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+
+import timber.log.Timber;
+
+public class ResourceUtils {
+ public static String readJSONResourceToString(Resources resources, int id) {
+ InputStream inputStream = resources.openRawResource(id);
+ return readStream(inputStream);
+ }
+
+ public static String readJSONResourceToString(InputStream inputStream) {
+ return readStream(inputStream);
+ }
+
+ private static String readStream(InputStream inputStream) {
+ Writer writer = new StringWriter();
+ try {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
+ String line = reader.readLine();
+ while (line != null) {
+ writer.write(line);
+ line = reader.readLine();
+ }
+ } catch (Exception e) {
+ Timber.e(e, "Unhandled exception while using readJSONFromResource");
+ } finally {
+ try {
+ inputStream.close();
+ } catch (Exception e) {
+ Timber.e(e, "Unhandled exception while using readJSONFromResource");
+ }
+ }
+
+ return writer.toString();
+ }
+}
+
diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java
index 0d59104c..393f0b2b 100644
--- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java
+++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java
@@ -5,6 +5,8 @@ import androidx.annotation.VisibleForTesting;
import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils;
import org.joda.time.DateTimeZone;
+import org.joda.time.IllegalInstantException;
+import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder;
@@ -33,9 +35,8 @@ public class ThmmyDateTimeParser {
.append(null, parsers)
.toFormatter();
- //TODO: Replace with Locale.forLanguageTag() (with "el-GR","en-US") when KitKat support is dropped
- private static final Locale greekLocale = new Locale("el", "GR");
- private static final Locale englishLocale = new Locale("en", "US");
+ private static final Locale greekLocale = Locale.forLanguageTag("el-GR");
+ private static final Locale englishLocale = Locale.forLanguageTag("en-US");
private static final Pattern pattern = Pattern.compile("\\s((1[3-9]|2[0-3]):)");
@@ -64,8 +65,9 @@ public class ThmmyDateTimeParser {
thmmyDateTime = thmmyDateTime.replaceAll("\\spm", "");
DateTime dateTime;
+ LocalDateTime localDateTime;
try {
- dateTime = formatter.withZone(dtz).withLocale(englishLocale).parseDateTime(thmmyDateTime);
+ localDateTime = formatter.withLocale(englishLocale).parseLocalDateTime(thmmyDateTime);
} catch (IllegalArgumentException e1) {
Timber.v("Parsing DateTime %s using English Locale failed.", thmmyDateTime);
try {
@@ -73,13 +75,23 @@ public class ThmmyDateTimeParser {
thmmyDateTime = thmmyDateTime.replace("am", dfs.getAmPmStrings()[0]);
thmmyDateTime = thmmyDateTime.replace("pm", dfs.getAmPmStrings()[1]);
Timber.v("Attempting to parse DateTime %s using Greek Locale...", thmmyDateTime);
- dateTime = formatter.withZone(dtz).withLocale(greekLocale).parseDateTime(thmmyDateTime);
+ localDateTime = formatter.withLocale(greekLocale).parseLocalDateTime(thmmyDateTime);
} catch (IllegalArgumentException e2) {
- Timber.d("Parsing DateTime %s using Greek Locale failed too.", thmmyDateTime);
+ Timber.v("Parsing DateTime %s using Greek Locale failed too.", thmmyDateTime);
Timber.e("Couldn't convert DateTime %s to timestamp!", originalDateTime);
return null;
}
}
+
+ // Ensure DST time overlaps/ gaps are handled properly
+ try{
+ // For autumn overlaps
+ dateTime = localDateTime.toDateTime(dtz).withEarlierOffsetAtOverlap();
+ } catch (IllegalInstantException e2) {
+ // For spring gaps
+ dateTime = localDateTime.plusHours(1).toDateTime(dtz);
+ }
+
String timestamp = Long.toString(dateTime.getMillis());
Timber.v("DateTime %s was converted to %s, or %s", originalDateTime, timestamp, dateTime.toString());
diff --git a/app/src/main/res/layout-v21/activity_profile.xml b/app/src/main/res/layout-v21/activity_profile.xml
deleted file mode 100644
index f7998829..00000000
--- a/app/src/main/res/layout-v21/activity_profile.xml
+++ /dev/null
@@ -1,124 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout-v21/activity_topic_post_row.xml b/app/src/main/res/layout-v21/activity_topic_post_row.xml
deleted file mode 100644
index b795224e..00000000
--- a/app/src/main/res/layout-v21/activity_topic_post_row.xml
+++ /dev/null
@@ -1,262 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml
index cecc5cb0..f7998829 100644
--- a/app/src/main/res/layout/activity_profile.xml
+++ b/app/src/main/res/layout/activity_profile.xml
@@ -41,6 +41,7 @@
android:adjustViewBounds="true"
android:contentDescription="@string/post_thumbnail"
android:fitsSystemWindows="true"
+ android:transitionName="user_thumbnail"
app:layout_collapseMode="parallax" />
@@ -197,8 +198,7 @@
android:gravity="start"
android:text=""
android:textColor="@color/accent"
- android:textSize="11sp"
- tools:text="date" />
+ android:textSize="11sp" />
-
-
-
-
-
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index c054ef62..a3b3775f 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,5 +1,4 @@
-
-
+
-
+