Browse Source

Version 2.2.0

master v2.2.0
Ezerous 2 years ago
parent
commit
96614bc2ba
  1. 12
      CONTRIBUTING.md
  2. 6
      PRIVACY.md
  3. 8
      README.md
  4. 15
      app/build.gradle
  5. 4
      app/gradle/grgit.gradle
  6. 18
      app/src/main/AndroidManifest.xml
  7. 4
      app/src/main/assets/PRIVACY.md
  8. 2
      app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java
  9. 16
      app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java
  10. 11
      app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java
  11. 64
      app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java
  12. 14
      app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksActivity.java
  13. 3
      app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java
  14. 4
      app/src/main/java/gr/thmmy/mthmmy/activities/create_content/NewTopicTask.java
  15. 52
      app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java
  16. 17
      app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsAdapter.java
  17. 20
      app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java
  18. 10
      app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java
  19. 2
      app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java
  20. 6
      app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java
  21. 6
      app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java
  22. 8
      app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java
  23. 12
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java
  24. 5
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsFragment.java
  25. 31
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java
  26. 11
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java
  27. 4
      app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java
  28. 16
      app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java
  29. 8
      app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java
  30. 79
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java
  31. 43
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
  32. 4
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/EditTask.java
  33. 10
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForEditTask.java
  34. 10
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForReplyResult.java
  35. 18
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForReplyTask.java
  36. 6
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java
  37. 26
      app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java
  38. 2
      app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadFieldsBuilderActivity.java
  39. 5
      app/src/main/java/gr/thmmy/mthmmy/activities/upload/multipart/MultipartUploadTask.java
  40. 93
      app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java
  41. 43
      app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java
  42. 2
      app/src/main/java/gr/thmmy/mthmmy/base/BaseFragment.java
  43. 4
      app/src/main/java/gr/thmmy/mthmmy/model/Category.java
  44. 29
      app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java
  45. 4
      app/src/main/java/gr/thmmy/mthmmy/services/DownloadHelper.java
  46. 50
      app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java
  47. 6
      app/src/main/java/gr/thmmy/mthmmy/session/LogoutTask.java
  48. 6
      app/src/main/java/gr/thmmy/mthmmy/session/MarkAsReadTask.java
  49. 22
      app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java
  50. 4
      app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java
  51. 19
      app/src/main/java/gr/thmmy/mthmmy/utils/FileUtils.java
  52. 14
      app/src/main/java/gr/thmmy/mthmmy/utils/HTMLUtils.java
  53. 2
      app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkTask.java
  54. 244
      app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java
  55. 6
      app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java
  56. 4
      app/src/main/java/gr/thmmy/mthmmy/utils/ui/ImageDownloadDialogBuilder.java
  57. 4
      app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java
  58. 8
      app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java
  59. 4
      app/src/main/java/gr/thmmy/mthmmy/views/RelativeTimeTextView.java
  60. 33
      app/src/main/java/gr/thmmy/mthmmy/views/editorview/EditorView.java
  61. 52
      app/src/main/res/layout-v23/activity_topic_overflow_menu.xml
  62. 2
      app/src/main/res/layout/activity_bookmarks.xml
  63. 22
      app/src/main/res/layout/activity_downloads.xml
  64. 2
      app/src/main/res/layout/activity_login.xml
  65. 1
      app/src/main/res/layout/activity_topic.xml
  66. 10
      app/src/main/res/layout/activity_topic_overflow_menu.xml
  67. 2
      app/src/main/res/menu/downloads_menu.xml
  68. 2
      app/src/main/res/menu/shoutbox_menu.xml
  69. 6
      app/src/main/res/menu/topic_menu.xml
  70. 2
      app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  71. 2
      app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  72. 4
      app/src/main/res/values/ic_launcher_background.xml
  73. 11
      app/src/main/res/values/strings.xml
  74. 12
      app/src/main/res/xml-v26/app_preferences_user.xml
  75. 12
      app/src/main/res/xml/app_preferences_user.xml
  76. 8
      app/src/test/java/gr/thmmy/mthmmy/utils/DateTimeUtilsTest.java
  77. 12
      app/src/test/java/gr/thmmy/mthmmy/utils/UploadsCoursesJSONReadingTest.java
  78. 14
      app/src/test/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParserTest.java
  79. 26
      build.gradle
  80. 11
      emojis/build.gradle
  81. 3
      emojis/src/main/AndroidManifest.xml
  82. 4
      gradle/wrapper/gradle-wrapper.properties

12
CONTRIBUTING.md

@ -7,7 +7,7 @@ to contribute to mTHMMY in a way that is efficient for everyone.
**Important!** Instead of creating publicly viewable issues for suspected security **Important!** Instead of creating publicly viewable issues for suspected security
vulnerabilities, please report them in private to vulnerabilities, please report them in private to
[thmmynolife@gmail.com](mailto:thmmynolife@gmail.com). [contact@thmmy.gr](mailto:contact@thmmy.gr).
## I want to contribute! ## I want to contribute!
@ -18,7 +18,7 @@ There are many ways of contributing to mTHMMY:
- Submitting bugs and ideas to our [issue tracker][github-issues] - Submitting bugs and ideas to our [issue tracker][github-issues]
- Forking mTHMMY and submitting [pull requests](#pull-requests) - Forking mTHMMY and submitting [pull requests](#pull-requests)
- Joining our core team - Joining our core team
- Contacting us by email at [thmmynolife@gmail.com](mailto:thmmynolife@gmail.com) - Contacting us by email at [contact@thmmy.gr](mailto:contact@thmmy.gr)
## Issue tracker ## Issue tracker
@ -35,15 +35,15 @@ Pull requests with fixes and improvements to mTHMMY are most welcome. Any develo
follow the workflow below to make a pull request (PR): follow the workflow below to make a pull request (PR):
1. Fork the project into your personal space on Github 1. Fork the project into your personal space on Github
1. Create a feature branch, away from [develop](https://github.com/ThmmyNoLife/mTHMMY/tree/develop) 1. Create a feature branch, away from [develop](https://github.com/THMMYgr/mTHMMY/tree/develop)
1. Push the commit(s) to your fork 1. Push the commit(s) to your fork
1. Create a PR targeting [develop at mTHMMY](https://github.com/ThmmyNoLife/mTHMMY/tree/develop) 1. Create a PR targeting [develop at mTHMMY](https://github.com/THMMYgr/mTHMMY/tree/develop)
1. Fill the PR title describing the change you want to make 1. Fill the PR title describing the change you want to make
1. Fill the PR description with a brief motive for your change and the method you used to achieve it 1. Fill the PR description with a brief motive for your change and the method you used to achieve it
1. Submit the PR. 1. Submit the PR.
[google-play]: https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy [google-play]: https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy
[github-issues]: https://github.com/ThmmyNoLife/mTHMMY/issues [github-issues]: https://github.com/THMMYgr/mTHMMY/issues
[discord-server]: https://discord.gg/CVt3yrn [discord-server]: https://discord.gg/CVt3yrn
[sisyphus]: https://github.com/ThmmyNoLife/Sisyphus [sisyphus]: https://github.com/THMMYgr/Sisyphus
[firebase-console]: https://console.firebase.google.com/ [firebase-console]: https://console.firebase.google.com/

6
PRIVACY.md

@ -29,7 +29,7 @@ The use of each Firebase service is explained below:
### Firebase Cloud Messaging ### Firebase Cloud Messaging
* **Purpose**: This service is essential for the funcionality of the App. It uses anonymous push notification tokens in order to determine which devices to deliver the appropriate messages to. * **Purpose**: This service is essential for the functionality of the App. It uses anonymous push notification tokens in order to determine which devices to deliver the appropriate messages to.
* **Data collected**: Instance IDs. * **Data collected**: Instance IDs.
* **Consent**: You will be prompted to agree to the use of this service when you open the App for the first time. * **Consent**: You will be prompted to agree to the use of this service when you open the App for the first time.
* **Retention**: Firebase retains Instance IDs until we make an API call for deletion. After the call, data are removed from live and backup systems within 180 days. * **Retention**: Firebase retains Instance IDs until we make an API call for deletion. After the call, data are removed from live and backup systems within 180 days.
@ -69,8 +69,8 @@ mTHMMY may contain links to third-party websites. Any access to and use of such
## Policy Updates ## Policy Updates
We may update this Privacy Policy from time to time and, thus, you are advised to review it periodically. The most recent version of our Privacy Policy can be found at <https://github.com/ThmmyNoLife/mTHMMY/blob/develop/PRIVACY.md>. We may update this Privacy Policy from time to time and, thus, you are advised to review it periodically. The most recent version of our Privacy Policy can be found at <https://github.com/THMMYgr/mTHMMY/blob/develop/PRIVACY.md>.
## Contact Us ## Contact Us
If you have any questions about our Privacy Policy, please contact us at [thmmynolife@gmail.com](mailto:thmmynolife@gmail.com). If you have any questions about our Privacy Policy, please contact us at [contact@thmmy.gr](mailto:contact@thmmy.gr).

8
README.md

@ -1,9 +1,9 @@
# mTHMMY # mTHMMY
[![GitHub release](https://img.shields.io/github/release/ThmmyNoLife/mTHMMY.svg?color=orange)](https://github.com/ThmmyNoLife/mTHMMY/releases) [![GitHub release](https://img.shields.io/github/release/THMMYgr/mTHMMY.svg?color=orange)](https://github.com/THMMYgr/mTHMMY/releases)
[![API](https://img.shields.io/badge/API-21%2B-blue.svg?style=flat)](https://android-arsenal.com/api?level=21) [![API](https://img.shields.io/badge/API-21%2B-blue.svg?style=flat)](https://android-arsenal.com/api?level=21)
[![Discord Channel](https://img.shields.io/discord/252539000571559947?style=flat&color=738bd7&label=discord)][discord-server] [![Discord Channel](https://img.shields.io/discord/252539000571559947?style=flat&color=738bd7&label=discord)][discord-server]
![Last Commit](https://img.shields.io/github/last-commit/ThmmyNoLife/mTHMMY/develop.svg?style=flat) ![Last Commit](https://img.shields.io/github/last-commit/THMMYgr/mTHMMY/develop.svg?style=flat)
![mTHMMY logo](app/src/main/res/mipmap-xhdpi/ic_launcher_round.png) ![mTHMMY logo](app/src/main/res/mipmap-xhdpi/ic_launcher_round.png)
@ -11,7 +11,7 @@ A mobile app for [thmmy.gr](https://www.thmmy.gr).
## Requirements ## Requirements
mTHMMY can be installed on any smartphone with Android 5.0 Lollipop or newer. mTHMMY can be installed on any smartphone with Android 6.0 (M) or newer.
## Download ## Download
@ -29,7 +29,7 @@ Our Privacy Policy can be found [here](/PRIVACY.md).
## Contact ## Contact
Do not hesitate to contact us for any matter, either by sending an email to [thmmynolife@gmail.com](mailto:thmmynolife@gmail.com), or by joining our [Discord server][discord-server]. Do not hesitate to contact us for any matter, either by sending an email to [contact@thmmy.gr](mailto:contact@thmmy.gr), or by joining our [Discord server][discord-server].
**Legal attribution: Google Play and the Google Play logo are trademarks of Google Inc.* **Legal attribution: Google Play and the Google Play logo are trademarks of Google Inc.*

15
app/build.gradle

@ -7,15 +7,14 @@ apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics' apply plugin: 'com.google.firebase.crashlytics'
android { android {
compileSdkVersion 31 compileSdkVersion 33
buildToolsVersion = '30.0.2'
defaultConfig { defaultConfig {
applicationId "gr.thmmy.mthmmy" applicationId "gr.thmmy.mthmmy"
minSdkVersion 21 minSdkVersion 23
targetSdkVersion 30 targetSdkVersion 33
versionCode 31 versionCode 32
versionName "2.1.0" versionName "2.2.0"
archivesBaseName = "mTHMMY-v$versionName" archivesBaseName = "mTHMMY-v$versionName"
buildConfigField "String", "CURRENT_BRANCH", "\"" + getCurrentBranch() + "\"" buildConfigField "String", "CURRENT_BRANCH", "\"" + getCurrentBranch() + "\""
buildConfigField "String", "COMMIT_HASH", "\"" + getCommitHash() + "\"" buildConfigField "String", "COMMIT_HASH", "\"" + getCommitHash() + "\""
@ -45,6 +44,8 @@ android {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
} }
namespace 'gr.thmmy.mthmmy'
} }
def firebaseReleaseProjectId = "mthmmy-release-3aef0" def firebaseReleaseProjectId = "mthmmy-release-3aef0"
@ -92,7 +93,7 @@ dependencies {
implementation 'com.google.firebase:firebase-crashlytics' implementation 'com.google.firebase:firebase-crashlytics'
implementation 'com.google.firebase:firebase-messaging' implementation 'com.google.firebase:firebase-messaging'
implementation 'com.google.code.gson:gson:2.8.8' implementation 'com.google.code.gson:gson:2.8.8'
implementation 'com.snatik:storage:2.1.0' implementation 'com.snatik:storage:2.1.0' //TODO: Replace (e.g. with https://github.com/anggrayudi/SimpleStorage)
implementation 'com.squareup.okhttp3:okhttp:3.14.9' implementation 'com.squareup.okhttp3:okhttp:3.14.9'
implementation 'org.jsoup:jsoup:1.14.2' implementation 'org.jsoup:jsoup:1.14.2'
implementation 'joda-time:joda-time:2.10.10' implementation 'joda-time:joda-time:2.10.10'

4
app/gradle/grgit.gradle

@ -2,11 +2,11 @@ import org.ajoberstar.grgit.Grgit
buildscript { buildscript {
repositories { repositories {
jcenter() mavenCentral()
} }
dependencies { dependencies {
classpath 'org.ajoberstar.grgit:grgit-core:3.1.1' classpath 'org.ajoberstar.grgit:grgit-core:5.0.0'
} }
} }

18
app/src/main/AndroidManifest.xml

@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="gr.thmmy.mthmmy"
android:installLocation="auto"> android:installLocation="auto">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
@ -54,19 +54,21 @@
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" /> <category android:name="android.intent.category.BROWSABLE" />
<data android:host="@string/forum_host" />
<data <data
android:host="thmmy.gr" android:host="@string/forum_host"
android:scheme="http" /> android:scheme="http" />
<data <data
android:host="www.thmmy.gr" android:host="@string/forum_host"
android:scheme="http" />
<data
android:host="www.thmmy.gr"
android:scheme="https" /> android:scheme="https" />
<data android:host="@string/forum_host_simple" />
<data
android:host="@string/forum_host_simple"
android:scheme="http" />
<data <data
android:host="thmmy.gr" android:host="@string/forum_host_simple"
android:scheme="https" /> android:scheme="https" />
<data android:host="thmmy.gr" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity

4
app/src/main/assets/PRIVACY.md

@ -69,8 +69,8 @@ mTHMMY may contain links to third-party websites. Any access to and use of such
## Policy Updates ## Policy Updates
We may update this Privacy Policy from time to time and, thus, you are advised to review it periodically. The most recent version of our Privacy Policy can be found at <https://github.com/ThmmyNoLife/mTHMMY/blob/develop/PRIVACY.md>. We may update this Privacy Policy from time to time and, thus, you are advised to review it periodically. The most recent version of our Privacy Policy can be found at <https://github.com/THMMYgr/mTHMMY/blob/develop/PRIVACY.md>.
## Contact Us ## Contact Us
If you have any questions about our Privacy Policy, please contact us at [thmmynolife@gmail.com](mailto:thmmynolife@gmail.com). If you have any questions about our Privacy Policy, please contact us at [contact@thmmy.gr](mailto:contact@thmmy.gr).

2
app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java

@ -105,7 +105,7 @@ public class AboutActivity extends BaseActivity {
if (gitExists) { if (gitExists) {
versionTextView.setOnClickListener(view -> { versionTextView.setOnClickListener(view -> {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/ThmmyNoLife/mTHMMY/commit/" + BuildConfig.COMMIT_HASH)); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://github.com/THMMYgr/mTHMMY/commit/" + BuildConfig.COMMIT_HASH));
startActivity(intent); startActivity(intent);
}); });
} }

16
app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java

@ -1,5 +1,13 @@
package gr.thmmy.mthmmy.activities; package gr.thmmy.mthmmy.activities;
import static gr.thmmy.mthmmy.session.SessionManager.BANNED_USER;
import static gr.thmmy.mthmmy.session.SessionManager.CONNECTION_ERROR;
import static gr.thmmy.mthmmy.session.SessionManager.EXCEPTION;
import static gr.thmmy.mthmmy.session.SessionManager.FAILURE;
import static gr.thmmy.mthmmy.session.SessionManager.SUCCESS;
import static gr.thmmy.mthmmy.session.SessionManager.WRONG_PASSWORD;
import static gr.thmmy.mthmmy.session.SessionManager.WRONG_USER;
import android.content.Intent; import android.content.Intent;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Bundle; import android.os.Bundle;
@ -22,14 +30,6 @@ import gr.thmmy.mthmmy.activities.main.MainActivity;
import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.base.BaseActivity;
import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseApplication;
import static gr.thmmy.mthmmy.session.SessionManager.BANNED_USER;
import static gr.thmmy.mthmmy.session.SessionManager.CONNECTION_ERROR;
import static gr.thmmy.mthmmy.session.SessionManager.EXCEPTION;
import static gr.thmmy.mthmmy.session.SessionManager.FAILURE;
import static gr.thmmy.mthmmy.session.SessionManager.SUCCESS;
import static gr.thmmy.mthmmy.session.SessionManager.WRONG_PASSWORD;
import static gr.thmmy.mthmmy.session.SessionManager.WRONG_USER;
public class LoginActivity extends BaseActivity { public class LoginActivity extends BaseActivity {
//-----------------------------------------CLASS VARIABLES------------------------------------------ //-----------------------------------------CLASS VARIABLES------------------------------------------

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

@ -59,6 +59,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
private String boardUrl; private String boardUrl;
private String boardTitle; private String boardTitle;
private String boardId;
private String parsedTitle; private String parsedTitle;
private String newTopicUrl; private String newTopicUrl;
@ -88,6 +89,8 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
if (!tmpUrlSbstr.substring(tmpUrlSbstr.indexOf("board=")).contains(".")) if (!tmpUrlSbstr.substring(tmpUrlSbstr.indexOf("board=")).contains("."))
boardUrl = tmpUrlSbstr + ".0"; boardUrl = tmpUrlSbstr + ".0";
boardId = ThmmyPage.getBoardId(boardUrl);
//Initializes graphics //Initializes graphics
toolbar = findViewById(R.id.toolbar); toolbar = findViewById(R.id.toolbar);
if (boardTitle != null && !Objects.equals(boardTitle, "")) toolbar.setTitle(boardTitle); if (boardTitle != null && !Objects.equals(boardTitle, "")) toolbar.setTitle(boardTitle);
@ -98,7 +101,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
getSupportActionBar().setDisplayShowHomeEnabled(true); getSupportActionBar().setDisplayShowHomeEnabled(true);
} }
thisPageBookmark = new Bookmark(boardTitle, ThmmyPage.getBoardId(boardUrl), true); thisPageBookmark = new Bookmark(boardTitle, boardId, true);
if (boardTitle != null && !Objects.equals(boardTitle, "")) if (boardTitle != null && !Objects.equals(boardTitle, ""))
setBoardBookmark(findViewById(R.id.bookmark)); setBoardBookmark(findViewById(R.id.bookmark));
@ -303,7 +306,8 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
if (!parsingFailed) if (!parsingFailed)
tempSubBoards.add(new Board(pUrl, pTitle, pMods, pStats, pLastPost, pLastPostUrl)); tempSubBoards.add(new Board(pUrl, pTitle, pMods, pStats, pLastPost, pLastPostUrl));
else else
Timber.e("Parsing failed (pLastPost came with: \"%s\", subBoardColumns html was \"%s\")", pLastPost, subBoardColumns); Timber.e("Parsing failed for a subBoard in board %s (subBoardRow html was \"%s\")",
boardId, subBoardRow);
} }
} }
} }
@ -338,7 +342,8 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
pLastUser = matcher.group(2); pLastUser = matcher.group(2);
} }
else { else {
Timber.e("Parsing failed (pLastPost came with: \"%s\", topicColumns html was \"%s\")", pLastPost, topicColumns); Timber.e("Parsing failed for a topic in board %s (topicRow html was \"%s\")",
boardId, topicRow);
continue; continue;
} }

64
app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java

@ -1,9 +1,13 @@
package gr.thmmy.mthmmy.activities.board; package gr.thmmy.mthmmy.activities.board;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
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;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -23,11 +27,6 @@ import gr.thmmy.mthmmy.model.Board;
import gr.thmmy.mthmmy.model.Topic; import gr.thmmy.mthmmy.model.Topic;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
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;
/** /**
* {@link RecyclerView.Adapter} that can display a {@link gr.thmmy.mthmmy.model.Board}. * {@link RecyclerView.Adapter} that can display a {@link gr.thmmy.mthmmy.model.Board}.
*/ */
@ -104,7 +103,7 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent); context.startActivity(intent);
}); });
if (boardExpandableVisibility.get(subBoardViewHolder.getAdapterPosition())) { if (boardExpandableVisibility.get(subBoardViewHolder.getBindingAdapterPosition())) {
subBoardViewHolder.boardExpandable.setVisibility(View.VISIBLE); subBoardViewHolder.boardExpandable.setVisibility(View.VISIBLE);
subBoardViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_up_accent_24dp); subBoardViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_up_accent_24dp);
} }
@ -113,16 +112,19 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
subBoardViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp); subBoardViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp);
} }
subBoardViewHolder.showHideExpandable.setOnClickListener(view -> { subBoardViewHolder.showHideExpandable.setOnClickListener(view -> {
final boolean visible = boardExpandableVisibility.get(subBoardViewHolder.getAdapterPosition()); final int pos = subBoardViewHolder.getBindingAdapterPosition();
if (visible) { if (pos >=0 && pos < boardExpandableVisibility.size()){
subBoardViewHolder.boardExpandable.setVisibility(View.GONE); final boolean visible = boardExpandableVisibility.get(subBoardViewHolder.getBindingAdapterPosition());
subBoardViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp); if (visible) {
} subBoardViewHolder.boardExpandable.setVisibility(View.GONE);
else { subBoardViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp);
subBoardViewHolder.boardExpandable.setVisibility(View.VISIBLE); }
subBoardViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_up_accent_24dp); else {
subBoardViewHolder.boardExpandable.setVisibility(View.VISIBLE);
subBoardViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_up_accent_24dp);
}
boardExpandableVisibility.set(subBoardViewHolder.getBindingAdapterPosition(), !visible);
} }
boardExpandableVisibility.set(subBoardViewHolder.getAdapterPosition(), !visible);
}); });
subBoardViewHolder.boardTitle.setText(subBoard.getTitle()); subBoardViewHolder.boardTitle.setText(subBoard.getTitle());
String mods = subBoard.getMods(); String mods = subBoard.getMods();
@ -174,7 +176,7 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent); context.startActivity(intent);
}); });
if (topicExpandableVisibility.get(topicViewHolder.getAdapterPosition() - parsedSubBoards if (topicExpandableVisibility.get(topicViewHolder.getBindingAdapterPosition() - parsedSubBoards
.size())) { .size())) {
topicViewHolder.topicExpandable.setVisibility(View.VISIBLE); topicViewHolder.topicExpandable.setVisibility(View.VISIBLE);
topicViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_up_accent_24dp); topicViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_up_accent_24dp);
@ -184,27 +186,29 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
topicViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp); topicViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp);
} }
topicViewHolder.showHideExpandable.setOnClickListener(view -> { topicViewHolder.showHideExpandable.setOnClickListener(view -> {
final boolean visible = topicExpandableVisibility.get(topicViewHolder. final int pos = topicViewHolder.getBindingAdapterPosition() - parsedSubBoards.size();
getAdapterPosition() - parsedSubBoards.size()); if (pos >=0 && pos < topicExpandableVisibility.size()) {
if (visible) { final boolean visible = topicExpandableVisibility.get(topicViewHolder.
topicViewHolder.topicExpandable.setVisibility(View.GONE); getBindingAdapterPosition() - parsedSubBoards.size());
topicViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp); if (visible) {
topicViewHolder.topicExpandable.setVisibility(View.GONE);
topicViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp);
}
else {
topicViewHolder.topicExpandable.setVisibility(View.VISIBLE);
topicViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_up_accent_24dp);
}
topicExpandableVisibility.set(topicViewHolder.getBindingAdapterPosition() -
parsedSubBoards.size(), !visible);
} }
else {
topicViewHolder.topicExpandable.setVisibility(View.VISIBLE);
topicViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_up_accent_24dp);
}
topicExpandableVisibility.set(topicViewHolder.getAdapterPosition() -
parsedSubBoards.size(), !visible);
}); });
topicViewHolder.topicSubject.setTypeface(Typeface.createFromAsset(context.getAssets() topicViewHolder.topicSubject.setTypeface(Typeface.createFromAsset(context.getAssets()
, "fonts/fontawesome-webfont.ttf")); , "fonts/fontawesome-webfont.ttf"));
topicViewHolder.topicUnreadDot.setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/fontawesome-webfont.ttf")); topicViewHolder.topicUnreadDot.setTypeface(Typeface.createFromAsset(context.getAssets(), "fonts/fontawesome-webfont.ttf"));
if (topic.isUnread()) if (topic.isUnread())
topicViewHolder.topicUnreadDot.setVisibility(View.VISIBLE); topicViewHolder.topicUnreadDot.setVisibility(View.VISIBLE);
else { else
topicViewHolder.topicUnreadDot.setVisibility(View.GONE); topicViewHolder.topicUnreadDot.setVisibility(View.GONE);
}
String lockedSticky = topic.getSubject(); String lockedSticky = topic.getSubject();
if (topic.isLocked()) if (topic.isLocked())
lockedSticky += " " + context.getResources().getString(R.string.fa_lock); lockedSticky += " " + context.getResources().getString(R.string.fa_lock);

14
app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksActivity.java

@ -1,5 +1,10 @@
package gr.thmmy.mthmmy.activities.bookmarks; package gr.thmmy.mthmmy.activities.bookmarks;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
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;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.widget.Toast; import android.widget.Toast;
@ -23,14 +28,9 @@ import gr.thmmy.mthmmy.base.BaseActivity;
import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseApplication;
import gr.thmmy.mthmmy.model.Bookmark; import gr.thmmy.mthmmy.model.Bookmark;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
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;
public class BookmarksActivity extends BaseActivity { public class BookmarksActivity extends BaseActivity {
private static final String TOPIC_URL = "https://www.thmmy.gr/smf/index.php?topic="; private static final String TOPIC_URL = forumUrl + "index.php?topic=";
private static final String BOARD_URL = "https://www.thmmy.gr/smf/index.php?board="; private static final String BOARD_URL = forumUrl + "index.php?board=";
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {

3
app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java

@ -1,7 +1,6 @@
package gr.thmmy.mthmmy.activities.bookmarks; package gr.thmmy.mthmmy.activities.bookmarks;
import android.app.Activity; import android.app.Activity;
import android.content.Intent;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@ -18,8 +17,6 @@ import androidx.fragment.app.Fragment;
import java.util.ArrayList; import java.util.ArrayList;
import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.activities.LoginActivity;
import gr.thmmy.mthmmy.activities.board.BoardActivity;
import gr.thmmy.mthmmy.model.Bookmark; import gr.thmmy.mthmmy.model.Bookmark;
//TODO refactor using RecyclerView //TODO refactor using RecyclerView

4
app/src/main/java/gr/thmmy/mthmmy/activities/create_content/NewTopicTask.java

@ -1,5 +1,7 @@
package gr.thmmy.mthmmy.activities.create_content; package gr.thmmy.mthmmy.activities.create_content;
import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus;
import android.os.AsyncTask; import android.os.AsyncTask;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
@ -15,8 +17,6 @@ import okhttp3.RequestBody;
import okhttp3.Response; import okhttp3.Response;
import timber.log.Timber; import timber.log.Timber;
import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus;
public class NewTopicTask extends AsyncTask<String, Void, Boolean> { public class NewTopicTask extends AsyncTask<String, Void, Boolean> {
private NewTopicTaskCallbacks listener; private NewTopicTaskCallbacks listener;

52
app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java

@ -1,5 +1,7 @@
package gr.thmmy.mthmmy.activities.downloads; package gr.thmmy.mthmmy.activities.downloads;
import static gr.thmmy.mthmmy.activities.upload.UploadActivity.BUNDLE_UPLOAD_CATEGORY;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
@ -37,8 +39,6 @@ import okhttp3.Request;
import okhttp3.Response; import okhttp3.Response;
import timber.log.Timber; import timber.log.Timber;
import static gr.thmmy.mthmmy.activities.upload.UploadActivity.BUNDLE_UPLOAD_CATEGORY;
public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.OnLoadMoreListener { public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.OnLoadMoreListener {
/** /**
* The key to use when putting download's url String to {@link DownloadsActivity}'s Bundle. * The key to use when putting download's url String to {@link DownloadsActivity}'s Bundle.
@ -48,7 +48,7 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
* The key to use when putting download's title String to {@link DownloadsActivity}'s Bundle. * The key to use when putting download's title String to {@link DownloadsActivity}'s Bundle.
*/ */
public static final String BUNDLE_DOWNLOADS_TITLE = "DOWNLOADS_TITLE"; public static final String BUNDLE_DOWNLOADS_TITLE = "DOWNLOADS_TITLE";
private static final String downloadsIndexUrl = "https://www.thmmy.gr/smf/index.php?action=tpmod;dl;"; private static final String downloadsIndexUrl = forumUrl + "index.php?action=tpmod;dl;";
private String downloadsUrl; private String downloadsUrl;
private String downloadsNav; private String downloadsNav;
private String downloadsTitle; private String downloadsTitle;
@ -57,7 +57,7 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
private MaterialProgressBar progressBar; private MaterialProgressBar progressBar;
private RecyclerView recyclerView; private RecyclerView recyclerView;
private DownloadsAdapter downloadsAdapter; private DownloadsAdapter downloadsAdapter;
private FloatingActionButton uploadFAB; // private FloatingActionButton uploadFAB;
private ParseDownloadPageTask parseDownloadPageTask; private ParseDownloadPageTask parseDownloadPageTask;
private int numberOfPages = -1; private int numberOfPages = -1;
@ -124,9 +124,9 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
} }
}); });
uploadFAB = findViewById(R.id.upload_fab); // uploadFAB = findViewById(R.id.upload_fab);
uploadFAB.setEnabled(false); // uploadFAB.setEnabled(false);
uploadFAB.hide(); // uploadFAB.hide();
parseDownloadPageTask = new ParseDownloadPageTask(); parseDownloadPageTask = new ParseDownloadPageTask();
parseDownloadPageTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, downloadsUrl); parseDownloadPageTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, downloadsUrl);
@ -135,26 +135,26 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
// Inflates the menu; this adds items to the action bar if it is present. // Inflates the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.downloads_menu, menu); // getMenuInflater().inflate(R.menu.downloads_menu, menu);
super.onCreateOptionsMenu(menu); super.onCreateOptionsMenu(menu);
return true; return true;
} }
@Override // @Override
public boolean onOptionsItemSelected(MenuItem item) { // public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items // // Handle presses on the action bar items
switch (item.getItemId()) { // switch (item.getItemId()) {
case R.id.menu_upload: // case R.id.menu_upload:
Intent intent = new Intent(DownloadsActivity.this, UploadActivity.class); // Intent intent = new Intent(DownloadsActivity.this, UploadActivity.class);
Bundle extras = new Bundle(); // Bundle extras = new Bundle();
extras.putString(BUNDLE_UPLOAD_CATEGORY, downloadsNav); // extras.putString(BUNDLE_UPLOAD_CATEGORY, downloadsNav);
intent.putExtras(extras); // intent.putExtras(extras);
startActivity(intent); // startActivity(intent);
return true; // return true;
default: // default:
return super.onOptionsItemSelected(item); // return super.onOptionsItemSelected(item);
} // }
} // }
@Override @Override
public void onLoadMore() { public void onLoadMore() {
@ -210,7 +210,7 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
@Override @Override
protected void onPreExecute() { protected void onPreExecute() {
if (!isLoadingMore) progressBar.setVisibility(ProgressBar.VISIBLE); if (!isLoadingMore) progressBar.setVisibility(ProgressBar.VISIBLE);
if (uploadFAB.getVisibility() != View.GONE) uploadFAB.setEnabled(false); // if (uploadFAB.getVisibility() != View.GONE) uploadFAB.setEnabled(false);
} }
@Override @Override
@ -283,7 +283,7 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
parsedDownloads.add(download); parsedDownloads.add(download);
} }
} catch (Exception e) { } catch (Exception e) {
throw new ParseException("Parsing failed (DownloadsActivity)"); throw new ParseException("Parsing failed (DownloadsActivity) for url " + downloadsUrl);
} }
} }
@ -312,7 +312,7 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
toolbar.setTitle(downloadsTitle); toolbar.setTitle(downloadsTitle);
++pagesLoaded; ++pagesLoaded;
if (uploadFAB.getVisibility() != View.GONE) uploadFAB.setEnabled(true); // if (uploadFAB.getVisibility() != View.GONE) uploadFAB.setEnabled(true);
progressBar.setVisibility(ProgressBar.INVISIBLE); progressBar.setVisibility(ProgressBar.INVISIBLE);
downloadsAdapter.notifyDataSetChanged(); downloadsAdapter.notifyDataSetChanged();
isLoadingMore = false; isLoadingMore = false;

17
app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsAdapter.java

@ -1,9 +1,12 @@
package gr.thmmy.mthmmy.activities.downloads; package gr.thmmy.mthmmy.activities.downloads;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_TITLE;
import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_URL;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -25,10 +28,6 @@ import gr.thmmy.mthmmy.model.Download;
import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.model.ThmmyFile;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_TITLE;
import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_URL;
class DownloadsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { class DownloadsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int VIEW_TYPE_DOWNLOAD = 0; private final int VIEW_TYPE_DOWNLOAD = 0;
private final int VIEW_TYPE_LOADING = 1; private final int VIEW_TYPE_LOADING = 1;
@ -132,13 +131,7 @@ class DownloadsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
} }
}); });
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { downloadViewHolder.upperLinear.setBackgroundColor(context.getResources().getColor(R.color.background, null));
downloadViewHolder.upperLinear.setBackgroundColor(context.getResources().getColor(R.color.background, null));
}
else {
//noinspection deprecation
downloadViewHolder.upperLinear.setBackgroundColor(context.getResources().getColor(R.color.background));
}
downloadViewHolder.informationExpandable.setVisibility(View.VISIBLE); downloadViewHolder.informationExpandable.setVisibility(View.VISIBLE);
downloadViewHolder.informationExpandableBtn.setVisibility(View.GONE); downloadViewHolder.informationExpandableBtn.setVisibility(View.GONE);
downloadViewHolder.informationExpandableBtn.setEnabled(false); downloadViewHolder.informationExpandableBtn.setEnabled(false);

20
app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java

@ -1,5 +1,15 @@
package gr.thmmy.mthmmy.activities.main; package gr.thmmy.mthmmy.activities.main;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL;
import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_TITLE;
import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_TITLE;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.net.Uri; import android.net.Uri;
@ -37,16 +47,6 @@ import gr.thmmy.mthmmy.model.ThmmyPage;
import gr.thmmy.mthmmy.model.TopicSummary; import gr.thmmy.mthmmy.model.TopicSummary;
import timber.log.Timber; import timber.log.Timber;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL;
import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_TITLE;
import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_TITLE;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL;
public class MainActivity extends BaseActivity implements RecentFragment.RecentFragmentInteractionListener, ForumFragment.ForumFragmentInteractionListener, UnreadFragment.UnreadFragmentInteractionListener { public class MainActivity extends BaseActivity implements RecentFragment.RecentFragmentInteractionListener, ForumFragment.ForumFragmentInteractionListener, UnreadFragment.UnreadFragmentInteractionListener {
//-----------------------------------------CLASS VARIABLES------------------------------------------ //-----------------------------------------CLASS VARIABLES------------------------------------------

10
app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java

@ -9,6 +9,8 @@ import android.widget.ProgressBar;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
@ -87,14 +89,14 @@ public class ForumFragment extends BaseFragment {
} }
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onViewCreated(view, savedInstanceState);
if (categories.isEmpty()) { if (categories.isEmpty()) {
forumTask = new ForumTask(this::onForumTaskStarted, this::onForumTaskFinished); forumTask = new ForumTask(this::onForumTaskStarted, this::onForumTaskFinished);
forumTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); forumTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
Timber.d("onActivityCreated"); Timber.d("onViewCreated");
} }
@Override @Override
@ -197,7 +199,7 @@ public class ForumFragment extends BaseFragment {
//---------------------------------------ASYNC TASK----------------------------------- //---------------------------------------ASYNC TASK-----------------------------------
private class ForumTask extends NewParseTask<ArrayList<Category>> { private class ForumTask extends NewParseTask<ArrayList<Category>> {
private HttpUrl forumUrl = SessionManager.forumUrl; //may change upon collapse/expand private HttpUrl forumUrl = SessionManager.getForumUrl(); //may change upon collapse/expand
ForumTask(OnTaskStartedListener onTaskStartedListener, ForumTask(OnTaskStartedListener onTaskStartedListener,
OnNetworkTaskFinishedListener<ArrayList<Category>> onParseTaskFinishedListener) { OnNetworkTaskFinishedListener<ArrayList<Category>> onParseTaskFinishedListener) {

2
app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java

@ -47,7 +47,7 @@ class RecentAdapter extends RecyclerView.Adapter<RecentAdapter.ViewHolder> {
if (BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) { if (BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) {
String timestamp = topicSummary.getLastPostTimestamp(); String timestamp = topicSummary.getLastPostTimestamp();
try { try {
holder.mDateTimeView.setReferenceTime(Long.valueOf(timestamp)); holder.mDateTimeView.setReferenceTime(Long.parseLong(timestamp));
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
Timber.e(e, "Invalid number format: %s", timestamp); Timber.e(e, "Invalid number format: %s", timestamp);
holder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime()); holder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime());

6
app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java

@ -9,6 +9,8 @@ import android.widget.ProgressBar;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
@ -79,8 +81,8 @@ public class RecentFragment extends BaseFragment {
} }
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onViewCreated(view, savedInstanceState);
if (topicSummaries.isEmpty()) { if (topicSummaries.isEmpty()) {
recentTask = new RecentTask(this::onRecentTaskStarted, this::onRecentTaskFinished); recentTask = new RecentTask(this::onRecentTaskStarted, this::onRecentTaskFinished);
recentTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.indexUrl.toString()); recentTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.indexUrl.toString());

6
app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java

@ -37,16 +37,16 @@ class UnreadAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@Override @Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) { public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) {
TopicSummary topicSummary = unreadList.get(holder.getAdapterPosition()); TopicSummary topicSummary = unreadList.get(holder.getBindingAdapterPosition());
final UnreadAdapter.ViewHolder viewHolder = (UnreadAdapter.ViewHolder) holder; final UnreadAdapter.ViewHolder viewHolder = (UnreadAdapter.ViewHolder) holder;
viewHolder.mTitleView.setText(topicSummary.getSubject()); viewHolder.mTitleView.setText(topicSummary.getSubject());
if (BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) { if (BaseApplication.getInstance().isDisplayRelativeTimeEnabled()) {
String timestamp = topicSummary.getLastPostTimestamp(); String timestamp = topicSummary.getLastPostTimestamp();
try { try {
viewHolder.mDateTimeView.setReferenceTime(Long.valueOf(timestamp)); viewHolder.mDateTimeView.setReferenceTime(Long.parseLong(timestamp));
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
Timber.e(e, "Invalid number format: %s", timestamp); Timber.e(e, "Invalid number format \"%s\" for %s", timestamp, topicSummary.getTopicUrl());
viewHolder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime()); viewHolder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime());
} }
} }

8
app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java

@ -10,6 +10,7 @@ import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
@ -91,8 +92,8 @@ public class UnreadFragment extends BaseFragment {
} }
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onViewCreated(view, savedInstanceState);
if (topicSummaries.isEmpty()) { if (topicSummaries.isEmpty()) {
hideMarkAsReadFAB(); hideMarkAsReadFAB();
unreadTask = new UnreadTask(this::onUnreadTaskStarted, UnreadFragment.this::onUnreadTaskCancelled, this::onUnreadTaskFinished); unreadTask = new UnreadTask(this::onUnreadTaskStarted, UnreadFragment.this::onUnreadTaskCancelled, this::onUnreadTaskFinished);
@ -104,7 +105,6 @@ public class UnreadFragment extends BaseFragment {
markAsReadTask = new MarkAsReadTask(UnreadFragment.this::onMarkAsReadTaskStarted, UnreadFragment.this::onMarkAsReadTaskFinished); markAsReadTask = new MarkAsReadTask(UnreadFragment.this::onMarkAsReadTaskStarted, UnreadFragment.this::onMarkAsReadTaskFinished);
} }
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
@ -244,7 +244,7 @@ public class UnreadFragment extends BaseFragment {
if (loadedPages < numberOfPages) { if (loadedPages < numberOfPages) {
unreadTask = new UnreadTask(this::onUnreadTaskStarted, UnreadFragment.this::onUnreadTaskCancelled, this::onUnreadTaskFinished); unreadTask = new UnreadTask(this::onUnreadTaskStarted, UnreadFragment.this::onUnreadTaskCancelled, this::onUnreadTaskFinished);
assert SessionManager.unreadUrl != null; assert SessionManager.unreadUrl != null;
unreadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.unreadUrl.toString() + ";start=" + loadedPages * 20); unreadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.unreadUrl + ";start=" + loadedPages * 20);
} }
else else
hideProgressUI(); hideProgressUI();

12
app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java

@ -1,5 +1,11 @@
package gr.thmmy.mthmmy.activities.profile; package gr.thmmy.mthmmy.activities.profile;
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;
import android.content.Intent; import android.content.Intent;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Typeface; import android.graphics.Typeface;
@ -54,12 +60,6 @@ import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import okhttp3.Response; import okhttp3.Response;
import timber.log.Timber; 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;
/** /**
* Activity for user profile. When creating an Intent of this activity you need to bundle a <b>String</b> * Activity for user profile. When creating an Intent of this activity you need to bundle a <b>String</b>
* containing this user's profile url using the key {@link #BUNDLE_PROFILE_URL}, a <b>String</b> containing * containing this user's profile url using the key {@link #BUNDLE_PROFILE_URL}, a <b>String</b> containing

5
app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsFragment.java

@ -7,6 +7,7 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@ -118,8 +119,8 @@ public class LatestPostsFragment extends BaseFragment {
} }
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onViewCreated(view, savedInstanceState);
if (parsedTopicSummaries.isEmpty() && userHasPosts) { if (parsedTopicSummaries.isEmpty() && userHasPosts) {
profileLatestPostsTask = new LatestPostsTask(); profileLatestPostsTask = new LatestPostsTask();
profileLatestPostsTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, profileUrl + ";sa=showPosts"); profileLatestPostsTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, profileUrl + ";sa=showPosts");

31
app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java

@ -2,7 +2,6 @@ package gr.thmmy.mthmmy.activities.profile.stats;
import android.graphics.Color; import android.graphics.Color;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -10,6 +9,8 @@ import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import com.github.mikephil.charting.charts.HorizontalBarChart; import com.github.mikephil.charting.charts.HorizontalBarChart;
@ -99,13 +100,13 @@ public class StatsFragment extends Fragment {
} }
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onViewCreated(view, savedInstanceState);
if (profileStatsTask == null) { if (profileStatsTask == null) {
profileStatsTask = new ProfileStatsTask(); profileStatsTask = new ProfileStatsTask();
profileStatsTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, profileUrl + ";sa=statPanel"); profileStatsTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, profileUrl + ";sa=statPanel");
} }
Timber.d("onActivityCreated"); Timber.d("onViewCreated");
} }
@Override @Override
@ -228,7 +229,6 @@ public class StatsFragment extends Fragment {
private void populateLayout() { private void populateLayout() {
onLoadingListener.onLoadingStats(true); onLoadingListener.onLoadingStats(true);
;
((TextView) mainContent.findViewById(R.id.general_statistics_title)) ((TextView) mainContent.findViewById(R.id.general_statistics_title))
.setText(generalStatisticsTitle); .setText(generalStatisticsTitle);
((TextView) mainContent.findViewById(R.id.general_statistics)) ((TextView) mainContent.findViewById(R.id.general_statistics))
@ -294,14 +294,9 @@ public class StatsFragment extends Fragment {
mostPopularBoardsByPostsChartYAxis.setGranularity(1f); mostPopularBoardsByPostsChartYAxis.setGranularity(1f);
BarDataSet mostPopularBoardsByPostsDataSet = new BarDataSet(mostPopularBoardsByPosts, null); BarDataSet mostPopularBoardsByPostsDataSet = new BarDataSet(mostPopularBoardsByPosts, null);
if (isAdded()) { if (isAdded())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { mostPopularBoardsByPostsDataSet.setColors(getResources().getColor(R.color.accent, null));
mostPopularBoardsByPostsDataSet.setColors(getResources().getColor(R.color.accent, null));
}
else
//noinspection deprecation
mostPopularBoardsByPostsDataSet.setColors(getResources().getColor(R.color.accent));
}
mostPopularBoardsByPostsDataSet.setDrawValues(false); mostPopularBoardsByPostsDataSet.setDrawValues(false);
mostPopularBoardsByPostsDataSet.setValueTextColor(Color.WHITE); mostPopularBoardsByPostsDataSet.setValueTextColor(Color.WHITE);
@ -336,14 +331,8 @@ public class StatsFragment extends Fragment {
mostPopularBoardsByActivityChartYAxis.setLabelCount(10, false); mostPopularBoardsByActivityChartYAxis.setLabelCount(10, false);
BarDataSet mostPopularBoardsByActivityDataSet = new BarDataSet(mostPopularBoardsByActivity, null); BarDataSet mostPopularBoardsByActivityDataSet = new BarDataSet(mostPopularBoardsByActivity, null);
if (isAdded()) { if (isAdded())
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { mostPopularBoardsByActivityDataSet.setColors(getResources().getColor(R.color.accent, null));
mostPopularBoardsByActivityDataSet.setColors(getResources().getColor(R.color.accent, null));
}
else
//noinspection deprecation
mostPopularBoardsByActivityDataSet.setColors(getResources().getColor(R.color.accent));
}
mostPopularBoardsByActivityDataSet.setDrawValues(false); mostPopularBoardsByActivityDataSet.setDrawValues(false);
mostPopularBoardsByActivityDataSet.setValueTextColor(Color.WHITE); mostPopularBoardsByActivityDataSet.setValueTextColor(Color.WHITE);

11
app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java

@ -12,6 +12,8 @@ import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
@ -84,8 +86,8 @@ public class SummaryFragment extends Fragment {
} }
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onViewCreated(view, savedInstanceState);
if (parsedProfileSummaryData.isEmpty()) { if (parsedProfileSummaryData.isEmpty()) {
summaryTask = new SummaryTask(); summaryTask = new SummaryTask();
summaryTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, profileSummaryDocument); summaryTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, profileSummaryDocument);
@ -187,10 +189,7 @@ public class SummaryFragment extends Fragment {
&& value.contains("@")) || key.startsWith("Website") || key.startsWith("Ιστοτόπος")) && value.contains("@")) || key.startsWith("Website") || key.startsWith("Ιστοτόπος"))
textView.setMovementMethod(LinkMovementMethod.getInstance()); textView.setMovementMethod(LinkMovementMethod.getInstance());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) textView.setTextColor(getResources().getColor(R.color.primary_text, null));
textView.setTextColor(getResources().getColor(R.color.primary_text, null));
else
textView.setTextColor(getResources().getColor(R.color.primary_text));
String textViewContent = "<b>" + key + "</b> " + value; String textViewContent = "<b>" + key + "</b> " + value;

4
app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java

@ -1,5 +1,7 @@
package gr.thmmy.mthmmy.activities.settings; package gr.thmmy.mthmmy.activities.settings;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DEFAULT_HOME_TAB;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -22,8 +24,6 @@ import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseApplication;
import timber.log.Timber; import timber.log.Timber;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DEFAULT_HOME_TAB;
public class SettingsFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener { public class SettingsFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener {
private enum PREFS_TYPE { private enum PREFS_TYPE {
NOT_SET, USER, GUEST NOT_SET, USER, GUEST

16
app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java

@ -1,5 +1,13 @@
package gr.thmmy.mthmmy.activities.shoutbox; package gr.thmmy.mthmmy.activities.shoutbox;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Color; import android.graphics.Color;
@ -24,14 +32,6 @@ import gr.thmmy.mthmmy.model.ThmmyPage;
import gr.thmmy.mthmmy.views.CustomRecyclerView; import gr.thmmy.mthmmy.views.CustomRecyclerView;
import gr.thmmy.mthmmy.views.ReactiveWebView; import gr.thmmy.mthmmy.views.ReactiveWebView;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL;
public class ShoutAdapter extends CustomRecyclerView.Adapter<ShoutAdapter.ShoutViewHolder> { public class ShoutAdapter extends CustomRecyclerView.Adapter<ShoutAdapter.ShoutViewHolder> {
private Context context; private Context context;
private Shout[] shouts; private Shout[] shouts;

8
app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java

@ -14,7 +14,7 @@ import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.R;
@ -100,9 +100,9 @@ public class ShoutboxFragment extends Fragment {
} }
@Override @Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onViewCreated(view, savedInstanceState);
shoutboxViewModel = ViewModelProviders.of(getActivity()).get(ShoutboxViewModel.class); shoutboxViewModel = new ViewModelProvider(getActivity()).get(ShoutboxViewModel.class);
shoutboxViewModel.getShoutboxMutableLiveData().observe(getViewLifecycleOwner(), shoutbox -> { shoutboxViewModel.getShoutboxMutableLiveData().observe(getViewLifecycleOwner(), shoutbox -> {
if (shoutbox != null) { if (shoutbox != null) {
Timber.i("Shoutbox loaded successfully"); Timber.i("Shoutbox loaded successfully");

79
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java

@ -1,5 +1,7 @@
package gr.thmmy.mthmmy.activities.topic; package gr.thmmy.mthmmy.activities.topic;
import static gr.thmmy.mthmmy.services.NotificationService.NEW_POST_TAG;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.content.ClipData; import android.content.ClipData;
@ -31,7 +33,7 @@ import android.widget.Toast;
import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AlertDialog;
import androidx.core.content.res.ResourcesCompat; import androidx.core.content.res.ResourcesCompat;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.floatingactionbutton.FloatingActionButton;
@ -60,8 +62,6 @@ import gr.thmmy.mthmmy.views.editorview.EmojiKeyboard;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import timber.log.Timber; import timber.log.Timber;
import static gr.thmmy.mthmmy.services.NotificationService.NEW_POST_TAG;
/** /**
* Activity for parsing and rendering topics. When creating an Intent of this activity you need to * Activity for parsing and rendering topics. When creating an Intent of this activity you need to
* bundle a <b>String</b> containing this topic's url using the key {@link #BUNDLE_TOPIC_URL}. * bundle a <b>String</b> containing this topic's url using the key {@link #BUNDLE_TOPIC_URL}.
@ -131,7 +131,7 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_topic); setContentView(R.layout.activity_topic);
// get TopicViewModel instance // get TopicViewModel instance
viewModel = ViewModelProviders.of(this).get(TopicViewModel.class); viewModel = new ViewModelProvider(this).get(TopicViewModel.class);
subscribeUI(); subscribeUI();
Bundle extras = getIntent().getExtras(); Bundle extras = getIntent().getExtras();
@ -228,42 +228,43 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
// Handle presses on the action bar items // Handle presses on the action bar items
switch (item.getItemId()) { int itemId = item.getItemId();
case R.id.menu_bookmark: if (itemId == R.id.menu_bookmark) {
topicMenuBookmarkClick(); topicMenuBookmarkClick();
return true; return true;
case R.id.menu_info: }
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyleAccent); else if (itemId == R.id.menu_info) {
LayoutInflater inflater = this.getLayoutInflater(); AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyleAccent);
LinearLayout infoDialog = (LinearLayout) inflater.inflate(R.layout.dialog_topic_info LayoutInflater inflater = this.getLayoutInflater();
, null); LinearLayout infoDialog = (LinearLayout) inflater.inflate(R.layout.dialog_topic_info
TextView treeAndMods = infoDialog.findViewById(R.id.topic_tree_and_mods); , null);
treeAndMods.setText(new SpannableStringBuilder("Loading...")); TextView treeAndMods = infoDialog.findViewById(R.id.topic_tree_and_mods);
treeAndMods.setMovementMethod(LinkMovementMethod.getInstance()); treeAndMods.setText(new SpannableStringBuilder("Loading..."));
TextView usersViewing = infoDialog.findViewById(R.id.users_viewing); treeAndMods.setMovementMethod(LinkMovementMethod.getInstance());
usersViewing.setText(new SpannableStringBuilder("Loading...")); TextView usersViewing = infoDialog.findViewById(R.id.users_viewing);
usersViewing.setMovementMethod(LinkMovementMethod.getInstance()); usersViewing.setText(new SpannableStringBuilder("Loading..."));
viewModel.getTopicTreeAndMods().observe(this, topicTreeAndMods -> { usersViewing.setMovementMethod(LinkMovementMethod.getInstance());
if (topicTreeAndMods == null) return; viewModel.getTopicTreeAndMods().observe(this, topicTreeAndMods -> {
treeAndMods.setText(HTMLUtils.getSpannableFromHtml(this, topicTreeAndMods)); if (topicTreeAndMods == null) return;
}); treeAndMods.setText(HTMLUtils.getSpannableFromHtml(this, topicTreeAndMods));
viewModel.getTopicViewers().observe(this, topicViewers -> { });
if (topicViewers == null) return; viewModel.getTopicViewers().observe(this, topicViewers -> {
usersViewing.setText(HTMLUtils.getSpannableFromHtml(this, topicViewers)); if (topicViewers == null) return;
}); usersViewing.setText(HTMLUtils.getSpannableFromHtml(this, topicViewers));
builder.setView(infoDialog); });
topicInfoDialog = builder.create(); builder.setView(infoDialog);
topicInfoDialog.show(); topicInfoDialog = builder.create();
return true; topicInfoDialog.show();
case R.id.menu_share: return true;
Intent sendIntent = new Intent(android.content.Intent.ACTION_SEND); }
sendIntent.setType("text/plain"); else if (itemId == R.id.menu_share) {
sendIntent.putExtra(android.content.Intent.EXTRA_TEXT, viewModel.getTopicUrl()); Intent sendIntent = new Intent(Intent.ACTION_SEND);
startActivity(Intent.createChooser(sendIntent, "Share via")); sendIntent.setType("text/plain");
return true; //invalidateOptionsMenu(); sendIntent.putExtra(Intent.EXTRA_TEXT, viewModel.getTopicUrl());
default: startActivity(Intent.createChooser(sendIntent, "Share via"));
return super.onOptionsItemSelected(item); return true; //invalidateOptionsMenu();
} }
return super.onOptionsItemSelected(item);
} }
@Override @Override

43
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java

@ -1,5 +1,18 @@
package gr.thmmy.mthmmy.activities.topic; package gr.thmmy.mthmmy.activities.topic;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL;
import static gr.thmmy.mthmmy.activities.topic.TopicParser.USER_COLOR_WHITE;
import static gr.thmmy.mthmmy.activities.topic.TopicParser.USER_COLOR_YELLOW;
import static gr.thmmy.mthmmy.base.BaseActivity.getSessionManager;
import static gr.thmmy.mthmmy.utils.FileUtils.faIconFromFilename;
import static gr.thmmy.mthmmy.utils.ui.GlideUtils.isValidContextForGlide;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.annotation.TargetApi; import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
@ -77,19 +90,6 @@ import gr.thmmy.mthmmy.views.editorview.EditorView;
import gr.thmmy.mthmmy.views.editorview.IEmojiKeyboard; import gr.thmmy.mthmmy.views.editorview.IEmojiKeyboard;
import timber.log.Timber; import timber.log.Timber;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL;
import static gr.thmmy.mthmmy.activities.topic.TopicParser.USER_COLOR_WHITE;
import static gr.thmmy.mthmmy.activities.topic.TopicParser.USER_COLOR_YELLOW;
import static gr.thmmy.mthmmy.base.BaseActivity.getSessionManager;
import static gr.thmmy.mthmmy.utils.FileUtils.faIconFromFilename;
import static gr.thmmy.mthmmy.utils.ui.GlideUtils.isValidContextForGlide;
/** /**
* Custom {@link RecyclerView.Adapter} used for topics. * Custom {@link RecyclerView.Adapter} used for topics.
*/ */
@ -393,11 +393,7 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (currentPost.getAttachedFiles() != null && currentPost.getAttachedFiles().size() != 0) { if (currentPost.getAttachedFiles() != null && currentPost.getAttachedFiles().size() != 0) {
int filesTextColor; int filesTextColor;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { filesTextColor = context.getResources().getColor(R.color.accent, null);
filesTextColor = context.getResources().getColor(R.color.accent, null);
}
else
filesTextColor = context.getResources().getColor(R.color.accent);
for (final ThmmyFile attachedFile : currentPost.getAttachedFiles()) { for (final ThmmyFile attachedFile : currentPost.getAttachedFiles()) {
final TextView attached = new TextView(context); final TextView attached = new TextView(context);
@ -417,11 +413,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
} }
if (currentPost.getLastEdit() != null && currentPost.getLastEdit().length() > 0) { if (currentPost.getLastEdit() != null && currentPost.getLastEdit().length() > 0) {
int lastEditTextColor; int lastEditTextColor;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
lastEditTextColor = context.getResources().getColor(R.color.white, null); lastEditTextColor = context.getResources().getColor(R.color.white, null);
}
else
lastEditTextColor = context.getResources().getColor(R.color.white);
final TextView lastEdit = new TextView(context); final TextView lastEdit = new TextView(context);
lastEdit.setTextSize(12f); lastEdit.setTextSize(12f);
@ -709,8 +702,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
SharedPreferences drafts = context.getSharedPreferences(context.getString(R.string.pref_topic_drafts_key), SharedPreferences drafts = context.getSharedPreferences(context.getString(R.string.pref_topic_drafts_key),
Context.MODE_PRIVATE); Context.MODE_PRIVATE);
replyText += drafts.getString(String.valueOf(viewModel.getTopicId()), ""); replyText += drafts.getString(String.valueOf(viewModel.getTopicId()), "");
if (viewModel.getBuildedQuotes() != null && !viewModel.getBuildedQuotes().isEmpty()) if (viewModel.getBuiltQuotes() != null && !viewModel.getBuiltQuotes().isEmpty())
replyText += viewModel.getBuildedQuotes(); replyText += viewModel.getBuiltQuotes();
} }
holder.replyEditor.setText(replyText); holder.replyEditor.setText(replyText);
holder.replyEditor.getEditText().setSelection(holder.replyEditor.getText().length()); holder.replyEditor.getEditText().setSelection(holder.replyEditor.getText().length());

4
app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/EditTask.java

@ -1,5 +1,7 @@
package gr.thmmy.mthmmy.activities.topic.tasks; package gr.thmmy.mthmmy.activities.topic.tasks;
import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus;
import android.os.AsyncTask; import android.os.AsyncTask;
import java.io.IOException; import java.io.IOException;
@ -12,8 +14,6 @@ import okhttp3.RequestBody;
import okhttp3.Response; import okhttp3.Response;
import timber.log.Timber; import timber.log.Timber;
import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus;
public class EditTask extends AsyncTask<String, Void, Boolean> { public class EditTask extends AsyncTask<String, Void, Boolean> {
private EditTaskCallbacks listener; private EditTaskCallbacks listener;
private int position; private int position;

10
app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForEditTask.java

@ -7,8 +7,6 @@ import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element; import org.jsoup.nodes.Element;
import org.jsoup.select.Selector; import org.jsoup.select.Selector;
import java.io.IOException;
import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseApplication;
import okhttp3.OkHttpClient; import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
@ -61,8 +59,12 @@ public class PrepareForEditTask extends AsyncTask<String, Void, PrepareForEditRe
icon = form.select("select[name=icon]>option[selected]").first().attr("value"); icon = form.select("select[name=icon]>option[selected]").first().attr("value");
return new PrepareForEditResult(postText, commitEditURL, numReplies, seqnum, sc, topic, icon, position, true); return new PrepareForEditResult(postText, commitEditURL, numReplies, seqnum, sc, topic, icon, position, true);
} catch (IOException | Selector.SelectorParseException e) { } catch (NullPointerException | Selector.SelectorParseException e) {
Timber.e(e, "Prepare failed."); // TODO: Convert this task to (New)ParseTask (?) / handle parsing errors in a better way
Timber.e(e, "Preparing for edit failed (parsing error).");
return new PrepareForEditResult(null, null, null, null, null, null, null, position, false);
} catch (Exception e) {
Timber.i("Preparing for edit failed (other error).");
return new PrepareForEditResult(null, null, null, null, null, null, null, position, false); return new PrepareForEditResult(null, null, null, null, null, null, null, position, false);
} }
} }

10
app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForReplyResult.java

@ -1,17 +1,17 @@
package gr.thmmy.mthmmy.activities.topic.tasks; package gr.thmmy.mthmmy.activities.topic.tasks;
public class PrepareForReplyResult { public class PrepareForReplyResult {
private final String numReplies, seqnum, sc, topic, buildedQuotes; private final String numReplies, seqnum, sc, topic, builtQuotes;
private boolean successful; private boolean successful;
public PrepareForReplyResult(boolean successful, String numReplies, String seqnum, String sc, String topic, String buildedQuotes) { public PrepareForReplyResult(boolean successful, String numReplies, String seqnum, String sc, String topic, String builtQuotes) {
this.successful = successful; this.successful = successful;
this.numReplies = numReplies; this.numReplies = numReplies;
this.seqnum = seqnum; this.seqnum = seqnum;
this.sc = sc; this.sc = sc;
this.topic = topic; this.topic = topic;
this.buildedQuotes = buildedQuotes; this.builtQuotes = builtQuotes;
} }
public String getNumReplies() { public String getNumReplies() {
@ -30,8 +30,8 @@ public class PrepareForReplyResult {
return topic; return topic;
} }
public String getBuildedQuotes() { public String getBuiltQuotes() {
return buildedQuotes; return builtQuotes;
} }
public boolean isSuccessful() { public boolean isSuccessful() {

18
app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForReplyTask.java

@ -49,33 +49,33 @@ public class PrepareForReplyTask extends AsyncTask<Integer, Void, PrepareForRepl
seqnum = document.select("input[name=seqnum]").first().attr("value"); seqnum = document.select("input[name=seqnum]").first().attr("value");
sc = document.select("input[name=sc]").first().attr("value"); sc = document.select("input[name=sc]").first().attr("value");
topic = document.select("input[name=topic]").first().attr("value"); topic = document.select("input[name=topic]").first().attr("value");
} catch (NullPointerException e) { } catch (NullPointerException | Selector.SelectorParseException e) {
// TODO: Convert this task to (New)ParseTask (?) / handle parsing errors in a better way // TODO: Convert this task to (New)ParseTask (?) / handle parsing errors in a better way
Timber.e(e, "Prepare failed (1)"); Timber.e(e, "Preparing for reply failed (parsing error).");
return new PrepareForReplyResult(false, null, null, null, null, null); return new PrepareForReplyResult(false, null, null, null, null, null);
} catch (IOException | Selector.SelectorParseException e) { } catch (Exception e) {
Timber.e(e, "Prepare failed (2)"); Timber.i("Preparing for reply failed (other error).");
return new PrepareForReplyResult(false, null, null, null, null, null); return new PrepareForReplyResult(false, null, null, null, null, null);
} }
StringBuilder buildedQuotes = new StringBuilder(); StringBuilder builtQuotes = new StringBuilder();
for (Integer postIndex : postIndices) { for (Integer postIndex : postIndices) {
request = new Request.Builder() request = new Request.Builder()
.url("https://www.thmmy.gr/smf/index.php?action=quotefast;quote=" + .url(BaseApplication.getForumUrl() + "index.php?action=quotefast;quote=" +
postIndex + ";" + "sesc=" + sc + ";xml") postIndex + ";" + "sesc=" + sc + ";xml")
.build(); .build();
try { try {
Response response = client.newCall(request).execute(); Response response = client.newCall(request).execute();
String body = response.body().string(); String body = response.body().string();
body = Parser.unescapeEntities(body, false); body = Parser.unescapeEntities(body, false);
buildedQuotes.append(body.substring(body.indexOf("<quote>") + 7, body.indexOf("</quote>"))); builtQuotes.append(body.substring(body.indexOf("<quote>") + 7, body.indexOf("</quote>")));
buildedQuotes.append("\n\n"); builtQuotes.append("\n\n");
} catch (IOException | Selector.SelectorParseException e) { } catch (IOException | Selector.SelectorParseException e) {
Timber.e(e, "Quote building failed."); Timber.e(e, "Quote building failed.");
return new PrepareForReplyResult(false, null, null, null, null, null); return new PrepareForReplyResult(false, null, null, null, null, null);
} }
} }
return new PrepareForReplyResult(true, numReplies, seqnum, sc, topic, buildedQuotes.toString()); return new PrepareForReplyResult(true, numReplies, seqnum, sc, topic, builtQuotes.toString());
} }
@Override @Override

6
app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java

@ -1,5 +1,7 @@
package gr.thmmy.mthmmy.activities.topic.tasks; package gr.thmmy.mthmmy.activities.topic.tasks;
import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus;
import android.os.AsyncTask; import android.os.AsyncTask;
import java.io.IOException; import java.io.IOException;
@ -13,8 +15,6 @@ import okhttp3.RequestBody;
import okhttp3.Response; import okhttp3.Response;
import timber.log.Timber; import timber.log.Timber;
import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus;
public class ReplyTask extends AsyncTask<String, Void, Posting.REPLY_STATUS> { public class ReplyTask extends AsyncTask<String, Void, Posting.REPLY_STATUS> {
private ReplyTaskCallbacks listener; private ReplyTaskCallbacks listener;
private boolean includeAppSignature; private boolean includeAppSignature;
@ -45,7 +45,7 @@ public class ReplyTask extends AsyncTask<String, Void, Posting.REPLY_STATUS> {
.addFormDataPart("icon", "xx") .addFormDataPart("icon", "xx")
.build(); .build();
Request post = new Request.Builder() Request post = new Request.Builder()
.url("https://www.thmmy.gr/smf/index.php?action=post2") .url(BaseApplication.getForumUrl() + "index.php?action=post2")
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36") .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36")
.post(postBody) .post(postBody)
.build(); .build();

26
app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java

@ -1,5 +1,15 @@
package gr.thmmy.mthmmy.activities.upload; package gr.thmmy.mthmmy.activities.upload;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.UPLOADING_APP_SIGNATURE_ENABLE_KEY;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.BUNDLE_UPLOAD_FIELD_BUILDER_COURSE_GREEKLISH_NAME;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.BUNDLE_UPLOAD_FIELD_BUILDER_COURSE_MINIFIED_NAME;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.BUNDLE_UPLOAD_FIELD_BUILDER_COURSE_NAME;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.BUNDLE_UPLOAD_FIELD_BUILDER_SEMESTER;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.RESULT_DESCRIPTION;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.RESULT_FILENAME;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.RESULT_TITLE;
import static gr.thmmy.mthmmy.utils.FileUtils.faIconFromFilename;
import android.app.Activity; import android.app.Activity;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
@ -74,16 +84,6 @@ import gr.thmmy.mthmmy.views.AppCompatSpinnerWithoutDefault;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import timber.log.Timber; import timber.log.Timber;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.UPLOADING_APP_SIGNATURE_ENABLE_KEY;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.BUNDLE_UPLOAD_FIELD_BUILDER_COURSE_GREEKLISH_NAME;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.BUNDLE_UPLOAD_FIELD_BUILDER_COURSE_MINIFIED_NAME;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.BUNDLE_UPLOAD_FIELD_BUILDER_COURSE_NAME;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.BUNDLE_UPLOAD_FIELD_BUILDER_SEMESTER;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.RESULT_DESCRIPTION;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.RESULT_FILENAME;
import static gr.thmmy.mthmmy.activities.upload.UploadFieldsBuilderActivity.RESULT_TITLE;
import static gr.thmmy.mthmmy.utils.FileUtils.faIconFromFilename;
public class UploadActivity extends BaseActivity { public class UploadActivity extends BaseActivity {
/** /**
* The key to use when putting upload's category String to {@link UploadActivity}'s Bundle. * The key to use when putting upload's category String to {@link UploadActivity}'s Bundle.
@ -91,7 +91,7 @@ public class UploadActivity extends BaseActivity {
public static final String BUNDLE_UPLOAD_CATEGORY = "UPLOAD_CATEGORY"; public static final String BUNDLE_UPLOAD_CATEGORY = "UPLOAD_CATEGORY";
public static final String firebaseConfigUploadsCoursesKey = "uploads_courses"; public static final String firebaseConfigUploadsCoursesKey = "uploads_courses";
private static final String uploadIndexUrl = "https://www.thmmy.gr/smf/index.php?action=tpmod;dl=upload"; private static final String uploadIndexUrl = forumUrl + "index.php?action=tpmod;dl=upload";
private static final String uploadedFromTHMMYPromptHtml = "<br /><div style=\"text-align: right;\"><span style=\"font-style: italic;\">uploaded from <a href=\"https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy\">mTHMMY</a></span>"; private static final String uploadedFromTHMMYPromptHtml = "<br /><div style=\"text-align: right;\"><span style=\"font-style: italic;\">uploaded from <a href=\"https://play.google.com/store/apps/details?id=gr.thmmy.mthmmy\">mTHMMY</a></span>";
/** /**
* Request codes used in activities for result (AFR) calls * Request codes used in activities for result (AFR) calls
@ -169,7 +169,7 @@ public class UploadActivity extends BaseActivity {
} }
createDrawer(); createDrawer();
drawer.setSelection(UPLOAD_ID); // drawer.setSelection(UPLOAD_ID);
progressBar = findViewById(R.id.progressBar); progressBar = findViewById(R.id.progressBar);
@ -434,7 +434,7 @@ public class UploadActivity extends BaseActivity {
@Override @Override
protected void onResume() { protected void onResume() {
drawer.setSelection(UPLOAD_ID); // drawer.setSelection(UPLOAD_ID);
super.onResume(); super.onResume();
} }

2
app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadFieldsBuilderActivity.java

@ -99,7 +99,7 @@ public class UploadFieldsBuilderActivity extends BaseActivity {
} }
createDrawer(); createDrawer();
drawer.setSelection(UPLOAD_ID, false); // drawer.setSelection(UPLOAD_ID, false);
semesterChooserLinear = findViewById(R.id.upload_fields_builder_choose_semester); semesterChooserLinear = findViewById(R.id.upload_fields_builder_choose_semester);
semesterRadio = findViewById(R.id.upload_fields_builder_semester_radio_group); semesterRadio = findViewById(R.id.upload_fields_builder_semester_radio_group);

5
app/src/main/java/gr/thmmy/mthmmy/activities/upload/multipart/MultipartUploadTask.java

@ -11,6 +11,7 @@ import net.gotev.uploadservice.http.BodyWriter;
import java.io.IOException; import java.io.IOException;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
/** /**
* Extended MultipartUploadTask from gotev/android-upload-service to include a fix for the parameter * Extended MultipartUploadTask from gotev/android-upload-service to include a fix for the parameter
@ -21,7 +22,7 @@ public class MultipartUploadTask extends HttpUploadTask {
static final String PARAM_UTF8_CHARSET = "multipartUtf8Charset"; static final String PARAM_UTF8_CHARSET = "multipartUtf8Charset";
private static final String BOUNDARY_SIGNATURE = "-------AndroidUploadService"; private static final String BOUNDARY_SIGNATURE = "-------AndroidUploadService";
private static final Charset US_ASCII = Charset.forName("US-ASCII"); private static final Charset US_ASCII = StandardCharsets.US_ASCII;
private static final String NEW_LINE = "\r\n"; private static final String NEW_LINE = "\r\n";
private static final String TWO_HYPHENS = "--"; private static final String TWO_HYPHENS = "--";
@ -42,7 +43,7 @@ public class MultipartUploadTask extends HttpUploadTask {
boundaryBytes = (TWO_HYPHENS + boundary + NEW_LINE).getBytes(US_ASCII); boundaryBytes = (TWO_HYPHENS + boundary + NEW_LINE).getBytes(US_ASCII);
trailerBytes = (TWO_HYPHENS + boundary + TWO_HYPHENS + NEW_LINE).getBytes(US_ASCII); trailerBytes = (TWO_HYPHENS + boundary + TWO_HYPHENS + NEW_LINE).getBytes(US_ASCII);
charset = intent.getBooleanExtra(PARAM_UTF8_CHARSET, false) ? charset = intent.getBooleanExtra(PARAM_UTF8_CHARSET, false) ?
Charset.forName("UTF-8") : US_ASCII; StandardCharsets.UTF_8 : US_ASCII;
httpParams.addHeader("Connection", "Keep-Alive"); httpParams.addHeader("Connection", "Keep-Alive");
httpParams.addHeader("Content-Type", "multipart/form-data; boundary=" + boundary); httpParams.addHeader("Content-Type", "multipart/form-data; boundary=" + boundary);

93
app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java

@ -1,5 +1,15 @@
package gr.thmmy.mthmmy.base; package gr.thmmy.mthmmy.base;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_TITLE;
import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DEFAULT_HOME_TAB;
import static gr.thmmy.mthmmy.services.DownloadHelper.SAVE_DIR;
import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType;
import android.Manifest; import android.Manifest;
import android.app.ProgressDialog; import android.app.ProgressDialog;
import android.content.Context; import android.content.Context;
@ -8,7 +18,6 @@ import android.content.SharedPreferences;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.net.Uri; import android.net.Uri;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
@ -23,7 +32,7 @@ import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider; import androidx.core.content.FileProvider;
import androidx.lifecycle.ViewModelProviders; import androidx.lifecycle.ViewModelProvider;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import com.google.android.material.bottomsheet.BottomSheetDialog; import com.google.android.material.bottomsheet.BottomSheetDialog;
@ -67,16 +76,6 @@ import ru.noties.markwon.Markwon;
import ru.noties.markwon.SpannableConfiguration; import ru.noties.markwon.SpannableConfiguration;
import timber.log.Timber; import timber.log.Timber;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_TITLE;
import static gr.thmmy.mthmmy.activities.downloads.DownloadsActivity.BUNDLE_DOWNLOADS_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DEFAULT_HOME_TAB;
import static gr.thmmy.mthmmy.services.DownloadHelper.SAVE_DIR;
import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType;
public abstract class BaseActivity extends AppCompatActivity { public abstract class BaseActivity extends AppCompatActivity {
// Client & Cookies // Client & Cookies
protected static OkHttpClient client; protected static OkHttpClient client;
@ -106,6 +105,8 @@ public abstract class BaseActivity extends AppCompatActivity {
private boolean isMainActivity; private boolean isMainActivity;
private boolean isUserConsentDialogShown; //Needed because sometimes onResume is being called twice private boolean isUserConsentDialogShown; //Needed because sometimes onResume is being called twice
protected static String forumUrl = BaseApplication.getForumUrl(); // For convenience
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -126,7 +127,7 @@ public abstract class BaseActivity extends AppCompatActivity {
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
BaseViewModel baseViewModel = ViewModelProviders.of(this).get(BaseViewModel.class); BaseViewModel baseViewModel = new ViewModelProvider(this).get(BaseViewModel.class);
baseViewModel.getCurrentPageBookmark().observe(this, thisPageBookmark -> setTopicBookmark(thisPageBookmarkMenuButton)); baseViewModel.getCurrentPageBookmark().observe(this, thisPageBookmark -> setTopicBookmark(thisPageBookmarkMenuButton));
storage = new Storage(getApplicationContext()); storage = new Storage(getApplicationContext());
@ -166,7 +167,7 @@ public abstract class BaseActivity extends AppCompatActivity {
//------------------------------------------DRAWER STUFF---------------------------------------- //------------------------------------------DRAWER STUFF----------------------------------------
protected static final int HOME_ID = 0; protected static final int HOME_ID = 0;
protected static final int DOWNLOADS_ID = 1; protected static final int DOWNLOADS_ID = 1;
protected static final int UPLOAD_ID = 2; //protected static final int UPLOAD_ID = 2; //Removed until fixed
protected static final int BOOKMARKS_ID = 3; protected static final int BOOKMARKS_ID = 3;
protected static final int LOG_ID = 4; protected static final int LOG_ID = 4;
protected static final int ABOUT_ID = 5; protected static final int ABOUT_ID = 5;
@ -266,14 +267,14 @@ public abstract class BaseActivity extends AppCompatActivity {
.withIcon(downloadsIcon) .withIcon(downloadsIcon)
.withSelectedIcon(downloadsIconSelected); .withSelectedIcon(downloadsIconSelected);
uploadItem = new PrimaryDrawerItem() // uploadItem = new PrimaryDrawerItem()
.withTextColor(primaryColor) // .withTextColor(primaryColor)
.withSelectedColor(selectedPrimaryColor) // .withSelectedColor(selectedPrimaryColor)
.withSelectedTextColor(selectedSecondaryColor) // .withSelectedTextColor(selectedSecondaryColor)
.withIdentifier(UPLOAD_ID) // .withIdentifier(UPLOAD_ID)
.withName(R.string.upload) // .withName(R.string.upload)
.withIcon(uploadIcon) // .withIcon(uploadIcon)
.withSelectedIcon(uploadIconSelected); // .withSelectedIcon(uploadIconSelected);
shoutboxItem = new PrimaryDrawerItem() shoutboxItem = new PrimaryDrawerItem()
.withTextColor(primaryColor) .withTextColor(primaryColor)
@ -346,7 +347,7 @@ public abstract class BaseActivity extends AppCompatActivity {
if (sessionManager.isLoggedIn()) { if (sessionManager.isLoggedIn()) {
Intent intent = new Intent(BaseActivity.this, ProfileActivity.class); Intent intent = new Intent(BaseActivity.this, ProfileActivity.class);
Bundle extras = new Bundle(); Bundle extras = new Bundle();
extras.putString(BUNDLE_PROFILE_URL, "https://www.thmmy.gr/smf/index.php?action=profile"); extras.putString(BUNDLE_PROFILE_URL, forumUrl + "index.php?action=profile");
if (!sessionManager.hasAvatar()) if (!sessionManager.hasAvatar())
extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, ""); extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, "");
else else
@ -394,12 +395,12 @@ public abstract class BaseActivity extends AppCompatActivity {
startActivity(intent); startActivity(intent);
} }
} }
else if (drawerItem.equals(UPLOAD_ID)) { // else if (drawerItem.equals(UPLOAD_ID)) {
if (!(BaseActivity.this instanceof UploadActivity)) { // if (!(BaseActivity.this instanceof UploadActivity)) {
Intent intent = new Intent(BaseActivity.this, UploadActivity.class); // Intent intent = new Intent(BaseActivity.this, UploadActivity.class);
startActivity(intent); // startActivity(intent);
} // }
} // }
else if (drawerItem.equals(BOOKMARKS_ID)) { else if (drawerItem.equals(BOOKMARKS_ID)) {
if (!(BaseActivity.this instanceof BookmarksActivity)) { if (!(BaseActivity.this instanceof BookmarksActivity)) {
Intent intent = new Intent(BaseActivity.this, BookmarksActivity.class); Intent intent = new Intent(BaseActivity.this, BookmarksActivity.class);
@ -452,7 +453,7 @@ public abstract class BaseActivity extends AppCompatActivity {
if (drawer != null) { 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(DOWNLOADS_ID);
drawer.removeItem(UPLOAD_ID); //drawer.removeItem(UPLOAD_ID);
loginLogoutItem.withName(R.string.login).withIcon(loginIcon); //Swap logout with login loginLogoutItem.withName(R.string.login).withIcon(loginIcon); //Swap logout with login
profileDrawerItem.withName(sessionManager.getUsername()); profileDrawerItem.withName(sessionManager.getUsername());
setDefaultAvatar(); setDefaultAvatar();
@ -693,29 +694,23 @@ public abstract class BaseActivity extends AppCompatActivity {
//True if permissions are OK //True if permissions are OK
protected boolean checkPerms() { protected boolean checkPerms() {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) { Timber.i("Checking storage permissions.");
Timber.i("Checking storage permissions."); String[] PERMISSIONS_STORAGE = {
String[] PERMISSIONS_STORAGE = { Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
Manifest.permission.WRITE_EXTERNAL_STORAGE};
return !(checkSelfPermission(PERMISSIONS_STORAGE[0]) == PackageManager.PERMISSION_DENIED ||
return !(checkSelfPermission(PERMISSIONS_STORAGE[0]) == PackageManager.PERMISSION_DENIED || checkSelfPermission(PERMISSIONS_STORAGE[1]) == PackageManager.PERMISSION_DENIED);
checkSelfPermission(PERMISSIONS_STORAGE[1]) == PackageManager.PERMISSION_DENIED);
}
return true;
} }
//Display popup for user to grant permission //Display popup for user to grant permission
protected void requestPerms(int code) { protected void requestPerms(int code) {
//Runtime permissions request for devices with API >= 23 String[] PERMISSIONS_STORAGE = {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) { Manifest.permission.READ_EXTERNAL_STORAGE,
String[] PERMISSIONS_STORAGE = { Manifest.permission.WRITE_EXTERNAL_STORAGE};
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE}; Timber.i("Requesting storage permissions (code %d).", code);
requestPermissions(PERMISSIONS_STORAGE, code);
Timber.i("Requesting storage permissions (code %d).", code);
requestPermissions(PERMISSIONS_STORAGE, code);
}
} }
@Override @Override

43
app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java

@ -1,8 +1,14 @@
package gr.thmmy.mthmmy.base; package gr.thmmy.mthmmy.base;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DISPLAY_COMPACT_TABS;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DISPLAY_RELATIVE_TIME;
import static gr.thmmy.mthmmy.activities.upload.UploadActivity.firebaseConfigUploadsCoursesKey;
import static gr.thmmy.mthmmy.utils.io.ResourceUtils.readJSONResourceToString;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
@ -44,16 +50,16 @@ import okhttp3.OkHttpClient;
import okhttp3.Request; import okhttp3.Request;
import timber.log.Timber; import timber.log.Timber;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DISPLAY_COMPACT_TABS;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.DISPLAY_RELATIVE_TIME;
import static gr.thmmy.mthmmy.activities.upload.UploadActivity.firebaseConfigUploadsCoursesKey;
import static gr.thmmy.mthmmy.utils.io.ResourceUtils.readJSONResourceToString;
public class BaseApplication extends Application implements Executor{ public class BaseApplication extends Application implements Executor{
private static BaseApplication baseApplication; //BaseApplication singleton private static BaseApplication baseApplication; //BaseApplication singleton
private CrashReportingTree crashReportingTree; private CrashReportingTree crashReportingTree;
//Global variables
private static String forumUrl;
private static String forumHost;
private static String forumHostSimple;
//Firebase //Firebase
private static String firebaseProjectId; private static String firebaseProjectId;
private FirebaseAnalytics firebaseAnalytics; private FirebaseAnalytics firebaseAnalytics;
@ -70,10 +76,6 @@ public class BaseApplication extends Application implements Executor{
private static float widthDp; private static float widthDp;
private static int widthPxl, heightPxl; private static int widthPxl, heightPxl;
public static BaseApplication getInstance() {
return baseApplication;
}
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
@ -83,6 +85,11 @@ public class BaseApplication extends Application implements Executor{
if (BuildConfig.DEBUG) if (BuildConfig.DEBUG)
Timber.plant(new Timber.DebugTree()); Timber.plant(new Timber.DebugTree());
Resources resources = getApplicationContext().getResources();
forumUrl = resources.getString(R.string.forum_url);
forumHost = resources.getString(R.string.forum_host);
forumHostSimple= resources.getString(R.string.forum_host_simple);
//Shared Preferences //Shared Preferences
SharedPreferences sessionSharedPrefs = getSharedPreferences(getString(R.string.session_shared_prefs), MODE_PRIVATE); SharedPreferences sessionSharedPrefs = getSharedPreferences(getString(R.string.session_shared_prefs), MODE_PRIVATE);
SharedPreferences settingsSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences settingsSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
@ -157,7 +164,7 @@ public class BaseApplication extends Application implements Executor{
.addInterceptor(chain -> { .addInterceptor(chain -> {
Request request = chain.request(); Request request = chain.request();
HttpUrl oldUrl = chain.request().url(); HttpUrl oldUrl = chain.request().url();
if (Objects.equals(chain.request().url().host(), "www.thmmy.gr") if (Objects.equals(chain.request().url().host(), forumHost)
&& !oldUrl.toString().contains("theme=4")) { && !oldUrl.toString().contains("theme=4")) {
//Probably works but needs more testing: //Probably works but needs more testing:
HttpUrl newUrl = oldUrl.newBuilder().addQueryParameter("theme", "4").build(); HttpUrl newUrl = oldUrl.newBuilder().addQueryParameter("theme", "4").build();
@ -208,6 +215,22 @@ public class BaseApplication extends Application implements Executor{
//-------------------- Getters -------------------- //-------------------- Getters --------------------
public static BaseApplication getInstance() {
return baseApplication;
}
public static String getForumUrl() {
return forumUrl;
}
public static String getForumHost() {
return forumHost;
}
public static String getForumHostSimple() {
return forumHostSimple;
}
public Context getContext() { public Context getContext() {
return getApplicationContext(); return getApplicationContext();
} }

2
app/src/main/java/gr/thmmy/mthmmy/base/BaseFragment.java

@ -31,7 +31,7 @@ public abstract class BaseFragment extends Fragment {
if (context instanceof FragmentInteractionListener) if (context instanceof FragmentInteractionListener)
fragmentInteractionListener = (FragmentInteractionListener) context; fragmentInteractionListener = (FragmentInteractionListener) context;
else else
throw new RuntimeException(context.toString() throw new RuntimeException(context
+ " must implement OnFragmentInteractionListener"); + " must implement OnFragmentInteractionListener");
} }

4
app/src/main/java/gr/thmmy/mthmmy/model/Category.java

@ -1,12 +1,12 @@
package gr.thmmy.mthmmy.model; package gr.thmmy.mthmmy.model;
import static android.R.attr.id;
import com.bignerdranch.expandablerecyclerview.model.Parent; import com.bignerdranch.expandablerecyclerview.model.Parent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import static android.R.attr.id;
public class Category implements Parent<Board> { public class Category implements Parent<Board> {
private final String title; private final String title;
private final String categoryURL; private final String categoryURL;

29
app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java

@ -6,6 +6,7 @@ import java.util.Objects;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import gr.thmmy.mthmmy.base.BaseApplication;
import timber.log.Timber; import timber.log.Timber;
/** /**
@ -20,6 +21,14 @@ public class ThmmyPage {
@SuppressWarnings("unused") @SuppressWarnings("unused")
private static final String TAG = "LinkTarget"; private static final String TAG = "LinkTarget";
private static final String forumUrl = BaseApplication.getForumUrl();
private static final String forumHost = BaseApplication.getForumHost();
private static final String forumHostHttp = "http://" + forumHost;
private static final String forumHostHttps = "https://" + forumHost;
private static final String forumHostSimple = BaseApplication.getForumHostSimple();
private static final String forumHostSimpleHttp = "http://" + forumHostSimple;
private static final String forumHostSimpleHttps = "https://" + forumHostSimple;
/** /**
* An enum describing a link's target by defining the types:<ul> * An enum describing a link's target by defining the types:<ul>
* <li>{@link #NOT_THMMY}</li> * <li>{@link #NOT_THMMY}</li>
@ -142,9 +151,9 @@ public class ThmmyPage {
final String host = uri.getHost(); final String host = uri.getHost();
final String uriString = uri.toString(); final String uriString = uri.toString();
if (Objects.equals(uriString, "http://thmmy.gr") if (Objects.equals(uriString, forumHostSimpleHttp)
|| Objects.equals(uriString, "https://thmmy.gr")) return PageCategory.INDEX; || Objects.equals(uriString, forumHostSimpleHttps)) return PageCategory.INDEX;
if (Objects.equals(host, "www.thmmy.gr")) { if (Objects.equals(host, forumHost)) {
if (uriString.contains("topic=")) return PageCategory.TOPIC; if (uriString.contains("topic=")) return PageCategory.TOPIC;
else if (uriString.contains("board=")) return PageCategory.BOARD; else if (uriString.contains("board=")) return PageCategory.BOARD;
else if (uriString.contains("action=profile")) { else if (uriString.contains("action=profile")) {
@ -160,12 +169,12 @@ public class ThmmyPage {
return PageCategory.DOWNLOADS_FILE; return PageCategory.DOWNLOADS_FILE;
else if (uriString.contains("action=tpmod;dl")) else if (uriString.contains("action=tpmod;dl"))
return PageCategory.DOWNLOADS_CATEGORY; return PageCategory.DOWNLOADS_CATEGORY;
else if (uriString.contains("action=forum") || Objects.equals(uriString, "www.thmmy.gr") else if (uriString.contains("action=forum") || Objects.equals(uriString, forumHost)
|| Objects.equals(uriString, "http://www.thmmy.gr") || Objects.equals(uriString, forumHostHttp)
|| Objects.equals(uriString, "https://www.thmmy.gr") || Objects.equals(uriString, forumHostHttps)
|| Objects.equals(uriString, "https://www.thmmy.gr/smf/index.php")) || Objects.equals(uriString, forumUrl + "index.php"))
return PageCategory.INDEX; return PageCategory.INDEX;
Timber.v("Unknown thmmy link found, link: %s", uriString); Timber.v("Unknown thmmy link found, link: %s", uriString); //TODO: maybe report this?
return PageCategory.UNKNOWN_THMMY; return PageCategory.UNKNOWN_THMMY;
} }
return PageCategory.NOT_THMMY; return PageCategory.NOT_THMMY;
@ -184,10 +193,8 @@ public class ThmmyPage {
public static String getTopicId(String topicUrl) { public static String getTopicId(String topicUrl) {
if (resolvePageCategory(Uri.parse(topicUrl)) == PageCategory.TOPIC) { if (resolvePageCategory(Uri.parse(topicUrl)) == PageCategory.TOPIC) {
Matcher topicIdMatcher = Pattern.compile("topic=[0-9]+").matcher(topicUrl); Matcher topicIdMatcher = Pattern.compile("topic=[0-9]+").matcher(topicUrl);
if (topicIdMatcher.find()) { if (topicIdMatcher.find())
return topicUrl.substring(topicIdMatcher.start() + 6, topicIdMatcher.end()); return topicUrl.substring(topicIdMatcher.start() + 6, topicIdMatcher.end());
}
else return null;
} }
return null; return null;
} }

4
app/src/main/java/gr/thmmy/mthmmy/services/DownloadHelper.java

@ -1,5 +1,7 @@
package gr.thmmy.mthmmy.services; package gr.thmmy.mthmmy.services;
import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType;
import android.app.DownloadManager; import android.app.DownloadManager;
import android.content.Context; import android.content.Context;
import android.net.Uri; import android.net.Uri;
@ -15,8 +17,6 @@ import gr.thmmy.mthmmy.model.ThmmyFile;
import okhttp3.Cookie; import okhttp3.Cookie;
import timber.log.Timber; import timber.log.Timber;
import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType;
/** /**
* Not an actual service, but simply a helper class that adds a download to the queue of Android's * Not an actual service, but simply a helper class that adds a download to the queue of Android's
* DownloadManager system service. * DownloadManager system service.

50
app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java

@ -1,5 +1,17 @@
package gr.thmmy.mthmmy.services; package gr.thmmy.mthmmy.services;
import static androidx.core.app.NotificationCompat.PRIORITY_MAX;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.NOTIFICATION_LED_KEY;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.NOTIFICATION_VIBRATION_KEY;
import static gr.thmmy.mthmmy.activities.settings.SettingsFragment.SELECTED_RINGTONE;
import static gr.thmmy.mthmmy.activities.settings.SettingsFragment.SETTINGS_SHARED_PREFS;
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.base.BaseActivity.BOOKMARKED_BOARDS_KEY;
import static gr.thmmy.mthmmy.base.BaseActivity.BOOKMARKED_TOPICS_KEY;
import static gr.thmmy.mthmmy.base.BaseActivity.BOOKMARKS_SHARED_PREFS;
import static gr.thmmy.mthmmy.model.Bookmark.matchExistsById;
import android.app.Notification; import android.app.Notification;
import android.app.NotificationChannel; import android.app.NotificationChannel;
import android.app.NotificationManager; import android.app.NotificationManager;
@ -13,7 +25,6 @@ import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.service.notification.StatusBarNotification; import android.service.notification.StatusBarNotification;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
@ -34,18 +45,6 @@ import gr.thmmy.mthmmy.model.Bookmark;
import gr.thmmy.mthmmy.model.PostNotification; import gr.thmmy.mthmmy.model.PostNotification;
import timber.log.Timber; import timber.log.Timber;
import static androidx.core.app.NotificationCompat.PRIORITY_MAX;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.NOTIFICATION_LED_KEY;
import static gr.thmmy.mthmmy.activities.settings.SettingsActivity.NOTIFICATION_VIBRATION_KEY;
import static gr.thmmy.mthmmy.activities.settings.SettingsFragment.SELECTED_RINGTONE;
import static gr.thmmy.mthmmy.activities.settings.SettingsFragment.SETTINGS_SHARED_PREFS;
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.base.BaseActivity.BOOKMARKED_BOARDS_KEY;
import static gr.thmmy.mthmmy.base.BaseActivity.BOOKMARKED_TOPICS_KEY;
import static gr.thmmy.mthmmy.base.BaseActivity.BOOKMARKS_SHARED_PREFS;
import static gr.thmmy.mthmmy.model.Bookmark.matchExistsById;
public class NotificationService extends FirebaseMessagingService { public class NotificationService extends FirebaseMessagingService {
private static final int buildVersion = Build.VERSION.SDK_INT; private static final int buildVersion = Build.VERSION.SDK_INT;
private static final int disabledNotifiationsLedColor = Color.argb(0, 0, 0, 0); private static final int disabledNotifiationsLedColor = Color.argb(0, 0, 0, 0);
@ -171,7 +170,7 @@ public class NotificationService extends FirebaseMessagingService {
} }
//Builds notification //Builds notification
String topicUrl = "https://www.thmmy.gr/smf/index.php?topic=" + postNotification.getTopicId() + "." + postNotification.getPostId(); String topicUrl = BaseApplication.getForumUrl() + "index.php?topic=" + postNotification.getTopicId() + "." + postNotification.getPostId();
Intent intent = new Intent(this, MainActivity.class); Intent intent = new Intent(this, MainActivity.class);
Bundle extras = new Bundle(); Bundle extras = new Bundle();
extras.putString(BUNDLE_TOPIC_URL, topicUrl); extras.putString(BUNDLE_TOPIC_URL, topicUrl);
@ -204,15 +203,13 @@ public class NotificationService extends FirebaseMessagingService {
int newPostsCount = 1; int newPostsCount = 1;
if (buildVersion >= Build.VERSION_CODES.M) { Notification existingNotification = getActiveNotification(notificationId);
Notification existingNotification = getActiveNotification(notificationId); if (existingNotification != null) {
if (existingNotification != null) { newPostsCount = existingNotification.extras.getInt(NEW_POSTS_COUNT) + 1;
newPostsCount = existingNotification.extras.getInt(NEW_POSTS_COUNT) + 1; if (isTopicNotification)
if (isTopicNotification) contentText = newPostsCount + " new posts";
contentText = newPostsCount + " new posts"; else
else contentText = newPostsCount + " new posts in " + postNotification.getTopicTitle();
contentText = newPostsCount + " new posts in " + postNotification.getTopicTitle();
}
} }
Bundle notificationExtras = new Bundle(); Bundle notificationExtras = new Bundle();
@ -250,10 +247,7 @@ public class NotificationService extends FirebaseMessagingService {
if (buildVersion < Build.VERSION_CODES.O) if (buildVersion < Build.VERSION_CODES.O)
notificationBuilder.setPriority(PRIORITY_MAX); notificationBuilder.setPriority(PRIORITY_MAX);
boolean createSummaryNotification = false; boolean createSummaryNotification = otherNotificationsExist(notificationId);
if (buildVersion >= Build.VERSION_CODES.M)
createSummaryNotification = otherNotificationsExist(notificationId);
NotificationCompat.Builder summaryNotificationBuilder = null; NotificationCompat.Builder summaryNotificationBuilder = null;
if (createSummaryNotification) { if (createSummaryNotification) {
@ -281,7 +275,6 @@ public class NotificationService extends FirebaseMessagingService {
notificationManager.notify(SUMMARY_TAG, 0, summaryNotificationBuilder.build()); notificationManager.notify(SUMMARY_TAG, 0, summaryNotificationBuilder.build());
} }
@RequiresApi(api = Build.VERSION_CODES.M)
private Notification getActiveNotification(int notificationId) { private Notification getActiveNotification(int notificationId) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) { if (notificationManager != null) {
@ -295,7 +288,6 @@ public class NotificationService extends FirebaseMessagingService {
return null; return null;
} }
@RequiresApi(api = Build.VERSION_CODES.M)
private boolean otherNotificationsExist(int notificationId) { private boolean otherNotificationsExist(int notificationId) {
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) { if (notificationManager != null) {

6
app/src/main/java/gr/thmmy/mthmmy/session/LogoutTask.java

@ -1,5 +1,8 @@
package gr.thmmy.mthmmy.session; package gr.thmmy.mthmmy.session;
import static gr.thmmy.mthmmy.session.SessionManager.baseLogoutLink;
import static gr.thmmy.mthmmy.session.SessionManager.indexUrl;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
import org.jsoup.select.Elements; import org.jsoup.select.Elements;
@ -11,9 +14,6 @@ import gr.thmmy.mthmmy.utils.parsing.ParseException;
import okhttp3.Response; import okhttp3.Response;
import timber.log.Timber; 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<Void> { public class LogoutTask extends NetworkTask<Void> {
private String logoutLink; private String logoutLink;

6
app/src/main/java/gr/thmmy/mthmmy/session/MarkAsReadTask.java

@ -1,5 +1,8 @@
package gr.thmmy.mthmmy.session; package gr.thmmy.mthmmy.session;
import static gr.thmmy.mthmmy.session.SessionManager.baseMarkAllAsReadLink;
import static gr.thmmy.mthmmy.session.SessionManager.unreadUrl;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
import org.jsoup.select.Elements; import org.jsoup.select.Elements;
@ -9,9 +12,6 @@ import gr.thmmy.mthmmy.utils.networking.NetworkTask;
import gr.thmmy.mthmmy.utils.parsing.ParseException; import gr.thmmy.mthmmy.utils.parsing.ParseException;
import okhttp3.Response; import okhttp3.Response;
import static gr.thmmy.mthmmy.session.SessionManager.baseMarkAllAsReadLink;
import static gr.thmmy.mthmmy.session.SessionManager.unreadUrl;
public class MarkAsReadTask extends NetworkTask<Void> { public class MarkAsReadTask extends NetworkTask<Void> {
private String markAsReadLink; private String markAsReadLink;

22
app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java

@ -18,6 +18,7 @@ import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import gr.thmmy.mthmmy.base.BaseApplication;
import gr.thmmy.mthmmy.utils.parsing.ParseException; import gr.thmmy.mthmmy.utils.parsing.ParseException;
import okhttp3.Cookie; import okhttp3.Cookie;
import okhttp3.FormBody; import okhttp3.FormBody;
@ -34,13 +35,14 @@ import timber.log.Timber;
*/ */
public class SessionManager { public class SessionManager {
//Generic constants //Generic constants
public static final HttpUrl indexUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?theme=4"); private final static String FORUM_URL = BaseApplication.getForumUrl();
public static final HttpUrl forumUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=forum;theme=4"); public static final HttpUrl indexUrl = HttpUrl.parse(FORUM_URL + "index.php?theme=4");
private static final HttpUrl loginUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=login2"); private static final HttpUrl forumUrl = HttpUrl.parse(FORUM_URL + "index.php?action=forum;theme=4");
public static final HttpUrl unreadUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=unread;all;start=0;theme=4"); private static final HttpUrl loginUrl = HttpUrl.parse(FORUM_URL + "index.php?action=login2");
public static final HttpUrl shoutboxUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=tpmod;sa=shoutbox;theme=4"); public static final HttpUrl unreadUrl = HttpUrl.parse(FORUM_URL + "index.php?action=unread;all;start=0;theme=4");
static final String baseLogoutLink = "https://www.thmmy.gr/smf/index.php?action=logout;sesc="; public static final HttpUrl shoutboxUrl = HttpUrl.parse(FORUM_URL + "index.php?action=tpmod;sa=shoutbox;theme=4");
static final String baseMarkAllAsReadLink = "https://www.thmmy.gr/smf/index.php?action=markasread;sa=all;sesc="; static final String baseLogoutLink = FORUM_URL + "index.php?action=logout;sesc=";
static final String baseMarkAllAsReadLink = FORUM_URL + "index.php?action=markasread;sa=all;sesc=";
private static final String guestName = "Guest"; private static final String guestName = "Guest";
//Response Codes - make sure they do not overlap with NetworkResultCodes, just in case //Response Codes - make sure they do not overlap with NetworkResultCodes, just in case
@ -190,6 +192,10 @@ public class SessionManager {
} }
//--------------------------------------- GETTERS ------------------------------------------------ //--------------------------------------- GETTERS ------------------------------------------------
public static HttpUrl getForumUrl() {
return forumUrl;
}
public String getUsername() { public String getUsername() {
return sessionSharedPrefs.getString(USERNAME, USERNAME); return sessionSharedPrefs.getString(USERNAME, USERNAME);
} }
@ -291,7 +297,7 @@ public class SessionManager {
if (elements.size() == 1) { if (elements.size() == 1) {
String link = elements.first().attr("href"); String link = elements.first().attr("href");
Pattern pattern = Pattern.compile("https://www.thmmy.gr/smf/index.php\\?action=profile;u=(\\d*);sa=showPosts"); Pattern pattern = Pattern.compile(FORUM_URL + "index.php\\?action=profile;u=(\\d*);sa=showPosts");
Matcher matcher = pattern.matcher(link); Matcher matcher = pattern.matcher(link);
if (matcher.find()) if (matcher.find())
return Integer.parseInt(matcher.group(1)); return Integer.parseInt(matcher.group(1));

4
app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java

@ -1,13 +1,13 @@
package gr.thmmy.mthmmy.utils; package gr.thmmy.mthmmy.utils;
import androidx.annotation.VisibleForTesting;
import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS;
import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS;
import static android.text.format.DateUtils.YEAR_IN_MILLIS; import static android.text.format.DateUtils.YEAR_IN_MILLIS;
import androidx.annotation.VisibleForTesting;
public class DateTimeUtils { public class DateTimeUtils {
private static final long MONTH_IN_MILLIS = 30 * DAY_IN_MILLIS; private static final long MONTH_IN_MILLIS = 30 * DAY_IN_MILLIS;

19
app/src/main/java/gr/thmmy/mthmmy/utils/FileUtils.java

@ -1,5 +1,7 @@
package gr.thmmy.mthmmy.utils; package gr.thmmy.mthmmy.utils;
import static gr.thmmy.mthmmy.services.DownloadHelper.SAVE_DIR;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
@ -10,18 +12,17 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import java.io.File; import java.io.File;
import java.util.Locale;
import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.R;
import static gr.thmmy.mthmmy.services.DownloadHelper.SAVE_DIR;
public class FileUtils { public class FileUtils {
@NonNull @NonNull
public static String getMimeType(@NonNull String fileName) { public static String getMimeType(@NonNull String fileName) {
String type = null; String type = null;
final String extension = MimeTypeMap.getFileExtensionFromUrl(fileName); final String extension = MimeTypeMap.getFileExtensionFromUrl(fileName);
if (extension != null) if (extension != null)
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase()); type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase(Locale.ROOT));
if (type == null) if (type == null)
type = "*/*"; type = "*/*";
@ -39,7 +40,7 @@ public class FileUtils {
if (!filename.contains(".")) { if (!filename.contains(".")) {
return null; return null;
} }
if (filename.toLowerCase().endsWith(".tar.gz")) { if (filename.toLowerCase(Locale.ROOT).endsWith(".tar.gz")) {
fileExtension = filename.substring(filename.length() - 7); fileExtension = filename.substring(filename.length() - 7);
} }
else { else {
@ -63,7 +64,9 @@ public class FileUtils {
if (uri.getScheme().equals("content")) { if (uri.getScheme().equals("content")) {
try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) { try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
filename = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); final int columnIndex = (cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
if(columnIndex>=0)
filename = cursor.getString(columnIndex);
} }
} }
} }
@ -81,7 +84,9 @@ public class FileUtils {
public static long sizeFromUri(Context context, @NonNull Uri uri) { public static long sizeFromUri(Context context, @NonNull Uri uri) {
try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) { try (Cursor cursor = context.getContentResolver().query(uri, null, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) { if (cursor != null && cursor.moveToFirst()) {
return cursor.getLong(cursor.getColumnIndex(OpenableColumns.SIZE)); final int columnIndex = (cursor.getColumnIndex(OpenableColumns.SIZE));
if(columnIndex>=0)
return cursor.getLong(columnIndex);
} }
} }
return -1; return -1;
@ -97,7 +102,7 @@ public class FileUtils {
*/ */
@NonNull @NonNull
public static String faIconFromFilename(Context context, String filename) { public static String faIconFromFilename(Context context, String filename) {
filename = filename.toLowerCase(); filename = filename.toLowerCase(Locale.ROOT);
if (filename.contains("jpg") || filename.contains("gif") || filename.contains("jpeg") if (filename.contains("jpg") || filename.contains("gif") || filename.contains("jpeg")
|| filename.contains("png")) || filename.contains("png"))

14
app/src/main/java/gr/thmmy/mthmmy/utils/HTMLUtils.java

@ -1,5 +1,12 @@
package gr.thmmy.mthmmy.utils; package gr.thmmy.mthmmy.utils;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -17,13 +24,6 @@ import gr.thmmy.mthmmy.activities.main.MainActivity;
import gr.thmmy.mthmmy.activities.profile.ProfileActivity; import gr.thmmy.mthmmy.activities.profile.ProfileActivity;
import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.model.ThmmyPage;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_TITLE;
import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
public class HTMLUtils { public class HTMLUtils {
private HTMLUtils() { private HTMLUtils() {
} }

2
app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkTask.java

@ -57,7 +57,7 @@ public abstract class NetworkTask<T> extends ExternalAsyncTask<String, Parcel<T>
try { try {
response = sendRequest(BaseApplication.getInstance().getClient(), input); response = sendRequest(BaseApplication.getInstance().getClient(), input);
} catch (IOException e) { } catch (IOException e) {
Timber.e(e, "Error connecting to thmmy.gr"); Timber.e(e, "Error connecting to forum!");
return new Parcel<>(NetworkResultCodes.NETWORK_ERROR, null); return new Parcel<>(NetworkResultCodes.NETWORK_ERROR, null);
} }
String responseBodyString; String responseBodyString;

244
app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java

@ -9,13 +9,15 @@ import java.util.HashMap;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import gr.thmmy.mthmmy.base.BaseApplication;
/** /**
* This class consists exclusively of static classes (enums) and methods (excluding methods of inner * This class consists exclusively of static classes (enums) and methods (excluding methods of inner
* classes). It can be used to resolve a page's language and state or fix embedded videos html code * classes). It can be used to resolve a page's language and state or fix embedded videos html code
* and obfuscated emails. * and obfuscated emails.
*/ */
public class ParseHelpers { public class ParseHelpers {
private final static String FORUM_URL = BaseApplication.getForumUrl();
/** /**
* An enum describing a forum page's language by defining the types:<ul> * An enum describing a forum page's language by defining the types:<ul>
* <li>{@link #PAGE_INCOMPLETE}</li> * <li>{@link #PAGE_INCOMPLETE}</li>
@ -185,138 +187,138 @@ public class ParseHelpers {
* @return the base URL of the given topic * @return the base URL of the given topic
*/ */
public static String getBaseURL(String topicURL) { public static String getBaseURL(String topicURL) {
String forumUrl = "https://www.thmmy.gr/smf/index.php?"; String indexUrl = FORUM_URL + "index.php?";
Matcher baseUrlMatcher = Pattern.compile("topic=[0-9]+").matcher(topicURL); Matcher baseUrlMatcher = Pattern.compile("topic=[0-9]+").matcher(topicURL);
if (baseUrlMatcher.find()) if (baseUrlMatcher.find())
return forumUrl + topicURL.substring(baseUrlMatcher.start(), baseUrlMatcher.end()); return indexUrl + topicURL.substring(baseUrlMatcher.start(), baseUrlMatcher.end());
else return ""; else return "";
} }
public static String emojiTagToHtml(String emojiTagedString) { public static String emojiTagToHtml(String emojiTagedString) {
HashMap<Pattern, String> tagToHtmlMap = new HashMap<>(); HashMap<Pattern, String> tagToHtmlMap = new HashMap<>();
tagToHtmlMap.put(Pattern.compile(Pattern.quote(":)"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/smiley.gif\" alt=\"Smiley\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote(":)"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/smiley.gif\" alt=\"Smiley\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote(";)"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/wink.gif\" alt=\"Wink\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote(";)"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/wink.gif\" alt=\"Wink\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote(":D"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/cheesy.gif\" alt=\"Cheesy\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote(":D"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/cheesy.gif\" alt=\"Cheesy\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote(";D"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/grin.gif\" alt=\"Grin\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote(";D"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/grin.gif\" alt=\"Grin\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("&gt;:("), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/angry.gif\" alt=\"Angry\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("&gt;:("), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/angry.gif\" alt=\"Angry\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote(":("), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/sad.gif\" alt=\"Sad\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote(":("), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/sad.gif\" alt=\"Sad\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote(":o"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/shocked.gif\" alt=\"Shocked\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote(":o"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/shocked.gif\" alt=\"Shocked\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("8))"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/cool.gif\" alt=\"Cool\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("8))"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/cool.gif\" alt=\"Cool\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote(":???:"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/huh.gif\" alt=\"Huh\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote(":???:"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/huh.gif\" alt=\"Huh\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote(":P"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/tongue.gif\" alt=\"Tongue\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote(":P"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/tongue.gif\" alt=\"Tongue\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote(":-["), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/embarrassed.gif\" alt=\"Embarrassed\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote(":-["), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/embarrassed.gif\" alt=\"Embarrassed\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote(":-X"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/lipsrsealed.gif\" alt=\"Lips Sealed\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote(":-X"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/lipsrsealed.gif\" alt=\"Lips Sealed\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote(":-\\"), Pattern.MULTILINE), "<img src =\"https://www.thmmy.gr/smf/Smileys/default_dither/undecided.gif\" alt=\"Undecided\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote(":-\\"), Pattern.MULTILINE), "<img src =\"" + FORUM_URL + "Smileys/default_dither/undecided.gif\" alt=\"Undecided\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote(":-*"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/kiss.gif\" alt=\"Kiss\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote(":-*"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/kiss.gif\" alt=\"Kiss\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote(":'("), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/cry.gif\" alt=\"Cry\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote(":'("), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/cry.gif\" alt=\"Cry\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("&lt;3"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/heart.gif\" alt=\"heart\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("&lt;3"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/heart.gif\" alt=\"heart\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^locked^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/locked.gif\" alt=\"kleidaria\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^locked^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/locked.gif\" alt=\"kleidaria\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^rollover^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/roll_over.gif\" alt=\"roll_over\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^rollover^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/roll_over.gif\" alt=\"roll_over\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^redface^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/redface.gif\" alt=\"redface\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^redface^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/redface.gif\" alt=\"redface\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^confused^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/confused.gif\" alt=\"confused\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^confused^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/confused.gif\" alt=\"confused\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^innocent^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/innocent.gif\" alt=\"innocent\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^innocent^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/innocent.gif\" alt=\"innocent\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^sleep^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/sleep.gif\" alt=\"sleep\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^sleep^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/sleep.gif\" alt=\"sleep\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^sealed^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/lips_sealed.gif\" alt=\"lips_sealed\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^sealed^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/lips_sealed.gif\" alt=\"lips_sealed\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^cool^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/cool.bmp\" alt=\"cool\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^cool^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/cool.bmp\" alt=\"cool\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^crazy^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/crazy.jpg\" alt=\"crazy\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^crazy^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/crazy.jpg\" alt=\"crazy\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^mad^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/mad.jpg\" alt=\"mad\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^mad^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/mad.jpg\" alt=\"mad\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^wav^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/wav.gif\" alt=\"wav\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^wav^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/wav.gif\" alt=\"wav\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^binkybaby^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/binkybaby.gif\" alt=\"BinkyBaby\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^binkybaby^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/binkybaby.gif\" alt=\"BinkyBaby\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^Police^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/Police.gif\" alt=\"\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^Police^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/Police.gif\" alt=\"\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^dontknow^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/dontknow.gif\" alt=\"DontKnow\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^dontknow^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/dontknow.gif\" alt=\"DontKnow\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote(":angry4:"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/angry4.gif\" alt=\"angry4\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote(":angry4:"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/angry4.gif\" alt=\"angry4\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^angryhot^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/angry_hot.gif\" alt=\"angryAndHot\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^angryhot^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/angry_hot.gif\" alt=\"angryAndHot\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^angry^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/angry.gif\" alt=\"angry\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^angry^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/angry.gif\" alt=\"angry\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^fouska^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/foyska.gif\" alt=\"\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^fouska^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/foyska.gif\" alt=\"\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^nysta^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/nista.gif\" alt=\"\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^nysta^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/nista.gif\" alt=\"\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^sfinaki^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/10_7_3.gif\" alt=\"\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^sfinaki^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/10_7_3.gif\" alt=\"\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^banghead^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/BangHead.gif\" alt=\"bang_head\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^banghead^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/BangHead.gif\" alt=\"bang_head\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^crybaby^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/crybaby.gif\" alt=\"CryBaby\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^crybaby^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/crybaby.gif\" alt=\"CryBaby\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^hello^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/hello.gif\" alt=\"Hello\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^hello^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/hello.gif\" alt=\"Hello\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^jerk^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/jerk.gif\" alt=\"jerk\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^jerk^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/jerk.gif\" alt=\"jerk\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^nono^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/nono.gif\" alt=\"NoNo\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^nono^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/nono.gif\" alt=\"NoNo\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^notworthy^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/notworthy.gif\" alt=\"NotWorthy\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^notworthy^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/notworthy.gif\" alt=\"NotWorthy\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^off-topic^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/off -topic.gif\" alt=\"Off-topic\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^off-topic^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/off -topic.gif\" alt=\"Off-topic\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^puke^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/puke.gif\" alt=\"Puke\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^puke^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/puke.gif\" alt=\"Puke\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^shout^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/shout.gif\" alt=\"Shout\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^shout^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/shout.gif\" alt=\"Shout\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^slurp^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/slurp.gif\" alt=\"Slurp\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^slurp^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/slurp.gif\" alt=\"Slurp\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^superconfused^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/superconfused.gif\" alt=\"SuperConfused\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^superconfused^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/superconfused.gif\" alt=\"SuperConfused\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^superinnocent^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/superinnocent.gif\" alt=\"SuperInnocent\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^superinnocent^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/superinnocent.gif\" alt=\"SuperInnocent\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^cellPhone^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/cellPhone.gif\" alt=\"CellPhone\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^cellPhone^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/cellPhone.gif\" alt=\"CellPhone\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^idiot^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/idiot.gif\" alt=\"Idiot\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^idiot^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/idiot.gif\" alt=\"Idiot\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^knuppel^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/knuppel.gif\" alt=\"Knuppel\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^knuppel^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/knuppel.gif\" alt=\"Knuppel\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^tickedOff^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/tickedoff.gif\" alt=\"TickedOff\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^tickedOff^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/tickedoff.gif\" alt=\"TickedOff\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^peace^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/peace.gif\" alt=\"Peace\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^peace^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/peace.gif\" alt=\"Peace\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^suspicious^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/suspicious.gif\" alt=\"Suspicious\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^suspicious^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/suspicious.gif\" alt=\"Suspicious\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^caffine^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/caffine.gif\" alt=\"Caffine\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^caffine^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/caffine.gif\" alt=\"Caffine\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^argue^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/argue.gif\" alt=\"argue\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^argue^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/argue.gif\" alt=\"argue\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^banned2^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/banned2.gif\" alt=\"banned2\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^banned2^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/banned2.gif\" alt=\"banned2\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^banned^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/banned.gif\" alt=\"banned\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^banned^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/banned.gif\" alt=\"banned\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^bath^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/bath.gif\" alt=\"bath\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^bath^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/bath.gif\" alt=\"bath\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^beg^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/beg.gif\" alt=\"beg\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^beg^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/beg.gif\" alt=\"beg\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^bluescreen^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/bluescreen.gif\" alt=\"bluescreen\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^bluescreen^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/bluescreen.gif\" alt=\"bluescreen\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^boil^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/boil.gif\" alt=\"boil\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^boil^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/boil.gif\" alt=\"boil\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^bye^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/bye.gif\" alt=\"bye\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^bye^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/bye.gif\" alt=\"bye\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^callmerip^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/callmerip.gif\" alt=\"callmerip\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^callmerip^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/callmerip.gif\" alt=\"callmerip\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^carnaval^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/carnaval.gif\" alt=\"carnaval\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^carnaval^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/carnaval.gif\" alt=\"carnaval\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^clap^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/clap.gif\" alt=\"clap\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^clap^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/clap.gif\" alt=\"clap\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^coffepot^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/coffeepot.gif\" alt=\"coffepot\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^coffepot^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/coffeepot.gif\" alt=\"coffepot\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^crap^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/crap.gif\" alt=\"crap\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^crap^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/crap.gif\" alt=\"crap\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^curses^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/curses.gif\" alt=\"curses\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^curses^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/curses.gif\" alt=\"curses\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^funny^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/funny.gif\" alt=\"funny\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^funny^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/funny.gif\" alt=\"funny\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^guitar^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/guitar1.gif\" alt=\"guitar\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^guitar^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/guitar1.gif\" alt=\"guitar\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^kissy^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/icon_kissy.gif\" alt=\"kissy\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^kissy^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/icon_kissy.gif\" alt=\"kissy\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^band^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/band.gif\" alt=\"band\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^band^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/band.gif\" alt=\"band\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^ivres^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/ivres.gif\" alt=\"ivres\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^ivres^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/ivres.gif\" alt=\"ivres\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^kaloe^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/kaloe.gif\" alt=\"kaloe\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^kaloe^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/kaloe.gif\" alt=\"kaloe\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^kremala^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/kremala.gif\" alt=\"kremala\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^kremala^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/kremala.gif\" alt=\"kremala\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^moon^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/moon.gif\" alt=\"moon\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^moon^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/moon.gif\" alt=\"moon\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^mopping^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/mopping.gif\" alt=\"mopping\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^mopping^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/mopping.gif\" alt=\"mopping\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^mountza^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/mountza.gif\" alt=\"mountza\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^mountza^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/mountza.gif\" alt=\"mountza\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^pcsleep^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/pcsleep.gif\" alt=\"pcsleep\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^pcsleep^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/pcsleep.gif\" alt=\"pcsleep\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^pinokio^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/pinokio.gif\" alt=\"pinokio\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^pinokio^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/pinokio.gif\" alt=\"pinokio\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^poke^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/poke.gif\" alt=\"poke\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^poke^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/poke.gif\" alt=\"poke\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^seestars^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/seestars.gif\" alt=\"seestars\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^seestars^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/seestars.gif\" alt=\"seestars\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^sfyri^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/sfyri.gif\" alt=\"sfyri\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^sfyri^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/sfyri.gif\" alt=\"sfyri\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^spam^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/spam2.gif\" alt=\"spam\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^spam^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/spam2.gif\" alt=\"spam\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^super^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/super.gif\" alt=\"super\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^super^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/super.gif\" alt=\"super\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^tafos^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/tafos.gif\" alt=\"tafos\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^tafos^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/tafos.gif\" alt=\"tafos\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^tomato^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/tomatomourh.gif\" alt=\"tomato\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^tomato^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/tomatomourh.gif\" alt=\"tomato\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^ytold^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/ytold.gif\" alt=\"ytold\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^ytold^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/ytold.gif\" alt=\"ytold\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^beer^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/beer2.gif\" alt=\"beer\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^beer^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/beer2.gif\" alt=\"beer\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^yue^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/yu.gif\" alt=\"\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^yue^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/yu.gif\" alt=\"\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^eatpaper^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/a-eatpaper.gif\" alt=\"\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^eatpaper^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/a-eatpaper.gif\" alt=\"\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^fritz^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/fritz.gif\" alt=\"ο fritz!!!\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^fritz^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/fritz.gif\" alt=\"ο fritz!!!\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^wade^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/wade.gif\" alt=\"o Wade!!!\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^wade^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/wade.gif\" alt=\"o Wade!!!\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^lypi^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/lypi.gif\" alt=\"\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^lypi^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/lypi.gif\" alt=\"\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^aytoxeir^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/megashok1wq.gif\" alt=\"\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^aytoxeir^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/megashok1wq.gif\" alt=\"\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^victory^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/victory.gif\" alt=\"\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^victory^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/victory.gif\" alt=\"\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^filarakia^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/filarakia.gif\" alt=\"\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^filarakia^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/filarakia.gif\" alt=\"\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^hat^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/bonjour-97213.gif\" alt=\"bonjour\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^hat^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/bonjour-97213.gif\" alt=\"bonjour\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^miss^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/curtseyqi9.gif\" alt=\"bonjour2\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^miss^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/curtseyqi9.gif\" alt=\"bonjour2\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^rolfmao^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/rofl.gif\" alt=\"\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^rolfmao^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/rofl.gif\" alt=\"\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^lock^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/locked.gif\" alt=\"\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^lock^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/locked.gif\" alt=\"\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^que^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/question.gif\" alt=\"question\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^que^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/question.gif\" alt=\"question\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^shifty^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/shifty.gif\" alt=\"shifty\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^shifty^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/shifty.gif\" alt=\"shifty\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^shy^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/shy.png\" alt=\"shy\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^shy^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/shy.png\" alt=\"shy\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^music_listen^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/music.gif\" alt=\"music_listenning\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^music_listen^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/music.gif\" alt=\"music_listenning\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^bagface^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/shamed_bag.jpg\" alt=\"bag_face\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^bagface^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/shamed_bag.jpg\" alt=\"bag_face\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^rotate^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/rotfl.gif\" alt=\"rotation\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^rotate^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/rotfl.gif\" alt=\"rotation\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^love^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/love.jpg\" alt=\"love\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^love^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/love.jpg\" alt=\"love\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^speech^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/speech.gif\" alt=\"speech\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^speech^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/speech.gif\" alt=\"speech\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^facepalm^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/facepalm.gif\" alt=\"\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^facepalm^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/facepalm.gif\" alt=\"\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^shocked^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/shocked.png\" alt=\"shocked\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^shocked^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/shocked.png\" alt=\"shocked\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^ex_shocked^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/extremely_shocked.png\" alt=\"extremely_shocked\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^ex_shocked^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/extremely_shocked.png\" alt=\"extremely_shocked\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^smurf^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/smurf.gif\" alt=\"smurf\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^smurf^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/smurf.gif\" alt=\"smurf\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^monster^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/monster.bmp\" alt=\"monster\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^monster^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/monster.bmp\" alt=\"monster\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^pig^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/noffe.gif\" alt=\"pig\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^pig^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/noffe.gif\" alt=\"pig\" border=\"0\">");
tagToHtmlMap.put(Pattern.compile(Pattern.quote("^lol^"), Pattern.MULTILINE), "<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/LoL.jpg\" alt=\"lol\" border=\"0\">"); tagToHtmlMap.put(Pattern.compile(Pattern.quote("^lol^"), Pattern.MULTILINE), "<img src=\"" + FORUM_URL + "Smileys/default_dither/LoL.jpg\" alt=\"lol\" border=\"0\">");
//Needs priority over the rest tags //Needs priority over the rest tags
final Pattern pattern = Pattern.compile(Pattern.quote("::)"), Pattern.MULTILINE); final Pattern pattern = Pattern.compile(Pattern.quote("::)"), Pattern.MULTILINE);
Matcher matcher = pattern.matcher(emojiTagedString); Matcher matcher = pattern.matcher(emojiTagedString);
emojiTagedString = matcher.replaceAll("<img src=\"https://www.thmmy.gr/smf/Smileys/default_dither/rolleyes.gif\" alt=\"Roll Eyes\" border=\"0\">"); emojiTagedString = matcher.replaceAll("<img src=\"" + FORUM_URL + "Smileys/default_dither/rolleyes.gif\" alt=\"Roll Eyes\" border=\"0\">");
for (Pattern patternKey : tagToHtmlMap.keySet()) { for (Pattern patternKey : tagToHtmlMap.keySet()) {
matcher = patternKey.matcher(emojiTagedString); matcher = patternKey.matcher(emojiTagedString);

6
app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java

@ -40,8 +40,7 @@ public class ThmmyDateTimeParser {
private static final Pattern pattern = Pattern.compile("\\s((1[3-9]|2[0-3]):)"); private static final Pattern pattern = Pattern.compile("\\s((1[3-9]|2[0-3]):)");
private ThmmyDateTimeParser() { private ThmmyDateTimeParser() {}
}
public static String convertToTimestamp(String thmmyDateTime) { public static String convertToTimestamp(String thmmyDateTime) {
Timber.v("Will attempt to convert %s to timestamp.", thmmyDateTime); Timber.v("Will attempt to convert %s to timestamp.", thmmyDateTime);
@ -78,7 +77,8 @@ public class ThmmyDateTimeParser {
localDateTime = formatter.withLocale(greekLocale).parseLocalDateTime(thmmyDateTime); localDateTime = formatter.withLocale(greekLocale).parseLocalDateTime(thmmyDateTime);
} catch (IllegalArgumentException e2) { } catch (IllegalArgumentException e2) {
Timber.v("Parsing DateTime %s using Greek Locale failed too.", thmmyDateTime); Timber.v("Parsing DateTime %s using Greek Locale failed too.", thmmyDateTime);
Timber.e("Couldn't convert DateTime %s to timestamp!", originalDateTime); Timber.e("Couldn't convert DateTime to timestamp (original: \"%s\", modified: \"%s\")!",
originalDateTime, thmmyDateTime);
return null; return null;
} }
} }

4
app/src/main/java/gr/thmmy/mthmmy/utils/ui/ImageDownloadDialogBuilder.java

@ -1,5 +1,7 @@
package gr.thmmy.mthmmy.utils.ui; package gr.thmmy.mthmmy.utils.ui;
import static android.content.Context.CLIPBOARD_SERVICE;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
@ -18,8 +20,6 @@ import gr.thmmy.mthmmy.base.BaseApplication;
import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.model.ThmmyFile;
import timber.log.Timber; import timber.log.Timber;
import static android.content.Context.CLIPBOARD_SERVICE;
public class ImageDownloadDialogBuilder extends AlertDialog.Builder { public class ImageDownloadDialogBuilder extends AlertDialog.Builder {
private static final String[] colors = {"Copy image location", "Save Image"}; private static final String[] colors = {"Copy image location", "Save Image"};

4
app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java

@ -484,10 +484,10 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
return prepareForEditResult.getValue().getPostText(); return prepareForEditResult.getValue().getPostText();
} }
public String getBuildedQuotes() { public String getBuiltQuotes() {
if (prepareForReplyResult.getValue() == null) if (prepareForReplyResult.getValue() == null)
throw new NullPointerException("Reply preparation was not found"); throw new NullPointerException("Reply preparation was not found");
return prepareForReplyResult.getValue().getBuildedQuotes(); return prepareForReplyResult.getValue().getBuiltQuotes();
} }
public int postCount() { public int postCount() {

8
app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java

@ -1,5 +1,9 @@
package gr.thmmy.mthmmy.views; package gr.thmmy.mthmmy.views;
import static android.content.Context.CLIPBOARD_SERVICE;
import static gr.thmmy.mthmmy.utils.parsing.ParseHelpers.VIDEO_ID_PARAMETER;
import static gr.thmmy.mthmmy.utils.ui.PhotoViewUtils.displayPhotoViewImage;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
@ -13,10 +17,6 @@ import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.base.BaseApplication; import gr.thmmy.mthmmy.base.BaseApplication;
import gr.thmmy.mthmmy.utils.ui.ImageDownloadDialogBuilder; import gr.thmmy.mthmmy.utils.ui.ImageDownloadDialogBuilder;
import static android.content.Context.CLIPBOARD_SERVICE;
import static gr.thmmy.mthmmy.utils.parsing.ParseHelpers.VIDEO_ID_PARAMETER;
import static gr.thmmy.mthmmy.utils.ui.PhotoViewUtils.displayPhotoViewImage;
public class ReactiveWebView extends WebView { public class ReactiveWebView extends WebView {
private final static long MAX_TOUCH_DURATION = 100; private final static long MAX_TOUCH_DURATION = 100;
private final Context context; private final Context context;

4
app/src/main/java/gr/thmmy/mthmmy/views/RelativeTimeTextView.java

@ -1,5 +1,7 @@
package gr.thmmy.mthmmy.views; package gr.thmmy.mthmmy.views;
import static gr.thmmy.mthmmy.utils.DateTimeUtils.getRelativeTimeSpanString;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
@ -15,8 +17,6 @@ import java.lang.ref.WeakReference;
import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.R;
import static gr.thmmy.mthmmy.utils.DateTimeUtils.getRelativeTimeSpanString;
/** /**
* A modified version of https://github.com/curioustechizen/android-ago * A modified version of https://github.com/curioustechizen/android-ago
*/ */

33
app/src/main/java/gr/thmmy/mthmmy/views/editorview/EditorView.java

@ -8,7 +8,6 @@ import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.AsyncTask; import android.os.AsyncTask;
import android.os.Build;
import android.text.Editable; import android.text.Editable;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
@ -201,24 +200,24 @@ public class EditorView extends LinearLayout implements EmojiInputField {
}); });
} }
popupWindow.showAsDropDown(view); popupWindow.showAsDropDown(view);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... voids) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Timber.e(e);
}
return null;
}
@Override new AsyncTask<Void, Void, Void>() {
protected void onPostExecute(Void aVoid) { @Override
editText.setSelection(selectionStart, selectionEnd); protected Void doInBackground(Void... voids) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Timber.e(e);
} }
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); return null;
} }
@Override
protected void onPostExecute(Void aVoid) {
editText.setSelection(selectionStart, selectionEnd);
}
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
break; break;
case R.drawable.ic_format_size: case R.drawable.ic_format_size:
hadTextSelection = editText.hasSelection(); hadTextSelection = editText.hasSelection();

52
app/src/main/res/layout-v23/activity_topic_overflow_menu.xml

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/background_light"
android:orientation="vertical">
<TextView
android:id="@+id/post_share_button"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:background="@color/background_light"
android:foreground="?android:attr/selectableItemBackground"
android:drawablePadding="5dp"
android:gravity="center_vertical"
android:paddingBottom="6dp"
android:paddingEnd="12dp"
android:paddingStart="12dp"
android:paddingTop="6dp"
android:text="@string/post_share_button"
android:textColor="@color/primary_text" />
<TextView
android:id="@+id/edit_post"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:background="@color/background_light"
android:foreground="?android:attr/selectableItemBackground"
android:drawablePadding="5dp"
android:gravity="center_vertical"
android:paddingBottom="6dp"
android:paddingEnd="12dp"
android:paddingStart="12dp"
android:paddingTop="6dp"
android:text="@string/post_edit_button"
android:textColor="@color/primary_text" />
<TextView
android:id="@+id/delete_post"
android:layout_width="wrap_content"
android:layout_height="35dp"
android:background="@color/background_light"
android:foreground="?android:attr/selectableItemBackground"
android:drawablePadding="5dp"
android:gravity="center_vertical"
android:paddingBottom="6dp"
android:paddingEnd="12dp"
android:paddingStart="12dp"
android:paddingTop="6dp"
android:text="@string/post_delete_button"
android:textColor="@color/primary_text" />
</LinearLayout>

2
app/src/main/res/layout/activity_bookmarks.xml

@ -21,7 +21,7 @@
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" android:background="?attr/colorPrimary"
android:gravity="center" android:gravity="center"
app:popupTheme="@style/ToolbarTheme"></androidx.appcompat.widget.Toolbar> app:popupTheme="@style/ToolbarTheme" />
<com.google.android.material.tabs.TabLayout <com.google.android.material.tabs.TabLayout
android:id="@+id/bookmark_tabs" android:id="@+id/bookmark_tabs"

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

@ -20,7 +20,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" android:background="?attr/colorPrimary"
app:popupTheme="@style/ToolbarTheme"></androidx.appcompat.widget.Toolbar> app:popupTheme="@style/ToolbarTheme" />
</com.google.android.material.appbar.AppBarLayout> </com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
@ -31,7 +31,7 @@
android:background="@color/background" android:background="@color/background"
android:scrollbars="none" android:scrollbars="none"
app:layout_behavior="@string/appbar_scrolling_view_behavior" app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context="gr.thmmy.mthmmy.activities.downloads.DownloadsActivity"></androidx.recyclerview.widget.RecyclerView> tools:context="gr.thmmy.mthmmy.activities.downloads.DownloadsActivity" />
<me.zhanghai.android.materialprogressbar.MaterialProgressBar <me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="@+id/progressBar" android:id="@+id/progressBar"
@ -45,13 +45,13 @@
app:mpb_indeterminateTint="@color/accent" app:mpb_indeterminateTint="@color/accent"
app:mpb_progressStyle="horizontal" /> app:mpb_progressStyle="horizontal" />
<com.google.android.material.floatingactionbutton.FloatingActionButton <!-- <com.google.android.material.floatingactionbutton.FloatingActionButton-->
android:id="@+id/upload_fab" <!-- android:id="@+id/upload_fab"-->
android:layout_width="wrap_content" <!-- android:layout_width="wrap_content"-->
android:layout_height="wrap_content" <!-- android:layout_height="wrap_content"-->
android:layout_gravity="bottom|end" <!-- android:layout_gravity="bottom|end"-->
android:layout_marginBottom="@dimen/fab_margins" <!-- android:layout_marginBottom="@dimen/fab_margins"-->
android:layout_marginEnd="@dimen/fab_margins" <!-- android:layout_marginEnd="@dimen/fab_margins"-->
app:layout_behavior="gr.thmmy.mthmmy.utils.ui.ScrollAwareFABBehavior" <!-- app:layout_behavior="gr.thmmy.mthmmy.utils.ui.ScrollAwareFABBehavior"-->
app:srcCompat="@drawable/ic_file_upload_white_24dp" /> <!-- app:srcCompat="@drawable/ic_file_upload_white_24dp" />-->
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

2
app/src/main/res/layout/activity_login.xml

@ -31,7 +31,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_horizontal" android:layout_gravity="center_horizontal"
android:contentDescription="@string/thmmy_img_description" /> android:contentDescription="@string/mthmmy_logo" />
<Space <Space
android:layout_width="match_parent" android:layout_width="match_parent"

1
app/src/main/res/layout/activity_topic.xml

@ -148,6 +148,7 @@
android:layout_gravity="bottom|end" android:layout_gravity="bottom|end"
android:layout_marginEnd="@dimen/fab_margins" android:layout_marginEnd="@dimen/fab_margins"
android:layout_marginBottom="50dp" android:layout_marginBottom="50dp"
android:contentDescription="@string/reply_button"
app:layout_behavior="gr.thmmy.mthmmy.utils.ui.ScrollAwareFABBehavior" app:layout_behavior="gr.thmmy.mthmmy.utils.ui.ScrollAwareFABBehavior"
app:srcCompat="@drawable/ic_reply" /> app:srcCompat="@drawable/ic_reply" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>

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

@ -2,13 +2,15 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/background_light"
android:orientation="vertical"> android:orientation="vertical">
<TextView <TextView
android:id="@+id/post_share_button" android:id="@+id/post_share_button"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="35dp" android:layout_height="35dp"
android:background="?android:attr/selectableItemBackground" android:background="@color/background_light"
android:foreground="?android:attr/selectableItemBackground"
android:drawablePadding="5dp" android:drawablePadding="5dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingBottom="6dp" android:paddingBottom="6dp"
@ -22,7 +24,8 @@
android:id="@+id/edit_post" android:id="@+id/edit_post"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="35dp" android:layout_height="35dp"
android:background="?android:attr/selectableItemBackground" android:background="@color/background_light"
android:foreground="?android:attr/selectableItemBackground"
android:drawablePadding="5dp" android:drawablePadding="5dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingBottom="6dp" android:paddingBottom="6dp"
@ -36,7 +39,8 @@
android:id="@+id/delete_post" android:id="@+id/delete_post"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="35dp" android:layout_height="35dp"
android:background="?android:attr/selectableItemBackground" android:background="@color/background_light"
android:foreground="?android:attr/selectableItemBackground"
android:drawablePadding="5dp" android:drawablePadding="5dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:paddingBottom="6dp" android:paddingBottom="6dp"

2
app/src/main/res/menu/downloads_menu.xml

@ -5,5 +5,5 @@
android:id="@+id/menu_upload" android:id="@+id/menu_upload"
android:icon="@drawable/ic_file_upload_white_24dp" android:icon="@drawable/ic_file_upload_white_24dp"
app:showAsAction="ifRoom" app:showAsAction="ifRoom"
android:title="@string/upload_button"></item> android:title="@string/upload_button" />
</menu> </menu>

2
app/src/main/res/menu/shoutbox_menu.xml

@ -5,5 +5,5 @@
android:id="@+id/menu_refresh" android:id="@+id/menu_refresh"
android:icon="@drawable/ic_refresh_white_24dp" android:icon="@drawable/ic_refresh_white_24dp"
app:showAsAction="ifRoom" app:showAsAction="ifRoom"
android:title="@string/refresh"></item> android:title="@string/refresh" />
</menu> </menu>

6
app/src/main/res/menu/topic_menu.xml

@ -5,15 +5,15 @@
android:id="@+id/menu_bookmark" android:id="@+id/menu_bookmark"
android:icon="@drawable/ic_bookmark_false_accent_24dp" android:icon="@drawable/ic_bookmark_false_accent_24dp"
app:showAsAction="ifRoom" app:showAsAction="ifRoom"
android:title="@string/bookmark"></item> android:title="@string/bookmark" />
<item <item
android:id="@+id/menu_share" android:id="@+id/menu_share"
android:icon="@drawable/ic_share_white_24dp" android:icon="@drawable/ic_share_white_24dp"
app:showAsAction="ifRoom" app:showAsAction="ifRoom"
android:title="@string/share"></item> android:title="@string/share" />
<item <item
android:id="@+id/menu_info" android:id="@+id/menu_info"
android:icon="@drawable/ic_info_outline_white_24dp" android:icon="@drawable/ic_info_outline_white_24dp"
app:showAsAction="ifRoom" app:showAsAction="ifRoom"
android:title="@string/info"></item> android:title="@string/info" />
</menu> </menu>

2
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background" /> <background android:drawable="@color/primary_light" />
<foreground android:drawable="@drawable/ic_launcher_foreground" /> <foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon> </adaptive-icon>

2
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background" /> <background android:drawable="@color/primary_light" />
<foreground android:drawable="@drawable/ic_launcher_foreground" /> <foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon> </adaptive-icon>

4
app/src/main/res/values/ic_launcher_background.xml

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#333333</color>
</resources>

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

@ -1,5 +1,8 @@
<resources> <resources>
<string name="app_name">mTHMMY</string> <string name="app_name">mTHMMY</string>
<string name="forum_url">https://www.thmmy.gr/smf/</string>
<string name="forum_host">www.thmmy.gr</string>
<string name="forum_host_simple">thmmy.gr</string>
<!--Base Activity--> <!--Base Activity-->
<string name="login">Login</string> <string name="login">Login</string>
@ -26,7 +29,7 @@
<string name="no_unread_topics">No unread topics!</string> <string name="no_unread_topics">No unread topics!</string>
<!--Login Activity--> <!--Login Activity-->
<string name="thmmy_img_description">thmmy.gr</string> <string name="mthmmy_logo">mTHMMY</string>
<string name="hint_username">Username</string> <string name="hint_username">Username</string>
<string name="hint_password">Password</string> <string name="hint_password">Password</string>
<string name="btn_login">LOGIN</string> <string name="btn_login">LOGIN</string>
@ -76,6 +79,7 @@
</plurals> </plurals>
<string name="show_vote_options_button">hide results</string> <string name="show_vote_options_button">hide results</string>
<string name="pref_topic_drafts_key">preference-topic-drafts-key</string> <string name="pref_topic_drafts_key">preference-topic-drafts-key</string>
<string name="reply_button">Reply</string>
<!--Profile Activity--> <!--Profile Activity-->
<string name="username">Username</string> <string name="username">Username</string>
@ -95,10 +99,9 @@
<string name="epl_libraries"><u>Eclipse Public License v1.0 libraries</u></string> <string name="epl_libraries"><u>Eclipse Public License v1.0 libraries</u></string>
<string name="other_libraries"><u>Other libraries</u></string> <string name="other_libraries"><u>Other libraries</u></string>
<string name="contact">Contact</string> <string name="contact">Contact</string>
<string name="contact_text">Do not hesitate to contact us for any technical matter, either by email at thmmynolife@gmail.com, or by joining our Discord server using https://discord.gg/CVt3yrn&#8203;. <string name="contact_text">Do not hesitate to contact us for any matter, either by email at contact@thmmy.gr, or by joining our Discord server using https://discord.gg/CVt3yrn .</string>
For account-related issues, please contact the administration team of thmmy.gr by email at contact@thmmy.gr.</string>
<string name="open_source">Open Source</string> <string name="open_source">Open Source</string>
<string name="open_source_text">The source code of mTHMMY can be found on Github at https://github.com/ThmmyNoLife/mTHMMY, along with further details of how one can contribute.</string> <string name="open_source_text">The source code of mTHMMY can be found on Github at https://github.com/THMMYgr/mTHMMY, along with further details of how one can contribute.</string>
<string name="trollPic">You should see a funny pic!</string> <string name="trollPic">You should see a funny pic!</string>
<string name="privacy_policy">Privacy policy</string> <string name="privacy_policy">Privacy policy</string>

12
app/src/main/res/xml-v26/app_preferences_user.xml

@ -40,18 +40,6 @@
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
</androidx.preference.PreferenceCategory> </androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory
android:key="@string/pref_category_uploading_key"
android:title="@string/pref_category_uploading"
app:iconSpaceReserved="false">
<androidx.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="@string/pref_uploading_app_signature_enable_key"
android:title="@string/pref_title_uploading_app_signature_enable"
android:summary="@string/pref_summary_uploading_app_signature_enable"
app:iconSpaceReserved="false" />
</androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory <androidx.preference.PreferenceCategory
android:key="@string/pref_category_privacy_key" android:key="@string/pref_category_privacy_key"
android:title="@string/pref_category_privacy" android:title="@string/pref_category_privacy"

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

@ -61,18 +61,6 @@
app:iconSpaceReserved="false" /> app:iconSpaceReserved="false" />
</androidx.preference.PreferenceCategory> </androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory
android:key="@string/pref_category_uploading_key"
android:title="@string/pref_category_uploading"
app:iconSpaceReserved="false">
<androidx.preference.SwitchPreferenceCompat
android:defaultValue="true"
android:key="@string/pref_uploading_app_signature_enable_key"
android:title="@string/pref_title_uploading_app_signature_enable"
android:summary="@string/pref_summary_uploading_app_signature_enable"
app:iconSpaceReserved="false" />
</androidx.preference.PreferenceCategory>
<androidx.preference.PreferenceCategory <androidx.preference.PreferenceCategory
android:key="@string/pref_category_privacy_key" android:key="@string/pref_category_privacy_key"
android:title="@string/pref_category_privacy" android:title="@string/pref_category_privacy"

8
app/src/test/java/gr/thmmy/mthmmy/utils/DateTimeUtilsTest.java

@ -1,5 +1,9 @@
package gr.thmmy.mthmmy.utils; package gr.thmmy.mthmmy.utils;
import static org.junit.Assert.assertArrayEquals;
import static org.mockito.Mockito.when;
import static gr.thmmy.mthmmy.utils.DateTimeUtils.getRelativeTimeSpanString;
import net.lachlanmckee.timberjunit.TimberTestRule; import net.lachlanmckee.timberjunit.TimberTestRule;
import org.joda.time.DateTime; import org.joda.time.DateTime;
@ -10,10 +14,6 @@ import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunner;
import static gr.thmmy.mthmmy.utils.DateTimeUtils.getRelativeTimeSpanString;
import static org.junit.Assert.assertArrayEquals;
import static org.mockito.Mockito.when;
@RunWith(PowerMockRunner.class) @RunWith(PowerMockRunner.class)
@PrepareForTest(DateTimeUtils.class) @PrepareForTest(DateTimeUtils.class)
public class DateTimeUtilsTest { public class DateTimeUtilsTest {

12
app/src/test/java/gr/thmmy/mthmmy/utils/UploadsCoursesJSONReadingTest.java

@ -1,5 +1,10 @@
package gr.thmmy.mthmmy.utils; package gr.thmmy.mthmmy.utils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static gr.thmmy.mthmmy.activities.upload.UploadsCourse.generateCoursesFromJSON;
import net.lachlanmckee.timberjunit.TimberTestRule; import net.lachlanmckee.timberjunit.TimberTestRule;
import org.json.JSONObject; import org.json.JSONObject;
@ -15,11 +20,6 @@ import java.util.HashMap;
import gr.thmmy.mthmmy.activities.upload.UploadsCourse; import gr.thmmy.mthmmy.activities.upload.UploadsCourse;
import gr.thmmy.mthmmy.utils.io.ResourceUtils; import gr.thmmy.mthmmy.utils.io.ResourceUtils;
import static gr.thmmy.mthmmy.activities.upload.UploadsCourse.generateCoursesFromJSON;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@RunWith(PowerMockRunner.class) @RunWith(PowerMockRunner.class)
@PrepareForTest(JSONObject.class) @PrepareForTest(JSONObject.class)
public class UploadsCoursesJSONReadingTest { public class UploadsCoursesJSONReadingTest {
@ -33,7 +33,7 @@ public class UploadsCoursesJSONReadingTest {
InputStream is = this.getClass().getClassLoader().getResourceAsStream(filePath); InputStream is = this.getClass().getClassLoader().getResourceAsStream(filePath);
assertNotNull(is); assertNotNull(is);
String uploadsCoursesJSON = ResourceUtils.readJSONResourceToString(is); String uploadsCoursesJSON = ResourceUtils.readJSONResourceToString(is);
assertNotNull(uploadsCoursesJSON);; assertNotNull(uploadsCoursesJSON);
JSONObject jsonObject = new JSONObject(uploadsCoursesJSON); JSONObject jsonObject = new JSONObject(uploadsCoursesJSON);
assertTrue(jsonObject.has("categories")); assertTrue(jsonObject.has("categories"));
HashMap<Integer, UploadsCourse> coursesHashMap = generateCoursesFromJSON(jsonObject); HashMap<Integer, UploadsCourse> coursesHashMap = generateCoursesFromJSON(jsonObject);

14
app/src/test/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParserTest.java

@ -1,5 +1,12 @@
package gr.thmmy.mthmmy.utils.parsing; package gr.thmmy.mthmmy.utils.parsing;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNotNull;
import static org.powermock.api.support.membermodification.MemberMatcher.method;
import static org.powermock.api.support.membermodification.MemberModifier.stub;
import static gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser.convertToTimestamp;
import static gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser.purifyTodayDateTime;
import net.lachlanmckee.timberjunit.TimberTestRule; import net.lachlanmckee.timberjunit.TimberTestRule;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
@ -9,13 +16,6 @@ import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner; import org.powermock.modules.junit4.PowerMockRunner;
import static gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser.convertToTimestamp;
import static gr.thmmy.mthmmy.utils.parsing.ThmmyDateTimeParser.purifyTodayDateTime;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertNotNull;
import static org.powermock.api.support.membermodification.MemberMatcher.method;
import static org.powermock.api.support.membermodification.MemberModifier.stub;
@RunWith(PowerMockRunner.class) @RunWith(PowerMockRunner.class)
@PrepareForTest(ThmmyDateTimeParser.class) @PrepareForTest(ThmmyDateTimeParser.class)
public class ThmmyDateTimeParserTest { public class ThmmyDateTimeParserTest {

26
build.gradle

@ -1,27 +1,33 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
apply plugin: "com.github.ben-manes.versions"
buildscript { buildscript {
repositories { repositories {
google() google()
jcenter() mavenCentral()
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
jcenter() // Just for snatik and uploadservice
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.1.3' classpath 'com.android.tools.build:gradle:7.4.2'
classpath 'com.google.gms:google-services:4.3.10' classpath 'com.google.gms:google-services:4.3.15'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.7.1' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.4'
classpath 'org.ajoberstar.grgit:grgit-core:3.1.1' // Also change in app/gradle/grgit.gradle classpath 'org.ajoberstar.grgit:grgit-core:5.0.0' // Also change in app/gradle/grgit.gradle
classpath "com.github.ben-manes:gradle-versions-plugin:0.21.0"
} }
} }
plugins {
id("com.github.ben-manes.versions") version "0.46.0"
}
allprojects { allprojects {
repositories { repositories {
maven { url "https://maven.google.com" }
google() google()
jcenter() mavenCentral()
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
jcenter() // Just for snatik and uploadservice
}
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xlint:unchecked" << "-Xlint:deprecation"
} }
} }

11
emojis/build.gradle

@ -1,14 +1,11 @@
apply plugin: 'com.android.library' apply plugin: 'com.android.library'
android { android {
compileSdkVersion 29 compileSdkVersion 33
buildToolsVersion "29.0.3"
defaultConfig { defaultConfig {
minSdkVersion 19 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 33
versionCode 1
versionName "1.0"
consumerProguardFiles 'consumer-rules.pro' consumerProguardFiles 'consumer-rules.pro'
} }
@ -19,4 +16,6 @@ android {
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
} }
} }
namespace 'gr.thmmy.emojis'
} }

3
emojis/src/main/AndroidManifest.xml

@ -1,2 +1 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android" />
package="gr.thmmy.emojis" />

4
gradle/wrapper/gradle-wrapper.properties

@ -1,6 +1,6 @@
#Thu Dec 03 14:56:57 EET 2020 #Sun Apr 02 13:22:00 EEST 2023
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip

Loading…
Cancel
Save