From f2b9c86ccbef84b9f984a8779360697317d902bb Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 8 Jun 2020 18:47:47 +0300 Subject: [PATCH 01/21] Migration to Firebase Crashlytics SDK --- app/build.gradle | 12 ++-- .../activities/settings/SettingsFragment.java | 5 +- .../gr/thmmy/mthmmy/base/BaseActivity.java | 4 +- .../gr/thmmy/mthmmy/base/BaseApplication.java | 56 +++++++++++-------- .../utils/crashreporting/CrashReporter.java | 13 +++-- .../crashreporting/CrashReportingTree.java | 16 ++++-- build.gradle | 4 +- 7 files changed, 65 insertions(+), 45 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index afd40760..e2eb5c50 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -3,7 +3,8 @@ import groovy.json.JsonSlurper apply from: 'gradle/grgit.gradle' apply plugin: 'com.android.application' -apply plugin: 'io.fabric' +apply plugin: 'com.google.gms.google-services' +apply plugin: 'com.google.firebase.crashlytics' android { compileSdkVersion 29 @@ -33,8 +34,9 @@ android { multiDexEnabled true def date = new Date().format('ddMMyy_HHmmss') archivesBaseName = archivesBaseName + "-$date" - // Disable fabric build ID generation for debug builds - ext.enableCrashlytics = false + firebaseCrashlytics { + mappingFileUploadEnabled false // Disable mapping file uploading for debug builds + } } } @@ -87,8 +89,8 @@ dependencies { 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.3' + implementation 'com.google.firebase:firebase-crashlytics:17.0.1' implementation 'com.google.firebase:firebase-messaging:20.2.0' - implementation 'com.crashlytics.sdk.android:crashlytics:2.10.1' 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 @@ -116,5 +118,3 @@ dependencies { testImplementation 'org.powermock:powermock-api-mockito2:2.0.2' testImplementation 'net.lachlanmckee:timber-junit-rule:1.0.1' } - -apply plugin: 'com.google.gms.google-services' diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java index edd06356..ef2d1693 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java @@ -200,14 +200,15 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared if (key.equals(getString(R.string.pref_privacy_crashlytics_enable_key))) { enabled = sharedPreferences.getBoolean(key, false); if(enabled) - BaseApplication.getInstance().startFirebaseCrashlyticsCollection(); + BaseApplication.getInstance().setFirebaseCrashlyticsEnabled(true); else { Timber.i("Crashlytics collection will be disabled after restarting."); + BaseApplication.getInstance().setFirebaseCrashlyticsEnabled(false); displayRestartAppToTakeEffectToast(); } } else if (key.equals(getString(R.string.pref_privacy_analytics_enable_key))) { enabled = sharedPreferences.getBoolean(key, false); - BaseApplication.getInstance().setFirebaseAnalyticsCollection(enabled); + BaseApplication.getInstance().setFirebaseAnalyticsEnabled(enabled); if(enabled) Timber.i("Analytics collection enabled."); else diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index 37f88876..5adfd788 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -807,8 +807,8 @@ public abstract class BaseActivity extends AppCompatActivity { builder.setPositiveButton("Yes, I want to help", (dialogInterface, i) -> { addUserConsent(); FirebaseMessaging.getInstance().setAutoInitEnabled(true); - BaseApplication.getInstance().startFirebaseCrashlyticsCollection(); - BaseApplication.getInstance().setFirebaseAnalyticsCollection(true); + BaseApplication.getInstance().setFirebaseCrashlyticsEnabled(true); + BaseApplication.getInstance().setFirebaseAnalyticsEnabled(true); setUserDataShareEnabled(true); }); builder.setNegativeButton("Nope, leave me alone", (dialogInterface, i) -> { 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 755b539a..51d01bba 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -14,13 +14,12 @@ import androidx.multidex.MultiDexApplication; import androidx.preference.PreferenceManager; import com.bumptech.glide.Glide; -import com.crashlytics.android.Crashlytics; -import com.crashlytics.android.core.CrashlyticsCore; import com.franmontiel.persistentcookiejar.PersistentCookieJar; import com.franmontiel.persistentcookiejar.cache.SetCookieCache; import com.franmontiel.persistentcookiejar.persistence.SharedPrefsCookiePersistor; 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; @@ -40,7 +39,6 @@ import gr.thmmy.mthmmy.BuildConfig; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.crashreporting.CrashReportingTree; -import io.fabric.sdk.android.Fabric; import okhttp3.CipherSuite; import okhttp3.ConnectionSpec; import okhttp3.HttpUrl; @@ -53,6 +51,8 @@ import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DISPLAY_RELAT public class BaseApplication extends MultiDexApplication { private static BaseApplication baseApplication; //BaseApplication singleton + private CrashReportingTree crashReportingTree; + //Firebase private static String firebaseProjectId; private FirebaseAnalytics firebaseAnalytics; @@ -88,19 +88,23 @@ public class BaseApplication extends MultiDexApplication { SharedPreferences settingsSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences draftsPrefs = getSharedPreferences(getString(R.string.pref_topic_drafts_key), MODE_PRIVATE); - if (settingsSharedPrefs.getBoolean(getString(R.string.pref_privacy_crashlytics_enable_key), false)) - startFirebaseCrashlyticsCollection(); - else - Timber.i("Starting app with Crashlytics disabled."); + if (settingsSharedPrefs.getBoolean(getString(R.string.pref_privacy_crashlytics_enable_key), false)){ + Timber.i("Starting app with Firebase Crashlytics enabled."); + setFirebaseCrashlyticsEnabled(true); + } + else { + Timber.i("Starting app with Firebase Crashlytics disabled."); + setFirebaseCrashlyticsEnabled(false); + } firebaseProjectId = FirebaseApp.getInstance().getOptions().getProjectId(); firebaseAnalytics = FirebaseAnalytics.getInstance(this); boolean enableAnalytics = settingsSharedPrefs.getBoolean(getString(R.string.pref_privacy_analytics_enable_key), false); firebaseAnalytics.setAnalyticsCollectionEnabled(enableAnalytics); if (enableAnalytics) - Timber.i("Starting app with Analytics enabled."); + Timber.i("Starting app with Firebase Analytics enabled."); else - Timber.i("Starting app with Analytics disabled."); + Timber.i("Starting app with Firebase Analytics disabled."); SharedPrefsCookiePersistor sharedPrefsCookiePersistor = new SharedPrefsCookiePersistor(getApplicationContext()); PersistentCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), sharedPrefsCookiePersistor); @@ -215,24 +219,32 @@ public class BaseApplication extends MultiDexApplication { firebaseAnalytics.logEvent(event, params); } - public void setFirebaseAnalyticsCollection(boolean enabled) { + public void setFirebaseAnalyticsEnabled(boolean enabled) { firebaseAnalytics.setAnalyticsCollectionEnabled(enabled); if (!enabled) firebaseAnalytics.resetAnalyticsData(); + + if(enabled) + Timber.i("Firebase Analytics enabled."); + else + Timber.i("Firebase Analytics disabled."); } - // Set up Crashlytics, disabled for debug builds - public void startFirebaseCrashlyticsCollection() { - if (!Fabric.isInitialized()) { - Crashlytics crashlyticsKit = new Crashlytics.Builder() - .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build()) - .build(); - // Initialize Fabric with the debug-disabled Crashlytics. - Fabric.with(this, crashlyticsKit); - Timber.plant(new CrashReportingTree()); - Timber.i("Crashlytics enabled."); - } else - Timber.i("Crashlytics were already initialized for this app session."); + public void setFirebaseCrashlyticsEnabled(boolean enable) { + FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(enable); + if(enable){ + crashReportingTree = new CrashReportingTree(); + Timber.plant(crashReportingTree); + Timber.i("CrashReporting tree planted."); + Timber.i("Firebase Crashlytics enabled."); + } + else{ + if(crashReportingTree!=null) { + Timber.uproot(crashReportingTree); + Timber.i("CrashReporting tree uprooted."); + } + Timber.i("Firebase Crashlytics disabled."); + } } public static String getFirebaseProjectId(){ diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReporter.java b/app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReporter.java index 65011440..4842013c 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReporter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReporter.java @@ -1,6 +1,7 @@ package gr.thmmy.mthmmy.utils.crashreporting; -import com.crashlytics.android.Crashlytics; + +import com.google.firebase.crashlytics.FirebaseCrashlytics; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; @@ -43,12 +44,14 @@ public class CrashReporter { else languageValue = "Unknown"; - Crashlytics.setString(themeKey, themeValue); - Crashlytics.setString(languageKey, languageValue); - Crashlytics.setBool("isLoggedIn", BaseApplication.getInstance().getSessionManager().isLoggedIn()); + FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance(); + crashlytics.setCustomKey(themeKey, themeValue); + crashlytics.setCustomKey(languageKey, languageValue); + crashlytics.setCustomKey("isLoggedIn", BaseApplication.getInstance().getSessionManager().isLoggedIn()); } public static void reportDocument(Document document, String key) { + FirebaseCrashlytics crashlytics = FirebaseCrashlytics.getInstance(); String documentString = document.toString(); ParseHelpers.Language language = ParseHelpers.Language.getLanguage(document); @@ -71,7 +74,7 @@ public class CrashReporter { batch = documentString.substring(i * STRING_BATCH_LENGTH, (i + 1) * STRING_BATCH_LENGTH); else batch = documentString.substring(i * STRING_BATCH_LENGTH); - Crashlytics.setString(key + "_" + i + 1, batch); + crashlytics.setCustomKey(key + "_" + i + 1, batch); } } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReportingTree.java b/app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReportingTree.java index f378000e..83e55a37 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReportingTree.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReportingTree.java @@ -2,12 +2,17 @@ package gr.thmmy.mthmmy.utils.crashreporting; import android.util.Log; -import com.crashlytics.android.Crashlytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; import timber.log.Timber.DebugTree; public class CrashReportingTree extends DebugTree { - + private FirebaseCrashlytics firebaseCrashlytics; + public CrashReportingTree() { + super(); + firebaseCrashlytics = FirebaseCrashlytics.getInstance(); + } + @Override protected void log(int priority, String tag, String message, Throwable t) { if (priority == Log.VERBOSE || priority == Log.DEBUG) { @@ -25,14 +30,13 @@ public class CrashReportingTree extends DebugTree { else level = 'A'; - Crashlytics.log(level + "/" + tag + ": " + message); + firebaseCrashlytics.log(level + "/" + tag + ": " + message); if(priority == Log.ERROR) { if (t!=null) - Crashlytics.logException(t); + firebaseCrashlytics.recordException(t); else - Crashlytics.logException(new Exception(message)); + firebaseCrashlytics.recordException(new Exception(message)); } - } } diff --git a/build.gradle b/build.gradle index 0400e33c..d966ef2f 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,6 @@ apply plugin: "com.github.ben-manes.versions" buildscript { repositories { - maven { url "https://maven.fabric.io/public" } google() jcenter() maven { url "https://jitpack.io" } @@ -11,7 +10,7 @@ buildscript { dependencies { classpath 'com.android.tools.build:gradle:3.6.3' classpath 'com.google.gms:google-services:4.3.3' - classpath 'io.fabric.tools:gradle:1.31.2' + classpath 'com.google.firebase:firebase-crashlytics-gradle:2.1.1' classpath 'org.ajoberstar.grgit:grgit-core:3.1.1' // Also change in app/gradle/grgit.gradle classpath "com.github.ben-manes:gradle-versions-plugin:0.21.0" } @@ -20,6 +19,7 @@ buildscript { allprojects { repositories { maven { url "https://maven.google.com" } + google() jcenter() maven { url "https://jitpack.io" } } From c5326e781c7285b3f653153f571961a9320d7256 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 8 Jun 2020 20:16:23 +0300 Subject: [PATCH 02/21] Glide crash fix --- .../activities/profile/ProfileActivity.java | 19 +++++++++++++------ .../mthmmy/activities/topic/TopicAdapter.java | 15 +++++++++------ .../gr/thmmy/mthmmy/utils/ui/GlideUtils.java | 17 +++++++++++++++++ 3 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/ui/GlideUtils.java 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 81f70fae..e88a22de 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 @@ -1,5 +1,7 @@ package gr.thmmy.mthmmy.activities.profile; +import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.graphics.Color; import android.graphics.Typeface; @@ -57,6 +59,7 @@ import timber.log.Timber; import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_TITLE; import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL; import static gr.thmmy.mthmmy.utils.parsing.ParseHelpers.emojiTagToHtml; +import static gr.thmmy.mthmmy.utils.ui.GlideUtils.isValidContextForGlide; import static gr.thmmy.mthmmy.utils.ui.PhotoViewUtils.displayPhotoViewImage; /** @@ -222,12 +225,16 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment avatarView.setOnClickListener(v -> displayPhotoViewImage(ProfileActivity.this, avatarUrl)); } - Glide.with(this) - .load(avatarUri) - .circleCrop() - .error(R.drawable.ic_default_user_avatar) - .placeholder(R.drawable.ic_default_user_avatar) - .into(avatarView); + if(isValidContextForGlide(this)){ + Glide.with(this) + .load(avatarUri) + .circleCrop() + .error(R.drawable.ic_default_user_avatar) + .placeholder(R.drawable.ic_default_user_avatar) + .into(avatarView); + } + else + Timber.d("Will not load Glide image (invalid context)"); } /** diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java index 213de341..e0f41e8f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java @@ -88,6 +88,7 @@ import static gr.thmmy.mthmmy.activities.topic.TopicParser.USER_COLOR_WHITE; import static gr.thmmy.mthmmy.activities.topic.TopicParser.USER_COLOR_YELLOW; import static gr.thmmy.mthmmy.base.BaseActivity.getSessionManager; import static gr.thmmy.mthmmy.utils.FileUtils.faIconFromFilename; +import static gr.thmmy.mthmmy.utils.ui.GlideUtils.isValidContextForGlide; /** * Custom {@link RecyclerView.Adapter} used for topics. @@ -810,12 +811,14 @@ class TopicAdapter extends RecyclerView.Adapter { if(imageUrl!=null) imageUrl = imageUrl.trim(); - Glide.with(context) - .load(imageUrl) - .circleCrop() - .error(R.drawable.ic_default_user_avatar_darker) - .placeholder(R.drawable.ic_default_user_avatar_darker) - .into(imageView); + if(isValidContextForGlide(context)) { + Glide.with(context) + .load(imageUrl) + .circleCrop() + .error(R.drawable.ic_default_user_avatar_darker) + .placeholder(R.drawable.ic_default_user_avatar_darker) + .into(imageView); + } } @Override diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/ui/GlideUtils.java b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/GlideUtils.java new file mode 100644 index 00000000..1f3f57c7 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/ui/GlideUtils.java @@ -0,0 +1,17 @@ +package gr.thmmy.mthmmy.utils.ui; + +import android.app.Activity; +import android.content.Context; + +public class GlideUtils { + public static boolean isValidContextForGlide(final Context context) { + if (context == null) + return false; + + if (context instanceof Activity) { + final Activity activity = (Activity) context; + return !activity.isDestroyed() && !activity.isFinishing(); + } + return true; + } +} From 05776162c2679550677a77228ebd44db76aca9cb Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 8 Jun 2020 20:27:55 +0300 Subject: [PATCH 03/21] Up appcompat version to fix WebView crash (Android 5.1) --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index e2eb5c50..da29d78f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -77,7 +77,7 @@ tasks.whenTaskAdded { task -> dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation project(":emojis") - implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.appcompat:appcompat:1.2.0-rc01' 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' From ca7cb4ce1b8ed663559630510eee007c1a992789 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 13 Jun 2020 23:39:23 +0300 Subject: [PATCH 04/21] Improved clickability of library links --- app/src/main/assets/libraries_style.css | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/main/assets/libraries_style.css b/app/src/main/assets/libraries_style.css index 39372a93..cbe97749 100644 --- a/app/src/main/assets/libraries_style.css +++ b/app/src/main/assets/libraries_style.css @@ -15,7 +15,6 @@ pre { h4, h5 { display: inline; - padding: 1em; } a, h4, h5 { @@ -23,6 +22,14 @@ a, h4, h5 { word-wrap: break-word; } +h4 { + padding: 1em; +} + li { color: #26A69A; +} + +ul a { + margin-left: 1em; } \ No newline at end of file From a12bc8d7be473cbaecf7ddbd323a6740fbb802e3 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 15 Jun 2020 00:42:38 +0300 Subject: [PATCH 05/21] Enable cleartext traffic for sciweavers.org (for Tex images) --- app/src/main/res/xml/network_security_config.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml index e87d713f..13da65b7 100644 --- a/app/src/main/res/xml/network_security_config.xml +++ b/app/src/main/res/xml/network_security_config.xml @@ -3,5 +3,6 @@ www.thmmy.gr + www.sciweavers.org From 74b4d727c306169114658c7904fed856d927449b Mon Sep 17 00:00:00 2001 From: Ezerous Date: Tue, 16 Jun 2020 19:56:32 +0300 Subject: [PATCH 06/21] Add release badge to README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fc28062a..96b10849 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # mTHMMY +[![GitHub release](https://img.shields.io/github/release/ThmmyNoLife/mTHMMY.svg)](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) [![Discord Channel](https://img.shields.io/badge/discord-public@mTHMMY-738bd7.svg?style=flat)][discord-server] ![Last Commit](https://img.shields.io/github/last-commit/ThmmyNoLife/mTHMMY/develop.svg?style=flat) From 6bd29c9dc7719653360ed27e39ade11fea424e97 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Wed, 17 Jun 2020 21:28:36 +0300 Subject: [PATCH 07/21] TopicTask crash fix --- .../activities/profile/ProfileActivity.java | 2 -- .../activities/topic/tasks/TopicTask.java | 17 ++++++++--------- 2 files changed, 8 insertions(+), 11 deletions(-) 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 e88a22de..016009ca 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 @@ -1,7 +1,5 @@ package gr.thmmy.mthmmy.activities.profile; -import android.app.Activity; -import android.content.Context; import android.content.Intent; import android.graphics.Color; import android.graphics.Typeface; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTask.java index 14899fa0..c3e78d8d 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTask.java @@ -11,6 +11,9 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Objects; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import gr.thmmy.mthmmy.activities.topic.TopicParser; import gr.thmmy.mthmmy.base.BaseApplication; @@ -29,6 +32,8 @@ import timber.log.Timber; * parameter.

*/ public class TopicTask extends AsyncTask { + private static final Pattern msgPattern = Pattern.compile("msg(\\d+)"); + private TopicTaskObserver topicTaskObserver; private OnTopicTaskCompleted finishListener; @@ -58,15 +63,9 @@ public class TopicTask extends AsyncTask { //Finds the index of message focus if present int postFocus = 0; - - //TODO: Better parseInt handling - may rarely fail - if (newPageUrl.contains("msg")) { - String tmp = newPageUrl.substring(newPageUrl.indexOf("msg") + 3); - if (tmp.contains(";")) - postFocus = Integer.parseInt(tmp.substring(0, tmp.indexOf(';'))); - else if (tmp.contains("#")) - postFocus = Integer.parseInt(tmp.substring(0, tmp.indexOf('#'))); - } + Matcher matcher = msgPattern.matcher(newPageUrl); + if (matcher.find()) + postFocus = Integer.parseInt(Objects.requireNonNull(matcher.group(1))); Request request = new Request.Builder() .url(newPageUrl) From d767d27072d6689e50d70af2d4a249a36aca3c17 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Thu, 18 Jun 2020 18:55:45 +0300 Subject: [PATCH 08/21] BoardActivity improvements --- .../activities/board/BoardActivity.java | 56 ++++++++++--------- .../mthmmy/activities/board/BoardAdapter.java | 22 +++++++- .../mthmmy/activities/topic/TopicAdapter.java | 1 - .../layout/activity_board_sub_board_row.xml | 9 ++- 4 files changed, 55 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java index 87e7d27b..aedda58b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java @@ -80,12 +80,11 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo Toast.makeText(this, "An error has occurred\nAborting.", Toast.LENGTH_SHORT).show(); finish(); } + //Fixes url - { - String tmpUrlSbstr = boardUrl.replaceAll("(.+)(board=)([0-9]*)(\\.*[0-9]*).*", "$1$2$3"); - if (!tmpUrlSbstr.substring(tmpUrlSbstr.indexOf("board=")).contains(".")) - boardUrl = tmpUrlSbstr + ".0"; - } + String tmpUrlSbstr = boardUrl.replaceAll("(.+)(board=)([0-9]*)(\\.*[0-9]*).*", "$1$2$3"); + if (!tmpUrlSbstr.substring(tmpUrlSbstr.indexOf("board=")).contains(".")) + boardUrl = tmpUrlSbstr + ".0"; //Initializes graphics toolbar = findViewById(R.id.toolbar); @@ -239,8 +238,12 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo pLastPost = "No posts yet", pLastPostUrl = ""; Elements subBoardColumns = subBoardRow.select(">td"); for (Element subBoardCol : subBoardColumns) { - if (Objects.equals(subBoardCol.className(), "windowbg")) + if (Objects.equals(subBoardCol.className(), "windowbg")){ pStats = subBoardCol.text(); + if(pStats.equals("--")) + pStats = ""; + } + else if (Objects.equals(subBoardCol.className(), "smalltext")) { pLastPost = subBoardCol.text(); if (pLastPost.contains(" in ")) { @@ -257,16 +260,15 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo "\n" + pLastPost.substring(pLastPost.lastIndexOf(" από ") + 1); pLastPostUrl = subBoardCol.select("a").first().attr("href"); - } else { - pLastPost = "No posts yet."; - pLastPostUrl = ""; - } + } else if (pLastPost.contains("redirected clicks")||pLastPost.contains("N/A")) + pLastPost = ""; + else + pLastPost = "No posts yet"; } else { pUrl = subBoardCol.select("a").first().attr("href"); pTitle = subBoardCol.select("a").first().text(); - if (subBoardCol.select("div.smalltext").first() != null) { + if (subBoardCol.select("div.smalltext").first() != null) pMods = subBoardCol.select("div.smalltext").first().text(); - } } } tempSubboards.add(new Board(pUrl, pTitle, pMods, pStats, pLastPost, pLastPostUrl)); @@ -282,18 +284,18 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo String pTopicUrl, pSubject, pStarter, pLastUser="", pLastPostDateTime="00:00:00", pLastPost, pLastPostUrl, pStats; boolean pLocked = false, pSticky = false, pUnread = false; Elements topicColumns = topicRow.select(">td"); - { - Element column = topicColumns.get(2); - Element tmp = column.select("span[id^=msg_] a").first(); - pTopicUrl = tmp.attr("href"); - pSubject = tmp.text(); - if (column.select("img[id^=stickyicon]").first() != null) - pSticky = true; - if (column.select("img[id^=lockicon]").first() != null) - pLocked = true; - if (column.select("a[id^=newicon]").first() != null) - pUnread = true; - } + + Element column = topicColumns.get(2); + Element tmp = column.select("span[id^=msg_] a").first(); + pTopicUrl = tmp.attr("href"); + pSubject = tmp.text(); + if (column.select("img[id^=stickyicon]").first() != null) + pSticky = true; + if (column.select("img[id^=lockicon]").first() != null) + pLocked = true; + if (column.select("a[id^=newicon]").first() != null) + pUnread = true; + pStarter = topicColumns.get(3).text(); pStats = "Replies: " + topicColumns.get(4).text() + ", Views: " + topicColumns.get(5).text(); @@ -304,8 +306,10 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo pLastPostDateTime = matcher.group(1); pLastUser = matcher.group(3); } - else - throw new ParseException("Parsing failed (pLastPost came with: \"" + pLastPost + "\")"); + else{ + Timber.e("Parsing failed (pLastPost came with: \"%s\", html was \"%s\")", pLastPost, topicColumns); + continue; + } pLastPostUrl = topicColumns.last().select("a:has(img)").first().attr("href"); tempTopics.add(new Topic(pTopicUrl, pSubject, pStarter, pLastUser, pLastPostDateTime, pLastPostUrl, diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java index c508fdc2..0a697706 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java @@ -161,9 +161,25 @@ class BoardAdapter extends RecyclerView.Adapter { boardExpandableVisibility.set(subBoardViewHolder.getAdapterPosition() - 1, !visible); }); subBoardViewHolder.boardTitle.setText(subBoard.getTitle()); - subBoardViewHolder.boardMods.setText(subBoard.getMods()); - subBoardViewHolder.boardStats.setText(subBoard.getStats()); - subBoardViewHolder.boardLastPost.setText(subBoard.getLastPost()); + String mods = subBoard.getMods(); + String stats = subBoard.getStats(); + String lastPost = subBoard.getLastPost(); + + if(!mods.isEmpty()){ + subBoardViewHolder.boardMods.setText(mods); + subBoardViewHolder.boardMods.setVisibility(View.VISIBLE); + } + + if(!stats.isEmpty()){ + subBoardViewHolder.boardStats.setText(stats); + subBoardViewHolder.boardStats.setVisibility(View.VISIBLE); + } + + if(!lastPost.isEmpty()){ + subBoardViewHolder.boardLastPost.setText(lastPost); + subBoardViewHolder.boardLastPost.setVisibility(View.VISIBLE); + } + if (!Objects.equals(subBoard.getLastPostUrl(), "")) { subBoardViewHolder.boardLastPost.setOnClickListener(view -> { Intent intent = new Intent(context, TopicActivity.class); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java index e0f41e8f..def64530 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java @@ -982,7 +982,6 @@ class TopicAdapter extends RecyclerView.Adapter { for (int i = 0; i < topicItems.size(); i++) { if (topicItems.get(i) instanceof Post && ((Post) topicItems.get(i)).getPostIndex() == testAgainst) { //same page - Timber.d(Integer.toString(i)); postFocusListener.onPostFocusChange(i); return true; } diff --git a/app/src/main/res/layout/activity_board_sub_board_row.xml b/app/src/main/res/layout/activity_board_sub_board_row.xml index 97335218..ac8eb60a 100644 --- a/app/src/main/res/layout/activity_board_sub_board_row.xml +++ b/app/src/main/res/layout/activity_board_sub_board_row.xml @@ -62,7 +62,8 @@ android:text="@string/child_board_mods" android:textColor="@color/secondary_text" android:textSize="12sp" - android:textStyle="italic" /> + android:textStyle="italic" + android:visibility="gone" /> + android:textSize="12sp" + android:visibility="gone" /> + android:textSize="12sp" + android:visibility="gone" /> \ No newline at end of file From daccf9df6a70b1b3fd106465bcc9a063c8db804b Mon Sep 17 00:00:00 2001 From: Ezerous Date: Thu, 18 Jun 2020 19:27:29 +0300 Subject: [PATCH 09/21] Bookmarks small fix --- .../java/gr/thmmy/mthmmy/activities/board/BoardActivity.java | 2 +- .../thmmy/mthmmy/activities/bookmarks/BookmarksActivity.java | 2 -- .../thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java | 1 + .../java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java | 5 ++++- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java index aedda58b..e9111365 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java @@ -327,7 +327,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo || !Objects.equals(boardTitle, parsedTitle)) { boardTitle = parsedTitle; toolbar.setTitle(boardTitle); - thisPageBookmark = new Bookmark(boardTitle, ThmmyPage.getBoardId(boardUrl), true); + thisPageBookmark = new Bookmark(boardTitle, thisPageBookmark.getId(), thisPageBookmark.isNotificationsEnabled()); setBoardBookmark(findViewById(R.id.bookmark)); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksActivity.java index ef2b79b6..7054db43 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksActivity.java @@ -26,8 +26,6 @@ import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL; import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_TITLE; import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL; -//TODO proper handling with adapter etc. -//TODO after clicking bookmark and then back button should return to this activity public class BookmarksActivity extends BaseActivity { private static final String TOPIC_URL = "https://www.thmmy.gr/smf/index.php?topic="; private static final String BOARD_URL = "https://www.thmmy.gr/smf/index.php?board="; 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 23562e0d..cdd6f714 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 @@ -20,6 +20,7 @@ import java.util.ArrayList; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.model.Bookmark; +//TODO refactor using RecyclerView public class BookmarksFragment extends Fragment { enum Type {TOPIC, BOARD} private static final String ARG_SECTION_NUMBER = "SECTION_NUMBER"; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java index f9145be5..907b1fb6 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java @@ -155,6 +155,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo } topicPageUrl = ThmmyPage.sanitizeTopicUrl(topicPageUrl); + //TODO if topicTitle provided is null make bookmark button unclickable until title is fetched (also for BoardActivity) thisPageBookmark = new Bookmark(topicTitle, ThmmyPage.getTopicId(topicPageUrl), true); //Initializes graphics @@ -671,8 +672,10 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo }); viewModel.getTopicTitle().observe(this, newTopicTitle -> { if (newTopicTitle == null) return; - if (!TextUtils.equals(toolbarTitle.getText(), newTopicTitle)) + if (!TextUtils.equals(toolbarTitle.getText(), newTopicTitle)) { + thisPageBookmark = new Bookmark(newTopicTitle, thisPageBookmark.getId(), thisPageBookmark.isNotificationsEnabled()); toolbarTitle.setText(newTopicTitle); + } }); viewModel.getPageTopicId().observe(this, pageTopicId -> { if (pageTopicId == null) return; From c242b009e0626071bf5a4290583852ae2da8dc9f Mon Sep 17 00:00:00 2001 From: Ezerous Date: Thu, 18 Jun 2020 19:30:55 +0300 Subject: [PATCH 10/21] UnreadFragment tiny tweak --- .../mthmmy/activities/main/unread/UnreadFragment.java | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index c3088094..f8097a81 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -119,16 +119,7 @@ public class UnreadFragment extends BaseFragment { progressBar = rootView.findViewById(R.id.progressBar); noUnreadTopicsTextView = rootView.findViewById(R.id.no_unread_topics); markAsReadFAB = rootView.findViewById(R.id.unread_fab); - - if(topicSummaries.isEmpty()){ - hideMarkAsReadFAB(); - noUnreadTopicsTextView.setVisibility(View.VISIBLE); - } - else{ - noUnreadTopicsTextView.setVisibility(View.INVISIBLE); - showMarkAsReadFAB(); - } - + unreadAdapter = new UnreadAdapter(topicSummaries, fragmentInteractionListener); CustomRecyclerView recyclerView = rootView.findViewById(R.id.list); From 423573cbc102702d3ce7b61859b3946d23eafc7c Mon Sep 17 00:00:00 2001 From: Ezerous Date: Fri, 19 Jun 2020 00:10:48 +0300 Subject: [PATCH 11/21] BoardActivity fixes --- .../activities/board/BoardActivity.java | 42 +++++++++++-------- .../mthmmy/activities/topic/TopicParser.java | 11 ----- 2 files changed, 24 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java index e9111365..c941269e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java @@ -236,6 +236,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo if (!Objects.equals(subBoardRow.className(), "titlebg")) { String pUrl = "", pTitle = "", pMods = "", pStats = "", pLastPost = "No posts yet", pLastPostUrl = ""; + boolean parsingFailed = false; Elements subBoardColumns = subBoardRow.select(">td"); for (Element subBoardCol : subBoardColumns) { if (Objects.equals(subBoardCol.className(), "windowbg")){ @@ -246,20 +247,22 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo else if (Objects.equals(subBoardCol.className(), "smalltext")) { pLastPost = subBoardCol.text(); - if (pLastPost.contains(" in ")) { - pLastPost = pLastPost.substring(0, pLastPost.indexOf(" in ")) + - "\n" + - pLastPost.substring(pLastPost.indexOf(" in ") + 1, pLastPost.indexOf(" by ")) + - "\n" + - pLastPost.substring(pLastPost.lastIndexOf(" by ") + 1); - pLastPostUrl = subBoardCol.select("a").first().attr("href"); - } else if (pLastPost.contains(" σε ")) { - pLastPost = pLastPost.substring(0, pLastPost.indexOf(" σε ")) + - "\n" + - pLastPost.substring(pLastPost.indexOf(" σε ") + 1, pLastPost.indexOf(" από ")) + - "\n" + - pLastPost.substring(pLastPost.lastIndexOf(" από ") + 1); - pLastPostUrl = subBoardCol.select("a").first().attr("href"); + if (pLastPost.contains(" in ") || pLastPost.contains(" σε ")) { + Pattern pattern = Pattern.compile("(?:Last post on |Τελευταίο μήνυμα στις )((?:(?!(?:in|σε)).)*)\\s(?:in|σε)\\s.*"); + Matcher matcher = pattern.matcher(pLastPost); + if (matcher.find()){ + String pLastPostDateTime = matcher.group(1); + String pSubject = subBoardCol.select("a").first().attr("title"); + String pLastUser = subBoardCol.select("a").last().text(); + pLastPost = "Last post on: " + pLastPostDateTime + "\nin: " + pSubject + "\nby " +pLastUser; + + pLastPostUrl = subBoardCol.select("a").first().attr("href"); + } + else{ + parsingFailed = true; + break; + } + } else if (pLastPost.contains("redirected clicks")||pLastPost.contains("N/A")) pLastPost = ""; else @@ -271,7 +274,10 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo pMods = subBoardCol.select("div.smalltext").first().text(); } } - tempSubboards.add(new Board(pUrl, pTitle, pMods, pStats, pLastPost, pLastPostUrl)); + if(!parsingFailed) + tempSubboards.add(new Board(pUrl, pTitle, pMods, pStats, pLastPost, pLastPostUrl)); + else + Timber.e("Parsing failed (pLastPost came with: \"%s\", subBoardColumns html was \"%s\")", pLastPost, subBoardColumns); } } } @@ -300,14 +306,14 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo pStats = "Replies: " + topicColumns.get(4).text() + ", Views: " + topicColumns.get(5).text(); pLastPost = topicColumns.last().text(); - Pattern pattern = Pattern.compile("(.+)\\s(by|από)\\s(.+)$"); + Pattern pattern = Pattern.compile("((?:(?!(?:by|από)).)*)\\s(?:by|από)\\s(.*)"); Matcher matcher = pattern.matcher(pLastPost); if (matcher.find()){ pLastPostDateTime = matcher.group(1); - pLastUser = matcher.group(3); + pLastUser = matcher.group(2); } else{ - Timber.e("Parsing failed (pLastPost came with: \"%s\", html was \"%s\")", pLastPost, topicColumns); + Timber.e("Parsing failed (pLastPost came with: \"%s\", topicColumns html was \"%s\")", pLastPost, topicColumns); continue; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java index 901ce553..1a7922ff 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java @@ -18,7 +18,6 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import gr.thmmy.mthmmy.base.BaseActivity; -import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.model.Poll; import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyFile; @@ -26,8 +25,6 @@ import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import timber.log.Timber; -import static gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser.convertToTimestamp; - /** * Singleton used for parsing a topic. @@ -178,7 +175,6 @@ public class TopicParser { p_specialRank, p_gender, p_personalText, p_numberOfPosts, p_postLastEditDate, p_postURL, p_deletePostURL, p_editPostURL; int p_postNum, p_postIndex, p_numberOfStars, p_userColor; - long p_timestamp; boolean p_isDeleted = false, p_isUserMentionedInPost = false; ArrayList p_attachedFiles; @@ -195,7 +191,6 @@ public class TopicParser { p_postLastEditDate = null; p_deletePostURL = null; p_editPostURL = null; - p_timestamp = 0; //Language independent parsing //Finds thumbnail url @@ -272,12 +267,6 @@ public class TopicParser { p_postDate = p_postDate.substring(p_postDate.indexOf("στις:") + 6 , p_postDate.indexOf(" »")); - if (BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) { - String timestamp = convertToTimestamp(p_postDate); - if(timestamp!=null) - p_timestamp = Long.valueOf(timestamp); - } - //Finds post's reply index number Element postNum = thisRow.select("div.smalltext:matches(Απάντηση #)").first(); if (postNum == null) { //Topic starter From 43567e03b58b34f07bfafe5de7f2e71267fbc047 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Fri, 19 Jun 2020 12:07:19 +0300 Subject: [PATCH 12/21] Include edge cases in BoardActivity parsing --- .../activities/board/BoardActivity.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java index c941269e..9e297dcf 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java @@ -229,6 +229,9 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo if (newTopicButton == null) newTopicButton = boardPage.select("a:has(img[alt=Νέο θέμα])").first(); if (newTopicButton != null) newTopicUrl = newTopicButton.attr("href"); + + final Pattern pLastPostPattern = Pattern.compile("((?:(?!(?:by|από)).)*)\\s(?:by|από)\\s(.*)"); + if(pagesLoaded == 0) { //Finds sub boards Elements subBoardRows = boardPage.select("div.tborder>table>tbody>tr"); if (subBoardRows != null && !subBoardRows.isEmpty()) { @@ -253,12 +256,25 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo if (matcher.find()){ String pLastPostDateTime = matcher.group(1); String pSubject = subBoardCol.select("a").first().attr("title"); - String pLastUser = subBoardCol.select("a").last().text(); + + // Purification for extreme edge cases + String pSubjectConcat = subBoardCol.select("a").first().text(); + pLastPost = pLastPost.replaceAll(pSubjectConcat, ""); + + String pLastUser; + matcher = pLastPostPattern.matcher(pLastPost); //Don't even try simply grabbing , user might be guest + if (matcher.find()) + pLastUser = matcher.group(2); + else { + parsingFailed = true; + break; + } + pLastPost = "Last post on: " + pLastPostDateTime + "\nin: " + pSubject + "\nby " +pLastUser; pLastPostUrl = subBoardCol.select("a").first().attr("href"); } - else{ + else { parsingFailed = true; break; } @@ -306,8 +322,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo pStats = "Replies: " + topicColumns.get(4).text() + ", Views: " + topicColumns.get(5).text(); pLastPost = topicColumns.last().text(); - Pattern pattern = Pattern.compile("((?:(?!(?:by|από)).)*)\\s(?:by|από)\\s(.*)"); - Matcher matcher = pattern.matcher(pLastPost); + Matcher matcher = pLastPostPattern.matcher(pLastPost); if (matcher.find()){ pLastPostDateTime = matcher.group(1); pLastUser = matcher.group(2); From 2af55e1acaaaefdf3d62041369a49d0b966da90a Mon Sep 17 00:00:00 2001 From: Ezerous Date: Fri, 26 Jun 2020 23:48:37 +0300 Subject: [PATCH 13/21] Add InvalidSessionException, refactoring --- .../activities/main/forum/ForumFragment.java | 2 +- .../main/recent/RecentFragment.java | 2 +- .../main/unread/UnreadFragment.java | 36 +++++++------ .../activities/profile/ProfileActivity.java | 2 +- .../activities/shoutbox/SendShoutTask.java | 4 +- .../activities/shoutbox/ShoutboxFragment.java | 2 +- .../activities/shoutbox/ShoutboxTask.java | 2 +- .../activities/topic/TopicActivity.java | 2 +- .../activities/topic/tasks/DeleteTask.java | 4 +- .../topic/tasks/RemoveVoteTask.java | 4 +- .../topic/tasks/SubmitVoteTask.java | 4 +- .../gr/thmmy/mthmmy/base/BaseActivity.java | 4 +- .../session/InvalidSessionException.java | 13 +++++ .../thmmy/mthmmy/session/SessionManager.java | 50 +++++++++---------- .../java/gr/thmmy/mthmmy/utils/Parcel.java | 1 - .../{ => networking}/NetworkResultCodes.java | 2 +- .../utils/{ => networking}/NetworkTask.java | 13 ++++- .../mthmmy/utils/parsing/NewParseTask.java | 7 ++- .../mthmmy/viewmodel/TopicViewModel.java | 2 +- app/src/main/res/layout/fragment_unread.xml | 1 + 20 files changed, 92 insertions(+), 65 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/session/InvalidSessionException.java rename app/src/main/java/gr/thmmy/mthmmy/utils/{ => networking}/NetworkResultCodes.java (94%) rename app/src/main/java/gr/thmmy/mthmmy/utils/{ => networking}/NetworkTask.java (86%) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java index 061db9d2..3344d089 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java @@ -30,7 +30,7 @@ import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.Board; import gr.thmmy.mthmmy.model.Category; import gr.thmmy.mthmmy.session.SessionManager; -import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; import gr.thmmy.mthmmy.utils.parsing.ParseException; import gr.thmmy.mthmmy.views.CustomRecyclerView; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java index 5b27c570..625f7440 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java @@ -26,7 +26,7 @@ import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.session.SessionManager; -import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; import gr.thmmy.mthmmy.utils.parsing.ParseException; import gr.thmmy.mthmmy.views.CustomRecyclerView; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index f8097a81..a8ba7f10 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -29,9 +29,10 @@ import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; +import gr.thmmy.mthmmy.session.InvalidSessionException; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.session.ValidateSessionTask; -import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; import gr.thmmy.mthmmy.utils.parsing.ParseException; import gr.thmmy.mthmmy.views.CustomRecyclerView; @@ -266,6 +267,8 @@ public class UnreadFragment extends BaseFragment { hideProgressUI(); if (resultCode == NetworkResultCodes.NETWORK_ERROR) Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); + else if (resultCode == SessionManager.INVALID_SESSION) + Toast.makeText(getContext(), "Session verification failed. Please try logging in again.", Toast.LENGTH_LONG).show(); else Toast.makeText(getContext(), "Unexpected error," + " please contact the developers with the details", Toast.LENGTH_LONG).show(); @@ -278,7 +281,10 @@ public class UnreadFragment extends BaseFragment { } @Override - protected ArrayList parse(Document document, Response response) throws ParseException { + protected ArrayList parse(Document document, Response response) throws ParseException, InvalidSessionException { + if(!document.select("td:containsOwn(Only registered members are allowed to access this section.)").isEmpty()) + throw new InvalidSessionException(); + Elements unread = document.select("table.bordercolor[cellspacing=1] tr:not(.titlebg)"); ArrayList fetchedTopicSummaries = new ArrayList<>(); if (!unread.isEmpty()) { @@ -338,42 +344,42 @@ public class UnreadFragment extends BaseFragment { progressBar.setVisibility(ProgressBar.VISIBLE); } - private void onMarkReadTaskFinished(int resultCode, Boolean isSessionVerified) { + private void onMarkReadTaskFinished(int resultCode, Void isSessionVerified) { hideProgressUI(); - if (resultCode == NetworkResultCodes.SUCCESSFUL) { - if (!isSessionVerified){ - Toast.makeText(getContext(), "Session verification failed", Toast.LENGTH_SHORT).show(); - startValidateSessionTask(); - } - else + if (resultCode == NetworkResultCodes.SUCCESSFUL) startUnreadTask(); - } else{ hideProgressUI(); if (resultCode == NetworkResultCodes.NETWORK_ERROR) Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); + else if (resultCode == SessionManager.INVALID_SESSION){ + Toast.makeText(getContext(), "Session verification failed. Please try logging out and back in again", Toast.LENGTH_LONG).show(); + startValidateSessionTask(); + } else Toast.makeText(getContext(), "Unexpected error," + " please contact the developers with the details", Toast.LENGTH_LONG).show(); } } - private class MarkReadTask extends NewParseTask { - MarkReadTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onParseTaskFinishedListener) { + private class MarkReadTask extends NewParseTask { + MarkReadTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onParseTaskFinishedListener) { super(onTaskStartedListener, onParseTaskFinishedListener); } @Override - protected Boolean parse(Document document, Response response) throws ParseException { + protected Void parse(Document document, Response response) throws ParseException { Elements sessionVerificationFailed = document.select("td:containsOwn(Session " + "verification failed. Please try logging out and back in again, and then try " + "again.), td:containsOwn(Η επαλήθευση συνόδου απέτυχε. Παρακαλούμε κάντε " + "αποσύνδεση, επανασύνδεση και ξαναδοκιμάστε.)"); - return sessionVerificationFailed.isEmpty(); + if(!sessionVerificationFailed.isEmpty()) + throw new InvalidSessionException(); + return null; } @Override - protected int getResultCode(Response response, Boolean isSessionVerified) { + protected int getResultCode(Response response, Void v) { return NetworkResultCodes.SUCCESSFUL; } } 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 016009ca..223f36e9 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 @@ -45,8 +45,8 @@ import gr.thmmy.mthmmy.activities.topic.TopicActivity; import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.model.PostSummary; import gr.thmmy.mthmmy.model.ThmmyPage; -import gr.thmmy.mthmmy.utils.NetworkResultCodes; import gr.thmmy.mthmmy.utils.Parcel; +import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; import gr.thmmy.mthmmy.utils.parsing.ParseException; import gr.thmmy.mthmmy.utils.ui.CenterVerticalSpan; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/SendShoutTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/SendShoutTask.java index 3b2af22f..171be1e3 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/SendShoutTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/SendShoutTask.java @@ -4,8 +4,8 @@ import org.jsoup.nodes.Document; import java.io.IOException; -import gr.thmmy.mthmmy.utils.NetworkResultCodes; -import gr.thmmy.mthmmy.utils.NetworkTask; +import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.networking.NetworkTask; import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.Request; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java index 0049fa6b..e776423f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java @@ -21,7 +21,7 @@ import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.model.Shout; import gr.thmmy.mthmmy.model.Shoutbox; -import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; import gr.thmmy.mthmmy.viewmodel.ShoutboxViewModel; import gr.thmmy.mthmmy.views.CustomRecyclerView; import gr.thmmy.mthmmy.views.editorview.EditorView; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxTask.java index 8a1d3768..5fbb1415 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxTask.java @@ -7,7 +7,7 @@ import java.util.ArrayList; import gr.thmmy.mthmmy.model.Shout; import gr.thmmy.mthmmy.model.Shoutbox; -import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; import gr.thmmy.mthmmy.utils.parsing.ParseException; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java index 907b1fb6..3621057f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java @@ -54,7 +54,7 @@ import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.HTMLUtils; -import gr.thmmy.mthmmy.utils.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; import gr.thmmy.mthmmy.views.CustomLinearLayoutManager; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java index b277d2bd..96600b7b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/DeleteTask.java @@ -4,8 +4,8 @@ import org.jsoup.nodes.Document; import java.io.IOException; -import gr.thmmy.mthmmy.utils.NetworkResultCodes; -import gr.thmmy.mthmmy.utils.NetworkTask; +import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.networking.NetworkTask; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/RemoveVoteTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/RemoveVoteTask.java index f94ae027..484522c1 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/RemoveVoteTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/RemoveVoteTask.java @@ -2,8 +2,8 @@ package gr.thmmy.mthmmy.activities.topic.tasks; import org.jsoup.nodes.Document; -import gr.thmmy.mthmmy.utils.NetworkResultCodes; -import gr.thmmy.mthmmy.utils.NetworkTask; +import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.networking.NetworkTask; import okhttp3.Response; public class RemoveVoteTask extends NetworkTask { diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java index ec3773f7..75dc37e3 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/SubmitVoteTask.java @@ -4,8 +4,8 @@ import org.jsoup.nodes.Document; import java.io.IOException; -import gr.thmmy.mthmmy.utils.NetworkResultCodes; -import gr.thmmy.mthmmy.utils.NetworkTask; +import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.networking.NetworkTask; import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.Request; diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index 5adfd788..defaa6d3 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -463,8 +463,7 @@ public abstract class BaseActivity extends AppCompatActivity { private void updateDrawer() { if (drawer != null) { - if (!sessionManager.isLoggedIn()) //When logged out or if user is guest - { + if (!sessionManager.isLoggedIn()){ //When logged out or if user is guest drawer.removeItem(DOWNLOADS_ID); drawer.removeItem(UPLOAD_ID); loginLogoutItem.withName(R.string.login).withIcon(loginIcon); //Swap logout with login @@ -486,7 +485,6 @@ public abstract class BaseActivity extends AppCompatActivity { } accountHeader.updateProfile(profileDrawerItem); drawer.updateItem(loginLogoutItem); - } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/InvalidSessionException.java b/app/src/main/java/gr/thmmy/mthmmy/session/InvalidSessionException.java new file mode 100644 index 00000000..37bc2ddd --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/session/InvalidSessionException.java @@ -0,0 +1,13 @@ +package gr.thmmy.mthmmy.session; + +public class InvalidSessionException extends RuntimeException { + public InvalidSessionException() {} + + public InvalidSessionException(String message) { + super(message); + } + + public InvalidSessionException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java index 36490d56..e87cdf05 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java +++ b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java @@ -43,15 +43,16 @@ public class SessionManager { private static final String baseMarkAllAsReadLink = "https://www.thmmy.gr/smf/index.php?action=markasread;sa=all;sesc="; private static final String guestName = "Guest"; - //Response Codes - public static final int SUCCESS = 0; - public static final int FAILURE = 1; //Generic Error - public static final int WRONG_USER = 2; - public static final int WRONG_PASSWORD = 3; - public static final int CANCELLED = 4; - public static final int CONNECTION_ERROR = 5; - public static final int EXCEPTION = 6; - public static final int BANNED_USER = 7; + //Response Codes - make sure they do not overlap with NetworkResultCodes, just in case + public static final int SUCCESS = 20; + public static final int FAILURE = 21; //Generic Error + public static final int WRONG_USER = 22; + public static final int WRONG_PASSWORD = 23; + public static final int CANCELLED = 24; + public static final int CONNECTION_ERROR = 25; + public static final int EXCEPTION = 26; + public static final int BANNED_USER = 27; + public static final int INVALID_SESSION = 28; // Client & Cookies private final OkHttpClient client; @@ -63,12 +64,12 @@ public class SessionManager { private final SharedPreferences draftsPrefs; private static final String USERNAME = "Username"; private static final String USER_ID = "UserID"; - private static final String AVATAR_LINK = "AvatarLink"; - private static final String HAS_AVATAR = "HasAvatar"; + public static final String AVATAR_LINK = "AvatarLink"; + public static final String HAS_AVATAR = "HasAvatar"; private static final String SESC = "Sesc"; private static final String LOGOUT_LINK = "LogoutLink"; private static final String MARK_ALL_AS_READ_LINK = "MarkAllAsReadLink"; - private static final String LOGGED_IN = "LoggedIn"; + public static final String LOGGED_IN = "LoggedIn"; private static final String LOGIN_SCREEN_AS_DEFAULT = "LoginScreenAsDefault"; //Constructor @@ -224,8 +225,7 @@ public class SessionManager { Document document = Jsoup.parse(response.body().string()); Elements loginButton = document.select("[value=Login]"); //Attempt to find login button - if (!loginButton.isEmpty()) //If login button exists, logout was successful - { + if (!loginButton.isEmpty()){ //If login button exists, logout was successful Timber.i("Logout successful!"); return SUCCESS; } else { @@ -245,6 +245,16 @@ public class SessionManager { } } + public void clearSessionData() { + cookieJar.clear(); + sharedPrefs.edit().clear().apply(); //Clear session data + sharedPrefs.edit().putString(USERNAME, guestName).apply(); + sharedPrefs.edit().putInt(USER_ID, -1).apply(); + sharedPrefs.edit().putBoolean(LOGGED_IN, false).apply(); //User logs out + draftsPrefs.edit().clear().apply(); //Clear saved drafts + Timber.i("Session data cleared."); + } + public void refreshSescFromUrl(String url){ String sesc = extractSescFromLink(url); if(sesc!=null){ @@ -356,16 +366,6 @@ public class SessionManager { } - private void clearSessionData() { - cookieJar.clear(); - sharedPrefs.edit().clear().apply(); //Clear session data - sharedPrefs.edit().putString(USERNAME, guestName).apply(); - sharedPrefs.edit().putInt(USER_ID, -1).apply(); - sharedPrefs.edit().putBoolean(LOGGED_IN, false).apply(); //User logs out - draftsPrefs.edit().clear().apply(); //Clear saved drafts - Timber.i("Session data cleared."); - } - private void setLoginScreenAsDefault(boolean b){ sharedPrefs.edit().putBoolean(LOGIN_SCREEN_AS_DEFAULT, b).apply(); } @@ -421,7 +421,6 @@ public class SessionManager { return -1; } - @Nullable private String extractAvatarLink(@NonNull Document doc) { Elements avatar = doc.getElementsByClass("avatar"); @@ -461,5 +460,4 @@ public class SessionManager { return baseMarkAllAsReadLink + sesc; } //----------------------------------OTHER FUNCTIONS END----------------------------------------- - } \ No newline at end of file diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/Parcel.java b/app/src/main/java/gr/thmmy/mthmmy/utils/Parcel.java index 83e65285..8733bf8c 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/Parcel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/Parcel.java @@ -1,7 +1,6 @@ package gr.thmmy.mthmmy.utils; public class Parcel { - private int resultCode; private T data; diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkResultCodes.java b/app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkResultCodes.java similarity index 94% rename from app/src/main/java/gr/thmmy/mthmmy/utils/NetworkResultCodes.java rename to app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkResultCodes.java index 90cd8771..958435e1 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkResultCodes.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkResultCodes.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils; +package gr.thmmy.mthmmy.utils.networking; public class NetworkResultCodes { /** diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkTask.java similarity index 86% rename from app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java rename to app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkTask.java index a8c42c8b..a12d5757 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/NetworkTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkTask.java @@ -1,4 +1,4 @@ -package gr.thmmy.mthmmy.utils; +package gr.thmmy.mthmmy.utils.networking; import android.content.SharedPreferences; import android.preference.PreferenceManager; @@ -10,6 +10,10 @@ import java.io.IOException; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.base.BaseApplication; +import gr.thmmy.mthmmy.session.InvalidSessionException; +import gr.thmmy.mthmmy.session.SessionManager; +import gr.thmmy.mthmmy.utils.ExternalAsyncTask; +import gr.thmmy.mthmmy.utils.Parcel; import gr.thmmy.mthmmy.utils.crashreporting.CrashReporter; import gr.thmmy.mthmmy.utils.parsing.ParseException; import okhttp3.OkHttpClient; @@ -63,7 +67,12 @@ public abstract class NetworkTask extends ExternalAsyncTask .getString(R.string.pref_privacy_crashlytics_enable_key), false)) CrashReporter.reportForumInfo(Jsoup.parse(responseBodyString)); return new Parcel<>(NetworkResultCodes.PARSE_ERROR, null); - } catch (Exception e) { + } catch (InvalidSessionException ise) { + //TODO: Uncomment the lines below when UI is ready to auto-adjust to changes in session data + // BaseApplication.getInstance().getSessionManager().clearSessionData(); + // BaseApplication.getInstance().getSessionManager().guestLogin(); + return new Parcel<>(SessionManager.INVALID_SESSION, null); + }catch (Exception e) { Timber.e(e); return new Parcel<>(NetworkResultCodes.PERFORM_TASK_ERROR, null); } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java index def14c2f..754e7825 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java @@ -2,7 +2,8 @@ package gr.thmmy.mthmmy.utils.parsing; import org.jsoup.nodes.Document; -import gr.thmmy.mthmmy.utils.NetworkTask; +import gr.thmmy.mthmmy.session.InvalidSessionException; +import gr.thmmy.mthmmy.utils.networking.NetworkTask; import okhttp3.Response; public abstract class NewParseTask extends NetworkTask { @@ -22,8 +23,10 @@ public abstract class NewParseTask extends NetworkTask { protected final T performTask(Document document, Response response) { try { return parse(document, response); + } catch (InvalidSessionException ise) { + throw ise; } catch (Exception e) { - throw new ParseException("Parse failed.", e); + throw new ParseException("Parsing failed", e); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java index 8f8f4c3a..49f619c2 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java +++ b/app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java @@ -30,7 +30,7 @@ import gr.thmmy.mthmmy.model.Post; import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.ExternalAsyncTask; -import gr.thmmy.mthmmy.utils.NetworkTask; +import gr.thmmy.mthmmy.utils.networking.NetworkTask; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import timber.log.Timber; diff --git a/app/src/main/res/layout/fragment_unread.xml b/app/src/main/res/layout/fragment_unread.xml index 4d1d5506..3da5651c 100644 --- a/app/src/main/res/layout/fragment_unread.xml +++ b/app/src/main/res/layout/fragment_unread.xml @@ -61,6 +61,7 @@ android:layout_gravity="bottom|end" android:layout_marginEnd="@dimen/fab_margins" android:layout_marginBottom="@dimen/fab_margins" + android:visibility="gone" app:layout_behavior="gr.thmmy.mthmmy.utils.ui.ScrollAwareFABBehavior" app:srcCompat="@drawable/ic_mark_as_read" /> \ No newline at end of file From 2bdb37a2dfcadc7a74aa770a2f2b08a9486d08d8 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 27 Jun 2020 12:51:24 +0300 Subject: [PATCH 14/21] Refactoring --- .../gr/thmmy/mthmmy/base/BaseApplication.java | 59 ++++++++++++------- .../thmmy/mthmmy/session/SessionManager.java | 48 +++++++-------- app/src/main/res/values/strings.xml | 8 ++- 3 files changed, 68 insertions(+), 47 deletions(-) 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 51d01bba..390faf5c 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -48,6 +48,7 @@ import timber.log.Timber; import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DISPLAY_RELATIVE_TIME; +// TODO: Replace MultiDexApplication with Application after KitKat support is dropped public class BaseApplication extends MultiDexApplication { private static BaseApplication baseApplication; //BaseApplication singleton @@ -63,9 +64,6 @@ public class BaseApplication extends MultiDexApplication { private boolean displayRelativeTime; - //TODO: maybe use PreferenceManager.getDefaultSharedPreferences here as well? - private static final String SHARED_PREFS = "ThmmySharedPrefs"; - //Display Metrics private static float widthDp; private static int widthPxl, heightPxl; @@ -84,10 +82,32 @@ public class BaseApplication extends MultiDexApplication { Timber.plant(new Timber.DebugTree()); //Shared Preferences - SharedPreferences sharedPrefs = getSharedPreferences(SHARED_PREFS, MODE_PRIVATE); + SharedPreferences sessionSharedPrefs = getSharedPreferences(getString(R.string.session_shared_prefs), MODE_PRIVATE); SharedPreferences settingsSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences draftsPrefs = getSharedPreferences(getString(R.string.pref_topic_drafts_key), MODE_PRIVATE); + initFirebase(settingsSharedPrefs); + + SharedPrefsCookiePersistor sharedPrefsCookiePersistor = new SharedPrefsCookiePersistor(getApplicationContext()); + PersistentCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), sharedPrefsCookiePersistor); + + initOkHttp(cookieJar); + + sessionManager = new SessionManager(client, cookieJar, sharedPrefsCookiePersistor, sessionSharedPrefs, draftsPrefs); + + //Sets up upload service + UploadService.NAMESPACE = BuildConfig.APPLICATION_ID; + UploadService.HTTP_STACK = new OkHttpStack(client); + + //Initialize and create the image loader logic for the drawer + initDrawerImageLoader(); + + setDisplayMetrics(); + + displayRelativeTime = settingsSharedPrefs.getBoolean(DISPLAY_RELATIVE_TIME, true); + } + + private void initFirebase(SharedPreferences settingsSharedPrefs){ if (settingsSharedPrefs.getBoolean(getString(R.string.pref_privacy_crashlytics_enable_key), false)){ Timber.i("Starting app with Firebase Crashlytics enabled."); setFirebaseCrashlyticsEnabled(true); @@ -105,9 +125,10 @@ public class BaseApplication extends MultiDexApplication { Timber.i("Starting app with Firebase Analytics enabled."); else Timber.i("Starting app with Firebase Analytics disabled."); + } + + private void initOkHttp(PersistentCookieJar cookieJar){ - SharedPrefsCookiePersistor sharedPrefsCookiePersistor = new SharedPrefsCookiePersistor(getApplicationContext()); - PersistentCookieJar cookieJar = new PersistentCookieJar(new SetCookieCache(), sharedPrefsCookiePersistor); OkHttpClient.Builder builder = new OkHttpClient.Builder() .cookieJar(cookieJar) .addInterceptor(chain -> { @@ -115,9 +136,9 @@ public class BaseApplication extends MultiDexApplication { HttpUrl oldUrl = chain.request().url(); if (Objects.equals(chain.request().url().host(), "www.thmmy.gr") && !oldUrl.toString().contains("theme=4")) { - //Probably works but needs more testing: - HttpUrl newUrl = oldUrl.newBuilder().addQueryParameter("theme", "4").build(); - request = request.newBuilder().url(newUrl).build(); + //Probably works but needs more testing: + HttpUrl newUrl = oldUrl.newBuilder().addQueryParameter("theme", "4").build(); + request = request.newBuilder().url(newUrl).build(); } return chain.proceed(request); }) @@ -143,14 +164,9 @@ public class BaseApplication extends MultiDexApplication { builder.addInterceptor(new OkHttpProfilerInterceptor()); client = builder.build(); + } - sessionManager = new SessionManager(client, cookieJar, sharedPrefsCookiePersistor, sharedPrefs, draftsPrefs); - - //Sets up upload service - UploadService.NAMESPACE = BuildConfig.APPLICATION_ID; - UploadService.HTTP_STACK = new OkHttpStack(client); - - //Initialize and create the image loader logic + private void initDrawerImageLoader(){ DrawerImageLoader.init(new AbstractDrawerImageLoader() { @Override public void set(ImageView imageView, Uri uri, Drawable placeholder, String tag) { @@ -167,24 +183,25 @@ public class BaseApplication extends MultiDexApplication { if (DrawerImageLoader.Tags.PROFILE.name().equals(tag)) { return new IconicsDrawable(ctx).icon(FontAwesome.Icon.faw_user) .paddingDp(10) - .color(ContextCompat.getColor(ctx, R.color.primary_light)) + .color(ContextCompat.getColor(ctx, R.color.iron)) .backgroundColor(ContextCompat.getColor(ctx, R.color.primary)); } return super.placeholder(ctx, tag); } }); + } + private void setDisplayMetrics(){ DisplayMetrics displayMetrics = getApplicationContext().getResources().getDisplayMetrics(); widthPxl = displayMetrics.widthPixels; widthDp = widthPxl / displayMetrics.density; heightPxl = displayMetrics.heightPixels; - - displayRelativeTime = settingsSharedPrefs.getBoolean(DISPLAY_RELATIVE_TIME, true); } - //Getters + + //-------------------- Getters -------------------- public Context getContext() { return getApplicationContext(); } @@ -213,7 +230,7 @@ public class BaseApplication extends MultiDexApplication { return displayRelativeTime; } - //--------------------Firebase-------------------- + //-------------------- Firebase -------------------- public void logFirebaseAnalyticsEvent(String event, Bundle params) { firebaseAnalytics.logEvent(event, params); diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java index e87cdf05..2c5cc42b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java +++ b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java @@ -60,25 +60,25 @@ public class SessionManager { private final SharedPrefsCookiePersistor cookiePersistor; //Used to explicitly edit cookies in cookieJar //Shared Preferences & its keys - private final SharedPreferences sharedPrefs; + private final SharedPreferences sessionSharedPrefs; private final SharedPreferences draftsPrefs; private static final String USERNAME = "Username"; private static final String USER_ID = "UserID"; - public static final String AVATAR_LINK = "AvatarLink"; - public static final String HAS_AVATAR = "HasAvatar"; + private static final String AVATAR_LINK = "AvatarLink"; + private static final String HAS_AVATAR = "HasAvatar"; private static final String SESC = "Sesc"; private static final String LOGOUT_LINK = "LogoutLink"; private static final String MARK_ALL_AS_READ_LINK = "MarkAllAsReadLink"; - public static final String LOGGED_IN = "LoggedIn"; + private static final String LOGGED_IN = "LoggedIn"; private static final String LOGIN_SCREEN_AS_DEFAULT = "LoginScreenAsDefault"; //Constructor public SessionManager(OkHttpClient client, PersistentCookieJar cookieJar, - SharedPrefsCookiePersistor cookiePersistor, SharedPreferences sharedPrefs, SharedPreferences draftsPrefs) { + SharedPrefsCookiePersistor cookiePersistor, SharedPreferences sessionSharedPrefs, SharedPreferences draftsPrefs) { this.client = client; this.cookiePersistor = cookiePersistor; this.cookieJar = cookieJar; - this.sharedPrefs = sharedPrefs; + this.sessionSharedPrefs = sessionSharedPrefs; this.draftsPrefs = draftsPrefs; } @@ -124,7 +124,7 @@ public class SessionManager { setPersistentCookieSession(); //Store cookies //Edit SharedPreferences, save session's data - SharedPreferences.Editor editor = sharedPrefs.edit(); + SharedPreferences.Editor editor = sessionSharedPrefs.edit(); setLoginScreenAsDefault(false); editor.putBoolean(LOGGED_IN, true); editor.putString(USERNAME, extractUserName(document)); @@ -247,10 +247,10 @@ public class SessionManager { public void clearSessionData() { cookieJar.clear(); - sharedPrefs.edit().clear().apply(); //Clear session data - sharedPrefs.edit().putString(USERNAME, guestName).apply(); - sharedPrefs.edit().putInt(USER_ID, -1).apply(); - sharedPrefs.edit().putBoolean(LOGGED_IN, false).apply(); //User logs out + sessionSharedPrefs.edit().clear().apply(); //Clear session data + sessionSharedPrefs.edit().putString(USERNAME, guestName).apply(); + sessionSharedPrefs.edit().putInt(USER_ID, -1).apply(); + sessionSharedPrefs.edit().putBoolean(LOGGED_IN, false).apply(); //User logs out draftsPrefs.edit().clear().apply(); //Clear saved drafts Timber.i("Session data cleared."); } @@ -267,15 +267,15 @@ public class SessionManager { //---------------------------------------GETTERS------------------------------------------------ public String getUsername() { - return sharedPrefs.getString(USERNAME, USERNAME); + return sessionSharedPrefs.getString(USERNAME, USERNAME); } public int getUserId() { - return sharedPrefs.getInt(USER_ID, -1); + return sessionSharedPrefs.getInt(USER_ID, -1); } public String getAvatarLink() { - return sharedPrefs.getString(AVATAR_LINK, AVATAR_LINK); + return sessionSharedPrefs.getString(AVATAR_LINK, AVATAR_LINK); } public Cookie getThmmyCookie() { @@ -288,7 +288,7 @@ public class SessionManager { } public String getMarkAllAsReadLink() { - String markAsReadLink = sharedPrefs.getString(MARK_ALL_AS_READ_LINK, null); + String markAsReadLink = sessionSharedPrefs.getString(MARK_ALL_AS_READ_LINK, null); if(markAsReadLink == null){ //For older versions, extract it from logout link (otherwise user would have to login again) String sesc = extractSescFromLink(getLogoutLink()); if(sesc!=null) { @@ -302,38 +302,38 @@ public class SessionManager { } private String getLogoutLink() { - return sharedPrefs.getString(LOGOUT_LINK, null); + return sessionSharedPrefs.getString(LOGOUT_LINK, null); } public boolean hasAvatar() { - return sharedPrefs.getBoolean(HAS_AVATAR, false); + return sessionSharedPrefs.getBoolean(HAS_AVATAR, false); } public boolean isLoggedIn() { - return sharedPrefs.getBoolean(LOGGED_IN, false); + return sessionSharedPrefs.getBoolean(LOGGED_IN, false); } public boolean isLoginScreenDefault() { - return sharedPrefs.getBoolean(LOGIN_SCREEN_AS_DEFAULT, true); + return sessionSharedPrefs.getBoolean(LOGIN_SCREEN_AS_DEFAULT, true); } //--------------------------------------GETTERS END--------------------------------------------- //---------------------------------------SETTERS------------------------------------------------ private void setSesc(String sesc){ - SharedPreferences.Editor editor = sharedPrefs.edit(); + SharedPreferences.Editor editor = sessionSharedPrefs.edit(); editor.putString(SESC, sesc); editor.apply(); } private void setMarkAsReadLink(String markAllAsReadLink){ - SharedPreferences.Editor editor = sharedPrefs.edit(); + SharedPreferences.Editor editor = sessionSharedPrefs.edit(); editor.putString(MARK_ALL_AS_READ_LINK, markAllAsReadLink); editor.apply(); } private void setLogoutLink(String logoutLink){ - SharedPreferences.Editor editor = sharedPrefs.edit(); + SharedPreferences.Editor editor = sessionSharedPrefs.edit(); editor.putString(LOGOUT_LINK, logoutLink); editor.apply(); } @@ -367,7 +367,7 @@ public class SessionManager { } private void setLoginScreenAsDefault(boolean b){ - sharedPrefs.edit().putBoolean(LOGIN_SCREEN_AS_DEFAULT, b).apply(); + sessionSharedPrefs.edit().putBoolean(LOGIN_SCREEN_AS_DEFAULT, b).apply(); } @NonNull @@ -448,7 +448,7 @@ public class SessionManager { if (matcher.find()) return matcher.group(1); } - Timber.e(new ParseException("Parsing failed(extractSescFromLogoutLink)"),"ParseException"); + Timber.e(new ParseException("Parsing failed(extractSescFromLink)"),"ParseException"); return null; } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d1c69acb..f881b88d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -209,7 +209,7 @@ Analytics data reports Automatically send us anonymized data for analytical purposes - + Black Red Yellow @@ -229,8 +229,12 @@ Link text Required - + New topic Create topic Link copied + + + SessionSharedPrefs + From 5cc2e503f0f7879359b4aabe4a77eefc9ab0df4c Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 27 Jun 2020 18:54:49 +0300 Subject: [PATCH 15/21] SessionManager, mark unread & logout improvements --- .../main/unread/UnreadFragment.java | 87 ++------ .../gr/thmmy/mthmmy/base/BaseActivity.java | 71 +++---- .../gr/thmmy/mthmmy/base/BaseApplication.java | 1 - .../gr/thmmy/mthmmy/session/LogoutTask.java | 86 ++++++++ .../thmmy/mthmmy/session/MarkAsReadTask.java | 65 ++++++ .../thmmy/mthmmy/session/SessionManager.java | 196 ++---------------- .../mthmmy/session/ValidateSessionTask.java | 18 -- .../mthmmy/utils/networking/NetworkTask.java | 25 ++- 8 files changed, 235 insertions(+), 314 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/session/LogoutTask.java create mode 100644 app/src/main/java/gr/thmmy/mthmmy/session/MarkAsReadTask.java delete mode 100644 app/src/main/java/gr/thmmy/mthmmy/session/ValidateSessionTask.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index a8ba7f10..124c35c4 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -26,19 +26,17 @@ import java.util.ArrayList; import java.util.List; import gr.thmmy.mthmmy.R; -import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseFragment; import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.session.InvalidSessionException; +import gr.thmmy.mthmmy.session.MarkAsReadTask; import gr.thmmy.mthmmy.session.SessionManager; -import gr.thmmy.mthmmy.session.ValidateSessionTask; import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; import gr.thmmy.mthmmy.utils.parsing.NewParseTask; import gr.thmmy.mthmmy.utils.parsing.ParseException; import gr.thmmy.mthmmy.views.CustomRecyclerView; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import okhttp3.Response; -import timber.log.Timber; /** * A {@link BaseFragment} subclass. @@ -60,13 +58,11 @@ public class UnreadFragment extends BaseFragment { private UnreadAdapter unreadAdapter; private List topicSummaries; - private String markAsReadUrl; private int numberOfPages = 0; private int loadedPages = 0; private UnreadTask unreadTask; - private MarkReadTask markReadTask; - private ValidateSessionTask validateSessionTask; + private MarkAsReadTask markAsReadTask; // Required empty public constructor public UnreadFragment() {} @@ -90,11 +86,6 @@ public class UnreadFragment extends BaseFragment { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); topicSummaries = new ArrayList<>(); - markAsReadUrl = BaseApplication.getInstance().getSessionManager().getMarkAllAsReadLink(); - if(markAsReadUrl==null){ - Timber.i("MarkAsRead URL is null."); - startValidateSessionTask(); - } } @Override @@ -105,7 +96,7 @@ public class UnreadFragment extends BaseFragment { assert SessionManager.unreadUrl != null; unreadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.unreadUrl.toString()); } - markReadTask = new MarkReadTask(this::onMarkReadTaskStarted, this::onMarkReadTaskFinished); + markAsReadTask = new MarkAsReadTask(UnreadFragment.this::onMarkAsReadTaskStarted, UnreadFragment.this::onMarkAsReadTaskFinished); } @@ -146,17 +137,10 @@ public class UnreadFragment extends BaseFragment { public void onDestroy() { super.onDestroy(); cancelUnreadTaskIfRunning(); - if (markReadTask!=null){ - try{ - if(markReadTask.isRunning()) - markReadTask.cancel(true); - } // Yes, it happens even though we checked - catch (NullPointerException ignored){ } - } - if (validateSessionTask!=null){ + if (markAsReadTask !=null){ try{ - if(validateSessionTask.isRunning()) - validateSessionTask.cancel(true); + if(markAsReadTask.isRunning()) + markAsReadTask.cancel(true); } // Yes, it happens even though we checked catch (NullPointerException ignored){ } } @@ -179,11 +163,6 @@ public class UnreadFragment extends BaseFragment { } } - private void startValidateSessionTask(){ - validateSessionTask = new ValidateSessionTask(); - validateSessionTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - } - private void cancelUnreadTaskIfRunning(){ if (unreadTask!=null){ try{ @@ -215,9 +194,9 @@ public class UnreadFragment extends BaseFragment { builder.setTitle("Mark all as read"); builder.setMessage("Are you sure that you want to mark ALL topics as read?"); builder.setPositiveButton("Yep", (dialogInterface, i) -> { - if (!markReadTask.isRunning() && markAsReadUrl!=null){ - markReadTask = new MarkReadTask(this::onMarkReadTaskStarted, this::onMarkReadTaskFinished); - markReadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, markAsReadUrl); + if (!markAsReadTask.isRunning()){ + markAsReadTask = new MarkAsReadTask(this::onMarkAsReadTaskStarted, this::onMarkAsReadTaskFinished); + markAsReadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } }); builder.setNegativeButton("Nope", (dialogInterface, i) -> {}); @@ -304,12 +283,10 @@ public class UnreadFragment extends BaseFragment { } Element topBar = document.select("table:not(.bordercolor):not(#bodyarea):has(td.middletext)").first(); - Element pagesElement = null, markRead = null; - if (topBar != null) { + Element pagesElement = null; + if (topBar != null) pagesElement = topBar.select("td.middletext").first(); - markRead = document.select("table:not(.bordercolor):not([width])").select("a") - .first(); - } + if (numberOfPages == 0 && pagesElement != null) { Elements pages = pagesElement.select("a"); @@ -319,14 +296,6 @@ public class UnreadFragment extends BaseFragment { numberOfPages = 1; } - if (markRead != null && loadedPages == numberOfPages - 1){ - String retrievedMarkAsReadUrl = markRead.attr("href"); - if(!retrievedMarkAsReadUrl.equals(markAsReadUrl)) { - markAsReadUrl = retrievedMarkAsReadUrl; - BaseApplication.getInstance().getSessionManager().refreshSescFromUrl(retrievedMarkAsReadUrl); - } - } - return fetchedTopicSummaries; } return new ArrayList<>(); @@ -338,13 +307,13 @@ public class UnreadFragment extends BaseFragment { } } - //---------------------------------------MARKREAD TASK------------------------------------------ - private void onMarkReadTaskStarted() { + //---------------------------------------MARK AS READ TASK------------------------------------------ + private void onMarkAsReadTaskStarted() { cancelUnreadTaskIfRunning(); progressBar.setVisibility(ProgressBar.VISIBLE); } - private void onMarkReadTaskFinished(int resultCode, Void isSessionVerified) { + private void onMarkAsReadTaskFinished(int resultCode, Void v) { hideProgressUI(); if (resultCode == NetworkResultCodes.SUCCESSFUL) startUnreadTask(); @@ -352,35 +321,11 @@ public class UnreadFragment extends BaseFragment { hideProgressUI(); if (resultCode == NetworkResultCodes.NETWORK_ERROR) Toast.makeText(getContext(), "Network error", Toast.LENGTH_SHORT).show(); - else if (resultCode == SessionManager.INVALID_SESSION){ + else if (resultCode == SessionManager.INVALID_SESSION) Toast.makeText(getContext(), "Session verification failed. Please try logging out and back in again", Toast.LENGTH_LONG).show(); - startValidateSessionTask(); - } else Toast.makeText(getContext(), "Unexpected error," + " please contact the developers with the details", Toast.LENGTH_LONG).show(); } } - - private class MarkReadTask extends NewParseTask { - MarkReadTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onParseTaskFinishedListener) { - super(onTaskStartedListener, onParseTaskFinishedListener); - } - - @Override - protected Void parse(Document document, Response response) throws ParseException { - Elements sessionVerificationFailed = document.select("td:containsOwn(Session " + - "verification failed. Please try logging out and back in again, and then try " + - "again.), td:containsOwn(Η επαλήθευση συνόδου απέτυχε. Παρακαλούμε κάντε " + - "αποσύνδεση, επανασύνδεση και ξαναδοκιμάστε.)"); - if(!sessionVerificationFailed.isEmpty()) - throw new InvalidSessionException(); - return null; - } - - @Override - protected int getResultCode(Response response, Void v) { - return NetworkResultCodes.SUCCESSFUL; - } - } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index defaa6d3..6c571129 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -62,9 +62,11 @@ import gr.thmmy.mthmmy.model.Bookmark; import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.services.DownloadHelper; import gr.thmmy.mthmmy.services.UploadsReceiver; +import gr.thmmy.mthmmy.session.LogoutTask; import gr.thmmy.mthmmy.session.SessionManager; import gr.thmmy.mthmmy.utils.FileUtils; import gr.thmmy.mthmmy.utils.io.AssetUtils; +import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; import gr.thmmy.mthmmy.viewmodel.BaseViewModel; import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import okhttp3.OkHttpClient; @@ -82,7 +84,6 @@ import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_ import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DEFAULT_HOME_TAB; import static gr.thmmy.mthmmy.services.DownloadHelper.SAVE_DIR; import static gr.thmmy.mthmmy.services.UploadsReceiver.UPLOAD_ID_KEY; -import static gr.thmmy.mthmmy.session.SessionManager.SUCCESS; import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType; public abstract class BaseActivity extends AppCompatActivity { @@ -497,47 +498,35 @@ public abstract class BaseActivity extends AppCompatActivity { } //-------------------------------------------LOGOUT------------------------------------------------- - - /** - * Result toast will always display a success, because when user chooses logout all data are - * cleared regardless of the actual outcome - */ - private class LogoutTask extends AsyncTask { //Attempt logout - ProgressDialog progressDialog; - - protected Integer doInBackground(Void... voids) { - return sessionManager.logout(); - } - - protected void onPreExecute() { //Show a progress dialog until done - progressDialog = new ProgressDialog(BaseActivity.this, - R.style.AppTheme_Dark_Dialog); - progressDialog.setCancelable(false); - progressDialog.setIndeterminate(true); - progressDialog.setMessage("Logging out..."); - progressDialog.show(); - } - - protected void onPostExecute(Integer result) { - if (result == SUCCESS) { - SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); - if (sharedPrefs.getString(DEFAULT_HOME_TAB, "0").equals("2")) { - SharedPreferences.Editor editor = sharedPrefs.edit(); - editor.putString(DEFAULT_HOME_TAB, "0").apply(); - } + private ProgressDialog progressDialog; + private void onLogoutTaskStarted() { + progressDialog = new ProgressDialog(BaseActivity.this, + R.style.AppTheme_Dark_Dialog); + progressDialog.setCancelable(false); + progressDialog.setIndeterminate(true); + progressDialog.setMessage("Logging out..."); + progressDialog.show(); + } + + private void onLogoutTaskFinished(int resultCode, Void v) { + if (resultCode == NetworkResultCodes.SUCCESSFUL) { + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); + if (sharedPrefs.getString(DEFAULT_HOME_TAB, "0").equals("2")) { + SharedPreferences.Editor editor = sharedPrefs.edit(); + editor.putString(DEFAULT_HOME_TAB, "0").apply(); } - - updateDrawer(); - if (mainActivity != null) - mainActivity.updateTabs(); - progressDialog.dismiss(); - //TODO: Redirect to Main only for some Activities (e.g. Topic, Board, Downloads) - //if (BaseActivity.this instanceof TopicActivity){ - Intent intent = new Intent(BaseActivity.this, MainActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - //} } + + updateDrawer(); + if (mainActivity != null) + mainActivity.updateTabs(); + progressDialog.dismiss(); + //TODO: Redirect to Main only for some Activities (e.g. Topic, Board, Downloads) + //if (BaseActivity.this instanceof TopicActivity){ + Intent intent = new Intent(BaseActivity.this, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + startActivity(intent); + //} } private void showLogoutDialog() { @@ -545,7 +534,7 @@ public abstract class BaseActivity extends AppCompatActivity { builder.setTitle("Logout"); builder.setMessage("Are you sure that you want to logout?"); builder.setPositiveButton("Yep", (dialogInterface, i) -> { - new LogoutTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); //Avoid delays between onPreExecute() and doInBackground() + new LogoutTask(this::onLogoutTaskStarted, this::onLogoutTaskFinished).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); //Avoid delays between onPreExecute() and doInBackground() }); builder.setNegativeButton("Nope", (dialogInterface, i) -> {}); builder.create().show(); 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 390faf5c..dea0808b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -128,7 +128,6 @@ public class BaseApplication extends MultiDexApplication { } private void initOkHttp(PersistentCookieJar cookieJar){ - OkHttpClient.Builder builder = new OkHttpClient.Builder() .cookieJar(cookieJar) .addInterceptor(chain -> { diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/LogoutTask.java b/app/src/main/java/gr/thmmy/mthmmy/session/LogoutTask.java new file mode 100644 index 00000000..66333739 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/session/LogoutTask.java @@ -0,0 +1,86 @@ +package gr.thmmy.mthmmy.session; + +import org.jsoup.nodes.Document; +import org.jsoup.select.Elements; + +import gr.thmmy.mthmmy.base.BaseApplication; +import gr.thmmy.mthmmy.utils.Parcel; +import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.networking.NetworkTask; +import gr.thmmy.mthmmy.utils.parsing.ParseException; +import okhttp3.Response; +import timber.log.Timber; + +import static gr.thmmy.mthmmy.session.SessionManager.baseLogoutLink; +import static gr.thmmy.mthmmy.session.SessionManager.indexUrl; + + +public class LogoutTask extends NetworkTask { + private String logoutLink; + + public LogoutTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onParseTaskFinishedListener) { + super(onTaskStartedListener, onParseTaskFinishedListener); + } + + @Override + protected Parcel doInBackground(String... input) { + /* Firstly we will find the logout link + Keep in mind, server changes sesc at will over time for a given session! + */ + Parcel parcel = executeInBackground(indexUrl.toString()); + if(parcel.getResultCode() == NetworkResultCodes.SUCCESSFUL) + return executeInBackground(logoutLink); // Now we will attempt to logout + else return parcel; + } + + @Override + protected Void performTask(Document document, Response response) { + try { + if(logoutLink==null) + logoutLink = extractLogoutLink(document); + else { // Just for logging purposes + Elements sessionVerificationFailed = document.select("td:containsOwn(Session " + + "verification failed. Please try logging out and back in again, and then try " + + "again.), td:containsOwn(Η επαλήθευση συνόδου απέτυχε. Παρακαλούμε κάντε " + + "αποσύνδεση, επανασύνδεση και ξαναδοκιμάστε.)"); + if(!sessionVerificationFailed.isEmpty()){ + Timber.i("Logout failed (invalid session)"); + throw new InvalidSessionException(); + } + Elements loginButton = document.select("[value=Login]"); //Attempt to find login button + if (!loginButton.isEmpty()) //If login button exists, logout was successful + Timber.i("Logout successful!"); + else + Timber.i("Logout failed"); + } + } catch (InvalidSessionException ise) { + throw ise; + } catch (Exception e) { + throw new ParseException("Parsing failed", e); + } + return null; + } + + @Override + protected void onPostExecute(Parcel voidParcel) { + super.onPostExecute(voidParcel); + //All data should always be cleared from device regardless the result of logout + BaseApplication.getInstance().getSessionManager().logoutCleanup(); + } + + @Override + protected int getResultCode(Response response, Void v) { + return NetworkResultCodes.SUCCESSFUL; + } + + private String extractLogoutLink(Document document){ + Elements logoutLink = document.select("a[href^=" + baseLogoutLink + "]"); + + if (!logoutLink.isEmpty()) { + String link = logoutLink.first().attr("href"); + if (link != null && !link.isEmpty()) + return link; + } + throw new ParseException("Parsing failed (logoutLink extraction)"); + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/MarkAsReadTask.java b/app/src/main/java/gr/thmmy/mthmmy/session/MarkAsReadTask.java new file mode 100644 index 00000000..684f87ba --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/session/MarkAsReadTask.java @@ -0,0 +1,65 @@ +package gr.thmmy.mthmmy.session; + +import org.jsoup.nodes.Document; +import org.jsoup.select.Elements; + +import gr.thmmy.mthmmy.utils.Parcel; +import gr.thmmy.mthmmy.utils.networking.NetworkResultCodes; +import gr.thmmy.mthmmy.utils.networking.NetworkTask; +import gr.thmmy.mthmmy.utils.parsing.ParseException; +import okhttp3.Response; + +import static gr.thmmy.mthmmy.session.SessionManager.baseMarkAllAsReadLink; +import static gr.thmmy.mthmmy.session.SessionManager.unreadUrl; + +public class MarkAsReadTask extends NetworkTask { + private String markAsReadLink; + + public MarkAsReadTask(OnTaskStartedListener onTaskStartedListener, OnNetworkTaskFinishedListener onParseTaskFinishedListener) { + super(onTaskStartedListener, onParseTaskFinishedListener); + } + + @Override + protected Parcel doInBackground(String... input) { + Parcel parcel = executeInBackground(unreadUrl.toString()); + if(parcel.getResultCode() == NetworkResultCodes.SUCCESSFUL) + return executeInBackground(markAsReadLink); + else return parcel; + } + + @Override + protected Void performTask(Document document, Response response) { + try { + Elements sessionVerificationFailed = document.select("td:containsOwn(Session " + + "verification failed. Please try logging out and back in again, and then try " + + "again.), td:containsOwn(Η επαλήθευση συνόδου απέτυχε. Παρακαλούμε κάντε " + + "αποσύνδεση, επανασύνδεση και ξαναδοκιμάστε.)"); + if(!sessionVerificationFailed.isEmpty()) + throw new InvalidSessionException(); + if(markAsReadLink==null) + markAsReadLink = extractMarkAsReadLink(document); + + } catch (InvalidSessionException ise) { + throw ise; + } catch (Exception e) { + throw new ParseException("Parsing failed", e); + } + return null; + } + + @Override + protected int getResultCode(Response response, Void v) { + return NetworkResultCodes.SUCCESSFUL; + } + + private String extractMarkAsReadLink(Document document){ + Elements markAllAsReadLink = document.select("a[href^=" + baseMarkAllAsReadLink + "]"); + + if (!markAllAsReadLink.isEmpty()) { + String link = markAllAsReadLink.first().attr("href"); + if (link != null && !link.isEmpty()) + return link; + } + throw new ParseException("Parsing failed (markAllAsReadLink extraction)"); + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java index 2c5cc42b..fff30acf 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java +++ b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java @@ -39,8 +39,8 @@ public class SessionManager { private static final HttpUrl loginUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=login2"); public static final HttpUrl unreadUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=unread;all;start=0;theme=4"); public static final HttpUrl shoutboxUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=tpmod;sa=shoutbox;theme=4"); - private static final String baseLogoutLink = "https://www.thmmy.gr/smf/index.php?action=logout;sesc="; - private static final String baseMarkAllAsReadLink = "https://www.thmmy.gr/smf/index.php?action=markasread;sa=all;sesc="; + static final String baseLogoutLink = "https://www.thmmy.gr/smf/index.php?action=logout;sesc="; + static final String baseMarkAllAsReadLink = "https://www.thmmy.gr/smf/index.php?action=markasread;sa=all;sesc="; private static final String guestName = "Guest"; //Response Codes - make sure they do not overlap with NetworkResultCodes, just in case @@ -66,9 +66,6 @@ public class SessionManager { private static final String USER_ID = "UserID"; private static final String AVATAR_LINK = "AvatarLink"; private static final String HAS_AVATAR = "HasAvatar"; - private static final String SESC = "Sesc"; - private static final String LOGOUT_LINK = "LogoutLink"; - private static final String MARK_ALL_AS_READ_LINK = "MarkAllAsReadLink"; private static final String LOGGED_IN = "LoggedIn"; private static final String LOGIN_SCREEN_AS_DEFAULT = "LoginScreenAsDefault"; @@ -82,37 +79,29 @@ public class SessionManager { this.draftsPrefs = draftsPrefs; } - //------------------------------------AUTH BEGINS---------------------------------------------- + //------------------------------------ AUTH ---------------------------------------------- /** * Login function with two options: (username, password) or nothing (using saved cookies). * Always call it in a separate thread. */ - public int login(String... strings) { + public int login(String username, String password) { Timber.d("Logging in..."); //Build the login request for each case Request request; - if (strings.length == 2) { - clearSessionData(); - - String loginName = strings[0]; - String password = strings[1]; - - RequestBody formBody = new FormBody.Builder() - .add("user", loginName) - .add("passwrd", password) - .add("cookielength", "-1") //-1 is forever - .build(); - request = new Request.Builder() - .url(loginUrl) - .post(formBody) - .build(); - } else { - request = new Request.Builder() - .url(loginUrl) - .build(); - } + clearSessionData(); + + RequestBody formBody = new FormBody.Builder() + .add("user", username) + .add("passwrd", password) + .add("cookielength", "-1") //-1 is forever + .build(); + request = new Request.Builder() + .url(loginUrl) + .post(formBody) + .build(); + try { //Make request & handle response @@ -133,10 +122,6 @@ public class SessionManager { if (avatar != null) editor.putString(AVATAR_LINK, avatar); editor.putBoolean(HAS_AVATAR, avatar != null); - String sesc = extractSesc(document); - editor.putString(SESC, sesc); - editor.putString(LOGOUT_LINK, generateLogoutLink(sesc)); - editor.putString(MARK_ALL_AS_READ_LINK, generateMarkAllAsReadLink(sesc)); editor.apply(); return SUCCESS; @@ -179,29 +164,6 @@ public class SessionManager { } } - /** - * A function that checks the validity of the current saved session (if it exists). - * If isLoggedIn() is true, it will call login() with cookies. On failure, this can only return - * the code FAILURE. CANCELLED, CONNECTION_ERROR and EXCEPTION are simply considered a SUCCESS - * (e.g. no internet connection), at least until a more thorough handling of different - * exceptions is implemented (if considered mandatory). - * Always call it in a separate thread in a way that won't hinder performance (e.g. after - * fragments' data are retrieved). - */ - void validateSession() { - Timber.i("Validating session..."); - if (isLoggedIn()) { - Timber.i("Refreshing session..."); - int loginResult = login(); - if (loginResult != FAILURE) - return; - } else if (isLoginScreenDefault()) - return; - - setLoginScreenAsDefault(true); - clearSessionData(); - } - /** * Call this function when user explicitly chooses to continue as a guest (UI thread). */ @@ -211,41 +173,12 @@ public class SessionManager { setLoginScreenAsDefault(false); } - /** - * Logout function. Always call it in a separate thread. - */ - public int logout() { - Timber.i("Logging out..."); - try { - Request request = new Request.Builder() - .url(getLogoutLink()) - .build(); - //Make request & handle response - Response response = client.newCall(request).execute(); - Document document = Jsoup.parse(response.body().string()); - - Elements loginButton = document.select("[value=Login]"); //Attempt to find login button - if (!loginButton.isEmpty()){ //If login button exists, logout was successful - Timber.i("Logout successful!"); - return SUCCESS; - } else { - Timber.i("Logout failed."); - return FAILURE; - } - } catch (IOException e) { - Timber.w(e, "Logout IOException"); - return CONNECTION_ERROR; - } catch (Exception e) { - Timber.e(e, "Logout Exception"); - return EXCEPTION; - } finally { - //All data should always be cleared from device regardless the result of logout - clearSessionData(); - guestLogin(); - } + void logoutCleanup() { + clearSessionData(); + guestLogin(); } - public void clearSessionData() { + private void clearSessionData() { cookieJar.clear(); sessionSharedPrefs.edit().clear().apply(); //Clear session data sessionSharedPrefs.edit().putString(USERNAME, guestName).apply(); @@ -255,17 +188,7 @@ public class SessionManager { Timber.i("Session data cleared."); } - public void refreshSescFromUrl(String url){ - String sesc = extractSescFromLink(url); - if(sesc!=null){ - setSesc(sesc); - setLogoutLink(generateLogoutLink(sesc)); - setMarkAsReadLink(sesc); - } - } - //--------------------------------------AUTH ENDS----------------------------------------------- - - //---------------------------------------GETTERS------------------------------------------------ + //--------------------------------------- GETTERS ------------------------------------------------ public String getUsername() { return sessionSharedPrefs.getString(USERNAME, USERNAME); } @@ -287,24 +210,6 @@ public class SessionManager { return null; } - public String getMarkAllAsReadLink() { - String markAsReadLink = sessionSharedPrefs.getString(MARK_ALL_AS_READ_LINK, null); - if(markAsReadLink == null){ //For older versions, extract it from logout link (otherwise user would have to login again) - String sesc = extractSescFromLink(getLogoutLink()); - if(sesc!=null) { - setSesc(sesc); - markAsReadLink = generateMarkAllAsReadLink(sesc); - setMarkAsReadLink(markAsReadLink); - return markAsReadLink; - } - } - return markAsReadLink; // Warning: it can be null - } - - private String getLogoutLink() { - return sessionSharedPrefs.getString(LOGOUT_LINK, null); - } - public boolean hasAvatar() { return sessionSharedPrefs.getBoolean(HAS_AVATAR, false); } @@ -317,34 +222,10 @@ public class SessionManager { return sessionSharedPrefs.getBoolean(LOGIN_SCREEN_AS_DEFAULT, true); } - //--------------------------------------GETTERS END--------------------------------------------- - - //---------------------------------------SETTERS------------------------------------------------ - private void setSesc(String sesc){ - SharedPreferences.Editor editor = sessionSharedPrefs.edit(); - editor.putString(SESC, sesc); - editor.apply(); - } - - private void setMarkAsReadLink(String markAllAsReadLink){ - SharedPreferences.Editor editor = sessionSharedPrefs.edit(); - editor.putString(MARK_ALL_AS_READ_LINK, markAllAsReadLink); - editor.apply(); - } - - private void setLogoutLink(String logoutLink){ - SharedPreferences.Editor editor = sessionSharedPrefs.edit(); - editor.putString(LOGOUT_LINK, logoutLink); - editor.apply(); - } - - //--------------------------------------SETTERS END--------------------------------------------- - - //------------------------------------OTHER FUNCTIONS------------------------------------------- + //------------------------------------ OTHER ------------------------------------------- private boolean validateRetrievedCookies() { List cookieList = cookieJar.loadForRequest(indexUrl); - for(Cookie cookie: cookieList) - { + for(Cookie cookie: cookieList) { if(cookie.name().equals("THMMYgrC00ki3")) return true; } @@ -363,7 +244,6 @@ public class SessionManager { cookieList.add(builder.build()); cookiePersistor.clear(); cookiePersistor.saveAll(cookieList); - } private void setLoginScreenAsDefault(boolean b){ @@ -430,34 +310,4 @@ public class SessionManager { Timber.i("Extracting avatar's link failed!"); return null; } - - private String extractSesc(@NonNull Document doc) { - Elements logoutLink = doc.select("a[href^=https://www.thmmy.gr/smf/index.php?action=logout;sesc=]"); - if (!logoutLink.isEmpty()) { - String link = logoutLink.first().attr("href"); - return extractSescFromLink(link); - } - Timber.e(new ParseException("Parsing failed(extractSesc)"),"ParseException"); - return null; - } - - private String extractSescFromLink(String link){ - if (link != null){ - Pattern pattern = Pattern.compile(".+;sesc=(\\w+)"); - Matcher matcher = pattern.matcher(link); - if (matcher.find()) - return matcher.group(1); - } - Timber.e(new ParseException("Parsing failed(extractSescFromLink)"),"ParseException"); - return null; - } - - private String generateLogoutLink(String sesc){ - return baseLogoutLink + sesc; - } - - private String generateMarkAllAsReadLink(String sesc){ - return baseMarkAllAsReadLink + sesc; - } - //----------------------------------OTHER FUNCTIONS END----------------------------------------- } \ No newline at end of file diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/ValidateSessionTask.java b/app/src/main/java/gr/thmmy/mthmmy/session/ValidateSessionTask.java deleted file mode 100644 index b5c1392f..00000000 --- a/app/src/main/java/gr/thmmy/mthmmy/session/ValidateSessionTask.java +++ /dev/null @@ -1,18 +0,0 @@ -package gr.thmmy.mthmmy.session; - -import android.os.AsyncTask; - -import gr.thmmy.mthmmy.base.BaseApplication; - - -public class ValidateSessionTask extends AsyncTask { - @Override - protected Void doInBackground(String... params) { - BaseApplication.getInstance().getSessionManager().validateSession(); - return null; - } - - public boolean isRunning(){ - return getStatus() == AsyncTask.Status.RUNNING; - } -} diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkTask.java b/app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkTask.java index a12d5757..0ba26dd3 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkTask.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkTask.java @@ -1,7 +1,8 @@ package gr.thmmy.mthmmy.utils.networking; import android.content.SharedPreferences; -import android.preference.PreferenceManager; + +import androidx.preference.PreferenceManager; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -38,7 +39,19 @@ public abstract class NetworkTask extends ExternalAsyncTask public NetworkTask() {} @Override - protected final Parcel doInBackground(String... input) { + protected Parcel doInBackground(String... input) { + return executeInBackground(input); + } + + @Override + protected void onPostExecute(Parcel tParcel) { + if (onNetworkTaskFinishedListener != null) + onNetworkTaskFinishedListener.onNetworkTaskFinished(tParcel.getResultCode(), tParcel.getData()); + else + super.onPostExecute(tParcel); + } + + protected Parcel executeInBackground(String... input) { Response response; try { response = sendRequest(BaseApplication.getInstance().getClient(), input); @@ -78,14 +91,6 @@ public abstract class NetworkTask extends ExternalAsyncTask } } - @Override - protected void onPostExecute(Parcel tParcel) { - if (onNetworkTaskFinishedListener != null) - onNetworkTaskFinishedListener.onNetworkTaskFinished(tParcel.getResultCode(), tParcel.getData()); - else - super.onPostExecute(tParcel); - } - protected Response sendRequest(OkHttpClient client, String... input) throws IOException { String url = input[0]; Request request = new Request.Builder() From 573751acf4d92bf0fe0757cc0b8a3d7746ad7f58 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 27 Jun 2020 19:36:25 +0300 Subject: [PATCH 16/21] UnreadFragment FAB tiny fix --- .../thmmy/mthmmy/activities/main/unread/UnreadFragment.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java index 124c35c4..661ed1be 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java @@ -92,10 +92,13 @@ public class UnreadFragment extends BaseFragment { public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (topicSummaries.isEmpty()){ + hideMarkAsReadFAB(); unreadTask = new UnreadTask(this::onUnreadTaskStarted, UnreadFragment.this::onUnreadTaskCancelled, this::onUnreadTaskFinished); assert SessionManager.unreadUrl != null; unreadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.unreadUrl.toString()); } + else + showMarkAsReadFAB(); markAsReadTask = new MarkAsReadTask(UnreadFragment.this::onMarkAsReadTaskStarted, UnreadFragment.this::onMarkAsReadTaskFinished); } @@ -129,7 +132,6 @@ public class UnreadFragment extends BaseFragment { this::startUnreadTask ); } - return rootView; } From e96d0bd7999ff25cb4739d658b170a49a3198edf Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 27 Jun 2020 20:11:52 +0300 Subject: [PATCH 17/21] Colors refactoring --- app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java | 8 ++++---- .../main/java/gr/thmmy/mthmmy/base/BaseApplication.java | 2 +- app/src/main/res/layout/activity_about.xml | 2 +- app/src/main/res/layout/activity_settings.xml | 2 +- app/src/main/res/layout/activity_upload.xml | 6 +++--- .../main/res/layout/activity_upload_fields_builder.xml | 2 +- .../res/layout/activity_upload_filename_info_popup.xml | 2 +- app/src/main/res/layout/download_prompt_dialog.xml | 2 +- app/src/main/res/layout/fragment_bookmarks.xml | 2 +- app/src/main/res/layout/fragment_forum_board_row.xml | 2 +- app/src/main/res/layout/fragment_forum_category_row.xml | 2 +- app/src/main/res/layout/fragment_recent_row.xml | 2 +- app/src/main/res/layout/fragment_unread_row.xml | 2 +- app/src/main/res/values/colors.xml | 7 ++++--- app/src/main/res/values/styles.xml | 6 +++--- 15 files changed, 25 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index 6c571129..d31b7993 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -206,7 +206,7 @@ public abstract class BaseActivity extends AppCompatActivity { */ protected void createDrawer() { final int primaryColor = ContextCompat.getColor(this, R.color.iron); - final int selectedPrimaryColor = ContextCompat.getColor(this, R.color.primary_dark); + final int selectedPrimaryColor = ContextCompat.getColor(this, R.color.primary_light); final int selectedSecondaryColor = ContextCompat.getColor(this, R.color.accent); PrimaryDrawerItem homeItem, bookmarksItem, settingsItem, aboutItem, shoutboxItem; @@ -361,7 +361,7 @@ public abstract class BaseActivity extends AppCompatActivity { .withActivity(this) .withCompactStyle(true) .withSelectionListEnabledForSingleProfile(false) - .withHeaderBackground(R.color.primary) + .withHeaderBackground(R.color.primary_dark) .withTextColor(getResources().getColor(R.color.iron)) .addProfiles(profileDrawerItem) .withOnAccountHeaderListener((view, profile, currentProfile) -> { @@ -390,7 +390,7 @@ public abstract class BaseActivity extends AppCompatActivity { .withActivity(this) .withToolbar(toolbar) .withDrawerWidthDp((int) BaseApplication.getInstance().getWidthInDp() / 2) - .withSliderBackgroundColor(ContextCompat.getColor(this, R.color.primary_light)) + .withSliderBackgroundColor(ContextCompat.getColor(this, R.color.primary_lighter)) .withAccountHeader(accountHeader) .withOnDrawerItemClickListener((view, position, drawerItem) -> { if (drawerItem.equals(HOME_ID)) { @@ -494,7 +494,7 @@ public abstract class BaseActivity extends AppCompatActivity { .icon(FontAwesome.Icon.faw_user) .paddingDp(10) .color(ContextCompat.getColor(this, R.color.iron)) - .backgroundColor(ContextCompat.getColor(this, R.color.primary_light))); + .backgroundColor(ContextCompat.getColor(this, R.color.primary_lighter))); } //-------------------------------------------LOGOUT------------------------------------------------- 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 dea0808b..49ff1c0e 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -183,7 +183,7 @@ public class BaseApplication extends MultiDexApplication { 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)); + .backgroundColor(ContextCompat.getColor(ctx, R.color.primary_lighter)); } return super.placeholder(ctx, tag); } diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index 87d99723..8bd337e9 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -28,7 +28,7 @@ android:id="@+id/scrollview" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@color/primary_light" + android:background="@color/primary_lighter" app:layout_behavior="@string/appbar_scrolling_view_behavior"> \ No newline at end of file diff --git a/app/src/main/res/layout/activity_upload.xml b/app/src/main/res/layout/activity_upload.xml index 2282efae..1760ff1f 100644 --- a/app/src/main/res/layout/activity_upload.xml +++ b/app/src/main/res/layout/activity_upload.xml @@ -28,7 +28,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="top|start" - android:background="@color/primary_light" + android:background="@color/primary_lighter" android:paddingStart="@dimen/activity_horizontal_margin" android:paddingEnd="@dimen/activity_horizontal_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior" @@ -37,7 +37,7 @@ @@ -46,7 +46,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="8dp" - android:background="@color/primary_light" + android:background="@color/primary_lighter" android:orientation="vertical"> diff --git a/app/src/main/res/layout/fragment_bookmarks.xml b/app/src/main/res/layout/fragment_bookmarks.xml index 8d1372c0..aa1bbaab 100644 --- a/app/src/main/res/layout/fragment_bookmarks.xml +++ b/app/src/main/res/layout/fragment_bookmarks.xml @@ -9,7 +9,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="top|start" - android:background="@color/primary_light" + android:background="@color/primary_lighter" android:scrollbars="none" app:layout_behavior="@string/appbar_scrolling_view_behavior"> diff --git a/app/src/main/res/layout/fragment_forum_board_row.xml b/app/src/main/res/layout/fragment_forum_board_row.xml index 871c5450..3f6eb4e6 100644 --- a/app/src/main/res/layout/fragment_forum_board_row.xml +++ b/app/src/main/res/layout/fragment_forum_board_row.xml @@ -2,7 +2,7 @@ + android:background="@color/primary_lighter"> #2B2B2B - #333333 - #3C3C3C - #494949 + #333333 + #3C3C3C + #494949 + #222222 #26A69A #E7E7E7 #757575 diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 1e092378..28fe1690 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -2,7 +2,7 @@ @@ -86,6 +86,6 @@ From 96f5821c9f366f927f7de1b4be3653385e552c50 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sat, 27 Jun 2020 20:41:19 +0300 Subject: [PATCH 18/21] Use a consistent guest avatar --- app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java | 6 +----- .../main/java/gr/thmmy/mthmmy/base/BaseApplication.java | 8 ++------ 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java index d31b7993..733e12b8 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java @@ -490,11 +490,7 @@ public abstract class BaseActivity extends AppCompatActivity { } private void setDefaultAvatar() { - profileDrawerItem.withIcon(new IconicsDrawable(this) - .icon(FontAwesome.Icon.faw_user) - .paddingDp(10) - .color(ContextCompat.getColor(this, R.color.iron)) - .backgroundColor(ContextCompat.getColor(this, R.color.primary_lighter))); + profileDrawerItem.withIcon(R.drawable.ic_default_user_avatar); } //-------------------------------------------LOGOUT------------------------------------------------- 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 49ff1c0e..131ae24b 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -179,12 +179,8 @@ public class BaseApplication extends MultiDexApplication { @Override public Drawable placeholder(Context ctx, String tag) { - if (DrawerImageLoader.Tags.PROFILE.name().equals(tag)) { - 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)); - } + if (DrawerImageLoader.Tags.PROFILE.name().equals(tag)) + return BaseApplication.getInstance().getResources().getDrawable(R.drawable.ic_default_user_avatar); return super.placeholder(ctx, tag); } }); From 06883907e4b78595b37003069a729bca0dd3a7be Mon Sep 17 00:00:00 2001 From: Ezerous Date: Sun, 5 Jul 2020 11:20:28 +0300 Subject: [PATCH 19/21] Globally enable cleartext traffic, as some avatars require it --- app/src/main/AndroidManifest.xml | 2 +- app/src/main/res/drawable/ic_default_user_avatar.xml | 2 +- app/src/main/res/xml/network_security_config.xml | 8 -------- 3 files changed, 2 insertions(+), 10 deletions(-) delete mode 100644 app/src/main/res/xml/network_security_config.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e36ad051..fa42ba6b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -19,7 +19,7 @@ android:label="@string/app_name" android:supportsRtl="true" android:requestLegacyExternalStorage="true" - android:networkSecurityConfig="@xml/network_security_config" + android:usesCleartextTraffic="true" android:theme="@style/AppTheme" tools:ignore="UnusedAttribute"> - + diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml deleted file mode 100644 index 13da65b7..00000000 --- a/app/src/main/res/xml/network_security_config.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - www.thmmy.gr - www.sciweavers.org - - From e94c0150a1aacc276f7aa260fd02c3fcb8c0fcd3 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Thu, 9 Jul 2020 21:44:02 +0300 Subject: [PATCH 20/21] Attachments parsing fix, up version --- app/build.gradle | 4 ++-- .../java/gr/thmmy/mthmmy/activities/board/BoardActivity.java | 2 +- .../java/gr/thmmy/mthmmy/activities/topic/TopicParser.java | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index da29d78f..62af4345 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { applicationId "gr.thmmy.mthmmy" minSdkVersion 19 targetSdkVersion 29 - versionCode 24 - versionName "1.8.1" + versionCode 25 + versionName "1.8.2" archivesBaseName = "mTHMMY-v$versionName" buildConfigField "String", "CURRENT_BRANCH", "\"" + getCurrentBranch() + "\"" buildConfigField "String", "COMMIT_HASH", "\"" + getCommitHash() + "\"" diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java index 9e297dcf..0623111f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java @@ -259,7 +259,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo // Purification for extreme edge cases String pSubjectConcat = subBoardCol.select("a").first().text(); - pLastPost = pLastPost.replaceAll(pSubjectConcat, ""); + pLastPost = pLastPost.replace(pSubjectConcat, ""); String pLastUser; matcher = pLastPostPattern.matcher(pLastPost); //Don't even try simply grabbing , user might be guest diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java index 1a7922ff..7f28e8dc 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java @@ -294,7 +294,7 @@ public class TopicParser { Timber.e(e, "Attached file malformed url"); break; } - String attachedFileName = tmpAttachedFileUrlAndName.text().substring(1); + String attachedFileName = tmpAttachedFileUrlAndName.wholeText().substring(1); //Gets file's info (size and download count) String postAttachmentsTextSbstr = postAttachmentsText.substring( @@ -366,7 +366,7 @@ public class TopicParser { Timber.e(e, "Attached file malformed url"); break; } - String attachedFileName = tmpAttachedFileUrlAndName.text().substring(1); + String attachedFileName = tmpAttachedFileUrlAndName.wholeText().substring(1); //Gets file's info (size and download count) String postAttachmentsTextSbstr = postAttachmentsText.substring( From 4b14151f8b840ca4da127e87be832351bc547d85 Mon Sep 17 00:00:00 2001 From: Ezerous Date: Mon, 20 Jul 2020 14:16:35 +0300 Subject: [PATCH 21/21] Small BaseApp & gradle fixes --- .gitignore | 1 + app/build.gradle | 13 +++++++------ app/src/main/AndroidManifest.xml | 1 + .../java/gr/thmmy/mthmmy/base/BaseApplication.java | 12 ++++++++++-- build.gradle | 2 +- emojis/build.gradle | 9 +-------- gradle/wrapper/gradle-wrapper.properties | 4 ++-- 7 files changed, 23 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 3f32039e..8b2da229 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ bin/ gen/ out/ output.json +output-metadata.json # Gradle files .gradle/ diff --git a/app/build.gradle b/app/build.gradle index 62af4345..603d2651 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,7 @@ android { buildToolsVersion = '29.0.3' defaultConfig { - vectorDrawables.useSupportLibrary = true + vectorDrawables.useSupportLibrary = true //TODO: Remove when minSdkVersion >= 21 applicationId "gr.thmmy.mthmmy" minSdkVersion 19 targetSdkVersion 29 @@ -25,13 +25,14 @@ 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 + multiDexEnabled true //TODO: Remove when minSdkVersion >= 21 def date = new Date().format('ddMMyy_HHmmss') archivesBaseName = archivesBaseName + "-$date" firebaseCrashlytics { @@ -77,7 +78,7 @@ tasks.whenTaskAdded { task -> dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation project(":emojis") - implementation 'androidx.appcompat:appcompat:1.2.0-rc01' + implementation 'androidx.appcompat:appcompat:1.3.0-alpha01' 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' @@ -88,9 +89,9 @@ dependencies { 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.3' - implementation 'com.google.firebase:firebase-crashlytics:17.0.1' - implementation 'com.google.firebase:firebase-messaging:20.2.0' + implementation 'com.google.firebase:firebase-analytics:17.4.4' + implementation 'com.google.firebase:firebase-crashlytics:17.1.1' + implementation 'com.google.firebase:firebase-messaging:20.2.3' 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 diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fa42ba6b..7c7ab811 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ + 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 131ae24b..feed7496 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java +++ b/app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java @@ -179,8 +179,16 @@ public class BaseApplication extends MultiDexApplication { @Override public Drawable placeholder(Context ctx, String tag) { - if (DrawerImageLoader.Tags.PROFILE.name().equals(tag)) - return BaseApplication.getInstance().getResources().getDrawable(R.drawable.ic_default_user_avatar); + 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 super.placeholder(ctx, tag); } }); diff --git a/build.gradle b/build.gradle index d966ef2f..72da44f0 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ buildscript { maven { url "https://jitpack.io" } } dependencies { - classpath 'com.android.tools.build:gradle:3.6.3' + classpath 'com.android.tools.build:gradle:4.0.1' classpath 'com.google.gms:google-services:4.3.3' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.1.1' classpath 'org.ajoberstar.grgit:grgit-core:3.1.1' // Also change in app/gradle/grgit.gradle diff --git a/emojis/build.gradle b/emojis/build.gradle index 6aef90cf..46608744 100644 --- a/emojis/build.gradle +++ b/emojis/build.gradle @@ -4,7 +4,6 @@ android { compileSdkVersion 29 buildToolsVersion "29.0.3" - defaultConfig { minSdkVersion 19 targetSdkVersion 29 @@ -20,10 +19,4 @@ android { proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } - -} - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'androidx.appcompat:appcompat:1.1.0' -} +} \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 669ee9b7..0e03b907 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sat May 09 21:06:12 EEST 2020 +#Mon Jul 20 13:59:13 EEST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip