Browse Source

Merge branch 'develop' into bookdrag

pull/71/head
Nikolaos Bampaliaris 4 years ago
committed by GitHub
parent
commit
8fe7cfdb29
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 31
      app/build.gradle
  2. 124
      app/src/main/assets/apache_libraries.html
  3. 7
      app/src/main/assets/epl_libraries.html
  4. 13
      app/src/main/assets/mit_libraries.html
  5. 4
      app/src/main/assets/other_libraries.html
  6. 39
      app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java
  7. 13
      app/src/main/java/gr/thmmy/mthmmy/activities/LoginActivity.java
  8. 27
      app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardActivity.java
  9. 45
      app/src/main/java/gr/thmmy/mthmmy/activities/board/BoardAdapter.java
  10. 4
      app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksActivity.java
  11. 26
      app/src/main/java/gr/thmmy/mthmmy/activities/bookmarks/BookmarksFragment.java
  12. 7
      app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java
  13. 3
      app/src/main/java/gr/thmmy/mthmmy/activities/create_content/NewTopicTask.java
  14. 18
      app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsActivity.java
  15. 21
      app/src/main/java/gr/thmmy/mthmmy/activities/downloads/DownloadsAdapter.java
  16. 48
      app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java
  17. 21
      app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java
  18. 7
      app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java
  19. 18
      app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java
  20. 7
      app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java
  21. 62
      app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java
  22. 32
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java
  23. 8
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java
  24. 11
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsFragment.java
  25. 18
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java
  26. 14
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java
  27. 3
      app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsActivity.java
  28. 53
      app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsFragment.java
  29. 1
      app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/SendShoutTask.java
  30. 9
      app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutAdapter.java
  31. 3
      app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxActivity.java
  32. 12
      app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxFragment.java
  33. 2
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/Posting.java
  34. 76
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java
  35. 126
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
  36. 41
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java
  37. 1
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/EditTask.java
  38. 1
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForEditTask.java
  39. 5
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/PrepareForReplyTask.java
  40. 1
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/ReplyTask.java
  41. 4
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/tasks/TopicTask.java
  42. 111
      app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadActivity.java
  43. 18
      app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadFieldsBuilderActivity.java
  44. 14
      app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsCourse.java
  45. 4
      app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsHelper.java
  46. 10
      app/src/main/java/gr/thmmy/mthmmy/activities/upload/multipart/MultipartUploadRequest.java
  47. 8
      app/src/main/java/gr/thmmy/mthmmy/activities/upload/multipart/MultipartUploadTask.java
  48. 74
      app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java
  49. 29
      app/src/main/java/gr/thmmy/mthmmy/base/BaseApplication.java
  50. 3
      app/src/main/java/gr/thmmy/mthmmy/base/BaseFragment.java
  51. 2
      app/src/main/java/gr/thmmy/mthmmy/model/Bookmark.java
  52. 4
      app/src/main/java/gr/thmmy/mthmmy/model/Download.java
  53. 3
      app/src/main/java/gr/thmmy/mthmmy/model/Poll.java
  54. 6
      app/src/main/java/gr/thmmy/mthmmy/model/Post.java
  55. 12
      app/src/main/java/gr/thmmy/mthmmy/model/PostNotification.java
  56. 2
      app/src/main/java/gr/thmmy/mthmmy/model/ThmmyFile.java
  57. 11
      app/src/main/java/gr/thmmy/mthmmy/model/ThmmyPage.java
  58. 9
      app/src/main/java/gr/thmmy/mthmmy/services/DownloadHelper.java
  59. 43
      app/src/main/java/gr/thmmy/mthmmy/services/NotificationService.java
  60. 15
      app/src/main/java/gr/thmmy/mthmmy/services/UploadsReceiver.java
  61. 3
      app/src/main/java/gr/thmmy/mthmmy/session/InvalidSessionException.java
  62. 8
      app/src/main/java/gr/thmmy/mthmmy/session/LogoutTask.java
  63. 8
      app/src/main/java/gr/thmmy/mthmmy/session/MarkAsReadTask.java
  64. 26
      app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java
  65. 56
      app/src/main/java/gr/thmmy/mthmmy/utils/DateTimeUtils.java
  66. 5
      app/src/main/java/gr/thmmy/mthmmy/utils/ExternalAsyncTask.java
  67. 3
      app/src/main/java/gr/thmmy/mthmmy/utils/FileUtils.java
  68. 12
      app/src/main/java/gr/thmmy/mthmmy/utils/HTMLUtils.java
  69. 6
      app/src/main/java/gr/thmmy/mthmmy/utils/LaunchType.java
  70. 2
      app/src/main/java/gr/thmmy/mthmmy/utils/TakePhoto.java
  71. 3
      app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReporter.java
  72. 9
      app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReportingTree.java
  73. 5
      app/src/main/java/gr/thmmy/mthmmy/utils/networking/NetworkTask.java
  74. 5
      app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java
  75. 3
      app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseException.java
  76. 7
      app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseHelpers.java
  77. 7
      app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseTask.java
  78. 56
      app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyDateTimeParser.java
  79. 6
      app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyParser.java
  80. 2
      app/src/main/java/gr/thmmy/mthmmy/utils/ui/CenterVerticalSpan.java
  81. 10
      app/src/main/java/gr/thmmy/mthmmy/utils/ui/ImageDownloadDialogBuilder.java
  82. 3
      app/src/main/java/gr/thmmy/mthmmy/utils/ui/ScrollAwareFABBehavior.java
  83. 3
      app/src/main/java/gr/thmmy/mthmmy/utils/ui/ScrollAwareLinearBehavior.java
  84. 3
      app/src/main/java/gr/thmmy/mthmmy/viewmodel/ShoutboxViewModel.java
  85. 32
      app/src/main/java/gr/thmmy/mthmmy/viewmodel/TopicViewModel.java
  86. 22
      app/src/main/java/gr/thmmy/mthmmy/views/ReactiveWebView.java
  87. 16
      app/src/main/java/gr/thmmy/mthmmy/views/RelativeTimeTextView.java
  88. 1
      app/src/main/java/gr/thmmy/mthmmy/views/ToggledBackgroundButton.java
  89. 495
      app/src/main/java/gr/thmmy/mthmmy/views/editorview/EditorView.java
  90. 1
      app/src/main/java/gr/thmmy/mthmmy/views/editorview/EmojiInputField.java
  91. 9
      app/src/main/java/gr/thmmy/mthmmy/views/editorview/FormatButtonsAdapter.java
  92. 4
      app/src/main/java/gr/thmmy/mthmmy/views/editorview/IEmojiKeyboard.java
  93. 2
      app/src/main/res/anim/push_left_in.xml
  94. 2
      app/src/main/res/anim/push_left_out.xml
  95. 2
      app/src/main/res/anim/push_right_in.xml
  96. 2
      app/src/main/res/anim/push_right_out.xml
  97. 8
      app/src/main/res/drawable/guest_button_border_bg.xml
  98. 13
      app/src/main/res/drawable/ic_access_time_white_24dp.xml
  99. 10
      app/src/main/res/drawable/ic_add_fab.xml
  100. 13
      app/src/main/res/drawable/ic_announcement.xml

31
app/build.gradle

@ -15,8 +15,8 @@ android {
applicationId "gr.thmmy.mthmmy" applicationId "gr.thmmy.mthmmy"
minSdkVersion 19 minSdkVersion 19
targetSdkVersion 29 targetSdkVersion 29
versionCode 28 versionCode 29
versionName "1.8.5" versionName "1.9.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() + "\""
@ -53,23 +53,21 @@ tasks.whenTaskAdded { task ->
if (task.name.contains("assembleRelease")) { if (task.name.contains("assembleRelease")) {
task.getDependsOn().add({ task.getDependsOn().add({
def googleServicesFile = new File("app/src/release/google-services.json") def googleServicesFile = new File("app/src/release/google-services.json")
if(googleServicesFile.exists()){ if (googleServicesFile.exists()) {
def json = new JsonSlurper().parseText(googleServicesFile.text) def json = new JsonSlurper().parseText(googleServicesFile.text)
if (json.project_info.project_id != firebaseReleaseProjectId) if (json.project_info.project_id != firebaseReleaseProjectId)
throw new GradleException('Please supply the correct google-services.json for release in app/src/release/ directory!') throw new GradleException('Please supply the correct google-services.json for release in app/src/release/ directory!')
} } else
else
throw new GradleException('Please add the release google-services.json in app/src/release/ directory!') throw new GradleException('Please add the release google-services.json in app/src/release/ directory!')
}) })
} else if (task.name.contains("assembleDebug")) { } else if (task.name.contains("assembleDebug")) {
task.getDependsOn().add({ task.getDependsOn().add({
def googleServicesFile = new File("app/src/debug/google-services.json") def googleServicesFile = new File("app/src/debug/google-services.json")
if(googleServicesFile.exists()){ if (googleServicesFile.exists()) {
def json = new JsonSlurper().parseText(googleServicesFile.text) def json = new JsonSlurper().parseText(googleServicesFile.text)
if (json.project_info.project_id == firebaseReleaseProjectId) if (json.project_info.project_id == firebaseReleaseProjectId)
throw new GradleException('Please replace google-services.json in app/src/debug/ with a debug one!') throw new GradleException('Please replace google-services.json in app/src/debug/ with a debug one!')
} } else
else
throw new GradleException('Please add a debug google-services.json in app/src/debug/ directory!') throw new GradleException('Please add a debug google-services.json in app/src/debug/ directory!')
}) })
} }
@ -85,19 +83,20 @@ dependencies {
implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.cardview:cardview:1.0.0'
implementation 'androidx.recyclerview:recyclerview:1.1.0' implementation 'androidx.recyclerview:recyclerview:1.1.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3' implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'androidx.exifinterface:exifinterface:1.2.0' implementation 'androidx.exifinterface:exifinterface:1.2.0'
implementation 'androidx.multidex:multidex:2.0.1' //TODO: Remove when minSdkVersion >= 21 implementation 'androidx.multidex:multidex:2.0.1' //TODO: Remove when minSdkVersion >= 21
implementation 'com.google.android.material:material:1.1.0' implementation 'com.google.android.material:material:1.1.0'
implementation 'com.google.firebase:firebase-analytics:17.4.4' implementation 'com.google.firebase:firebase-analytics:17.4.4'
implementation 'com.google.firebase:firebase-crashlytics:17.1.1' implementation 'com.google.firebase:firebase-crashlytics:17.3.0'
implementation 'com.google.firebase:firebase-messaging:20.2.4' implementation 'com.google.firebase:firebase-messaging:21.0.0'
implementation 'com.snatik:storage:2.1.0' implementation 'com.snatik:storage:2.1.0'
implementation ('com.squareup.okhttp3:okhttp:3.12.12') { //TODO: Warning: OkHttp has dropped support for Android 19 since OkHttp 3.13! implementation('com.squareup.okhttp3:okhttp:3.12.12') {
//TODO: Warning: OkHttp has dropped support for Android 19 since OkHttp 3.13!
force = true //TODO: Remove when minSdkVersion >= 21 force = true //TODO: Remove when minSdkVersion >= 21
} }
implementation 'org.jsoup:jsoup:1.13.1' implementation 'org.jsoup:jsoup:1.13.1'
implementation 'joda-time:joda-time:2.10.4' implementation 'joda-time:joda-time:2.10.8'
implementation 'com.github.franmontiel:PersistentCookieJar:1.0.1' implementation 'com.github.franmontiel:PersistentCookieJar:1.0.1'
implementation 'com.github.PhilJay:MPAndroidChart:3.0.3' implementation 'com.github.PhilJay:MPAndroidChart:3.0.3'
implementation 'com.mikepenz:materialdrawer:6.1.1' implementation 'com.mikepenz:materialdrawer:6.1.1'
@ -109,8 +108,10 @@ dependencies {
implementation 'com.jakewharton.timber:timber:4.7.1' implementation 'com.jakewharton.timber:timber:4.7.1'
implementation 'ru.noties:markwon:2.0.2' implementation 'ru.noties:markwon:2.0.2'
implementation 'net.gotev:uploadservice:3.5.2' implementation 'net.gotev:uploadservice:3.5.2'
implementation 'net.gotev:uploadservice-okhttp:3.4.2' //TODO: Warning: v.3.5 depends on okhttp 3.13! implementation 'net.gotev:uploadservice-okhttp:3.4.2'
implementation 'com.itkacher.okhttpprofiler:okhttpprofiler:1.0.7' //Plugin: https://plugins.jetbrains.com/plugin/11249-okhttp-profiler //TODO: Warning: v.3.5 depends on okhttp 3.13!
implementation 'com.itkacher.okhttpprofiler:okhttpprofiler:1.0.7'
//Plugin: https://plugins.jetbrains.com/plugin/11249-okhttp-profiler
implementation 'com.github.bumptech.glide:glide:4.11.0' implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0' annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'

124
app/src/main/assets/apache_libraries.html

@ -1,60 +1,72 @@
<html> <html>
<head> <head>
<link rel="stylesheet" type="text/css" href="libraries_style.css" /> <link rel="stylesheet" type="text/css" href="libraries_style.css"/>
</head> </head>
<body> <body>
<ul> <ul>
<li> <li>
<h5><a href="https://square.github.io/okhttp/">OkHttp</a>&nbsp;v3.12.12 (Copyright ©2019 Square, Inc.)</h5> <h5><a href="https://square.github.io/okhttp/">OkHttp</a>&nbsp;v3.12.12 (Copyright ©2019
</li> Square, Inc.)</h5>
<li> </li>
<h5><a href="https://github.com/franmontiel/PersistentCookieJar">PersistentCookieJar</a>&nbsp;v1.0.1 (Copyright ©2016 Francisco José Montiel Navarro)</h5> <li>
</li> <h5><a href="https://github.com/franmontiel/PersistentCookieJar">PersistentCookieJar</a>&nbsp;v1.0.1
<li> (Copyright ©2016 Francisco José Montiel Navarro)</h5>
<h5><a href="https://github.com/PhilJay/MPAndroidChart">MPAndroidChart</a>&nbsp;v3.0.3 (Copyright ©2018 Philipp Jahoda)</h5> </li>
</li> <li>
<li> <h5><a href="https://github.com/PhilJay/MPAndroidChart">MPAndroidChart</a>&nbsp;v3.0.3
<h5><a href="https://github.com/mikepenz/MaterialDrawer">MaterialDrawer</a>&nbsp;v6.1.1 (Copyright ©2018 Mike Penz)</h5> (Copyright ©2018 Philipp Jahoda)</h5>
</li> </li>
<li> <li>
<h5><a href="https://github.com/chrisbanes/PhotoView">PhotoView</a>&nbsp;v2.3.0 (Copyright ©2018 Chris Banes)</h5> <h5><a href="https://github.com/mikepenz/MaterialDrawer">MaterialDrawer</a>&nbsp;v6.1.1
</li> (Copyright ©2018 Mike Penz)</h5>
<li> </li>
<h5><a href="https://github.com/mikepenz/Android-Iconics">Android-Iconics</a>&nbsp;v2.9.5 (Copyright ©2016 Mike Penz)</h5> <li>
</li> <h5><a href="https://github.com/chrisbanes/PhotoView">PhotoView</a>&nbsp;v2.3.0 (Copyright
<li> ©2018 Chris Banes)</h5>
<h5><a href="https://github.com/DreaminginCodeZH/MaterialProgressBar">MaterialProgressBar</a>&nbsp;v1.4.2 (Copyright ©2015 Zhang Hai)</h5> </li>
</li> <li>
<li> <h5><a href="https://github.com/mikepenz/Android-Iconics">Android-Iconics</a>&nbsp;v2.9.5
<h5><a href="https://github.com/JakeWharton/timber">Timber</a>&nbsp;v4.7.1 (Copyright ©2013 Jake Wharton)</h5> (Copyright ©2016 Mike Penz)</h5>
</li> </li>
<li> <li>
<h5><a href="https://github.com/gotev/android-upload-service">Android Upload Service</a>&nbsp;v3.5.2 (Copyright ©2013-2019 Aleksandar Gotev)</h5> <h5>
</li> <a href="https://github.com/DreaminginCodeZH/MaterialProgressBar">MaterialProgressBar</a>&nbsp;v1.4.2
<li> (Copyright ©2015 Zhang Hai)</h5>
<h5><a href="https://github.com/noties/Markwon">Markwon</a>&nbsp;v2.0.2 (Copyright ©2017 Dimitry Ivanov)</h5> </li>
</li> <li>
<li> <h5><a href="https://github.com/JakeWharton/timber">Timber</a>&nbsp;v4.7.1 (Copyright ©2013
<h5><a href="https://github.com/ajoberstar/grgit">Grgit</a>&nbsp;v3.0.0 (Copyright ©2018 Andrew Oberstar)</h5> Jake Wharton)</h5>
</li> </li>
<li> <li>
<h5><a href="https://github.com/JodaOrg/joda-time">Joda-Time</a>&nbsp;v2.10.4 (Copyright ©2002-2019 Joda.org)</h5> <h5><a href="https://github.com/gotev/android-upload-service">Android Upload Service</a>&nbsp;v3.5.2
</li> (Copyright ©2013-2019 Aleksandar Gotev)</h5>
<li> </li>
<h5><a href="https://github.com/powermock/powermock">PowerMock</a>&nbsp;v2.0.2</h5> <li>
</li> <h5><a href="https://github.com/noties/Markwon">Markwon</a>&nbsp;v2.0.2 (Copyright ©2017
<li> Dimitry Ivanov)</h5>
<h5><a href="https://github.com/sromku/android-storage">android-storage</a>&nbsp;v2.1.0</h5> </li>
</li> <li>
<li> <h5><a href="https://github.com/ajoberstar/grgit">Grgit</a>&nbsp;v3.0.0 (Copyright ©2018
<h5><a href=https://github.com/itkacher/OkHttpProfiler">OkHttpProfiler</a>&nbsp;v1.0.7</h5> Andrew Oberstar)</h5>
</li> </li>
</ul> <li>
<h5><a href="https://github.com/JodaOrg/joda-time">Joda-Time</a>&nbsp;v2.10.8 (Copyright
©2002-2020 Joda.org)</h5>
</li>
<pre> <li>
<h5><a href="https://github.com/powermock/powermock">PowerMock</a>&nbsp;v2.0.2</h5>
</li>
<li>
<h5><a href="https://github.com/sromku/android-storage">android-storage</a>&nbsp;v2.1.0</h5>
</li>
<li>
<h5><a href=https://github.com/itkacher/OkHttpProfiler">OkHttpProfiler</a>&nbsp;v1.0.7</h5>
</li>
</ul>
<pre>
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -67,9 +79,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
</pre> </pre>
<br/> <br/>
<h4>Apache License v2.0</h4> <h4>Apache License v2.0</h4>
<pre> <pre>
Apache License Apache License
Version 2.0, January 2004 Version 2.0, January 2004
@ -125,6 +137,6 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
END OF TERMS AND CONDITIONS END OF TERMS AND CONDITIONS
</pre> </pre>
</body> </body>
</html> </html>

7
app/src/main/assets/epl_libraries.html

@ -1,19 +1,20 @@
<html> <html>
<head> <head>
<link rel="stylesheet" type="text/css" href="libraries_style.css" /> <link rel="stylesheet" type="text/css" href="libraries_style.css"/>
</head> </head>
<body> <body>
<ul> <ul>
<li> <li>
<h5><a href="https://github.com/junit-team/junit4">JUnit</a>&nbsp;v4.12 (Copyright © 2002-2019, JUnit)</h5> <h5><a href="https://github.com/junit-team/junit4">JUnit</a>&nbsp;v4.12 (Copyright ©
2002-2019, JUnit)</h5>
</li> </li>
</ul> </ul>
<br/> <br/>
<h4>Eclipse Public License v1.0</h4> <h4>Eclipse Public License v1.0</h4>
<pre> <pre>
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC
LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM
CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.

13
app/src/main/assets/mit_libraries.html

@ -1,25 +1,28 @@
<html> <html>
<head> <head>
<link rel="stylesheet" type="text/css" href="libraries_style.css" /> <link rel="stylesheet" type="text/css" href="libraries_style.css"/>
</head> </head>
<body> <body>
<ul> <ul>
<li> <li>
<h5><a href="https://jsoup.org">jsoup</a>&nbsp;v1.13.1 (Copyright ©2009-2020, Jonathan Hedley &lt;jonathan@hedley.net&gt;)</h5> <h5><a href="https://jsoup.org">jsoup</a>&nbsp;v1.13.1 (Copyright ©2009-2020, Jonathan
Hedley &lt;jonathan@hedley.net&gt;)</h5>
</li> </li>
<li> <li>
<h5><a href="https://github.com/bignerdranch/expandable-recycler-view">Expandable RecyclerView</a>&nbsp;v3.0.0-RC1 (Copyright ©2015, Big Nerd Ranch)</h5> <h5><a href="https://github.com/bignerdranch/expandable-recycler-view">Expandable
RecyclerView</a>&nbsp;v3.0.0-RC1 (Copyright ©2015, Big Nerd Ranch)</h5>
</li> </li>
<li> <li>
<h5><a href="https://github.com/LachlanMcKee/timber-junit-rule">Timber JUnit-Rule</a>&nbsp;v1.0.1 (Copyright ©2017, Lachlan McKee)</h5> <h5><a href="https://github.com/LachlanMcKee/timber-junit-rule">Timber JUnit-Rule</a>&nbsp;v1.0.1
(Copyright ©2017, Lachlan McKee)</h5>
</li> </li>
</ul> </ul>
<br/> <br/>
<h4>The MIT License</h4> <h4>The MIT License</h4>
<pre> <pre>
Copyright &lt;YEAR&gt; &lt;COPYRIGHT HOLDER&gt; Copyright &lt;YEAR&gt; &lt;COPYRIGHT HOLDER&gt;
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy

4
app/src/main/assets/other_libraries.html

@ -1,6 +1,6 @@
<html> <html>
<head> <head>
<link rel="stylesheet" type="text/css" href="libraries_style.css" /> <link rel="stylesheet" type="text/css" href="libraries_style.css"/>
</head> </head>
<body> <body>
@ -13,7 +13,7 @@
<br/> <br/>
<h4>Glide License</h4> <h4>Glide License</h4>
<pre> <pre>
License for everything not in third_party and not otherwise marked: License for everything not in third_party and not otherwise marked:
Copyright 2014 Google, Inc. All rights reserved. Copyright 2014 Google, Inc. All rights reserved.

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

@ -58,7 +58,7 @@ public class AboutActivity extends BaseActivity {
gitExists = false; gitExists = false;
String versionInfo = ""; String versionInfo = "";
if(gitExists) if (gitExists)
versionInfo = "-" + BuildConfig.CURRENT_BRANCH + "-" + commitHash versionInfo = "-" + BuildConfig.CURRENT_BRANCH + "-" + commitHash
+ (BuildConfig.IS_CLEAN ? "" : "-dirty") + (BuildConfig.IS_CLEAN ? "" : "-dirty")
+ " "; // Avoid last letter being cut in italics styled TextView + " "; // Avoid last letter being cut in italics styled TextView
@ -89,7 +89,8 @@ public class AboutActivity extends BaseActivity {
showEasterEgg(); showEasterEgg();
mVersionLastPressedTime = System.currentTimeMillis(); mVersionLastPressedTime = System.currentTimeMillis();
++mVersionPressedCounter; ++mVersionPressedCounter;
} else { }
else {
mVersionLastPressedTime = System.currentTimeMillis(); mVersionLastPressedTime = System.currentTimeMillis();
mVersionPressedCounter = 0; mVersionPressedCounter = 0;
} }
@ -102,7 +103,7 @@ public class AboutActivity extends BaseActivity {
else else
versionTextView.setText(getString(R.string.version, versionName)); versionTextView.setText(getString(R.string.version, versionName));
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/ThmmyNoLife/mTHMMY/commit/" + BuildConfig.COMMIT_HASH));
startActivity(intent); startActivity(intent);
@ -132,7 +133,7 @@ public class AboutActivity extends BaseActivity {
@Override @Override
public void onBackPressed() { public void onBackPressed() {
if(easterEggImage.getVisibility()==View.INVISIBLE) if (easterEggImage.getVisibility() == View.INVISIBLE)
super.onBackPressed(); super.onBackPressed();
else else
hideEasterEgg(); hideEasterEgg();
@ -140,29 +141,29 @@ public class AboutActivity extends BaseActivity {
public void displayLibraries(View v) { public void displayLibraries(View v) {
String libraryType = v.getTag().toString(); String libraryType = v.getTag().toString();
String title="", fileName=""; String title = "", fileName = "";
switch(libraryType) { switch (libraryType) {
case "APACHE": case "APACHE":
title=getString(R.string.apache_v2_0_libraries); title = getString(R.string.apache_v2_0_libraries);
fileName="apache_libraries.html"; fileName = "apache_libraries.html";
break; break;
case "MIT": case "MIT":
title=getString(R.string.the_mit_libraries); title = getString(R.string.the_mit_libraries);
fileName="mit_libraries.html"; fileName = "mit_libraries.html";
break; break;
case "EPL": case "EPL":
title=getString(R.string.epl_libraries); title = getString(R.string.epl_libraries);
fileName="epl_libraries.html"; fileName = "epl_libraries.html";
break; break;
case "OTHER": case "OTHER":
title=getString(R.string.other_libraries); title = getString(R.string.other_libraries);
fileName="other_libraries.html"; fileName = "other_libraries.html";
break; break;
default: default:
break; break;
} }
String htmlContent = AssetUtils.readFileToText(this,fileName); String htmlContent = AssetUtils.readFileToText(this, fileName);
LayoutInflater inflater = LayoutInflater.from(this); LayoutInflater inflater = LayoutInflater.from(this);
WebView webView = (WebView) inflater.inflate(R.layout.dialog_licenses, coordinatorLayout, false); WebView webView = (WebView) inflater.inflate(R.layout.dialog_licenses, coordinatorLayout, false);
@ -176,13 +177,13 @@ public class AboutActivity extends BaseActivity {
.setView(webView) .setView(webView)
.setPositiveButton(android.R.string.ok, null) .setPositiveButton(android.R.string.ok, null)
.show(); .show();
if(alertDialog.getWindow()!=null) if (alertDialog.getWindow() != null)
alertDialog.getWindow().setLayout(width, height); alertDialog.getWindow().setLayout(width, height);
} }
@SuppressLint("SourceLockedOrientationActivity") @SuppressLint("SourceLockedOrientationActivity")
private void showEasterEgg(){ private void showEasterEgg() {
if(getResources().getConfiguration().orientation==ActivityInfo.SCREEN_ORIENTATION_PORTRAIT){ if (getResources().getConfiguration().orientation == ActivityInfo.SCREEN_ORIENTATION_PORTRAIT) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); //TODO: why? setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); //TODO: why?
appBar.setVisibility(View.INVISIBLE); appBar.setVisibility(View.INVISIBLE);
mainContent.setVisibility(View.INVISIBLE); mainContent.setVisibility(View.INVISIBLE);
@ -191,7 +192,7 @@ public class AboutActivity extends BaseActivity {
} }
} }
private void hideEasterEgg(){ private void hideEasterEgg() {
appBar.setVisibility(View.VISIBLE); appBar.setVisibility(View.VISIBLE);
mainContent.setVisibility(View.VISIBLE); mainContent.setVisibility(View.VISIBLE);
easterEggImage.setVisibility(View.INVISIBLE); easterEggImage.setVisibility(View.INVISIBLE);

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

@ -100,7 +100,7 @@ public class LoginActivity extends BaseActivity {
if (loginTask != null && loginTask.getStatus() == AsyncTask.Status.RUNNING) { if (loginTask != null && loginTask.getStatus() == AsyncTask.Status.RUNNING) {
loginTask.cancel(true); loginTask.cancel(true);
} }
if(!isTaskRoot()) if (!isTaskRoot())
overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out); overridePendingTransition(R.anim.push_left_in, R.anim.push_left_out);
} }
@ -117,7 +117,8 @@ public class LoginActivity extends BaseActivity {
inputUsername.setError("Enter a valid username"); inputUsername.setError("Enter a valid username");
inputUsername.requestFocus(); inputUsername.requestFocus();
valid = false; valid = false;
} else { }
else {
inputUsername.setError(null); inputUsername.setError(null);
} }
@ -126,7 +127,8 @@ public class LoginActivity extends BaseActivity {
if (valid) if (valid)
inputPassword.requestFocus(); inputPassword.requestFocus();
valid = false; valid = false;
} else { }
else {
inputPassword.setError(null); inputPassword.setError(null);
} }
@ -170,10 +172,11 @@ public class LoginActivity extends BaseActivity {
"Welcome, " + sessionManager.getUsername() + "!", Toast.LENGTH_LONG) "Welcome, " + sessionManager.getUsername() + "!", Toast.LENGTH_LONG)
.show(); .show();
BaseApplication.getInstance().logFirebaseAnalyticsEvent(FirebaseAnalytics.Event.LOGIN, null); BaseApplication.getInstance().logFirebaseAnalyticsEvent(FirebaseAnalytics.Event.LOGIN, null);
if(initialRedirect){ if (initialRedirect) {
Intent intent = new Intent(LoginActivity.this, MainActivity.class); Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent); startActivity(intent);
} else }
else
onBackPressed(); onBackPressed();
finish(); finish();

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

@ -116,7 +116,8 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
intent.putExtra(CreateContentActivity.EXTRA_NEW_TOPIC_URL, newTopicUrl); intent.putExtra(CreateContentActivity.EXTRA_NEW_TOPIC_URL, newTopicUrl);
startActivity(intent); startActivity(intent);
} }
} else { }
else {
new AlertDialog.Builder(BoardActivity.this) new AlertDialog.Builder(BoardActivity.this)
.setMessage("You need to be logged in to create a new topic!") .setMessage("You need to be logged in to create a new topic!")
.setPositiveButton("Login", (dialogInterface, i) -> { .setPositiveButton("Login", (dialogInterface, i) -> {
@ -234,7 +235,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
final Pattern pLastPostPattern = Pattern.compile("((?:(?!(?:by|από)).)*)\\s(?:by|από)\\s(.*)"); final Pattern pLastPostPattern = Pattern.compile("((?:(?!(?:by|από)).)*)\\s(?:by|από)\\s(.*)");
if(pagesLoaded == 0) { //Finds sub boards if (pagesLoaded == 0) { //Finds sub boards
Elements subBoardRows = boardPage.select("div.tborder>table>tbody>tr"); Elements subBoardRows = boardPage.select("div.tborder>table>tbody>tr");
if (subBoardRows != null && !subBoardRows.isEmpty()) { if (subBoardRows != null && !subBoardRows.isEmpty()) {
for (Element subBoardRow : subBoardRows) { for (Element subBoardRow : subBoardRows) {
@ -244,9 +245,9 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
boolean parsingFailed = false; boolean parsingFailed = false;
Elements subBoardColumns = subBoardRow.select(">td"); Elements subBoardColumns = subBoardRow.select(">td");
for (Element subBoardCol : subBoardColumns) { for (Element subBoardCol : subBoardColumns) {
if (Objects.equals(subBoardCol.className(), "windowbg")){ if (Objects.equals(subBoardCol.className(), "windowbg")) {
pStats = subBoardCol.text(); pStats = subBoardCol.text();
if(pStats.equals("--")) if (pStats.equals("--"))
pStats = ""; pStats = "";
} }
@ -255,7 +256,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
if (pLastPost.contains(" in ") || pLastPost.contains(" σε ")) { if (pLastPost.contains(" in ") || pLastPost.contains(" σε ")) {
Pattern pattern = Pattern.compile("(?:Last post on |Τελευταίο μήνυμα στις )((?:(?!(?:in|σε)).)*)\\s(?:in|σε)\\s.*"); Pattern pattern = Pattern.compile("(?:Last post on |Τελευταίο μήνυμα στις )((?:(?!(?:in|σε)).)*)\\s(?:in|σε)\\s.*");
Matcher matcher = pattern.matcher(pLastPost); Matcher matcher = pattern.matcher(pLastPost);
if (matcher.find()){ if (matcher.find()) {
String pLastPostDateTime = matcher.group(1); String pLastPostDateTime = matcher.group(1);
String pSubject = subBoardCol.select("a").first().attr("title"); String pSubject = subBoardCol.select("a").first().attr("title");
@ -272,7 +273,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
break; break;
} }
pLastPost = "Last post on: " + pLastPostDateTime + "\nin: " + pSubject + "\nby " +pLastUser; pLastPost = "Last post on: " + pLastPostDateTime + "\nin: " + pSubject + "\nby " + pLastUser;
pLastPostUrl = subBoardCol.select("a").first().attr("href"); pLastPostUrl = subBoardCol.select("a").first().attr("href");
} }
@ -281,18 +282,20 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
break; break;
} }
} else if (pLastPost.contains("redirected clicks")||pLastPost.contains("N/A")) }
else if (pLastPost.contains("redirected clicks") || pLastPost.contains("N/A"))
pLastPost = ""; pLastPost = "";
else else
pLastPost = "No posts yet"; pLastPost = "No posts yet";
} else { }
else {
pUrl = subBoardCol.select("a").first().attr("href"); pUrl = subBoardCol.select("a").first().attr("href");
pTitle = subBoardCol.select("a").first().text(); pTitle = subBoardCol.select("a").first().text();
if (subBoardCol.select("div.smalltext").first() != null) if (subBoardCol.select("div.smalltext").first() != null)
pMods = subBoardCol.select("div.smalltext").first().text(); pMods = subBoardCol.select("div.smalltext").first().text();
} }
} }
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 (pLastPost came with: \"%s\", subBoardColumns html was \"%s\")", pLastPost, subBoardColumns);
@ -305,7 +308,7 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
if (topicRows != null && !topicRows.isEmpty()) { if (topicRows != null && !topicRows.isEmpty()) {
for (Element topicRow : topicRows) { for (Element topicRow : topicRows) {
if (!Objects.equals(topicRow.className(), "titlebg")) { if (!Objects.equals(topicRow.className(), "titlebg")) {
String pTopicUrl, pSubject, pStarter, pLastUser="", pLastPostDateTime="00:00:00", pLastPost, pLastPostUrl, pStats; String pTopicUrl, pSubject, pStarter, pLastUser = "", pLastPostDateTime = "00:00:00", pLastPost, pLastPostUrl, pStats;
boolean pLocked = false, pSticky = false, pUnread = false; boolean pLocked = false, pSticky = false, pUnread = false;
Elements topicColumns = topicRow.select(">td"); Elements topicColumns = topicRow.select(">td");
@ -325,11 +328,11 @@ public class BoardActivity extends BaseActivity implements BoardAdapter.OnLoadMo
pLastPost = topicColumns.get(6).text(); pLastPost = topicColumns.get(6).text();
Matcher matcher = pLastPostPattern.matcher(pLastPost); Matcher matcher = pLastPostPattern.matcher(pLastPost);
if (matcher.find()){ if (matcher.find()) {
pLastPostDateTime = matcher.group(1); pLastPostDateTime = matcher.group(1);
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 (pLastPost came with: \"%s\", topicColumns html was \"%s\")", pLastPost, topicColumns);
continue; continue;
} }

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

@ -59,7 +59,8 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (position <= parsedSubBoards.size()) { if (position <= parsedSubBoards.size()) {
if (position == 0) return VIEW_TYPE_SUB_BOARD_TITLE; if (position == 0) return VIEW_TYPE_SUB_BOARD_TITLE;
return VIEW_TYPE_SUB_BOARD; return VIEW_TYPE_SUB_BOARD;
} else if (position <= parsedSubBoards.size() + parsedTopics.size() + 1) { }
else if (position <= parsedSubBoards.size() + parsedTopics.size() + 1) {
if (position == parsedSubBoards.size() + 1) return VIEW_TYPE_TOPIC_TITLE; if (position == parsedSubBoards.size() + 1) return VIEW_TYPE_TOPIC_TITLE;
if (parsedTopics.get(position - parsedSubBoards.size() - 1 - 1) != null) if (parsedTopics.get(position - parsedSubBoards.size() - 1 - 1) != null)
return VIEW_TYPE_TOPIC; return VIEW_TYPE_TOPIC;
@ -79,7 +80,8 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
subBoardTitle.setBackgroundColor(context.getColor(R.color.background_light)); subBoardTitle.setBackgroundColor(context.getColor(R.color.background_light));
subBoardTitle.setTextColor(context.getColor(R.color.accent)); subBoardTitle.setTextColor(context.getColor(R.color.accent));
} else { }
else {
//noinspection deprecation //noinspection deprecation
subBoardTitle.setBackgroundColor(context.getResources().getColor(R.color.background_light)); subBoardTitle.setBackgroundColor(context.getResources().getColor(R.color.background_light));
//noinspection deprecation //noinspection deprecation
@ -89,11 +91,13 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
subBoardTitle.setTextSize(20f); subBoardTitle.setTextSize(20f);
return new TitlesViewHolder(subBoardTitle); return new TitlesViewHolder(subBoardTitle);
} else if (viewType == VIEW_TYPE_SUB_BOARD) { }
else if (viewType == VIEW_TYPE_SUB_BOARD) {
View subBoard = LayoutInflater.from(parent.getContext()). View subBoard = LayoutInflater.from(parent.getContext()).
inflate(R.layout.activity_board_sub_board_row, parent, false); inflate(R.layout.activity_board_sub_board_row, parent, false);
return new SubBoardViewHolder(subBoard); return new SubBoardViewHolder(subBoard);
} else if (viewType == VIEW_TYPE_TOPIC_TITLE) { }
else if (viewType == VIEW_TYPE_TOPIC_TITLE) {
TextView topicTitle = new TextView(context); TextView topicTitle = new TextView(context);
topicTitle.setLayoutParams(new LinearLayout.LayoutParams( topicTitle.setLayoutParams(new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT LinearLayout.LayoutParams.MATCH_PARENT
@ -102,7 +106,8 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
topicTitle.setTypeface(topicTitle.getTypeface(), Typeface.BOLD); topicTitle.setTypeface(topicTitle.getTypeface(), Typeface.BOLD);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
topicTitle.setTextColor(context.getColor(R.color.primary_text)); topicTitle.setTextColor(context.getColor(R.color.primary_text));
} else { }
else {
//noinspection deprecation //noinspection deprecation
topicTitle.setTextColor(context.getResources().getColor(R.color.primary_text)); topicTitle.setTextColor(context.getResources().getColor(R.color.primary_text));
} }
@ -110,11 +115,13 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
topicTitle.setTextSize(20f); topicTitle.setTextSize(20f);
return new TitlesViewHolder(topicTitle); return new TitlesViewHolder(topicTitle);
} else if (viewType == VIEW_TYPE_TOPIC) { }
else if (viewType == VIEW_TYPE_TOPIC) {
View topic = LayoutInflater.from(parent.getContext()). View topic = LayoutInflater.from(parent.getContext()).
inflate(R.layout.activity_board_topic_row, parent, false); inflate(R.layout.activity_board_topic_row, parent, false);
return new TopicViewHolder(topic); return new TopicViewHolder(topic);
} else if (viewType == VIEW_TYPE_LOADING) { }
else if (viewType == VIEW_TYPE_LOADING) {
View loading = LayoutInflater.from(parent.getContext()). View loading = LayoutInflater.from(parent.getContext()).
inflate(R.layout.recycler_loading_item, parent, false); inflate(R.layout.recycler_loading_item, parent, false);
return new LoadingViewHolder(loading); return new LoadingViewHolder(loading);
@ -145,7 +152,8 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (boardExpandableVisibility.get(subBoardViewHolder.getAdapterPosition() - 1)) { if (boardExpandableVisibility.get(subBoardViewHolder.getAdapterPosition() - 1)) {
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);
} else { }
else {
subBoardViewHolder.boardExpandable.setVisibility(View.GONE); subBoardViewHolder.boardExpandable.setVisibility(View.GONE);
subBoardViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp); subBoardViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp);
} }
@ -154,7 +162,8 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (visible) { if (visible) {
subBoardViewHolder.boardExpandable.setVisibility(View.GONE); subBoardViewHolder.boardExpandable.setVisibility(View.GONE);
subBoardViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp); subBoardViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp);
} else { }
else {
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);
} }
@ -165,17 +174,17 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
String stats = subBoard.getStats(); String stats = subBoard.getStats();
String lastPost = subBoard.getLastPost(); String lastPost = subBoard.getLastPost();
if(!mods.isEmpty()){ if (!mods.isEmpty()) {
subBoardViewHolder.boardMods.setText(mods); subBoardViewHolder.boardMods.setText(mods);
subBoardViewHolder.boardMods.setVisibility(View.VISIBLE); subBoardViewHolder.boardMods.setVisibility(View.VISIBLE);
} }
if(!stats.isEmpty()){ if (!stats.isEmpty()) {
subBoardViewHolder.boardStats.setText(stats); subBoardViewHolder.boardStats.setText(stats);
subBoardViewHolder.boardStats.setVisibility(View.VISIBLE); subBoardViewHolder.boardStats.setVisibility(View.VISIBLE);
} }
if(!lastPost.isEmpty()){ if (!lastPost.isEmpty()) {
subBoardViewHolder.boardLastPost.setText(lastPost); subBoardViewHolder.boardLastPost.setText(lastPost);
subBoardViewHolder.boardLastPost.setVisibility(View.VISIBLE); subBoardViewHolder.boardLastPost.setVisibility(View.VISIBLE);
} }
@ -191,7 +200,8 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
context.startActivity(intent); context.startActivity(intent);
}); });
} }
} else if (holder instanceof TopicViewHolder) { }
else if (holder instanceof TopicViewHolder) {
final Topic topic = parsedTopics.get(position - parsedSubBoards.size() - 1 - 1); final Topic topic = parsedTopics.get(position - parsedSubBoards.size() - 1 - 1);
final TopicViewHolder topicViewHolder = (TopicViewHolder) holder; final TopicViewHolder topicViewHolder = (TopicViewHolder) holder;
@ -213,7 +223,8 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
.size() - 2)) { .size() - 2)) {
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);
} else { }
else {
topicViewHolder.topicExpandable.setVisibility(View.GONE); topicViewHolder.topicExpandable.setVisibility(View.GONE);
topicViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp); topicViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp);
} }
@ -223,7 +234,8 @@ class BoardAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (visible) { if (visible) {
topicViewHolder.topicExpandable.setVisibility(View.GONE); topicViewHolder.topicExpandable.setVisibility(View.GONE);
topicViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp); topicViewHolder.showHideExpandable.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp);
} else { }
else {
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);
} }
@ -258,7 +270,8 @@ 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);
}); });
} else if (holder instanceof LoadingViewHolder) { }
else if (holder instanceof LoadingViewHolder) {
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder; LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
loadingViewHolder.progressBar.setIndeterminate(true); loadingViewHolder.progressBar.setIndeterminate(true);
} }

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

@ -69,9 +69,9 @@ public class BookmarksActivity extends BaseActivity {
} }
public boolean onFragmentRowInteractionListener(BookmarksFragment.Type type, String interactionType, Bookmark bookmark) { public boolean onFragmentRowInteractionListener(BookmarksFragment.Type type, String interactionType, Bookmark bookmark) {
if(type== BookmarksFragment.Type.TOPIC) if (type == BookmarksFragment.Type.TOPIC)
return onTopicInteractionListener(interactionType, bookmark); return onTopicInteractionListener(interactionType, bookmark);
else if (type==BookmarksFragment.Type.BOARD) else if (type == BookmarksFragment.Type.BOARD)
return onBoardInteractionListener(interactionType, bookmark); return onBoardInteractionListener(interactionType, bookmark);
return false; return false;

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

@ -26,6 +26,7 @@ import gr.thmmy.mthmmy.model.Bookmark;
//TODO refactor using RecyclerView //TODO refactor using RecyclerView
public class BookmarksFragment extends Fragment { public class BookmarksFragment extends Fragment {
enum Type {TOPIC, BOARD} enum Type {TOPIC, BOARD}
private static final String ARG_SECTION_NUMBER = "SECTION_NUMBER"; private static final String ARG_SECTION_NUMBER = "SECTION_NUMBER";
private static final String ARG_BOOKMARKS = "BOOKMARKS"; private static final String ARG_BOOKMARKS = "BOOKMARKS";
@ -35,7 +36,7 @@ public class BookmarksFragment extends Fragment {
static final String INTERACTION_CLICK_BOARD_BOOKMARK = "CLICK_BOARD_BOOKMARK"; static final String INTERACTION_CLICK_BOARD_BOOKMARK = "CLICK_BOARD_BOOKMARK";
static final String INTERACTION_TOGGLE_BOARD_NOTIFICATION = "TOGGLE_BOARD_NOTIFICATION"; static final String INTERACTION_TOGGLE_BOARD_NOTIFICATION = "TOGGLE_BOARD_NOTIFICATION";
static final String INTERACTION_REMOVE_BOARD_BOOKMARK= "REMOVE_BOARD_BOOKMARK"; static final String INTERACTION_REMOVE_BOARD_BOOKMARK = "REMOVE_BOARD_BOOKMARK";
private TextView nothingBookmarkedTextView; private TextView nothingBookmarkedTextView;
@ -49,16 +50,16 @@ public class BookmarksFragment extends Fragment {
public BookmarksFragment() {/* Required empty public constructor */} public BookmarksFragment() {/* Required empty public constructor */}
private BookmarksFragment(Type type) { private BookmarksFragment(Type type) {
this.type=type; this.type = type;
if(type==Type.TOPIC){ if (type == Type.TOPIC) {
this.interactionClick=INTERACTION_CLICK_TOPIC_BOOKMARK; this.interactionClick = INTERACTION_CLICK_TOPIC_BOOKMARK;
this.interactionToggle=INTERACTION_TOGGLE_TOPIC_NOTIFICATION; this.interactionToggle = INTERACTION_TOGGLE_TOPIC_NOTIFICATION;
this.interactionRemove=INTERACTION_REMOVE_TOPIC_BOOKMARK; this.interactionRemove = INTERACTION_REMOVE_TOPIC_BOOKMARK;
} }
else if (type==Type.BOARD){ else if (type == Type.BOARD) {
this.interactionClick=INTERACTION_CLICK_BOARD_BOOKMARK; this.interactionClick = INTERACTION_CLICK_BOARD_BOOKMARK;
this.interactionToggle=INTERACTION_TOGGLE_BOARD_NOTIFICATION; this.interactionToggle = INTERACTION_TOGGLE_BOARD_NOTIFICATION;
this.interactionRemove=INTERACTION_REMOVE_BOARD_BOOKMARK; this.interactionRemove = INTERACTION_REMOVE_BOARD_BOOKMARK;
} }
} }
@ -107,12 +108,14 @@ public class BookmarksFragment extends Fragment {
//Get the nothing bookmarked text view. //Get the nothing bookmarked text view.
nothingBookmarkedTextView = rootView.findViewById(R.id.nothing_bookmarked); nothingBookmarkedTextView = rootView.findViewById(R.id.nothing_bookmarked);
//Create the adapter. //Create the adapter.
BookmarksAdapter adapter = new BookmarksAdapter(this, notificationsEnabledButtonImage, notificationsDisabledButtonImage); BookmarksAdapter adapter = new BookmarksAdapter(this, notificationsEnabledButtonImage, notificationsDisabledButtonImage);
//Get the drag list view. //Get the drag list view.
DragListView mDragListView = (DragListView) rootView.findViewById(R.id.fragment_bookmarks_dragList); DragListView mDragListView = (DragListView) rootView.findViewById(R.id.fragment_bookmarks_dragList);
//Set the Drag List Listener. //Set the Drag List Listener.
mDragListView.setDragListListener(new DragListView.DragListListener() mDragListView.setDragListListener(new DragListView.DragListListener()
{ {
@ -217,6 +220,7 @@ public class BookmarksFragment extends Fragment {
//Notify the adapter, because I made changes to the bookmarks array. //Notify the adapter, because I made changes to the bookmarks array.
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
} }
}); });
//====================================This is the code for the Drag and Drop Functionality====================================// //====================================This is the code for the Drag and Drop Functionality====================================//
@ -241,6 +245,7 @@ public class BookmarksFragment extends Fragment {
} }
public void showNothingBookmarked() { public void showNothingBookmarked() {
if(nothingBookmarkedTextView!=null) if(nothingBookmarkedTextView!=null)
nothingBookmarkedTextView.setVisibility(View.VISIBLE); nothingBookmarkedTextView.setVisibility(View.VISIBLE);
@ -248,6 +253,7 @@ public class BookmarksFragment extends Fragment {
public void hideNothingBookmarked(){ public void hideNothingBookmarked(){
if(nothingBookmarkedTextView!=null) if(nothingBookmarkedTextView!=null)
nothingBookmarkedTextView.setVisibility(View.INVISIBLE); nothingBookmarkedTextView.setVisibility(View.INVISIBLE);
} }

7
app/src/main/java/gr/thmmy/mthmmy/activities/create_content/CreateContentActivity.java

@ -82,11 +82,13 @@ public class CreateContentActivity extends BaseActivity implements NewTopicTask.
} }
}); });
} }
@Override @Override
public void onBackPressed() { public void onBackPressed() {
if (emojiKeyboard.getVisibility() == View.VISIBLE) { if (emojiKeyboard.getVisibility() == View.VISIBLE) {
emojiKeyboard.setVisibility(View.GONE); emojiKeyboard.setVisibility(View.GONE);
} else { }
else {
super.onBackPressed(); super.onBackPressed();
} }
} }
@ -103,7 +105,8 @@ public class CreateContentActivity extends BaseActivity implements NewTopicTask.
if (success) { if (success) {
Timber.i("New topic created successfully"); Timber.i("New topic created successfully");
finish(); finish();
} else { }
else {
Timber.w("New topic creation failed"); Timber.w("New topic creation failed");
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Failed to create new topic!", Toast.LENGTH_LONG).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Failed to create new topic!", Toast.LENGTH_LONG).show();
finish(); finish();

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

@ -22,7 +22,7 @@ public class NewTopicTask extends AsyncTask<String, Void, Boolean> {
private NewTopicTaskCallbacks listener; private NewTopicTaskCallbacks listener;
private boolean includeAppSignature; private boolean includeAppSignature;
public NewTopicTask(NewTopicTaskCallbacks listener, boolean includeAppSignature){ public NewTopicTask(NewTopicTaskCallbacks listener, boolean includeAppSignature) {
this.listener = listener; this.listener = listener;
this.includeAppSignature = includeAppSignature; this.includeAppSignature = includeAppSignature;
} }
@ -96,6 +96,7 @@ public class NewTopicTask extends AsyncTask<String, Void, Boolean> {
public interface NewTopicTaskCallbacks { public interface NewTopicTaskCallbacks {
void onNewTopicTaskStarted(); void onNewTopicTaskStarted();
void onNewTopicTaskFinished(boolean success); void onNewTopicTaskFinished(boolean success);
} }
} }

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

@ -81,7 +81,8 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "An error has occurred\nAborting.", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "An error has occurred\nAborting.", Toast.LENGTH_SHORT).show();
finish(); finish();
} }
} else downloadsUrl = downloadsIndexUrl; }
else downloadsUrl = downloadsIndexUrl;
//Initialize toolbar //Initialize toolbar
toolbar = findViewById(R.id.toolbar); toolbar = findViewById(R.id.toolbar);
@ -166,7 +167,8 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
if (downloadsUrl.contains("tpstart")) if (downloadsUrl.contains("tpstart"))
parseDownloadPageTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, downloadsUrl.substring(0 parseDownloadPageTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, downloadsUrl.substring(0
, downloadsUrl.lastIndexOf(";tpstart=")) + ";tpstart=" + pagesLoaded * 10); , downloadsUrl.lastIndexOf(";tpstart=")) + ";tpstart=" + pagesLoaded * 10);
else parseDownloadPageTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, downloadsUrl + ";tpstart=" + pagesLoaded * 10); else
parseDownloadPageTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, downloadsUrl + ";tpstart=" + pagesLoaded * 10);
} }
} }
@ -237,7 +239,8 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
int pageNumber = Integer.parseInt(page.text()); int pageNumber = Integer.parseInt(page.text());
if (pageNumber > numberOfPages) numberOfPages = pageNumber; if (pageNumber > numberOfPages) numberOfPages = pageNumber;
} }
} else numberOfPages = 1; }
else numberOfPages = 1;
Elements rows = downloadPage.select("table.tborder>tbody>tr"); Elements rows = downloadPage.select("table.tborder>tbody>tr");
if (type == Download.DownloadItemType.DOWNLOADS_CATEGORY) { if (type == Download.DownloadItemType.DOWNLOADS_CATEGORY) {
@ -253,20 +256,23 @@ public class DownloadsActivity extends BaseActivity implements DownloadsAdapter.
parsedDownloads.add(new Download(type, url, title, subtitle, null, parsedDownloads.add(new Download(type, url, title, subtitle, null,
true, null)); true, null));
} else { }
else {
String stats = row.text(); String stats = row.text();
stats = stats.replace(title, "").replace(subtitle, "").trim(); stats = stats.replace(title, "").replace(subtitle, "").trim();
parsedDownloads.add(new Download(type, url, title, subtitle, stats, parsedDownloads.add(new Download(type, url, title, subtitle, stats,
false, null)); false, null));
} }
} else { }
else {
String stats = row.text(); String stats = row.text();
stats = stats.replace(title, "").replace(subtitle, "").trim(); stats = stats.replace(title, "").replace(subtitle, "").trim();
parsedDownloads.add(new Download(type, url, title, subtitle, stats, parsedDownloads.add(new Download(type, url, title, subtitle, stats,
false, null)); false, null));
} }
} }
} else { }
else {
download = new Download(type, download = new Download(type,
rows.select("b>a").first().attr("href"), rows.select("b>a").first().attr("href"),
rows.select("b>a").first().text(), rows.select("b>a").first().text(),

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

@ -57,7 +57,8 @@ class DownloadsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
View download = LayoutInflater.from(parent.getContext()). View download = LayoutInflater.from(parent.getContext()).
inflate(R.layout.activity_downloads_row, parent, false); inflate(R.layout.activity_downloads_row, parent, false);
return new DownloadViewHolder(download); return new DownloadViewHolder(download);
} else if (viewType == VIEW_TYPE_LOADING) { }
else if (viewType == VIEW_TYPE_LOADING) {
View loading = LayoutInflater.from(parent.getContext()). View loading = LayoutInflater.from(parent.getContext()).
inflate(R.layout.recycler_loading_item, parent, false); inflate(R.layout.recycler_loading_item, parent, false);
return new LoadingViewHolder(loading); return new LoadingViewHolder(loading);
@ -90,7 +91,8 @@ class DownloadsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (downloadExpandableVisibility.get(downloadViewHolder.getAdapterPosition())) { if (downloadExpandableVisibility.get(downloadViewHolder.getAdapterPosition())) {
downloadViewHolder.informationExpandable.setVisibility(View.VISIBLE); downloadViewHolder.informationExpandable.setVisibility(View.VISIBLE);
downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_up_accent_24dp); downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_up_accent_24dp);
} else { }
else {
downloadViewHolder.informationExpandable.setVisibility(View.GONE); downloadViewHolder.informationExpandable.setVisibility(View.GONE);
downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp); downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp);
} }
@ -100,7 +102,8 @@ class DownloadsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (visible) { if (visible) {
downloadViewHolder.informationExpandable.setVisibility(View.GONE); downloadViewHolder.informationExpandable.setVisibility(View.GONE);
downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp); downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_down_accent_24dp);
} else { }
else {
downloadViewHolder.informationExpandable.setVisibility(View.VISIBLE); downloadViewHolder.informationExpandable.setVisibility(View.VISIBLE);
downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_up_accent_24dp); downloadViewHolder.informationExpandableBtn.setImageResource(R.drawable.ic_arrow_drop_up_accent_24dp);
} }
@ -112,12 +115,14 @@ class DownloadsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
String tmp = context.getResources().getString(R.string.fa_folder) + " " String tmp = context.getResources().getString(R.string.fa_folder) + " "
+ download.getTitle(); + download.getTitle();
downloadViewHolder.title.setText(tmp); downloadViewHolder.title.setText(tmp);
} else { }
else {
String tmp = context.getResources().getString(R.string.fa_file) + " " String tmp = context.getResources().getString(R.string.fa_file) + " "
+ download.getTitle(); + download.getTitle();
downloadViewHolder.title.setText(tmp); downloadViewHolder.title.setText(tmp);
} }
} else { }
else {
downloadViewHolder.downloadRow.setOnClickListener(view -> { downloadViewHolder.downloadRow.setOnClickListener(view -> {
try { try {
((BaseActivity) context).downloadFile(new ThmmyFile( ((BaseActivity) context).downloadFile(new ThmmyFile(
@ -129,7 +134,8 @@ class DownloadsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 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 { }
else {
//noinspection deprecation //noinspection deprecation
downloadViewHolder.upperLinear.setBackgroundColor(context.getResources().getColor(R.color.background)); downloadViewHolder.upperLinear.setBackgroundColor(context.getResources().getColor(R.color.background));
} }
@ -148,7 +154,8 @@ class DownloadsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (tmp != null && !Objects.equals(tmp, "")) if (tmp != null && !Objects.equals(tmp, ""))
downloadViewHolder.uploaderDate.setText(tmp); downloadViewHolder.uploaderDate.setText(tmp);
else downloadViewHolder.uploaderDate.setVisibility(View.GONE); else downloadViewHolder.uploaderDate.setVisibility(View.GONE);
} else if (holder instanceof LoadingViewHolder) { }
else if (holder instanceof LoadingViewHolder) {
LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder; LoadingViewHolder loadingViewHolder = (LoadingViewHolder) holder;
loadingViewHolder.progressBar.setIndeterminate(true); loadingViewHolder.progressBar.setIndeterminate(true);
} }

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

@ -5,6 +5,8 @@ import android.content.SharedPreferences;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.Toast; import android.widget.Toast;
import androidx.appcompat.app.AppCompatDelegate; import androidx.appcompat.app.AppCompatDelegate;
@ -55,6 +57,7 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
private SectionsPagerAdapter sectionsPagerAdapter; private SectionsPagerAdapter sectionsPagerAdapter;
private ViewPager viewPager; private ViewPager viewPager;
private TabLayout tabLayout; private TabLayout tabLayout;
private boolean displayCompactTabs;
//Fix for vector drawables on android <21 //Fix for vector drawables on android <21
static { static {
@ -82,9 +85,15 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
return; //Avoid executing the code below return; //Avoid executing the code below
} }
toolbar = findViewById(R.id.toolbar); displayCompactTabs = BaseApplication.getInstance().isDisplayCompactTabsEnabled();
toolbar.setTitle("");
setSupportActionBar(toolbar); if (displayCompactTabs) {
toolbar = findViewById(R.id.toolbar);
ViewGroup.LayoutParams currentParams = toolbar.getLayoutParams();
toolbar.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, currentParams.height));
toolbar.setTitle("");
setSupportActionBar(toolbar);
}
//Initialize drawer //Initialize drawer
createDrawer(); createDrawer();
@ -108,8 +117,8 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
if ((preferredTab != 3 && preferredTab != 4) || sessionManager.isLoggedIn()) if ((preferredTab != 3 && preferredTab != 4) || sessionManager.isLoggedIn())
tabLayout.getTabAt(preferredTab).select(); tabLayout.getTabAt(preferredTab).select();
for (int i = 0; i < tabLayout.getTabCount(); i++) if (!displayCompactTabs)
updateTabIcon(i); updateTabIcons();
setMainActivity(this); setMainActivity(this);
} }
@ -164,7 +173,8 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
i.putExtra(BUNDLE_TOPIC_TITLE, topicSummary.getSubject()); i.putExtra(BUNDLE_TOPIC_TITLE, topicSummary.getSubject());
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i); startActivity(i);
} else }
else
Timber.e("onUnreadFragmentInteraction TopicSummary came without a link"); Timber.e("onUnreadFragmentInteraction TopicSummary came without a link");
} }
@ -188,7 +198,8 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
fragmentList.add(fragment); fragmentList.add(fragment);
fragmentTitleList.add(title); fragmentTitleList.add(title);
notifyDataSetChanged(); notifyDataSetChanged();
updateTabIcon(fragmentList.size() - 1); if (!displayCompactTabs)
updateTabIcon(fragmentList.size() - 1);
} }
void removeFragment(int position) { void removeFragment(int position) {
@ -233,6 +244,10 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
tabLayout.getTabAt(2).setIcon(getResources().getDrawable(R.drawable.ic_fiber_new_white_24dp)); tabLayout.getTabAt(2).setIcon(getResources().getDrawable(R.drawable.ic_fiber_new_white_24dp));
} }
private void updateTabIcons() {
for (int i = 0; i < tabLayout.getTabCount(); i++)
updateTabIcon(i);
}
public void updateTabs() { public void updateTabs() {
if (!sessionManager.isLoggedIn() && sectionsPagerAdapter.getCount() == 3) if (!sessionManager.isLoggedIn() && sectionsPagerAdapter.getCount() == 3)
@ -240,8 +255,8 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
else if (sessionManager.isLoggedIn() && sectionsPagerAdapter.getCount() == 2) else if (sessionManager.isLoggedIn() && sectionsPagerAdapter.getCount() == 2)
sectionsPagerAdapter.addFragment(UnreadFragment.newInstance(3), "UNREAD"); sectionsPagerAdapter.addFragment(UnreadFragment.newInstance(3), "UNREAD");
for (int i = 0; i < tabLayout.getTabCount(); i++) if (!displayCompactTabs)
updateTabIcon(i); updateTabIcons();
} }
//-------------------------------FragmentPagerAdapter END------------------------------------------- //-------------------------------FragmentPagerAdapter END-------------------------------------------
@ -256,26 +271,31 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF
redirectIntent.putExtra(BUNDLE_BOARD_URL, uri.toString()); redirectIntent.putExtra(BUNDLE_BOARD_URL, uri.toString());
redirectIntent.putExtra(BUNDLE_BOARD_TITLE, ""); redirectIntent.putExtra(BUNDLE_BOARD_TITLE, "");
startActivity(redirectIntent); startActivity(redirectIntent);
} else if (page.is(ThmmyPage.PageCategory.TOPIC)) { }
else if (page.is(ThmmyPage.PageCategory.TOPIC)) {
Intent redirectIntent = new Intent(MainActivity.this, TopicActivity.class); Intent redirectIntent = new Intent(MainActivity.this, TopicActivity.class);
redirectIntent.putExtra(BUNDLE_TOPIC_URL, uri.toString()); redirectIntent.putExtra(BUNDLE_TOPIC_URL, uri.toString());
redirectIntent.putExtra(BUNDLE_TOPIC_TITLE, ""); redirectIntent.putExtra(BUNDLE_TOPIC_TITLE, "");
startActivity(redirectIntent); startActivity(redirectIntent);
} else if (page.is(ThmmyPage.PageCategory.PROFILE)) { }
else if (page.is(ThmmyPage.PageCategory.PROFILE)) {
Intent redirectIntent = new Intent(MainActivity.this, ProfileActivity.class); Intent redirectIntent = new Intent(MainActivity.this, ProfileActivity.class);
redirectIntent.putExtra(BUNDLE_PROFILE_URL, uri.toString()); redirectIntent.putExtra(BUNDLE_PROFILE_URL, uri.toString());
redirectIntent.putExtra(BUNDLE_PROFILE_THUMBNAIL_URL, ""); redirectIntent.putExtra(BUNDLE_PROFILE_THUMBNAIL_URL, "");
redirectIntent.putExtra(BUNDLE_PROFILE_USERNAME, ""); redirectIntent.putExtra(BUNDLE_PROFILE_USERNAME, "");
startActivity(redirectIntent); startActivity(redirectIntent);
} else if (page.is(ThmmyPage.PageCategory.DOWNLOADS)) { }
else if (page.is(ThmmyPage.PageCategory.DOWNLOADS)) {
Intent redirectIntent = new Intent(MainActivity.this, DownloadsActivity.class); Intent redirectIntent = new Intent(MainActivity.this, DownloadsActivity.class);
redirectIntent.putExtra(BUNDLE_DOWNLOADS_URL, uri.toString()); redirectIntent.putExtra(BUNDLE_DOWNLOADS_URL, uri.toString());
redirectIntent.putExtra(BUNDLE_DOWNLOADS_TITLE, ""); redirectIntent.putExtra(BUNDLE_DOWNLOADS_TITLE, "");
startActivity(redirectIntent); startActivity(redirectIntent);
} else if (!page.is(ThmmyPage.PageCategory.INDEX)) { }
else if (!page.is(ThmmyPage.PageCategory.INDEX)) {
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "This thmmy sector is not yet supported.", Toast.LENGTH_LONG).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "This thmmy sector is not yet supported.", Toast.LENGTH_LONG).show();
} }
} else { }
else {
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "This is not thmmy.", Toast.LENGTH_LONG).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "This is not thmmy.", Toast.LENGTH_LONG).show();
} }
} }

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

@ -158,12 +158,13 @@ public class ForumFragment extends BaseFragment {
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
if (forumTask!=null){ if (forumTask != null) {
try{ try {
if(forumTask.isRunning()) if (forumTask.isRunning())
forumTask.cancel(true); forumTask.cancel(true);
} // Yes, it happens even though we checked } // Yes, it happens even though we checked
catch (NullPointerException ignored){ } catch (NullPointerException ignored) {
}
} }
} }
@ -180,9 +181,11 @@ public class ForumFragment extends BaseFragment {
categories.clear(); categories.clear();
categories.addAll(fetchedCategories); categories.addAll(fetchedCategories);
forumAdapter.notifyParentDataSetChanged(false); forumAdapter.notifyParentDataSetChanged(false);
} else if (resultCode == NetworkResultCodes.NETWORK_ERROR) { }
else if (resultCode == NetworkResultCodes.NETWORK_ERROR) {
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error", Toast.LENGTH_SHORT).show();
} else { }
else {
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Unexpected error," + Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Unexpected error," +
" please contact the developers with the details", Toast.LENGTH_LONG).show(); " please contact the developers with the details", Toast.LENGTH_LONG).show();
} }
@ -218,13 +221,15 @@ public class ForumFragment extends BaseFragment {
Board board = new Board(boardElement.attr("href"), boardElement.text(), null, null, null, null); Board board = new Board(boardElement.attr("href"), boardElement.text(), null, null, null, null);
category.getBoards().add(board); category.getBoards().add(board);
} }
} else }
else
category.setExpanded(false); category.setExpanded(false);
fetchedCategories.add(category); fetchedCategories.add(category);
} }
return fetchedCategories; return fetchedCategories;
} else }
else
throw new ParseException("Parsing failed"); throw new ParseException("Parsing failed");
} }

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

@ -44,12 +44,11 @@ class RecentAdapter extends RecyclerView.Adapter<RecentAdapter.ViewHolder> {
public void onBindViewHolder(final ViewHolder holder, final int position) { public void onBindViewHolder(final ViewHolder holder, final int position) {
TopicSummary topicSummary = recentList.get(position); TopicSummary topicSummary = recentList.get(position);
holder.mTitleView.setText(topicSummary.getSubject()); holder.mTitleView.setText(topicSummary.getSubject());
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.valueOf(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());
} }

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

@ -54,7 +54,8 @@ public class RecentFragment extends BaseFragment {
private RecentTask recentTask; private RecentTask recentTask;
// Required empty public constructor // Required empty public constructor
public RecentFragment() {} public RecentFragment() {
}
/** /**
* Use ONLY this factory method to create a new instance of * Use ONLY this factory method to create a new instance of
@ -123,12 +124,13 @@ public class RecentFragment extends BaseFragment {
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
if (recentTask!=null){ if (recentTask != null) {
try{ try {
if(recentTask.isRunning()) if (recentTask.isRunning())
recentTask.cancel(true); recentTask.cancel(true);
} // Yes, it happens even though we checked } // Yes, it happens even though we checked
catch (NullPointerException ignored){ } catch (NullPointerException ignored) {
}
} }
} }
@ -146,9 +148,11 @@ public class RecentFragment extends BaseFragment {
topicSummaries.clear(); topicSummaries.clear();
topicSummaries.addAll(fetchedRecent); topicSummaries.addAll(fetchedRecent);
recentAdapter.notifyDataSetChanged(); recentAdapter.notifyDataSetChanged();
} else if (resultCode == NetworkResultCodes.NETWORK_ERROR) { }
else if (resultCode == NetworkResultCodes.NETWORK_ERROR) {
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error", Toast.LENGTH_SHORT).show();
} else { }
else {
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Unexpected error," + Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Unexpected error," +
" please contact the developers with the details", Toast.LENGTH_LONG).show(); " please contact the developers with the details", Toast.LENGTH_LONG).show();
} }

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

@ -41,12 +41,11 @@ class UnreadAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
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.valueOf(timestamp));
} } catch (NumberFormatException e) {
catch(NumberFormatException e){
Timber.e(e, "Invalid number format: %s", timestamp); Timber.e(e, "Invalid number format: %s", timestamp);
viewHolder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime()); viewHolder.mDateTimeView.setText(topicSummary.getLastPostSimplifiedDateTime());
} }

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

@ -66,7 +66,8 @@ public class UnreadFragment extends BaseFragment {
private MarkAsReadTask markAsReadTask; private MarkAsReadTask markAsReadTask;
// Required empty public constructor // Required empty public constructor
public UnreadFragment() {} public UnreadFragment() {
}
/** /**
* Use ONLY this factory method to create a new instance of * Use ONLY this factory method to create a new instance of
@ -92,7 +93,7 @@ public class UnreadFragment extends BaseFragment {
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(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);
assert SessionManager.unreadUrl != null; assert SessionManager.unreadUrl != null;
@ -140,39 +141,41 @@ public class UnreadFragment extends BaseFragment {
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
cancelUnreadTaskIfRunning(); cancelUnreadTaskIfRunning();
if (markAsReadTask !=null){ if (markAsReadTask != null) {
try{ try {
if(markAsReadTask.isRunning()) if (markAsReadTask.isRunning())
markAsReadTask.cancel(true); markAsReadTask.cancel(true);
} // Yes, it happens even though we checked } // Yes, it happens even though we checked
catch (NullPointerException ignored){ } catch (NullPointerException ignored) {
}
} }
if(topicSummaries!=null) if (topicSummaries != null)
topicSummaries.clear(); topicSummaries.clear();
} }
private void startUnreadTask(){ private void startUnreadTask() {
if (unreadTask!=null) { if (unreadTask != null) {
try{ try {
if(!unreadTask.isRunning()){ if (!unreadTask.isRunning()) {
numberOfPages = 0; numberOfPages = 0;
loadedPages = 0; loadedPages = 0;
unreadTask = new UnreadTask(UnreadFragment.this::onUnreadTaskStarted, UnreadFragment.this::onUnreadTaskCancelled, UnreadFragment.this::onUnreadTaskFinished); unreadTask = new UnreadTask(UnreadFragment.this::onUnreadTaskStarted, UnreadFragment.this::onUnreadTaskCancelled, UnreadFragment.this::onUnreadTaskFinished);
assert SessionManager.unreadUrl != null; assert SessionManager.unreadUrl != null;
unreadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.unreadUrl.toString()); unreadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, SessionManager.unreadUrl.toString());
} }
} catch (NullPointerException ignored) {
} }
catch (NullPointerException ignored){ }
} }
} }
private void cancelUnreadTaskIfRunning(){ private void cancelUnreadTaskIfRunning() {
if (unreadTask!=null){ if (unreadTask != null) {
try{ try {
if(unreadTask.isRunning()) if (unreadTask.isRunning())
unreadTask.cancel(true); unreadTask.cancel(true);
} // Yes, it happens even though we checked } // Yes, it happens even though we checked
catch (NullPointerException ignored){ } catch (NullPointerException ignored) {
}
} }
} }
@ -197,16 +200,17 @@ public class UnreadFragment extends BaseFragment {
builder.setTitle("Mark all as read"); builder.setTitle("Mark all as read");
builder.setMessage("Are you sure that you want to mark ALL topics as read?"); builder.setMessage("Are you sure that you want to mark ALL topics as read?");
builder.setPositiveButton("Yep", (dialogInterface, i) -> { builder.setPositiveButton("Yep", (dialogInterface, i) -> {
if (!markAsReadTask.isRunning()){ if (!markAsReadTask.isRunning()) {
markAsReadTask = new MarkAsReadTask(this::onMarkAsReadTaskStarted, this::onMarkAsReadTaskFinished); markAsReadTask = new MarkAsReadTask(this::onMarkAsReadTaskStarted, this::onMarkAsReadTaskFinished);
markAsReadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); markAsReadTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
} }
}); });
builder.setNegativeButton("Nope", (dialogInterface, i) -> {}); builder.setNegativeButton("Nope", (dialogInterface, i) -> {
});
builder.create().show(); builder.create().show();
} }
private void hideProgressUI(){ private void hideProgressUI() {
progressBar.setVisibility(ProgressBar.INVISIBLE); progressBar.setVisibility(ProgressBar.INVISIBLE);
swipeRefreshLayout.setRefreshing(false); swipeRefreshLayout.setRefreshing(false);
} }
@ -221,10 +225,10 @@ public class UnreadFragment extends BaseFragment {
swipeRefreshLayout.setRefreshing(false); swipeRefreshLayout.setRefreshing(false);
} }
private void onUnreadTaskFinished(int resultCode, ArrayList<TopicSummary> fetchedUnread) { private void onUnreadTaskFinished(int resultCode, ArrayList<TopicSummary> fetchedUnread) {
if (resultCode == NetworkResultCodes.SUCCESSFUL) { if (resultCode == NetworkResultCodes.SUCCESSFUL) {
if(!fetchedUnread.isEmpty()){ if (!fetchedUnread.isEmpty()) {
if(loadedPages==0) if (loadedPages == 0)
topicSummaries.clear(); topicSummaries.clear();
topicSummaries.addAll(fetchedUnread); topicSummaries.addAll(fetchedUnread);
noUnreadTopicsTextView.setVisibility(View.INVISIBLE); noUnreadTopicsTextView.setVisibility(View.INVISIBLE);
@ -245,7 +249,7 @@ public class UnreadFragment extends BaseFragment {
else else
hideProgressUI(); hideProgressUI();
} }
else{ else {
hideProgressUI(); hideProgressUI();
if (resultCode == NetworkResultCodes.NETWORK_ERROR) if (resultCode == NetworkResultCodes.NETWORK_ERROR)
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error", Toast.LENGTH_SHORT).show();
@ -258,13 +262,13 @@ public class UnreadFragment extends BaseFragment {
} }
private class UnreadTask extends NewParseTask<ArrayList<TopicSummary>> { private class UnreadTask extends NewParseTask<ArrayList<TopicSummary>> {
UnreadTask(OnTaskStartedListener onTaskStartedListener, OnTaskCancelledListener onTaskCancelledListener, OnNetworkTaskFinishedListener<ArrayList<TopicSummary>> onParseTaskFinishedListener) { UnreadTask(OnTaskStartedListener onTaskStartedListener, OnTaskCancelledListener onTaskCancelledListener, OnNetworkTaskFinishedListener<ArrayList<TopicSummary>> onParseTaskFinishedListener) {
super(onTaskStartedListener, onTaskCancelledListener, onParseTaskFinishedListener); super(onTaskStartedListener, onTaskCancelledListener, onParseTaskFinishedListener);
} }
@Override @Override
protected ArrayList<TopicSummary> parse(Document document, Response response) throws ParseException, InvalidSessionException { protected ArrayList<TopicSummary> parse(Document document, Response response) throws ParseException, InvalidSessionException {
if(!document.select("td:containsOwn(Only registered members are allowed to access this section.)").isEmpty()) if (!document.select("td:containsOwn(Only registered members are allowed to access this section.)").isEmpty())
throw new InvalidSessionException(); throw new InvalidSessionException();
Elements unread = document.select("table.bordercolor[cellspacing=1] tr:not(.titlebg)"); Elements unread = document.select("table.bordercolor[cellspacing=1] tr:not(.titlebg)");
@ -316,11 +320,11 @@ public class UnreadFragment extends BaseFragment {
progressBar.setVisibility(ProgressBar.VISIBLE); progressBar.setVisibility(ProgressBar.VISIBLE);
} }
private void onMarkAsReadTaskFinished(int resultCode, Void v) { private void onMarkAsReadTaskFinished(int resultCode, Void v) {
hideProgressUI(); hideProgressUI();
if (resultCode == NetworkResultCodes.SUCCESSFUL) if (resultCode == NetworkResultCodes.SUCCESSFUL)
startUnreadTask(); startUnreadTask();
else{ else {
hideProgressUI(); hideProgressUI();
if (resultCode == NetworkResultCodes.NETWORK_ERROR) if (resultCode == NetworkResultCodes.NETWORK_ERROR)
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error", Toast.LENGTH_SHORT).show();

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

@ -68,7 +68,7 @@ import static gr.thmmy.mthmmy.utils.ui.PhotoViewUtils.displayPhotoViewImage;
* this user's avatar url using the key {@link #BUNDLE_PROFILE_THUMBNAIL_URL} and a <b>String</b> containing * this user's avatar url using the key {@link #BUNDLE_PROFILE_THUMBNAIL_URL} and a <b>String</b> containing
* the username using the key {@link #BUNDLE_PROFILE_USERNAME}. * the username using the key {@link #BUNDLE_PROFILE_USERNAME}.
*/ */
public class ProfileActivity extends BaseActivity implements LatestPostsFragment.LatestPostsFragmentInteractionListener, LatestPostsFragment.OnLoadingListener, StatsFragment.OnLoadingListener{ public class ProfileActivity extends BaseActivity implements LatestPostsFragment.LatestPostsFragmentInteractionListener, LatestPostsFragment.OnLoadingListener, StatsFragment.OnLoadingListener {
/** /**
* The key to use when putting profile's url String to {@link ProfileActivity}'s Bundle. * The key to use when putting profile's url String to {@link ProfileActivity}'s Bundle.
*/ */
@ -185,7 +185,8 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
if (target.is(ThmmyPage.PageCategory.PROFILE_STATS)) { if (target.is(ThmmyPage.PageCategory.PROFILE_STATS)) {
profileUrl = profileUrl.substring(0, profileUrl.indexOf(";sa=statPanel")); profileUrl = profileUrl.substring(0, profileUrl.indexOf(";sa=statPanel"));
tabSelect = 2; tabSelect = 2;
} else if (target.is(ThmmyPage.PageCategory.PROFILE_LATEST_POSTS)) { }
else if (target.is(ThmmyPage.PageCategory.PROFILE_LATEST_POSTS)) {
profileUrl = profileUrl.substring(0, profileUrl.indexOf(";sa=showPosts")); profileUrl = profileUrl.substring(0, profileUrl.indexOf(";sa=showPosts"));
tabSelect = 1; tabSelect = 1;
} }
@ -220,8 +221,8 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
setBarVisibility(loading); setBarVisibility(loading);
} }
private void setBarVisibility (boolean visible){ private void setBarVisibility(boolean visible) {
if(visible) if (visible)
progressBar.setVisibility(ProgressBar.VISIBLE); progressBar.setVisibility(ProgressBar.VISIBLE);
else else
progressBar.setVisibility(ProgressBar.INVISIBLE); progressBar.setVisibility(ProgressBar.INVISIBLE);
@ -233,17 +234,17 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
if (pmFAB.getVisibility() != View.GONE) pmFAB.setEnabled(false); if (pmFAB.getVisibility() != View.GONE) pmFAB.setEnabled(false);
} }
private void loadAvatar(Boolean loadDefault){ private void loadAvatar(Boolean loadDefault) {
String avatarUri; String avatarUri;
if(loadDefault) if (loadDefault)
avatarUri = "R.drawable.ic_default_user_avatar"; avatarUri = "R.drawable.ic_default_user_avatar";
else { else {
avatarUri = avatarUrl; avatarUri = avatarUrl;
if(avatarUrl!=null) if (avatarUrl != null)
avatarView.setOnClickListener(v -> displayPhotoViewImage(ProfileActivity.this, avatarUrl)); avatarView.setOnClickListener(v -> displayPhotoViewImage(ProfileActivity.this, avatarUrl));
} }
if(isValidContextForGlide(this)){ if (isValidContextForGlide(this)) {
Glide.with(this) Glide.with(this)
.load(avatarUri) .load(avatarUri)
.circleCrop() .circleCrop()
@ -292,7 +293,8 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
Element tmpEl = profilePage.select("td.windowbg:nth-child(2)").first(); Element tmpEl = profilePage.select("td.windowbg:nth-child(2)").first();
if (tmpEl != null) { if (tmpEl != null) {
personalText = emojiTagToHtml(tmpEl.text().trim()); personalText = emojiTagToHtml(tmpEl.text().trim());
} else { }
else {
//Should never get here! //Should never get here!
//Something is wrong. //Something is wrong.
Timber.e("An error occurred while trying to find profile's personal text."); Timber.e("An error occurred while trying to find profile's personal text.");
@ -328,11 +330,13 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
if (usernameSpan != null) { if (usernameSpan != null) {
if (isOnline) { if (isOnline) {
usernameView.setTextColor(Color.parseColor("#4CAF50")); usernameView.setTextColor(Color.parseColor("#4CAF50"));
} else { }
else {
usernameView.setTextColor(Color.GRAY); usernameView.setTextColor(Color.GRAY);
} }
usernameView.setText(usernameSpan); usernameView.setText(usernameSpan);
} else if (usernameView.getText() != username) usernameView.setText(username); }
else if (usernameView.getText() != username) usernameView.setText(username);
if (avatarUrl != null && !Objects.equals(avatarUrl, "")) if (avatarUrl != null && !Objects.equals(avatarUrl, ""))
loadAvatar(false); loadAvatar(false);
else else
@ -349,12 +353,14 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
TabLayout.Tab tab = tabLayout.getTabAt(tabSelect); TabLayout.Tab tab = tabLayout.getTabAt(tabSelect);
if (tab != null) tab.select(); if (tab != null) tab.select();
} }
} else if (result == NetworkResultCodes.NETWORK_ERROR) { }
else if (result == NetworkResultCodes.NETWORK_ERROR) {
Timber.w("Network error while excecuting profile activity"); Timber.w("Network error while excecuting profile activity");
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error" Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Network error"
, Toast.LENGTH_LONG).show(); , Toast.LENGTH_LONG).show();
finish(); finish();
} else { }
else {
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Fatal error!\n Aborting..." Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Fatal error!\n Aborting..."
, Toast.LENGTH_LONG).show(); , Toast.LENGTH_LONG).show();
finish(); finish();

8
app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java

@ -51,17 +51,19 @@ class LatestPostsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
View view = LayoutInflater.from(parent.getContext()). View view = LayoutInflater.from(parent.getContext()).
inflate(R.layout.fragment_profile_latest_posts_row, parent, false); inflate(R.layout.fragment_profile_latest_posts_row, parent, false);
return new LatestPostViewHolder(view); return new LatestPostViewHolder(view);
} else { // viewType == VIEW_TYPE_EMPTY }
else { // viewType == VIEW_TYPE_EMPTY
View view = LayoutInflater.from(parent.getContext()). View view = LayoutInflater.from(parent.getContext()).
inflate(R.layout.fragment_profile_latest_posts_empty_message, parent, false); inflate(R.layout.fragment_profile_latest_posts_empty_message, parent, false);
return new RecyclerView.ViewHolder(view){}; return new RecyclerView.ViewHolder(view) {
};
} }
} }
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
@Override @Override
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) { public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) {
if (holder instanceof LatestPostViewHolder){ if (holder instanceof LatestPostViewHolder) {
PostSummary topic = parsedTopicSummaries.get(position); PostSummary topic = parsedTopicSummaries.get(position);
final LatestPostViewHolder latestPostViewHolder = (LatestPostViewHolder) holder; final LatestPostViewHolder latestPostViewHolder = (LatestPostViewHolder) holder;
latestPostViewHolder.postTitle.setText(topic.getSubject()); latestPostViewHolder.postTitle.setText(topic.getSubject());

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

@ -182,7 +182,7 @@ public class LatestPostsFragment extends BaseFragment {
protected void onPostExecute(Boolean result) { protected void onPostExecute(Boolean result) {
if (Boolean.FALSE.equals(result)) if (Boolean.FALSE.equals(result))
Timber.e(new ParseException("Parsing failed (latest posts)"),"ParseException"); //TODO: This is inaccurate (e.g. can also have an I/O cause) Timber.e(new ParseException("Parsing failed (latest posts)"), "ParseException"); //TODO: This is inaccurate (e.g. can also have an I/O cause)
int prevSize = parsedTopicSummaries.size(); int prevSize = parsedTopicSummaries.size();
parsedTopicSummaries.addAll(fetchedParsedTopicSummaries); parsedTopicSummaries.addAll(fetchedParsedTopicSummaries);
latestPostsAdapter.notifyItemRangeInserted(prevSize, parsedTopicSummaries.size() - prevSize); latestPostsAdapter.notifyItemRangeInserted(prevSize, parsedTopicSummaries.size() - prevSize);
@ -200,7 +200,7 @@ public class LatestPostsFragment extends BaseFragment {
select("td:has(table:Contains(Εμφάνιση μηνυμάτων)):not([style]) > table"); select("td:has(table:Contains(Εμφάνιση μηνυμάτων)):not([style]) > table");
if (!latestPostsRows.select("td:contains(Sorry, no matches were found)").isEmpty() || if (!latestPostsRows.select("td:contains(Sorry, no matches were found)").isEmpty() ||
!latestPostsRows.select("td:contains(Δυστυχώς δεν βρέθηκε τίποτα)").isEmpty()){ !latestPostsRows.select("td:contains(Δυστυχώς δεν βρέθηκε τίποτα)").isEmpty()) {
userHasPosts = false; userHasPosts = false;
fetchedParsedTopicSummaries.add(null); fetchedParsedTopicSummaries.add(null);
return true; return true;
@ -216,14 +216,15 @@ public class LatestPostsFragment extends BaseFragment {
numberOfPages = Integer.parseInt(page.text()); numberOfPages = Integer.parseInt(page.text());
} }
} }
} else { }
else {
Elements rowHeader = row.select("td.middletext"); Elements rowHeader = row.select("td.middletext");
if (rowHeader.size() != 2) if (rowHeader.size() != 2)
return false; return false;
else { else {
pTopicTitle = rowHeader.first().text().replaceAll("\\u00a0","").trim(); pTopicTitle = rowHeader.first().text().replaceAll("\\u00a0", "").trim();
pTopicUrl = rowHeader.first().select("a").last().attr("href"); pTopicUrl = rowHeader.first().select("a").last().attr("href");
pDateTime = rowHeader.last().text().replaceAll("(on: )|(στις: )",""); pDateTime = rowHeader.last().text().replaceAll("(on: )|(στις: )", "");
} }
pPost = ParseHelpers.youtubeEmbeddedFix(row.select("div.post").first()); pPost = ParseHelpers.youtubeEmbeddedFix(row.select("div.post").first());

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

@ -93,7 +93,7 @@ public class StatsFragment extends Fragment {
Bundle savedInstanceState) { Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_profile_stats, container, false); final View rootView = inflater.inflate(R.layout.fragment_profile_stats, container, false);
mainContent = rootView.findViewById(R.id.main_content); mainContent = rootView.findViewById(R.id.main_content);
if (profileStatsTask!=null && profileStatsTask.getStatus() == AsyncTask.Status.FINISHED) if (profileStatsTask != null && profileStatsTask.getStatus() == AsyncTask.Status.FINISHED)
populateLayout(); populateLayout();
return rootView; return rootView;
} }
@ -101,7 +101,7 @@ public class StatsFragment extends Fragment {
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(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");
} }
@ -158,7 +158,7 @@ public class StatsFragment extends Fragment {
protected void onPostExecute(Boolean result) { protected void onPostExecute(Boolean result) {
onLoadingListener.onLoadingStats(false); onLoadingListener.onLoadingStats(false);
if (!result) if (!result)
Timber.e(new ParseException("Parsing failed (user stats)"),"ParseException"); //TODO: This is inaccurate (e.g. can also have an I/O cause) Timber.e(new ParseException("Parsing failed (user stats)"), "ParseException"); //TODO: This is inaccurate (e.g. can also have an I/O cause)
else else
populateLayout(); populateLayout();
} }
@ -227,7 +227,8 @@ 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))
@ -261,7 +262,8 @@ public class StatsFragment extends Fragment {
if (isAdded()) { if (isAdded()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
postingActivityByTimeDataSet.setFillDrawable(getResources().getDrawable(R.drawable.line_chart_gradient, null)); postingActivityByTimeDataSet.setFillDrawable(getResources().getDrawable(R.drawable.line_chart_gradient, null));
} else }
else
//noinspection deprecation //noinspection deprecation
postingActivityByTimeDataSet.setFillDrawable(getResources().getDrawable(R.drawable.line_chart_gradient)); postingActivityByTimeDataSet.setFillDrawable(getResources().getDrawable(R.drawable.line_chart_gradient));
} }
@ -300,7 +302,8 @@ public class StatsFragment extends Fragment {
if (isAdded()) { if (isAdded()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 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 }
else
//noinspection deprecation //noinspection deprecation
mostPopularBoardsByPostsDataSet.setColors(getResources().getColor(R.color.accent)); mostPopularBoardsByPostsDataSet.setColors(getResources().getColor(R.color.accent));
} }
@ -341,7 +344,8 @@ public class StatsFragment extends Fragment {
if (isAdded()) { if (isAdded()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 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 }
else
//noinspection deprecation //noinspection deprecation
mostPopularBoardsByActivityDataSet.setColors(getResources().getColor(R.color.accent)); mostPopularBoardsByActivityDataSet.setColors(getResources().getColor(R.color.accent));
} }

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

@ -125,7 +125,7 @@ public class SummaryFragment extends Fragment {
* @see org.jsoup.Jsoup Jsoup * @see org.jsoup.Jsoup Jsoup
*/ */
LinkedHashMap<String, String> parseProfileSummary(Document profile) { LinkedHashMap<String, String> parseProfileSummary(Document profile) {
LinkedHashMap<String, String> parsedInformation = new LinkedHashMap<>(); LinkedHashMap<String, String> parsedInformation = new LinkedHashMap<>();
//Contains all summary's rows //Contains all summary's rows
Elements summaryRows = profile.select("td.windowbg > table > tbody > tr"); Elements summaryRows = profile.select("td.windowbg > table > tbody > tr");
@ -135,16 +135,16 @@ public class SummaryFragment extends Fragment {
int tdSize = summaryRow.select("td").size(); int tdSize = summaryRow.select("td").size();
if (tdSize > 1){ if (tdSize > 1) {
key = summaryRow.select("td").first().text().trim(); key = summaryRow.select("td").first().text().trim();
if (key.startsWith("Name") || key.startsWith("Όνομα")) if (key.startsWith("Name") || key.startsWith("Όνομα"))
continue; continue;
else if (key.startsWith("Signature") || key.startsWith("Υπογραφή")){ else if (key.startsWith("Signature") || key.startsWith("Υπογραφή")) {
key = summaryRow.selectFirst("td > table > tbody > tr > td").text().trim(); key = summaryRow.selectFirst("td > table > tbody > tr > td").text().trim();
summaryRow.selectFirst("td > table > tbody > tr").remove(); //key not needed, outer html needed for CSS summaryRow.selectFirst("td > table > tbody > tr").remove(); //key not needed, outer html needed for CSS
value = ParseHelpers.emojiTagToHtml(ParseHelpers.youtubeEmbeddedFix(summaryRow)); // Is emojiTagToHtml() really needed here? value = ParseHelpers.emojiTagToHtml(ParseHelpers.youtubeEmbeddedFix(summaryRow)); // Is emojiTagToHtml() really needed here?
if(summaryRow.text().trim().isEmpty()) if (summaryRow.text().trim().isEmpty())
continue; continue;
value = ("<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />\n" + value = ("<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />\n" +
"<link rel=\"stylesheet\" type=\"text/css\" href=\"style_light.css\" />\n" + "<link rel=\"stylesheet\" type=\"text/css\" href=\"style_light.css\" />\n" +
@ -176,7 +176,7 @@ public class SummaryFragment extends Fragment {
String key = entry.getKey(); String key = entry.getKey();
String value = entry.getValue(); String value = entry.getValue();
if (key.startsWith("Current Status") || key.startsWith("Κατάσταση")){ if (key.startsWith("Current Status") || key.startsWith("Κατάσταση")) {
addEmptyView(); addEmptyView();
continue; continue;
} }
@ -194,7 +194,7 @@ public class SummaryFragment extends Fragment {
String textViewContent = "<b>" + key + "</b> " + value; String textViewContent = "<b>" + key + "</b> " + value;
if (key.startsWith("Signature") || key.startsWith("Υπογραφή")){ if (key.startsWith("Signature") || key.startsWith("Υπογραφή")) {
addEmptyView(); addEmptyView();
textViewContent = "<b>" + key + "</b>"; textViewContent = "<b>" + key + "</b>";
} }
@ -219,7 +219,7 @@ public class SummaryFragment extends Fragment {
} }
} }
private void addEmptyView(){ private void addEmptyView() {
mainContent.addView(new TextView(this.getContext())); mainContent.addView(new TextView(this.getContext()));
} }
} }

3
app/src/main/java/gr/thmmy/mthmmy/activities/settings/SettingsActivity.java

@ -7,8 +7,9 @@ import androidx.fragment.app.FragmentTransaction;
import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.base.BaseActivity; import gr.thmmy.mthmmy.base.BaseActivity;
public class SettingsActivity extends BaseActivity { public class SettingsActivity extends BaseActivity {
public static final String DEFAULT_HOME_TAB = "pref_app_main_default_tab_key"; public static final String DEFAULT_HOME_TAB = "pref_app_main_default_tab_key";
public static final String DISPLAY_COMPACT_TABS = "pref_app_display_compact_tabs_key";
public static final String DISPLAY_RELATIVE_TIME = "pref_app_display_relative_time_key"; public static final String DISPLAY_RELATIVE_TIME = "pref_app_display_relative_time_key";
public static final String NOTIFICATION_LED_KEY = "pref_notification_led_enable_key"; public static final String NOTIFICATION_LED_KEY = "pref_notification_led_enable_key";
public static final String NOTIFICATION_VIBRATION_KEY = "pref_notification_vibration_enable_key"; public static final String NOTIFICATION_VIBRATION_KEY = "pref_notification_vibration_enable_key";

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

@ -66,7 +66,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared
defaultHomeTabValues.add("0"); defaultHomeTabValues.add("0");
defaultHomeTabValues.add("1"); defaultHomeTabValues.add("1");
if(isLoggedIn = BaseApplication.getInstance().getSessionManager().isLoggedIn()){ if (isLoggedIn = BaseApplication.getInstance().getSessionManager().isLoggedIn()) {
defaultHomeTabEntries.add(UNREAD); defaultHomeTabEntries.add(UNREAD);
defaultHomeTabValues.add("2"); defaultHomeTabValues.add("2");
} }
@ -97,11 +97,11 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared
public void onCreatePreferences(Bundle bundle, String rootKey) { public void onCreatePreferences(Bundle bundle, String rootKey) {
isLoggedIn = BaseApplication.getInstance().getSessionManager().isLoggedIn(); //Ensures it stays updated isLoggedIn = BaseApplication.getInstance().getSessionManager().isLoggedIn(); //Ensures it stays updated
// Add the Preferences from the XML file if needed // Add the Preferences from the XML file if needed
if(isLoggedIn&&(prefs_type==PREFS_TYPE.GUEST||prefs_type==PREFS_TYPE.NOT_SET)){ if (isLoggedIn && (prefs_type == PREFS_TYPE.GUEST || prefs_type == PREFS_TYPE.NOT_SET)) {
prefs_type = PREFS_TYPE.USER; prefs_type = PREFS_TYPE.USER;
addPreferencesFromResource(R.xml.app_preferences_user); addPreferencesFromResource(R.xml.app_preferences_user);
} }
else if(!isLoggedIn&&(prefs_type==PREFS_TYPE.USER||prefs_type==PREFS_TYPE.NOT_SET)){ else if (!isLoggedIn && (prefs_type == PREFS_TYPE.USER || prefs_type == PREFS_TYPE.NOT_SET)) {
prefs_type = PREFS_TYPE.GUEST; prefs_type = PREFS_TYPE.GUEST;
addPreferencesFromResource(R.xml.app_preferences_guest); addPreferencesFromResource(R.xml.app_preferences_guest);
} }
@ -133,17 +133,20 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared
if (existingValue.equals(SILENT_SELECTED)) { if (existingValue.equals(SILENT_SELECTED)) {
//Selects "Silent" //Selects "Silent"
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, (Uri) null); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, (Uri) null);
} else { }
else {
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Uri.parse(existingValue)); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Uri.parse(existingValue));
} }
} else { }
else {
//No ringtone has been selected, set to the default //No ringtone has been selected, set to the default
intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Settings.System.DEFAULT_NOTIFICATION_URI); intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Settings.System.DEFAULT_NOTIFICATION_URI);
} }
startActivityForResult(intent, REQUEST_CODE_ALERT_RINGTONE); startActivityForResult(intent, REQUEST_CODE_ALERT_RINGTONE);
return true; return true;
} else { }
else {
return super.onPreferenceTreeClick(preference); return super.onPreferenceTreeClick(preference);
} }
} }
@ -155,11 +158,13 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared
SharedPreferences.Editor editor = settingsFile.edit(); SharedPreferences.Editor editor = settingsFile.edit();
if (ringtone != null) { if (ringtone != null) {
editor.putString(SELECTED_RINGTONE, ringtone.toString()).apply(); editor.putString(SELECTED_RINGTONE, ringtone.toString()).apply();
} else { }
else {
//"Silent" was selected //"Silent" was selected
editor.putString(SELECTED_RINGTONE, SILENT_SELECTED).apply(); editor.putString(SELECTED_RINGTONE, SILENT_SELECTED).apply();
} }
} else { }
else {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
} }
} }
@ -169,19 +174,19 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared
updatePreferenceVisibility(); updatePreferenceVisibility();
} }
private void updatePreferenceVisibility(){ private void updatePreferenceVisibility() {
if(isLoggedIn&& prefs_type==PREFS_TYPE.GUEST) { if (isLoggedIn && prefs_type == PREFS_TYPE.GUEST) {
prefs_type = PREFS_TYPE.USER; prefs_type = PREFS_TYPE.USER;
setPreferencesFromResource(R.xml.app_preferences_user, getPreferenceScreen().getKey()); setPreferencesFromResource(R.xml.app_preferences_user, getPreferenceScreen().getKey());
if(!defaultHomeTabEntries.contains(UNREAD)){ if (!defaultHomeTabEntries.contains(UNREAD)) {
defaultHomeTabEntries.add(UNREAD); defaultHomeTabEntries.add(UNREAD);
defaultHomeTabValues.add("2"); defaultHomeTabValues.add("2");
} }
} }
else if(!isLoggedIn&&prefs_type==PREFS_TYPE.USER){ else if (!isLoggedIn && prefs_type == PREFS_TYPE.USER) {
prefs_type = PREFS_TYPE.GUEST; prefs_type = PREFS_TYPE.GUEST;
setPreferencesFromResource(R.xml.app_preferences_guest,getPreferenceScreen().getKey()); setPreferencesFromResource(R.xml.app_preferences_guest, getPreferenceScreen().getKey());
if(defaultHomeTabEntries.contains(UNREAD)){ if (defaultHomeTabEntries.contains(UNREAD)) {
defaultHomeTabEntries.remove(UNREAD); defaultHomeTabEntries.remove(UNREAD);
defaultHomeTabValues.remove("2"); defaultHomeTabValues.remove("2");
} }
@ -199,27 +204,33 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared
boolean enabled; boolean enabled;
if (key.equals(getString(R.string.pref_privacy_crashlytics_enable_key))) { if (key.equals(getString(R.string.pref_privacy_crashlytics_enable_key))) {
enabled = sharedPreferences.getBoolean(key, false); enabled = sharedPreferences.getBoolean(key, false);
if(enabled) if (enabled)
BaseApplication.getInstance().setFirebaseCrashlyticsEnabled(true); BaseApplication.getInstance().setFirebaseCrashlyticsEnabled(true);
else { else {
Timber.i("Crashlytics collection will be disabled after restarting."); Timber.i("Crashlytics collection will be disabled after restarting.");
BaseApplication.getInstance().setFirebaseCrashlyticsEnabled(false); BaseApplication.getInstance().setFirebaseCrashlyticsEnabled(false);
displayRestartAppToTakeEffectToast(); displayRestartAppToTakeEffectToast();
} }
} else if (key.equals(getString(R.string.pref_privacy_analytics_enable_key))) { }
else if (key.equals(getString(R.string.pref_privacy_analytics_enable_key))) {
enabled = sharedPreferences.getBoolean(key, false); enabled = sharedPreferences.getBoolean(key, false);
BaseApplication.getInstance().setFirebaseAnalyticsEnabled(enabled); BaseApplication.getInstance().setFirebaseAnalyticsEnabled(enabled);
if(enabled) if (enabled)
Timber.i("Analytics collection enabled."); Timber.i("Analytics collection enabled.");
else else
Timber.i("Analytics collection disabled."); Timber.i("Analytics collection disabled.");
} else if (key.equals(getString(R.string.pref_app_display_relative_time_key)) }
&& BaseApplication.getInstance().isDisplayRelativeTimeEnabled()!=sharedPreferences.getBoolean(key, false)){ else if (key.equals(getString(R.string.pref_app_display_relative_time_key))
displayRestartAppToTakeEffectToast(); && BaseApplication.getInstance().isDisplayRelativeTimeEnabled() != sharedPreferences.getBoolean(key, false)) {
displayRestartAppToTakeEffectToast();
}
else if (key.equals(getString(R.string.pref_app_display_compact_tabs_key))
&& BaseApplication.getInstance().isDisplayCompactTabsEnabled() != sharedPreferences.getBoolean(key, false)) {
displayRestartAppToTakeEffectToast();
} }
} }
private void displayRestartAppToTakeEffectToast(){ private void displayRestartAppToTakeEffectToast() {
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "This change will take effect once you restart the app.", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "This change will take effect once you restart the app.", Toast.LENGTH_SHORT).show();
} }
} }

1
app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/SendShoutTask.java

@ -37,7 +37,6 @@ public class SendShoutTask extends NetworkTask<Void> {
} }
@Override @Override
protected Void performTask(Document document, Response response) { protected Void performTask(Document document, Response response) {
return null; return null;

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

@ -59,7 +59,8 @@ public class ShoutAdapter extends CustomRecyclerView.Adapter<ShoutAdapter.ShoutV
public void onBindViewHolder(@NonNull ShoutViewHolder holder, int position) { public void onBindViewHolder(@NonNull ShoutViewHolder holder, int position) {
Shout currentShout = shouts[position]; Shout currentShout = shouts[position];
holder.author.setText(currentShout.getShouter()); holder.author.setText(currentShout.getShouter());
if (currentShout.isMemberOfTheMonth()) holder.author.setTextColor(context.getResources().getColor(R.color.member_of_the_month)); if (currentShout.isMemberOfTheMonth())
holder.author.setTextColor(context.getResources().getColor(R.color.member_of_the_month));
else holder.author.setTextColor(context.getResources().getColor(R.color.accent)); else holder.author.setTextColor(context.getResources().getColor(R.color.accent));
holder.author.setOnClickListener(view -> { holder.author.setOnClickListener(view -> {
Intent intent = new Intent(context, ProfileActivity.class); Intent intent = new Intent(context, ProfileActivity.class);
@ -125,7 +126,8 @@ public class ShoutAdapter extends CustomRecyclerView.Adapter<ShoutAdapter.ShoutV
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent); context.startActivity(intent);
return true; return true;
} else if (target.is(ThmmyPage.PageCategory.BOARD)) { }
else if (target.is(ThmmyPage.PageCategory.BOARD)) {
Intent intent = new Intent(context, BoardActivity.class); Intent intent = new Intent(context, BoardActivity.class);
Bundle extras = new Bundle(); Bundle extras = new Bundle();
extras.putString(BUNDLE_BOARD_URL, uriString); extras.putString(BUNDLE_BOARD_URL, uriString);
@ -134,7 +136,8 @@ public class ShoutAdapter extends CustomRecyclerView.Adapter<ShoutAdapter.ShoutV
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent); context.startActivity(intent);
return true; return true;
} else if (target.is(ThmmyPage.PageCategory.PROFILE)) { }
else if (target.is(ThmmyPage.PageCategory.PROFILE)) {
Intent intent = new Intent(context, ProfileActivity.class); Intent intent = new Intent(context, ProfileActivity.class);
Bundle extras = new Bundle(); Bundle extras = new Bundle();
extras.putString(BUNDLE_PROFILE_URL, uriString); extras.putString(BUNDLE_PROFILE_URL, uriString);

3
app/src/main/java/gr/thmmy/mthmmy/activities/shoutbox/ShoutboxActivity.java

@ -45,7 +45,8 @@ public class ShoutboxActivity extends BaseActivity {
if (count == 0) { if (count == 0) {
if (!shoutboxFragment.onBackPressed()) if (!shoutboxFragment.onBackPressed())
super.onBackPressed(); super.onBackPressed();
} else { }
else {
getSupportFragmentManager().popBackStack(); getSupportFragmentManager().popBackStack();
} }
} }

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

@ -93,7 +93,8 @@ public class ShoutboxFragment extends Fragment {
if (item.getItemId() == R.id.menu_refresh) { if (item.getItemId() == R.id.menu_refresh) {
shoutboxViewModel.loadShoutbox(true); shoutboxViewModel.loadShoutbox(true);
return true; return true;
} else { }
else {
return false; return false;
} }
} }
@ -142,7 +143,8 @@ public class ShoutboxFragment extends Fragment {
BaseApplication.getInstance().logFirebaseAnalyticsEvent("shout", null); BaseApplication.getInstance().logFirebaseAnalyticsEvent("shout", null);
editorView.getEditText().getText().clear(); editorView.getEditText().getText().clear();
shoutboxViewModel.loadShoutbox(true); shoutboxViewModel.loadShoutbox(true);
} else if (resultCode == NetworkResultCodes.NETWORK_ERROR) { }
else if (resultCode == NetworkResultCodes.NETWORK_ERROR) {
Timber.w("Failed to send shout"); Timber.w("Failed to send shout");
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "NetworkError", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "NetworkError", Toast.LENGTH_SHORT).show();
} }
@ -154,10 +156,12 @@ public class ShoutboxFragment extends Fragment {
shoutboxViewModel.setShoutbox(shoutbox); shoutboxViewModel.setShoutbox(shoutbox);
if (shoutbox.getShoutSend() != null) if (shoutbox.getShoutSend() != null)
editorView.setVisibility(View.VISIBLE); editorView.setVisibility(View.VISIBLE);
} else if (resultCode == NetworkResultCodes.NETWORK_ERROR) { }
else if (resultCode == NetworkResultCodes.NETWORK_ERROR) {
Timber.w("Failed to retreive shoutbox due to network error"); Timber.w("Failed to retreive shoutbox due to network error");
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "NetworkError", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "NetworkError", Toast.LENGTH_SHORT).show();
} else { }
else {
Timber.wtf("Failed to retreive shoutbox due to unknown error"); Timber.wtf("Failed to retreive shoutbox due to unknown error");
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Failed to retrieve shoutbox, please contact mthmmy developer team", Toast.LENGTH_LONG).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Failed to retrieve shoutbox, please contact mthmmy developer team", Toast.LENGTH_LONG).show();
} }

2
app/src/main/java/gr/thmmy/mthmmy/activities/topic/Posting.java

@ -62,7 +62,7 @@ public class Posting {
if (finalUrl.contains("action=post")) { if (finalUrl.contains("action=post")) {
Document postErrorPage = Jsoup.parse(response.body().string()); Document postErrorPage = Jsoup.parse(response.body().string());
Element errorsElement = postErrorPage.select("tr[id=errors] div[id=error_list]").first(); Element errorsElement = postErrorPage.select("tr[id=errors] div[id=error_list]").first();
if(errorsElement!=null){ if (errorsElement != null) {
String[] errors = errorsElement.toString().split("<br>"); String[] errors = errorsElement.toString().split("<br>");
for (int i = 0; i < errors.length; ++i) { //TODO test for (int i = 0; i < errors.length; ++i) { //TODO test
Timber.d(String.valueOf(i)); Timber.d(String.valueOf(i));

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

@ -198,7 +198,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
if (!sessionManager.isLoggedIn()) { if (!sessionManager.isLoggedIn()) {
replyFAB.hide(); replyFAB.hide();
replyFAB.setTag(false); replyFAB.setTag(false);
} else { }
else {
replyFAB.setOnClickListener(view -> { replyFAB.setOnClickListener(view -> {
if (sessionManager.isLoggedIn()) if (sessionManager.isLoggedIn())
viewModel.prepareForReply(); viewModel.prepareForReply();
@ -279,10 +280,12 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
if (drawer.isDrawerOpen()) { if (drawer.isDrawerOpen()) {
drawer.closeDrawer(); drawer.closeDrawer();
return; return;
} else if (emojiKeyboard.getVisibility() == View.VISIBLE) { }
else if (emojiKeyboard.getVisibility() == View.VISIBLE) {
emojiKeyboard.setVisibility(View.GONE); emojiKeyboard.setVisibility(View.GONE);
return; return;
} else if (viewModel.isWritingReply()) { }
else if (viewModel.isWritingReply()) {
// persist reply // persist reply
SharedPreferences drafts = getSharedPreferences(getString(R.string.pref_topic_drafts_key), MODE_PRIVATE); SharedPreferences drafts = getSharedPreferences(getString(R.string.pref_topic_drafts_key), MODE_PRIVATE);
Post reply = (Post) topicItems.get(topicItems.size() - 1); Post reply = (Post) topicItems.get(topicItems.size() - 1);
@ -296,7 +299,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
replyFAB.setTag(true); replyFAB.setTag(true);
bottomNavBar.setVisibility(View.VISIBLE); bottomNavBar.setVisibility(View.VISIBLE);
return; return;
} else if (viewModel.isEditingPost()) { }
else if (viewModel.isEditingPost()) {
((Post) topicItems.get(viewModel.getPostBeingEditedPosition())).setPostType(Post.TYPE_POST); ((Post) topicItems.get(viewModel.getPostBeingEditedPosition())).setPostType(Post.TYPE_POST);
topicAdapter.notifyItemChanged(viewModel.getPostBeingEditedPosition()); topicAdapter.notifyItemChanged(viewModel.getPostBeingEditedPosition());
topicAdapter.setBackButtonHidden(); topicAdapter.setBackButtonHidden();
@ -319,9 +323,9 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
@Override @Override
protected void onDestroy() { protected void onDestroy() {
super.onDestroy(); super.onDestroy();
if(topicInfoDialog!=null){ if (topicInfoDialog != null) {
topicInfoDialog.dismiss(); topicInfoDialog.dismiss();
topicInfoDialog=null; topicInfoDialog = null;
} }
recyclerView.setAdapter(null); recyclerView.setAdapter(null);
viewModel.stopLoading(); viewModel.stopLoading();
@ -364,7 +368,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
if (autoIncrement) { if (autoIncrement) {
viewModel.incrementPageRequestValue(step, false); viewModel.incrementPageRequestValue(step, false);
repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), REPEAT_DELAY); repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), REPEAT_DELAY);
} else if (autoDecrement) { }
else if (autoDecrement) {
viewModel.decrementPageRequestValue(step, false); viewModel.decrementPageRequestValue(step, false);
repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), REPEAT_DELAY); repeatUpdateHandler.postDelayed(new RepetitiveUpdater(step), REPEAT_DELAY);
} }
@ -383,19 +388,23 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
previousPage.setEnabled(false); previousPage.setEnabled(false);
nextPage.setEnabled(false); nextPage.setEnabled(false);
lastPage.setEnabled(false); lastPage.setEnabled(false);
} else if (exception == previousPage) { }
else if (exception == previousPage) {
firstPage.setEnabled(false); firstPage.setEnabled(false);
nextPage.setEnabled(false); nextPage.setEnabled(false);
lastPage.setEnabled(false); lastPage.setEnabled(false);
} else if (exception == nextPage) { }
else if (exception == nextPage) {
firstPage.setEnabled(false); firstPage.setEnabled(false);
previousPage.setEnabled(false); previousPage.setEnabled(false);
lastPage.setEnabled(false); lastPage.setEnabled(false);
} else if (exception == lastPage) { }
else if (exception == lastPage) {
firstPage.setEnabled(false); firstPage.setEnabled(false);
previousPage.setEnabled(false); previousPage.setEnabled(false);
nextPage.setEnabled(false); nextPage.setEnabled(false);
} else { }
else {
paginationEnabled(false); paginationEnabled(false);
} }
} }
@ -406,7 +415,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
increment.setOnClickListener(v -> { increment.setOnClickListener(v -> {
if (!autoIncrement && step == LARGE_STEP) { if (!autoIncrement && step == LARGE_STEP) {
viewModel.setPageIndicatorIndex(viewModel.getPageCount(), true); viewModel.setPageIndicatorIndex(viewModel.getPageCount(), true);
} else if (!autoIncrement) { }
else if (!autoIncrement) {
viewModel.incrementPageRequestValue(step, true); viewModel.incrementPageRequestValue(step, true);
} }
}); });
@ -428,11 +438,13 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
public boolean onTouch(View v, MotionEvent event) { public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) { if (event.getAction() == MotionEvent.ACTION_DOWN) {
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom()); rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
} else if (rect != null && event.getAction() == MotionEvent.ACTION_UP && autoIncrement) { }
else if (rect != null && event.getAction() == MotionEvent.ACTION_UP && autoIncrement) {
autoIncrement = false; autoIncrement = false;
paginationEnabled(true); paginationEnabled(true);
viewModel.loadPageIndicated(); viewModel.loadPageIndicated();
} else if (rect != null && event.getAction() == MotionEvent.ACTION_MOVE) { }
else if (rect != null && event.getAction() == MotionEvent.ACTION_MOVE) {
if (!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) { if (!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) {
autoIncrement = false; autoIncrement = false;
viewModel.setPageIndicatorIndex(viewModel.getCurrentPageIndex(), false); viewModel.setPageIndicatorIndex(viewModel.getCurrentPageIndex(), false);
@ -450,7 +462,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
decrement.setOnClickListener(v -> { decrement.setOnClickListener(v -> {
if (!autoDecrement && step == LARGE_STEP) { if (!autoDecrement && step == LARGE_STEP) {
viewModel.setPageIndicatorIndex(1, true); viewModel.setPageIndicatorIndex(1, true);
} else if (!autoDecrement) { }
else if (!autoDecrement) {
viewModel.decrementPageRequestValue(step, true); viewModel.decrementPageRequestValue(step, true);
} }
}); });
@ -472,11 +485,13 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
public boolean onTouch(View v, MotionEvent event) { public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) { if (event.getAction() == MotionEvent.ACTION_DOWN) {
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom()); rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
} else if (event.getAction() == MotionEvent.ACTION_UP && autoDecrement) { }
else if (event.getAction() == MotionEvent.ACTION_UP && autoDecrement) {
autoDecrement = false; autoDecrement = false;
paginationEnabled(true); paginationEnabled(true);
viewModel.loadPageIndicated(); viewModel.loadPageIndicated();
} else if (event.getAction() == MotionEvent.ACTION_MOVE) { }
else if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (rect != null && if (rect != null &&
!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) { !rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) {
autoIncrement = false; autoIncrement = false;
@ -514,7 +529,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
if (resultCode == NetworkResultCodes.SUCCESSFUL) { if (resultCode == NetworkResultCodes.SUCCESSFUL) {
Timber.i("Post deleted successfully"); Timber.i("Post deleted successfully");
viewModel.reloadPage(); viewModel.reloadPage();
} else { }
else {
Timber.w("Failed to delete post"); Timber.w("Failed to delete post");
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Delete failed!", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Delete failed!", Toast.LENGTH_SHORT).show();
} }
@ -551,7 +567,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
if ((((Post) topicItems.get(topicItems.size() - 1)).getPostNumber() + 1) % 15 == 0) { if ((((Post) topicItems.get(topicItems.size() - 1)).getPostNumber() + 1) % 15 == 0) {
Timber.i("Reply was posted in new page. Switching to last page."); Timber.i("Reply was posted in new page. Switching to last page.");
viewModel.loadUrl(ParseHelpers.getBaseURL(viewModel.getTopicUrl()) + "." + 2147483647); viewModel.loadUrl(ParseHelpers.getBaseURL(viewModel.getTopicUrl()) + "." + 2147483647);
} else { }
else {
viewModel.reloadPage(); viewModel.reloadPage();
} }
break; break;
@ -621,7 +638,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
bottomNavBar.setVisibility(View.VISIBLE); bottomNavBar.setVisibility(View.VISIBLE);
viewModel.setEditingPost(false); viewModel.setEditingPost(false);
viewModel.reloadPage(); viewModel.reloadPage();
} else { }
else {
Timber.i("Post edit unsuccessful"); Timber.i("Post edit unsuccessful");
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Edit failed!", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Edit failed!", Toast.LENGTH_SHORT).show();
recyclerView.getChildAt(viewModel.getPostBeingEditedPosition()).setAlpha(1); recyclerView.getChildAt(viewModel.getPostBeingEditedPosition()).setAlpha(1);
@ -689,7 +707,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
if (replyPageUrl == null) { if (replyPageUrl == null) {
replyFAB.hide(); replyFAB.hide();
replyFAB.setTag(false); replyFAB.setTag(false);
} else { }
else {
replyFAB.show(); replyFAB.show();
replyFAB.setTag(true); replyFAB.setTag(true);
} }
@ -742,7 +761,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
errorTextview.setVisibility(View.GONE); errorTextview.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE); recyclerView.setVisibility(View.VISIBLE);
}); });
} else { }
else {
// a page has already been loaded // a page has already been loaded
viewModel.setPageIndicatorIndex(viewModel.getCurrentPageIndex(), false); viewModel.setPageIndicatorIndex(viewModel.getCurrentPageIndex(), false);
snackbar = Snackbar.make(findViewById(R.id.main_content), snackbar = Snackbar.make(findViewById(R.id.main_content),
@ -787,7 +807,8 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
replyFAB.hide(); replyFAB.hide();
replyFAB.setTag(false); replyFAB.setTag(false);
bottomNavBar.setVisibility(View.GONE); bottomNavBar.setVisibility(View.GONE);
} else { }
else {
Timber.i("Prepare for reply unsuccessful"); Timber.i("Prepare for reply unsuccessful");
Snackbar.make(findViewById(R.id.main_content), getString(R.string.generic_network_error), Snackbar.LENGTH_SHORT).show(); Snackbar.make(findViewById(R.id.main_content), getString(R.string.generic_network_error), Snackbar.LENGTH_SHORT).show();
} }
@ -803,16 +824,19 @@ public class TopicActivity extends BaseActivity implements TopicAdapter.OnPostFo
replyFAB.hide(); replyFAB.hide();
replyFAB.setTag(false); replyFAB.setTag(false);
bottomNavBar.setVisibility(View.GONE); bottomNavBar.setVisibility(View.GONE);
} else { }
else {
Timber.i("Prepare for edit unsuccessful"); Timber.i("Prepare for edit unsuccessful");
Snackbar.make(findViewById(R.id.main_content), getString(R.string.generic_network_error), Snackbar.LENGTH_SHORT).show(); Snackbar.make(findViewById(R.id.main_content), getString(R.string.generic_network_error), Snackbar.LENGTH_SHORT).show();
} }
}); });
} }
/**This method sets a long click listener on the title of the topic. Once the /**
* This method sets a long click listener on the title of the topic. Once the
* listener gets triggered, it copies the link url of the topic in the clipboard. * listener gets triggered, it copies the link url of the topic in the clipboard.
* This method is getting called on the onCreate() of the TopicActivity*/ * This method is getting called on the onCreate() of the TopicActivity
*/
void setToolbarOnLongClickListener(String url) { void setToolbarOnLongClickListener(String url) {
toolbar.setOnLongClickListener(view -> { toolbar.setOnLongClickListener(view -> {
//Try to set the clipboard text //Try to set the clipboard text

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

@ -129,7 +129,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
View itemView = LayoutInflater.from(parent.getContext()) View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.activity_topic_post_row, parent, false); .inflate(R.layout.activity_topic_post_row, parent, false);
return new PostViewHolder(itemView); return new PostViewHolder(itemView);
} else if (viewType == Post.TYPE_QUICK_REPLY) { }
else if (viewType == Post.TYPE_QUICK_REPLY) {
View view = LayoutInflater.from(parent.getContext()). View view = LayoutInflater.from(parent.getContext()).
inflate(R.layout.activity_topic_quick_reply_row, parent, false); inflate(R.layout.activity_topic_quick_reply_row, parent, false);
@ -143,7 +144,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
quickReplyText.requestFocus(); quickReplyText.requestFocus();
return new QuickReplyViewHolder(view); return new QuickReplyViewHolder(view);
} else if (viewType == Post.TYPE_EDIT) { }
else if (viewType == Post.TYPE_EDIT) {
View view = LayoutInflater.from(parent.getContext()). View view = LayoutInflater.from(parent.getContext()).
inflate(R.layout.activity_topic_edit_row, parent, false); inflate(R.layout.activity_topic_edit_row, parent, false);
@ -157,11 +159,13 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
editPostEdittext.requestFocus(); editPostEdittext.requestFocus();
return new EditMessageViewHolder(view); return new EditMessageViewHolder(view);
} else if (viewType == Poll.TYPE_POLL) { }
else if (viewType == Poll.TYPE_POLL) {
View view = LayoutInflater.from(parent.getContext()). View view = LayoutInflater.from(parent.getContext()).
inflate(R.layout.activity_topic_poll, parent, false); inflate(R.layout.activity_topic_poll, parent, false);
return new PollViewHolder(view); return new PollViewHolder(view);
} else { }
else {
throw new IllegalArgumentException("Unknown view type"); throw new IllegalArgumentException("Unknown view type");
} }
} }
@ -227,7 +231,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
holder.voteChart.setVisibility(View.GONE); holder.voteChart.setVisibility(View.GONE);
holder.selectedEntry.setVisibility(View.GONE); holder.selectedEntry.setVisibility(View.GONE);
holder.optionsLayout.setVisibility(View.VISIBLE); holder.optionsLayout.setVisibility(View.VISIBLE);
} else if (poll.getAvailableVoteCount() == 1) { }
else if (poll.getAvailableVoteCount() == 1) {
// vote single option // vote single option
RadioGroup radioGroup = new RadioGroup(context); RadioGroup radioGroup = new RadioGroup(context);
for (int i = 0; i < entries.length; i++) { for (int i = 0; i < entries.length; i++) {
@ -236,7 +241,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
radioButton.setMovementMethod(LinkMovementMethod.getInstance()); radioButton.setMovementMethod(LinkMovementMethod.getInstance());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
radioButton.setText(Html.fromHtml(entries[i].getEntryName(), Html.FROM_HTML_MODE_LEGACY)); radioButton.setText(Html.fromHtml(entries[i].getEntryName(), Html.FROM_HTML_MODE_LEGACY));
} else }
else
radioButton.setText(Html.fromHtml(entries[i].getEntryName())); radioButton.setText(Html.fromHtml(entries[i].getEntryName()));
radioButton.setText(ThmmyParser.html2span(context, entries[i].getEntryName())); radioButton.setText(ThmmyParser.html2span(context, entries[i].getEntryName()));
@ -247,7 +253,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
holder.voteChart.setVisibility(View.GONE); holder.voteChart.setVisibility(View.GONE);
holder.selectedEntry.setVisibility(View.GONE); holder.selectedEntry.setVisibility(View.GONE);
holder.optionsLayout.setVisibility(View.VISIBLE); holder.optionsLayout.setVisibility(View.VISIBLE);
} else if (poll.isPollResultsHidden()) { }
else if (poll.isPollResultsHidden()) {
// vote already submitted but results are hidden // vote already submitted but results are hidden
Poll.Entry[] entries1 = poll.getEntries(); Poll.Entry[] entries1 = poll.getEntries();
for (int i = 0; i < entries1.length; i++) { for (int i = 0; i < entries1.length; i++) {
@ -272,7 +279,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
holder.voteChart.setVisibility(View.GONE); holder.voteChart.setVisibility(View.GONE);
holder.selectedEntry.setVisibility(View.GONE); holder.selectedEntry.setVisibility(View.GONE);
holder.optionsLayout.setVisibility(View.VISIBLE); holder.optionsLayout.setVisibility(View.VISIBLE);
} else { }
else {
// Showing results // Showing results
holder.optionsLayout.setVisibility(View.GONE); holder.optionsLayout.setVisibility(View.GONE);
@ -331,16 +339,19 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (poll.getRemoveVoteUrl() != null) { if (poll.getRemoveVoteUrl() != null) {
holder.removeVotesButton.setOnClickListener(v -> viewModel.removeVote()); holder.removeVotesButton.setOnClickListener(v -> viewModel.removeVote());
holder.removeVotesButton.setVisibility(View.VISIBLE); holder.removeVotesButton.setVisibility(View.VISIBLE);
} else holder.removeVotesButton.setVisibility(View.GONE); }
else holder.removeVotesButton.setVisibility(View.GONE);
if (poll.getShowVoteResultsUrl() != null) { if (poll.getShowVoteResultsUrl() != null) {
holder.showPollResultsButton.setOnClickListener(v -> viewModel.loadUrl(poll.getShowVoteResultsUrl())); holder.showPollResultsButton.setOnClickListener(v -> viewModel.loadUrl(poll.getShowVoteResultsUrl()));
holder.showPollResultsButton.setVisibility(View.VISIBLE); holder.showPollResultsButton.setVisibility(View.VISIBLE);
} else holder.showPollResultsButton.setVisibility(View.GONE); }
else holder.showPollResultsButton.setVisibility(View.GONE);
if (poll.getShowOptionsUrl() != null) { if (poll.getShowOptionsUrl() != null) {
holder.hidePollResultsButton.setOnClickListener(v -> viewModel.loadUrl(poll.getShowOptionsUrl())); holder.hidePollResultsButton.setOnClickListener(v -> viewModel.loadUrl(poll.getShowOptionsUrl()));
holder.hidePollResultsButton.setVisibility(View.VISIBLE); holder.hidePollResultsButton.setVisibility(View.VISIBLE);
} else holder.hidePollResultsButton.setVisibility(View.GONE); }
else holder.hidePollResultsButton.setVisibility(View.GONE);
if (poll.getPollFormUrl() != null) { if (poll.getPollFormUrl() != null) {
holder.submitButton.setOnClickListener(v -> { holder.submitButton.setOnClickListener(v -> {
if (!viewModel.submitVote(holder.optionsLayout)) { if (!viewModel.submitVote(holder.optionsLayout)) {
@ -351,8 +362,10 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
} }
}); });
holder.submitButton.setVisibility(View.VISIBLE); holder.submitButton.setVisibility(View.VISIBLE);
} else holder.submitButton.setVisibility(View.GONE); }
} else { else holder.submitButton.setVisibility(View.GONE);
}
else {
Post currentPost = (Post) topicItems.get(position); Post currentPost = (Post) topicItems.get(position);
if (currentHolder instanceof PostViewHolder) { if (currentHolder instanceof PostViewHolder) {
final PostViewHolder holder = (PostViewHolder) currentHolder; final PostViewHolder holder = (PostViewHolder) currentHolder;
@ -382,7 +395,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
int filesTextColor; int filesTextColor;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 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 }
else
filesTextColor = context.getResources().getColor(R.color.accent); filesTextColor = context.getResources().getColor(R.color.accent);
for (final ThmmyFile attachedFile : currentPost.getAttachedFiles()) { for (final ThmmyFile attachedFile : currentPost.getAttachedFiles()) {
@ -405,7 +419,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
int lastEditTextColor; int lastEditTextColor;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 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 }
else
lastEditTextColor = context.getResources().getColor(R.color.white); lastEditTextColor = context.getResources().getColor(R.color.white);
final TextView lastEdit = new TextView(context); final TextView lastEdit = new TextView(context);
@ -415,7 +430,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
lastEdit.setPadding(0, 3, 0, 3); lastEdit.setPadding(0, 3, 0, 3);
holder.postFooter.addView(lastEdit); holder.postFooter.addView(lastEdit);
} }
} else { }
else {
holder.bodyFooterDivider.setVisibility(View.GONE); holder.bodyFooterDivider.setVisibility(View.GONE);
holder.postFooter.removeAllViews(); holder.postFooter.removeAllViews();
} }
@ -430,7 +446,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
mNumberOfPosts = currentPost.getNumberOfPosts(); mNumberOfPosts = currentPost.getNumberOfPosts();
mPersonalText = currentPost.getPersonalText(); mPersonalText = currentPost.getPersonalText();
mNumberOfStars = currentPost.getNumberOfStars(); mNumberOfStars = currentPost.getNumberOfStars();
} else { }
else {
mSpecialRank = null; mSpecialRank = null;
mRank = null; mRank = null;
mGender = null; mGender = null;
@ -443,27 +460,32 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (!Objects.equals(mSpecialRank, "") && mSpecialRank != null) { if (!Objects.equals(mSpecialRank, "") && mSpecialRank != null) {
holder.specialRank.setText(mSpecialRank); holder.specialRank.setText(mSpecialRank);
holder.specialRank.setVisibility(View.VISIBLE); holder.specialRank.setVisibility(View.VISIBLE);
} else }
else
holder.specialRank.setVisibility(View.GONE); holder.specialRank.setVisibility(View.GONE);
if (!Objects.equals(mRank, "") && mRank != null) { if (!Objects.equals(mRank, "") && mRank != null) {
holder.rank.setText(mRank); holder.rank.setText(mRank);
holder.rank.setVisibility(View.VISIBLE); holder.rank.setVisibility(View.VISIBLE);
} else }
else
holder.rank.setVisibility(View.GONE); holder.rank.setVisibility(View.GONE);
if (!Objects.equals(mGender, "") && mGender != null) { if (!Objects.equals(mGender, "") && mGender != null) {
holder.gender.setText(mGender); holder.gender.setText(mGender);
holder.gender.setVisibility(View.VISIBLE); holder.gender.setVisibility(View.VISIBLE);
} else }
else
holder.gender.setVisibility(View.GONE); holder.gender.setVisibility(View.GONE);
if (!Objects.equals(mNumberOfPosts, "") && mNumberOfPosts != null) { if (!Objects.equals(mNumberOfPosts, "") && mNumberOfPosts != null) {
holder.numberOfPosts.setText(mNumberOfPosts); holder.numberOfPosts.setText(mNumberOfPosts);
holder.numberOfPosts.setVisibility(View.VISIBLE); holder.numberOfPosts.setVisibility(View.VISIBLE);
} else }
else
holder.numberOfPosts.setVisibility(View.GONE); holder.numberOfPosts.setVisibility(View.GONE);
if (!Objects.equals(mPersonalText, "") && mPersonalText != null) { if (!Objects.equals(mPersonalText, "") && mPersonalText != null) {
holder.personalText.setText("\"" + mPersonalText + "\""); holder.personalText.setText("\"" + mPersonalText + "\"");
holder.personalText.setVisibility(View.VISIBLE); holder.personalText.setVisibility(View.VISIBLE);
} else }
else
holder.personalText.setVisibility(View.GONE); holder.personalText.setVisibility(View.GONE);
if (mUserColor != USER_COLOR_YELLOW) if (mUserColor != USER_COLOR_YELLOW)
holder.username.setTextColor(mUserColor); holder.username.setTextColor(mUserColor);
@ -482,25 +504,30 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
holder.stars.setText(usersStars.toString()); holder.stars.setText(usersStars.toString());
holder.stars.setTextColor(mUserColor); holder.stars.setTextColor(mUserColor);
holder.stars.setVisibility(View.VISIBLE); holder.stars.setVisibility(View.VISIBLE);
} else }
else
holder.stars.setVisibility(View.GONE); holder.stars.setVisibility(View.GONE);
if (currentPost.isUserMentionedInPost()) { if (currentPost.isUserMentionedInPost()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
holder.cardChildLinear.setBackground(context.getResources(). holder.cardChildLinear.setBackground(context.getResources().
getDrawable(R.drawable.mention_card, null)); getDrawable(R.drawable.mention_card, null));
} else }
else
holder.cardChildLinear.setBackground(context.getResources(). holder.cardChildLinear.setBackground(context.getResources().
getDrawable(R.drawable.mention_card)); getDrawable(R.drawable.mention_card));
} else if (mUserColor == TopicParser.USER_COLOR_PINK) { }
else if (mUserColor == TopicParser.USER_COLOR_PINK) {
//Special card for special member of the month! //Special card for special member of the month!
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
holder.cardChildLinear.setBackground(context.getResources(). holder.cardChildLinear.setBackground(context.getResources().
getDrawable(R.drawable.member_of_the_month_card, null)); getDrawable(R.drawable.member_of_the_month_card, null));
} else }
else
holder.cardChildLinear.setBackground(context.getResources(). holder.cardChildLinear.setBackground(context.getResources().
getDrawable(R.drawable.member_of_the_month_card)); getDrawable(R.drawable.member_of_the_month_card));
} else holder.cardChildLinear.setBackground(null); }
else holder.cardChildLinear.setBackground(null);
//Avoid's view's visibility recycling //Avoid's view's visibility recycling
if (!currentPost.isDeleted() && viewModel.isUserExtraInfoVisible(holder.getAdapterPosition())) { if (!currentPost.isDeleted() && viewModel.isUserExtraInfoVisible(holder.getAdapterPosition())) {
@ -513,7 +540,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
holder.subject.setTextColor(Color.parseColor("#FFFFFF")); holder.subject.setTextColor(Color.parseColor("#FFFFFF"));
holder.subject.setMaxLines(Integer.MAX_VALUE); holder.subject.setMaxLines(Integer.MAX_VALUE);
holder.subject.setEllipsize(null); holder.subject.setEllipsize(null);
} else { }
else {
holder.userExtraInfo.setVisibility(View.GONE); holder.userExtraInfo.setVisibility(View.GONE);
holder.userExtraInfo.setAlpha(0.0f); holder.userExtraInfo.setAlpha(0.0f);
@ -554,7 +582,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
holder.subject, Color.parseColor("#FFFFFF"), holder.subject, Color.parseColor("#FFFFFF"),
Color.parseColor("#757575"), (LinearLayout) v); Color.parseColor("#757575"), (LinearLayout) v);
}); });
} else { }
else {
holder.header.setOnClickListener(null); holder.header.setOnClickListener(null);
holder.userExtraInfo.setOnClickListener(null); holder.userExtraInfo.setOnClickListener(null);
} }
@ -636,7 +665,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_unchecked_24dp); holder.quoteToggle.setImageResource(R.drawable.ic_format_quote_unchecked_24dp);
}); });
} }
} else if (currentHolder instanceof QuickReplyViewHolder) { }
else if (currentHolder instanceof QuickReplyViewHolder) {
final QuickReplyViewHolder holder = (QuickReplyViewHolder) currentHolder; final QuickReplyViewHolder holder = (QuickReplyViewHolder) currentHolder;
Post reply = (Post) topicItems.get(position); Post reply = (Post) topicItems.get(position);
@ -647,7 +677,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
holder.itemView.setEnabled(true); holder.itemView.setEnabled(true);
if (reply.getSubject() != null) { if (reply.getSubject() != null) {
holder.quickReplySubject.setText(reply.getSubject()); holder.quickReplySubject.setText(reply.getSubject());
} else { }
else {
holder.quickReplySubject.setText("Re: " + viewModel.getTopicTitle().getValue()); holder.quickReplySubject.setText("Re: " + viewModel.getTopicTitle().getValue());
} }
holder.quickReplySubject.setRawInputType(InputType.TYPE_CLASS_TEXT); holder.quickReplySubject.setRawInputType(InputType.TYPE_CLASS_TEXT);
@ -700,10 +731,11 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
backPressHidden = false; backPressHidden = false;
} }
holder.quickReplySubject.addTextChangedListener(createTextWatcher(holder, TextWatcherType.SUBJECT)); holder.quickReplySubject.addTextChangedListener(createTextWatcher(holder, TextWatcherType.SUBJECT));
} else if (currentHolder instanceof EditMessageViewHolder) { }
else if (currentHolder instanceof EditMessageViewHolder) {
final EditMessageViewHolder holder = (EditMessageViewHolder) currentHolder; final EditMessageViewHolder holder = (EditMessageViewHolder) currentHolder;
loadAvatar(getSessionManager().getAvatarLink(), holder.thumbnail, holder.itemView.getContext()); loadAvatar(getSessionManager().getAvatarLink(), holder.thumbnail, holder.itemView.getContext());
holder.username.setText(getSessionManager().getUsername()); holder.username.setText(getSessionManager().getUsername());
holder.editSubject.setText(currentPost.getSubject()); holder.editSubject.setText(currentPost.getSubject());
@ -749,33 +781,36 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private enum TextWatcherType { private enum TextWatcherType {
CONTENT, SUBJECT CONTENT, SUBJECT
} }
private TextWatcher createTextWatcher(@NonNull final RecyclerView.ViewHolder holder, TextWatcherType type){
private TextWatcher createTextWatcher(@NonNull final RecyclerView.ViewHolder holder, TextWatcherType type) {
return new TextWatcher() { return new TextWatcher() {
@Override @Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) { } public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override @Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) { public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
int position = holder.getAdapterPosition(); int position = holder.getAdapterPosition();
if (position >= 0 && position < topicItems.size()){ if (position >= 0 && position < topicItems.size()) {
Post post = ((Post) topicItems.get(position)); Post post = ((Post) topicItems.get(position));
if(type == TextWatcherType.CONTENT) if (type == TextWatcherType.CONTENT)
post.setBbContent(charSequence.toString()); post.setBbContent(charSequence.toString());
else if(type == TextWatcherType.SUBJECT) else if (type == TextWatcherType.SUBJECT)
post.setSubject(charSequence.toString()); post.setSubject(charSequence.toString());
} }
} }
@Override @Override
public void afterTextChanged(Editable editable) { } public void afterTextChanged(Editable editable) {
}
}; };
} }
private void loadAvatar(String imageUrl, ImageView imageView, Context context) { private void loadAvatar(String imageUrl, ImageView imageView, Context context) {
if(imageUrl!=null) if (imageUrl != null)
imageUrl = imageUrl.trim(); imageUrl = imageUrl.trim();
if(isValidContextForGlide(context)) { if (isValidContextForGlide(context)) {
Glide.with(context) Glide.with(context)
.load(imageUrl) .load(imageUrl)
.circleCrop() .circleCrop()
@ -948,7 +983,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
return true; return true;
} }
} }
} else if ((Objects.equals(uriString, ParseHelpers.getBaseURL(viewModel.getTopicUrl())) && }
else if ((Objects.equals(uriString, ParseHelpers.getBaseURL(viewModel.getTopicUrl())) &&
viewModel.getCurrentPageIndex() == 1) || viewModel.getCurrentPageIndex() == 1) ||
Integer.parseInt(uriString.substring(ParseHelpers.getBaseURL(viewModel.getTopicUrl()).length() + 1)) / 15 + 1 == Integer.parseInt(uriString.substring(ParseHelpers.getBaseURL(viewModel.getTopicUrl()).length() + 1)) / 15 + 1 ==
viewModel.getCurrentPageIndex()) { viewModel.getCurrentPageIndex()) {
@ -964,7 +1000,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent); context.startActivity(intent);
return true; return true;
} else if (target.is(ThmmyPage.PageCategory.BOARD)) { }
else if (target.is(ThmmyPage.PageCategory.BOARD)) {
Intent intent = new Intent(context, BoardActivity.class); Intent intent = new Intent(context, BoardActivity.class);
Bundle extras = new Bundle(); Bundle extras = new Bundle();
extras.putString(BUNDLE_BOARD_URL, uriString); extras.putString(BUNDLE_BOARD_URL, uriString);
@ -973,7 +1010,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent); context.startActivity(intent);
return true; return true;
} else if (target.is(ThmmyPage.PageCategory.PROFILE)) { }
else if (target.is(ThmmyPage.PageCategory.PROFILE)) {
Intent intent = new Intent(context, ProfileActivity.class); Intent intent = new Intent(context, ProfileActivity.class);
Bundle extras = new Bundle(); Bundle extras = new Bundle();
extras.putString(BUNDLE_PROFILE_URL, uriString); extras.putString(BUNDLE_PROFILE_URL, uriString);

41
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java

@ -37,7 +37,7 @@ import timber.log.Timber;
public class TopicParser { public class TopicParser {
private static Pattern mentionsPattern = Pattern. private static Pattern mentionsPattern = Pattern.
compile("<div class=\"quoteheader\">\\n\\s+?<a href=.+?>(Quote from|Παράθεση από): " compile("<div class=\"quoteheader\">\\n\\s+?<a href=.+?>(Quote from|Παράθεση από): "
+ BaseActivity.getSessionManager().getUsername() +"\\s(στις|on)"); + BaseActivity.getSessionManager().getUsername() + "\\s(στις|on)");
//User colors //User colors
private static final int USER_COLOR_BLACK = Color.parseColor("#000000"); private static final int USER_COLOR_BLACK = Color.parseColor("#000000");
@ -87,7 +87,8 @@ public class TopicParser {
break; break;
} }
} }
} else { }
else {
Elements findCurrentPage = topic.select("td:contains(Pages:)>b"); Elements findCurrentPage = topic.select("td:contains(Pages:)>b");
for (Element item : findCurrentPage) { for (Element item : findCurrentPage) {
@ -125,7 +126,8 @@ public class TopicParser {
returnPages = Integer.parseInt(item.text()); returnPages = Integer.parseInt(item.text());
} }
} }
} else { }
else {
Elements pages = topic.select("td:contains(Pages:)>a.navPages"); Elements pages = topic.select("td:contains(Pages:)>a.navPages");
if (pages.size() != 0) { if (pages.size() != 0) {
@ -220,7 +222,8 @@ public class TopicParser {
if (postIndex != null) { if (postIndex != null) {
String tmp = postIndex.attr("name"); String tmp = postIndex.attr("name");
p_postIndex = Integer.parseInt(tmp.substring(tmp.indexOf("msg") + 3)); p_postIndex = Integer.parseInt(tmp.substring(tmp.indexOf("msg") + 3));
} else { }
else {
postIndex = thisRow.select("div[id^=subject]").first(); postIndex = thisRow.select("div[id^=subject]").first();
if (postIndex == null) if (postIndex == null)
p_postIndex = NO_INDEX; p_postIndex = NO_INDEX;
@ -246,7 +249,8 @@ public class TopicParser {
.first().text(); .first().text();
p_userName = p_userName.substring(0, p_userName.indexOf(" Επισκέπτης")); p_userName = p_userName.substring(0, p_userName.indexOf(" Επισκέπτης"));
p_userColor = USER_COLOR_YELLOW; p_userColor = USER_COLOR_YELLOW;
} else { }
else {
p_userName = userName.html(); p_userName = userName.html();
p_profileURL = userName.attr("href"); p_profileURL = userName.attr("href");
} }
@ -271,7 +275,8 @@ public class TopicParser {
Element postNum = thisRow.select("div.smalltext:matches(Απάντηση #)").first(); Element postNum = thisRow.select("div.smalltext:matches(Απάντηση #)").first();
if (postNum == null) { //Topic starter if (postNum == null) { //Topic starter
p_postNum = 0; p_postNum = 0;
} else { }
else {
String tmp_str = postNum.text().substring(12); String tmp_str = postNum.text().substring(12);
p_postNum = Integer.parseInt(tmp_str.substring(0, tmp_str.indexOf(" στις"))); p_postNum = Integer.parseInt(tmp_str.substring(0, tmp_str.indexOf(" στις")));
} }
@ -306,7 +311,8 @@ public class TopicParser {
p_attachedFiles.add(new ThmmyFile(attachedUrl, attachedFileName, attachedFileInfo)); p_attachedFiles.add(new ThmmyFile(attachedUrl, attachedFileName, attachedFileInfo));
} }
} }
} else { }
else {
//Finds username //Finds username
userName = thisRow.select("a[title^=View the profile of]").first(); userName = thisRow.select("a[title^=View the profile of]").first();
if (userName == null) { //Deleted profile if (userName == null) { //Deleted profile
@ -316,7 +322,8 @@ public class TopicParser {
.first().text(); .first().text();
p_userName = p_userName.substring(0, p_userName.indexOf(" Guest")); p_userName = p_userName.substring(0, p_userName.indexOf(" Guest"));
p_userColor = USER_COLOR_YELLOW; p_userColor = USER_COLOR_YELLOW;
} else { }
else {
p_userName = userName.html(); p_userName = userName.html();
p_profileURL = userName.attr("href"); p_profileURL = userName.attr("href");
} }
@ -343,7 +350,8 @@ public class TopicParser {
Element postNum = thisRow.select("div.smalltext:matches(Reply #)").first(); Element postNum = thisRow.select("div.smalltext:matches(Reply #)").first();
if (postNum == null) { //Topic starter if (postNum == null) { //Topic starter
p_postNum = 0; p_postNum = 0;
} else { }
else {
String tmp_str = postNum.text().substring(9); String tmp_str = postNum.text().substring(9);
p_postNum = Integer.parseInt(tmp_str.substring(0, tmp_str.indexOf(" on"))); p_postNum = Integer.parseInt(tmp_str.substring(0, tmp_str.indexOf(" on")));
} }
@ -409,7 +417,8 @@ public class TopicParser {
.attr("abs:src")); .attr("abs:src"));
} }
} }
} else { }
else {
for (String line : infoList) { for (String line : infoList) {
if (line.contains("Posts:")) { if (line.contains("Posts:")) {
postsLineIndex = infoList.indexOf(line); postsLineIndex = infoList.indexOf(line);
@ -437,7 +446,8 @@ public class TopicParser {
if (starsLineIndex == -1 || starsLineIndex == 1) { if (starsLineIndex == -1 || starsLineIndex == 1) {
p_rank = infoList.get(0).trim(); //First line has the rank p_rank = infoList.get(0).trim(); //First line has the rank
p_specialRank = null; //They don't have a special rank p_specialRank = null; //They don't have a special rank
} else if (starsLineIndex == 2) { //This member has a special rank }
else if (starsLineIndex == 2) { //This member has a special rank
p_specialRank = infoList.get(0).trim(); //First line has the special rank p_specialRank = infoList.get(0).trim(); //First line has the special rank
p_rank = infoList.get(1).trim(); //Second line has the rank p_rank = infoList.get(1).trim(); //Second line has the rank
} }
@ -467,7 +477,8 @@ public class TopicParser {
, p_attachedFiles, p_postLastEditDate, p_postURL, p_deletePostURL, p_editPostURL , p_attachedFiles, p_postLastEditDate, p_postURL, p_deletePostURL, p_editPostURL
, p_isUserMentionedInPost, Post.TYPE_POST)); , p_isUserMentionedInPost, Post.TYPE_POST));
} else { //Deleted user }
else { //Deleted user
//Add new post in postsList, only standard information needed //Add new post in postsList, only standard information needed
parsedPostsList.add(new Post(p_thumbnailURL, p_userName, p_subject, p_post parsedPostsList.add(new Post(p_thumbnailURL, p_userName, p_subject, p_post
, null, p_postIndex, p_postNum, p_postDate, p_userColor, p_attachedFiles , null, p_postIndex, p_postNum, p_postDate, p_userColor, p_attachedFiles
@ -516,7 +527,8 @@ public class TopicParser {
availableVoteCount = Integer.parseInt(prompt.substring(integerMatcher.start(), integerMatcher.end())); availableVoteCount = Integer.parseInt(prompt.substring(integerMatcher.start(), integerMatcher.end()));
} }
links = formTableRows.get(1).child(1).select("a"); links = formTableRows.get(1).child(1).select("a");
} else { }
else {
availableVoteCount = 1; availableVoteCount = 1;
links = formTableRows.first().child(1).select("a"); links = formTableRows.first().child(1).select("a");
} }
@ -524,7 +536,8 @@ public class TopicParser {
if (links != null && links.size() > 0) { if (links != null && links.size() > 0) {
showVoteResultsUrl = links.first().attr("href"); showVoteResultsUrl = links.first().attr("href");
} }
} else { }
else {
// poll in results mode // poll in results mode
Elements entryRows = pollColumn.select("table[cellspacing] tr"); Elements entryRows = pollColumn.select("table[cellspacing] tr");
for (int i = 0; i < entryRows.size(); i++) { for (int i = 0; i < entryRows.size(); i++) {

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

@ -74,6 +74,7 @@ public class EditTask extends AsyncTask<String, Void, Boolean> {
public interface EditTaskCallbacks { public interface EditTaskCallbacks {
void onEditTaskStarted(); void onEditTaskStarted();
void onEditTaskFinished(boolean result, int position); void onEditTaskFinished(boolean result, int position);
} }
} }

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

@ -74,6 +74,7 @@ public class PrepareForEditTask extends AsyncTask<String, Void, PrepareForEditRe
public interface PrepareForEditCallbacks { public interface PrepareForEditCallbacks {
void onPrepareEditStarted(); void onPrepareEditStarted();
void onPrepareEditCancelled(); void onPrepareEditCancelled();
} }

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

@ -53,7 +53,7 @@ public class PrepareForReplyTask extends AsyncTask<Integer, Void, PrepareForRepl
// 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, "Prepare failed (1)");
return new PrepareForReplyResult(false, null, null, null, null, null); return new PrepareForReplyResult(false, null, null, null, null, null);
} catch (IOException | Selector.SelectorParseException e){ } catch (IOException | Selector.SelectorParseException e) {
Timber.e(e, "Prepare failed (2)"); Timber.e(e, "Prepare failed (2)");
return new PrepareForReplyResult(false, null, null, null, null, null); return new PrepareForReplyResult(false, null, null, null, null, null);
} }
@ -62,7 +62,7 @@ public class PrepareForReplyTask extends AsyncTask<Integer, Void, PrepareForRepl
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("https://www.thmmy.gr/smf/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();
@ -85,6 +85,7 @@ public class PrepareForReplyTask extends AsyncTask<Integer, Void, PrepareForRepl
public interface PrepareForReplyCallbacks { public interface PrepareForReplyCallbacks {
void onPrepareForReplyStarted(); void onPrepareForReplyStarted();
void onPrepareForReplyCancelled(); void onPrepareForReplyCancelled();
} }

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

@ -68,6 +68,7 @@ public class ReplyTask extends AsyncTask<String, Void, Posting.REPLY_STATUS> {
public interface ReplyTaskCallbacks { public interface ReplyTaskCallbacks {
void onReplyTaskStarted(); void onReplyTaskStarted();
void onReplyTaskFinished(Posting.REPLY_STATUS result); void onReplyTaskFinished(Posting.REPLY_STATUS result);
} }
} }

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

@ -123,7 +123,8 @@ public class TopicTask extends AsyncTask<String, Void, TopicTaskResult> {
if (isUnauthorized(topic)) { if (isUnauthorized(topic)) {
return new TopicTaskResult(ResultCode.UNAUTHORIZED, null, null, null, return new TopicTaskResult(ResultCode.UNAUTHORIZED, null, null, null,
0, 0, 0, 0, null, null); 0, 0, 0, 0, null, null);
} else { }
else {
Timber.e(e, "Topic parse failed"); Timber.e(e, "Topic parse failed");
return new TopicTaskResult(ResultCode.PARSING_ERROR, null, null, null, return new TopicTaskResult(ResultCode.PARSING_ERROR, null, null, null,
0, 0, 0, 0, null, null); 0, 0, 0, 0, null, null);
@ -149,6 +150,7 @@ public class TopicTask extends AsyncTask<String, Void, TopicTaskResult> {
public interface TopicTaskObserver { public interface TopicTaskObserver {
void onTopicTaskStarted(); void onTopicTaskStarted();
void onTopicTaskCancelled(); void onTopicTaskCancelled();
} }

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

@ -177,7 +177,7 @@ public class UploadActivity extends BaseActivity {
generateFieldsButton = findViewById(R.id.upload_title_description_builder); generateFieldsButton = findViewById(R.id.upload_title_description_builder);
generateFieldsButton.setEnabled(false); generateFieldsButton.setEnabled(false);
generateFieldsButton.setOnClickListener(view -> { generateFieldsButton.setOnClickListener(view -> {
if(uploadsCourse!=null && !uploadsCourse.getName().equals("") && !semester.equals("")){ if (uploadsCourse != null && !uploadsCourse.getName().equals("") && !semester.equals("")) {
Intent intent = new Intent(UploadActivity.this, UploadFieldsBuilderActivity.class); Intent intent = new Intent(UploadActivity.this, UploadFieldsBuilderActivity.class);
Bundle builderExtras = new Bundle(); Bundle builderExtras = new Bundle();
builderExtras.putString(BUNDLE_UPLOAD_FIELD_BUILDER_COURSE_NAME, uploadsCourse.getName()); builderExtras.putString(BUNDLE_UPLOAD_FIELD_BUILDER_COURSE_NAME, uploadsCourse.getName());
@ -329,7 +329,8 @@ public class UploadActivity extends BaseActivity {
tempFileUri = UploadsHelper.createTempFile(this, storage, tempFileUri = UploadsHelper.createTempFile(this, storage,
uploadFile.getFileUri(), uploadFile.getFileUri(),
FileUtils.getFilenameWithoutExtension(editTextFilename)); FileUtils.getFilenameWithoutExtension(editTextFilename));
} else { }
else {
//Renames the photo taken //Renames the photo taken
String photoPath = uploadFile.getPhotoFile().getPath(); String photoPath = uploadFile.getPhotoFile().getPath();
photoPath = photoPath.substring(0, photoPath.lastIndexOf(File.separator)); photoPath = photoPath.substring(0, photoPath.lastIndexOf(File.separator));
@ -348,14 +349,16 @@ public class UploadActivity extends BaseActivity {
uploadFile.setFileUri(FileProvider.getUriForFile(this, getPackageName() + uploadFile.setFileUri(FileProvider.getUriForFile(this, getPackageName() +
".provider", uploadFile.getPhotoFile())); ".provider", uploadFile.getPhotoFile()));
} }
} else { }
else {
requestPerms(UPLOAD_REQUEST_STORAGE_CODE); requestPerms(UPLOAD_REQUEST_STORAGE_CODE);
zipTask = null; zipTask = null;
dialog.cancel(); dialog.cancel();
return; return;
} }
} }
} else { }
else {
Uri[] filesListArray = new Uri[filesList.size()]; Uri[] filesListArray = new Uri[filesList.size()];
for (int i = 0; i < filesList.size(); ++i) { for (int i = 0; i < filesList.size(); ++i) {
filesListArray[i] = filesList.get(i).getFileUri(); filesListArray[i] = filesList.get(i).getFileUri();
@ -368,7 +371,8 @@ public class UploadActivity extends BaseActivity {
if (checkPerms()) { if (checkPerms()) {
zipTask.execute(filesListArray); zipTask.execute(filesListArray);
finish(); finish();
} else { }
else {
requestPerms(UPLOAD_REQUEST_STORAGE_CODE); requestPerms(UPLOAD_REQUEST_STORAGE_CODE);
dialog.cancel(); dialog.cancel();
} }
@ -384,7 +388,8 @@ public class UploadActivity extends BaseActivity {
? filesList.get(0).getFileUri() ? filesList.get(0).getFileUri()
: tempFileUri)) { : tempFileUri)) {
finish(); finish();
} else { }
else {
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Couldn't initiate upload.", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Couldn't initiate upload.", Toast.LENGTH_SHORT).show();
} }
}); });
@ -406,7 +411,8 @@ public class UploadActivity extends BaseActivity {
//Parses the uploads page //Parses the uploads page
parseUploadPageTask = new ParseUploadPageTask(); parseUploadPageTask = new ParseUploadPageTask();
parseUploadPageTask.execute(uploadIndexUrl); parseUploadPageTask.execute(uploadIndexUrl);
} else { }
else {
//Renders the already parsed data //Renders the already parsed data
updateUIElements(); updateUIElements();
generateFieldsButton.setEnabled(true); generateFieldsButton.setEnabled(true);
@ -465,7 +471,8 @@ public class UploadActivity extends BaseActivity {
addFileViewToList(filename); addFileViewToList(filename);
filesList.add(new UploadFile(false, newFileUri, null)); filesList.add(new UploadFile(false, newFileUri, null));
} }
} else { }
else {
Uri newFileUri = data.getData(); Uri newFileUri = data.getData();
if (newFileUri != null) { if (newFileUri != null) {
String filename = FileUtils.filenameFromUri(this, newFileUri); String filename = FileUtils.filenameFromUri(this, newFileUri);
@ -481,23 +488,30 @@ public class UploadActivity extends BaseActivity {
filename = filename.toLowerCase(); filename = filename.toLowerCase();
if (filename.endsWith(".jpg")) { if (filename.endsWith(".jpg")) {
fileIcon = "jpg_image.gif"; fileIcon = "jpg_image.gif";
} else if (filename.endsWith(".gif")) { }
else if (filename.endsWith(".gif")) {
fileIcon = "gif_image.gif"; fileIcon = "gif_image.gif";
} else if (filename.endsWith(".png")) { }
else if (filename.endsWith(".png")) {
fileIcon = "png_image.gif"; fileIcon = "png_image.gif";
} else if (filename.endsWith(".html") || filename.endsWith(".htm")) { }
else if (filename.endsWith(".html") || filename.endsWith(".htm")) {
fileIcon = "html_file.gif"; fileIcon = "html_file.gif";
} else if (filename.endsWith(".pdf") || filename.endsWith(".doc") || }
else if (filename.endsWith(".pdf") || filename.endsWith(".doc") ||
filename.endsWith("djvu")) { filename.endsWith("djvu")) {
fileIcon = "text_file.gif"; fileIcon = "text_file.gif";
} else if (filename.endsWith(".zip") || filename.endsWith(".rar") || }
else if (filename.endsWith(".zip") || filename.endsWith(".rar") ||
filename.endsWith(".tar") || filename.endsWith(".tar.gz") || filename.endsWith(".tar") || filename.endsWith(".tar.gz") ||
filename.endsWith(".gz")) { filename.endsWith(".gz")) {
fileIcon = "archive.gif"; fileIcon = "archive.gif";
} else { }
else {
fileIcon = "blank.gif"; fileIcon = "blank.gif";
} }
} else { }
else {
fileIcon = "archive.gif"; fileIcon = "archive.gif";
textWatcher.setFileExtension(".zip"); textWatcher.setFileExtension(".zip");
@ -509,7 +523,8 @@ public class UploadActivity extends BaseActivity {
filesList.add(new UploadFile(false, newFileUri, null)); filesList.add(new UploadFile(false, newFileUri, null));
} }
} }
} else if (requestCode == AFR_REQUEST_CODE_CAMERA) { }
else if (requestCode == AFR_REQUEST_CODE_CAMERA) {
if (resultCode == Activity.RESULT_CANCELED) { if (resultCode == Activity.RESULT_CANCELED) {
//Deletes image file //Deletes image file
storage.deleteFile(photoFileCreated.getAbsolutePath()); storage.deleteFile(photoFileCreated.getAbsolutePath());
@ -525,7 +540,8 @@ public class UploadActivity extends BaseActivity {
} }
fileIcon = "jpg_image.gif"; fileIcon = "jpg_image.gif";
} else { }
else {
fileIcon = "archive.gif"; fileIcon = "archive.gif";
textWatcher.setFileExtension(".zip"); textWatcher.setFileExtension(".zip");
@ -538,7 +554,8 @@ public class UploadActivity extends BaseActivity {
addFileViewToList(FileUtils.getFilenameWithoutExtension(FileUtils. addFileViewToList(FileUtils.getFilenameWithoutExtension(FileUtils.
filenameFromUri(this, newFile.getFileUri()))); filenameFromUri(this, newFile.getFileUri())));
filesList.add(newFile); filesList.add(newFile);
} else if (requestCode == AFR_REQUEST_CODE_FIELDS_BUILDER) { }
else if (requestCode == AFR_REQUEST_CODE_FIELDS_BUILDER) {
if (resultCode == Activity.RESULT_CANCELED) { if (resultCode == Activity.RESULT_CANCELED) {
return; return;
} }
@ -546,7 +563,8 @@ public class UploadActivity extends BaseActivity {
String previousName = uploadFilename.getText().toString(); String previousName = uploadFilename.getText().toString();
if (previousName.isEmpty()) { if (previousName.isEmpty()) {
uploadFilename.setText(data.getStringExtra(RESULT_FILENAME)); uploadFilename.setText(data.getStringExtra(RESULT_FILENAME));
} else { }
else {
String extractedExtension = FileUtils.getFileExtension(previousName); String extractedExtension = FileUtils.getFileExtension(previousName);
String filenameWithExtension = data.getStringExtra(RESULT_FILENAME) + String filenameWithExtension = data.getStringExtra(RESULT_FILENAME) +
(extractedExtension != null ? extractedExtension : ""); (extractedExtension != null ? extractedExtension : "");
@ -556,7 +574,8 @@ public class UploadActivity extends BaseActivity {
uploadTitle.setText(data.getStringExtra(RESULT_TITLE)); uploadTitle.setText(data.getStringExtra(RESULT_TITLE));
uploadDescription.setText(data.getStringExtra(RESULT_DESCRIPTION)); uploadDescription.setText(data.getStringExtra(RESULT_DESCRIPTION));
} else { }
else {
super.onActivityResult(requestCode, resultCode, data); super.onActivityResult(requestCode, resultCode, data);
} }
} }
@ -579,14 +598,15 @@ public class UploadActivity extends BaseActivity {
zipTask.execute(filesListArray); zipTask.execute(filesListArray);
finish(); finish();
} else { }
else {
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Please retry uploading.", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Please retry uploading.", Toast.LENGTH_SHORT).show();
} }
break; break;
} }
} }
private void setZipUploadFilename(){ private void setZipUploadFilename() {
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.FRANCE).format(new Date()); String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.FRANCE).format(new Date());
String zipFilename = "mTHMMY_" + timeStamp + ".zip"; String zipFilename = "mTHMMY_" + timeStamp + ".zip";
uploadFilename.setText(zipFilename); uploadFilename.setText(zipFilename);
@ -656,7 +676,8 @@ public class UploadActivity extends BaseActivity {
filesList.remove(fileIndex); filesList.remove(fileIndex);
if (filesList.isEmpty()) { if (filesList.isEmpty()) {
filesListView.setVisibility(View.GONE); filesListView.setVisibility(View.GONE);
} else if (filesList.size() == 1) { }
else if (filesList.size() == 1) {
textWatcher.setFileExtension(FileUtils.getFileExtension(FileUtils. textWatcher.setFileExtension(FileUtils.getFileExtension(FileUtils.
filenameFromUri(this, filesList.get(0).getFileUri()))); filenameFromUri(this, filesList.get(0).getFileUri())));
} }
@ -667,7 +688,7 @@ public class UploadActivity extends BaseActivity {
} }
public UploadNotificationConfig getConfigForUpload(Context context, String uploadID, public UploadNotificationConfig getConfigForUpload(Context context, String uploadID,
String filename) { String filename) {
UploadNotificationConfig uploadNotificationConfig = new UploadNotificationConfig(); UploadNotificationConfig uploadNotificationConfig = new UploadNotificationConfig();
uploadNotificationConfig.setIconForAllStatuses(android.R.drawable.stat_sys_upload); uploadNotificationConfig.setIconForAllStatuses(android.R.drawable.stat_sys_upload);
uploadNotificationConfig.setTitleForAllStatuses("Uploading " + filename); uploadNotificationConfig.setTitleForAllStatuses("Uploading " + filename);
@ -764,7 +785,8 @@ public class UploadActivity extends BaseActivity {
} }
@Override @Override
public void onTextChanged(CharSequence s, int start, int before, int count) { } public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
@ -773,7 +795,8 @@ public class UploadActivity extends BaseActivity {
if (filenameWithoutExtension != null && !filenameWithoutExtension.isEmpty() && if (filenameWithoutExtension != null && !filenameWithoutExtension.isEmpty() &&
!filenameWithoutExtension.matches("[0-9a-zA-Z~!@#$%^&()_+=\\-`\\[\\]{};',.]+")) { !filenameWithoutExtension.matches("[0-9a-zA-Z~!@#$%^&()_+=\\-`\\[\\]{};',.]+")) {
uploadFilenameInfo.setImageResource(R.drawable.ic_info_outline_warning_24dp); uploadFilenameInfo.setImageResource(R.drawable.ic_info_outline_warning_24dp);
} else { }
else {
uploadFilenameInfo.setImageResource(R.drawable.ic_info_outline_white_24dp); uploadFilenameInfo.setImageResource(R.drawable.ic_info_outline_white_24dp);
} }
@ -811,7 +834,8 @@ public class UploadActivity extends BaseActivity {
if (!oldFilename.isEmpty()) { if (!oldFilename.isEmpty()) {
newFilename = FileUtils.getFilenameWithoutExtension(oldFilename) + extension; newFilename = FileUtils.getFilenameWithoutExtension(oldFilename) + extension;
} else { }
else {
newFilename = extension; newFilename = extension;
} }
@ -888,9 +912,10 @@ public class UploadActivity extends BaseActivity {
} }
@Override @Override
public void onNothingSelected(AdapterView<?> parent) { } public void onNothingSelected(AdapterView<?> parent) {
}
private void setCourseAndSemester(){ private void setCourseAndSemester() {
uploadsCourse = null; uploadsCourse = null;
semester = ""; semester = "";
if (categorySelected.equals("-1")) return; if (categorySelected.equals("-1")) return;
@ -910,12 +935,14 @@ public class UploadActivity extends BaseActivity {
categoriesSpinners.getChildAt(numberOfSpinners - 2)).getSelectedItem(); categoriesSpinners.getChildAt(numberOfSpinners - 2)).getSelectedItem();
} }
else return; else return;
} else if (numberOfSpinners == 4) { }
else if (numberOfSpinners == 4) {
maybeSemester = (String) ((AppCompatSpinnerWithoutDefault) maybeSemester = (String) ((AppCompatSpinnerWithoutDefault)
categoriesSpinners.getChildAt(numberOfSpinners - 3)).getSelectedItem(); categoriesSpinners.getChildAt(numberOfSpinners - 3)).getSelectedItem();
maybeCourse = (String) ((AppCompatSpinnerWithoutDefault) maybeCourse = (String) ((AppCompatSpinnerWithoutDefault)
categoriesSpinners.getChildAt(numberOfSpinners - 1)).getSelectedItem(); categoriesSpinners.getChildAt(numberOfSpinners - 1)).getSelectedItem();
} else { }
else {
maybeSemester = (String) ((AppCompatSpinnerWithoutDefault) maybeSemester = (String) ((AppCompatSpinnerWithoutDefault)
categoriesSpinners.getChildAt(numberOfSpinners - 2)).getSelectedItem(); categoriesSpinners.getChildAt(numberOfSpinners - 2)).getSelectedItem();
maybeCourse = (String) ((AppCompatSpinnerWithoutDefault) maybeCourse = (String) ((AppCompatSpinnerWithoutDefault)
@ -926,14 +953,14 @@ public class UploadActivity extends BaseActivity {
if (maybeCourse == null) return; if (maybeCourse == null) return;
String retrievedCourse = maybeCourse.replaceAll("-", "") String retrievedCourse = maybeCourse.replaceAll("-", "")
.replaceAll("\\((πρώην|πρωην).*\\)","") .replaceAll("\\((πρώην|πρωην).*\\)", "")
.replace("(ΝΠΣ)", "") .replace("(ΝΠΣ)", "")
.trim(); .trim();
if(!retrievedCourse.isEmpty()){ if (!retrievedCourse.isEmpty()) {
UploadsCourse foundUploadsCourse = UploadsCourse.findCourse(retrievedCourse, uploadsCourses); UploadsCourse foundUploadsCourse = UploadsCourse.findCourse(retrievedCourse, uploadsCourses);
if(foundUploadsCourse != null){ if (foundUploadsCourse != null) {
uploadsCourse = foundUploadsCourse; uploadsCourse = foundUploadsCourse;
semester = maybeSemester.replaceAll("-", "").trim().substring(0, 1); semester = maybeSemester.replaceAll("-", "").trim().substring(0, 1);
Timber.d("Selected course: %s, semester: %s", uploadsCourse.getName(), semester); Timber.d("Selected course: %s, semester: %s", uploadsCourse.getName(), semester);
@ -974,25 +1001,29 @@ public class UploadActivity extends BaseActivity {
if (categoryText.startsWith("- ")) { if (categoryText.startsWith("- ")) {
//This is a level one subcategory //This is a level one subcategory
uploadRootCategories.get(uploadRootCategories.size() - 1).addSubCategory(categoryValue, categoryText); uploadRootCategories.get(uploadRootCategories.size() - 1).addSubCategory(categoryValue, categoryText);
} else if (categoryText.startsWith("-- ")) { }
else if (categoryText.startsWith("-- ")) {
//This is a level two subcategory //This is a level two subcategory
UploadCategory rootLevelCategory = uploadRootCategories.get(uploadRootCategories.size() - 1); UploadCategory rootLevelCategory = uploadRootCategories.get(uploadRootCategories.size() - 1);
UploadCategory firstLevelCategory = rootLevelCategory.getSubCategories().get(rootLevelCategory.getSubCategories().size() - 1); UploadCategory firstLevelCategory = rootLevelCategory.getSubCategories().get(rootLevelCategory.getSubCategories().size() - 1);
firstLevelCategory.addSubCategory(categoryValue, categoryText); firstLevelCategory.addSubCategory(categoryValue, categoryText);
} else if (categoryText.startsWith("--- ")) { }
else if (categoryText.startsWith("--- ")) {
//This is a level three subcategory //This is a level three subcategory
UploadCategory rootLevelCategory = uploadRootCategories.get(uploadRootCategories.size() - 1); UploadCategory rootLevelCategory = uploadRootCategories.get(uploadRootCategories.size() - 1);
UploadCategory firstLevelCategory = rootLevelCategory.getSubCategories().get(rootLevelCategory.getSubCategories().size() - 1); UploadCategory firstLevelCategory = rootLevelCategory.getSubCategories().get(rootLevelCategory.getSubCategories().size() - 1);
UploadCategory secondLevelCategory = firstLevelCategory.getSubCategories().get(firstLevelCategory.getSubCategories().size() - 1); UploadCategory secondLevelCategory = firstLevelCategory.getSubCategories().get(firstLevelCategory.getSubCategories().size() - 1);
secondLevelCategory.addSubCategory(categoryValue, categoryText); secondLevelCategory.addSubCategory(categoryValue, categoryText);
} else if (categoryText.startsWith("---- ")) { }
else if (categoryText.startsWith("---- ")) {
//This is a level four subcategory //This is a level four subcategory
UploadCategory rootLevelCategory = uploadRootCategories.get(uploadRootCategories.size() - 1); UploadCategory rootLevelCategory = uploadRootCategories.get(uploadRootCategories.size() - 1);
UploadCategory firstLevelCategory = rootLevelCategory.getSubCategories().get(rootLevelCategory.getSubCategories().size() - 1); UploadCategory firstLevelCategory = rootLevelCategory.getSubCategories().get(rootLevelCategory.getSubCategories().size() - 1);
UploadCategory secondLevelCategory = firstLevelCategory.getSubCategories().get(firstLevelCategory.getSubCategories().size() - 1); UploadCategory secondLevelCategory = firstLevelCategory.getSubCategories().get(firstLevelCategory.getSubCategories().size() - 1);
UploadCategory thirdLevelCategory = secondLevelCategory.getSubCategories().get(secondLevelCategory.getSubCategories().size() - 1); UploadCategory thirdLevelCategory = secondLevelCategory.getSubCategories().get(secondLevelCategory.getSubCategories().size() - 1);
thirdLevelCategory.addSubCategory(categoryValue, categoryText); thirdLevelCategory.addSubCategory(categoryValue, categoryText);
} else { }
else {
//This is a root category //This is a root category
uploadRootCategories.add(new UploadCategory(categoryValue, categoryText)); uploadRootCategories.add(new UploadCategory(categoryValue, categoryText));
} }

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

@ -49,7 +49,8 @@ public class UploadFieldsBuilderActivity extends BaseActivity {
int inputYear = Integer.parseInt(working); int inputYear = Integer.parseInt(working);
isValidYear = inputYear <= currentYear && inputYear > 1980; isValidYear = inputYear <= currentYear && inputYear > 1980;
} else }
else
isValidYear = false; isValidYear = false;
if (!isValidYear) if (!isValidYear)
@ -59,10 +60,12 @@ public class UploadFieldsBuilderActivity extends BaseActivity {
} }
@Override @Override
public void afterTextChanged(Editable s) { } public void afterTextChanged(Editable s) {
}
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { } public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
}; };
@Override @Override
@ -111,7 +114,8 @@ public class UploadFieldsBuilderActivity extends BaseActivity {
typeRadio.setOnCheckedChangeListener((group, checkedId) -> { typeRadio.setOnCheckedChangeListener((group, checkedId) -> {
if (checkedId == R.id.upload_fields_builder_radio_button_notes) { if (checkedId == R.id.upload_fields_builder_radio_button_notes) {
semesterChooserLinear.setVisibility(View.GONE); semesterChooserLinear.setVisibility(View.GONE);
} else { }
else {
semesterChooserLinear.setVisibility(View.VISIBLE); semesterChooserLinear.setVisibility(View.VISIBLE);
} }
}); });
@ -122,10 +126,12 @@ public class UploadFieldsBuilderActivity extends BaseActivity {
if (typeId == -1) { if (typeId == -1) {
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Please choose a type for the upload", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Please choose a type for the upload", Toast.LENGTH_SHORT).show();
return; return;
} else if (semesterChooserLinear.getVisibility() == View.VISIBLE && semesterId == -1) { }
else if (semesterChooserLinear.getVisibility() == View.VISIBLE && semesterId == -1) {
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Please choose a semester for the upload", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Please choose a semester for the upload", Toast.LENGTH_SHORT).show();
return; return;
} else if (year.getText().toString().isEmpty() || !isValidYear) { }
else if (year.getText().toString().isEmpty() || !isValidYear) {
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Please choose a valid year for the upload", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Please choose a valid year for the upload", Toast.LENGTH_SHORT).show();
return; return;
} }

14
app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsCourse.java

@ -33,31 +33,31 @@ class UploadsCourse {
return greeklishName; return greeklishName;
} }
static Map<String, UploadsCourse> generateUploadsCourses(String[] uploadsCoursesRes){ static Map<String, UploadsCourse> generateUploadsCourses(String[] uploadsCoursesRes) {
Map<String, UploadsCourse> uploadsCourses = new HashMap<>(); Map<String, UploadsCourse> uploadsCourses = new HashMap<>();
for(String uploadsCourseStr:uploadsCoursesRes) { for (String uploadsCourseStr : uploadsCoursesRes) {
String[] split = uploadsCourseStr.split(":"); String[] split = uploadsCourseStr.split(":");
UploadsCourse uploadsCourse = new UploadsCourse(split[0], split[1], split[2]); UploadsCourse uploadsCourse = new UploadsCourse(split[0], split[1], split[2]);
uploadsCourses.put(uploadsCourse.getName(),uploadsCourse); uploadsCourses.put(uploadsCourse.getName(), uploadsCourse);
} }
return uploadsCourses; return uploadsCourses;
} }
static UploadsCourse findCourse(String retrievedCourse, static UploadsCourse findCourse(String retrievedCourse,
Map<String, UploadsCourse> uploadsCourses){ Map<String, UploadsCourse> uploadsCourses) {
retrievedCourse = normalizeGreekNumbers(retrievedCourse); retrievedCourse = normalizeGreekNumbers(retrievedCourse);
UploadsCourse uploadsCourse = uploadsCourses.get(retrievedCourse); UploadsCourse uploadsCourse = uploadsCourses.get(retrievedCourse);
if(uploadsCourse != null) return uploadsCourse; if (uploadsCourse != null) return uploadsCourse;
String foundKey = null; String foundKey = null;
for (Map.Entry<String, UploadsCourse> entry : uploadsCourses.entrySet()) { for (Map.Entry<String, UploadsCourse> entry : uploadsCourses.entrySet()) {
String key = entry.getKey(); String key = entry.getKey();
if ((key.contains(retrievedCourse) || retrievedCourse.contains(key)) if ((key.contains(retrievedCourse) || retrievedCourse.contains(key))
&& (foundKey==null || key.length()>foundKey.length())) && (foundKey == null || key.length() > foundKey.length()))
foundKey = key; foundKey = key;
} }
if(foundKey==null){ if (foundKey == null) {
Timber.w("Couldn't find course that matches %s", retrievedCourse); Timber.w("Couldn't find course that matches %s", retrievedCourse);
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString("course_name", retrievedCourse); bundle.putString("course_name", retrievedCourse);

4
app/src/main/java/gr/thmmy/mthmmy/activities/upload/UploadsHelper.java

@ -87,8 +87,8 @@ public class UploadsHelper {
File.separator + "mTHMMY"); File.separator + "mTHMMY");
if (!zipFolder.exists() && !zipFolder.mkdirs()) { if (!zipFolder.exists() && !zipFolder.mkdirs()) {
Timber.w("Zip folder build returned false in %s", UploadsHelper.class.getSimpleName()); Timber.w("Zip folder build returned false in %s", UploadsHelper.class.getSimpleName());
return null; return null;
} }
return new File(zipFolder, zipFilename); return new File(zipFolder, zipFilename);

10
app/src/main/java/gr/thmmy/mthmmy/activities/upload/multipart/MultipartUploadRequest.java

@ -12,8 +12,8 @@ import java.io.FileNotFoundException;
import java.net.MalformedURLException; import java.net.MalformedURLException;
/** /**
From MultipartUploadRequest gotev/android-upload-service in order to use the local custom * From MultipartUploadRequest gotev/android-upload-service in order to use the local custom
MultipartUploadTask. * MultipartUploadTask.
*/ */
public class MultipartUploadRequest extends HttpUploadRequest<MultipartUploadRequest> { public class MultipartUploadRequest extends HttpUploadRequest<MultipartUploadRequest> {
@ -61,7 +61,8 @@ public class MultipartUploadRequest extends HttpUploadRequest<MultipartUploadReq
contentType = file.getContentType(context); contentType = file.getContentType(context);
Logger.debug(LOG_TAG, "Auto-detected MIME type for " + filePath Logger.debug(LOG_TAG, "Auto-detected MIME type for " + filePath
+ " is: " + contentType); + " is: " + contentType);
} else { }
else {
Logger.debug(LOG_TAG, "Content Type set for " + filePath Logger.debug(LOG_TAG, "Content Type set for " + filePath
+ " is: " + contentType); + " is: " + contentType);
} }
@ -71,7 +72,8 @@ public class MultipartUploadRequest extends HttpUploadRequest<MultipartUploadReq
if (fileName == null || "".equals(fileName)) { if (fileName == null || "".equals(fileName)) {
fileName = file.getName(context); fileName = file.getName(context);
Logger.debug(LOG_TAG, "Using original file name: " + fileName); Logger.debug(LOG_TAG, "Using original file name: " + fileName);
} else { }
else {
Logger.debug(LOG_TAG, "Using custom file name: " + fileName); Logger.debug(LOG_TAG, "Using custom file name: " + fileName);
} }

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

@ -13,8 +13,8 @@ import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
/** /**
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
tp_dluploadpic. Also changed Connection to keep-alive. * tp_dluploadpic. Also changed Connection to keep-alive.
*/ */
public class MultipartUploadTask extends HttpUploadTask { public class MultipartUploadTask extends HttpUploadTask {
@ -90,7 +90,7 @@ public class MultipartUploadTask extends HttpUploadTask {
} }
private byte[] getMultipartBytes(NameValue parameter) throws UnsupportedEncodingException { private byte[] getMultipartBytes(NameValue parameter) throws UnsupportedEncodingException {
if(parameter.getName().equals("tp_dluploadpic")){ if (parameter.getName().equals("tp_dluploadpic")) {
String header = "Content-Disposition: form-data; name=\"" + String header = "Content-Disposition: form-data; name=\"" +
parameter.getName() + "\"; filename=\"\"" + NEW_LINE + parameter.getName() + "\"; filename=\"\"" + NEW_LINE +
"Content-Type: application/octet-stream" + NEW_LINE + NEW_LINE; "Content-Type: application/octet-stream" + NEW_LINE + NEW_LINE;
@ -98,7 +98,7 @@ public class MultipartUploadTask extends HttpUploadTask {
} }
else else
return ("Content-Disposition: form-data; name=\"" + parameter.getName() + "\"" return ("Content-Disposition: form-data; name=\"" + parameter.getName() + "\""
+ NEW_LINE + NEW_LINE + parameter.getValue() + NEW_LINE).getBytes(charset); + NEW_LINE + NEW_LINE + parameter.getValue() + NEW_LINE).getBytes(charset);
} }
private byte[] getMultipartHeader(UploadFile file) private byte[] getMultipartHeader(UploadFile file)

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

@ -319,7 +319,8 @@ public abstract class BaseActivity extends AppCompatActivity {
.withName(R.string.logout) .withName(R.string.logout)
.withIcon(logoutIcon) .withIcon(logoutIcon)
.withSelectable(false); .withSelectable(false);
} else }
else
loginLogoutItem = new PrimaryDrawerItem() loginLogoutItem = new PrimaryDrawerItem()
.withTextColor(primaryColor) .withTextColor(primaryColor)
.withSelectedColor(selectedSecondaryColor) .withSelectedColor(selectedSecondaryColor)
@ -379,7 +380,8 @@ public abstract class BaseActivity extends AppCompatActivity {
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
startActivity(intent); startActivity(intent);
return false; return false;
} else }
else
startLoginActivity(); startLoginActivity();
return true; return true;
@ -399,12 +401,14 @@ public abstract class BaseActivity extends AppCompatActivity {
Intent intent = new Intent(BaseActivity.this, MainActivity.class); Intent intent = new Intent(BaseActivity.this, MainActivity.class);
startActivity(intent); startActivity(intent);
} }
} else if (drawerItem.equals(SHOUTBOX_ID)) { }
else if (drawerItem.equals(SHOUTBOX_ID)) {
if (!(BaseActivity.this instanceof ShoutboxActivity)) { if (!(BaseActivity.this instanceof ShoutboxActivity)) {
Intent intent = new Intent(BaseActivity.this, ShoutboxActivity.class); Intent intent = new Intent(BaseActivity.this, ShoutboxActivity.class);
startActivity(intent); startActivity(intent);
} }
} else if (drawerItem.equals(DOWNLOADS_ID)) { }
else if (drawerItem.equals(DOWNLOADS_ID)) {
if (!(BaseActivity.this instanceof DownloadsActivity)) { if (!(BaseActivity.this instanceof DownloadsActivity)) {
Intent intent = new Intent(BaseActivity.this, DownloadsActivity.class); Intent intent = new Intent(BaseActivity.this, DownloadsActivity.class);
Bundle extras = new Bundle(); Bundle extras = new Bundle();
@ -413,29 +417,34 @@ public abstract class BaseActivity extends AppCompatActivity {
intent.putExtras(extras); intent.putExtras(extras);
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);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent); startActivity(intent);
} }
} else if (drawerItem.equals(LOG_ID)) { }
else if (drawerItem.equals(LOG_ID)) {
if (!sessionManager.isLoggedIn()) //When logged out or if user is guest if (!sessionManager.isLoggedIn()) //When logged out or if user is guest
startLoginActivity(); startLoginActivity();
else else
showLogoutDialog(); showLogoutDialog();
} else if (drawerItem.equals(ABOUT_ID)) { }
else if (drawerItem.equals(ABOUT_ID)) {
if (!(BaseActivity.this instanceof AboutActivity)) { if (!(BaseActivity.this instanceof AboutActivity)) {
Intent intent = new Intent(BaseActivity.this, AboutActivity.class); Intent intent = new Intent(BaseActivity.this, AboutActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent); startActivity(intent);
} }
} else if (drawerItem.equals(SETTINGS_ID)) { }
else if (drawerItem.equals(SETTINGS_ID)) {
if (!(BaseActivity.this instanceof SettingsActivity)) { if (!(BaseActivity.this instanceof SettingsActivity)) {
Intent intent = new Intent(BaseActivity.this, SettingsActivity.class); Intent intent = new Intent(BaseActivity.this, SettingsActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
@ -465,13 +474,14 @@ public abstract class BaseActivity extends AppCompatActivity {
private void updateDrawer() { private void updateDrawer() {
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();
} else { }
else {
if (!drawer.getDrawerItems().contains(downloadsItem)) { if (!drawer.getDrawerItems().contains(downloadsItem)) {
drawer.addItemAtPosition(downloadsItem, 4); drawer.addItemAtPosition(downloadsItem, 4);
} }
@ -494,8 +504,9 @@ public abstract class BaseActivity extends AppCompatActivity {
profileDrawerItem.withIcon(R.drawable.ic_default_user_avatar); profileDrawerItem.withIcon(R.drawable.ic_default_user_avatar);
} }
//-------------------------------------------LOGOUT------------------------------------------------- //-------------------------------------------LOGOUT-------------------------------------------------
private ProgressDialog progressDialog; private ProgressDialog progressDialog;
private void onLogoutTaskStarted() { private void onLogoutTaskStarted() {
progressDialog = new ProgressDialog(BaseActivity.this, progressDialog = new ProgressDialog(BaseActivity.this,
R.style.AppTheme_Dark_Dialog); R.style.AppTheme_Dark_Dialog);
@ -505,7 +516,7 @@ public abstract class BaseActivity extends AppCompatActivity {
progressDialog.show(); progressDialog.show();
} }
private void onLogoutTaskFinished(int resultCode, Void v) { private void onLogoutTaskFinished(int resultCode, Void v) {
if (resultCode == NetworkResultCodes.SUCCESSFUL) { if (resultCode == NetworkResultCodes.SUCCESSFUL) {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext()); SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
if (sharedPrefs.getString(DEFAULT_HOME_TAB, "0").equals("2")) { if (sharedPrefs.getString(DEFAULT_HOME_TAB, "0").equals("2")) {
@ -533,7 +544,8 @@ public abstract class BaseActivity extends AppCompatActivity {
builder.setPositiveButton("Yep", (dialogInterface, i) -> { builder.setPositiveButton("Yep", (dialogInterface, i) -> {
new LogoutTask(this::onLogoutTaskStarted, this::onLogoutTaskFinished).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); //Avoid delays between onPreExecute() and doInBackground() new LogoutTask(this::onLogoutTaskStarted, this::onLogoutTaskFinished).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); //Avoid delays between onPreExecute() and doInBackground()
}); });
builder.setNegativeButton("Nope", (dialogInterface, i) -> {}); builder.setNegativeButton("Nope", (dialogInterface, i) -> {
});
builder.create().show(); builder.create().show();
} }
//-----------------------------------------LOGOUT END----------------------------------------------- //-----------------------------------------LOGOUT END-----------------------------------------------
@ -571,7 +583,8 @@ public abstract class BaseActivity extends AppCompatActivity {
thisPageBookmarkMenuButton.setIcon(R.drawable.ic_bookmark_false_accent_24dp); thisPageBookmarkMenuButton.setIcon(R.drawable.ic_bookmark_false_accent_24dp);
toggleTopicToBookmarks(thisPageBookmark); toggleTopicToBookmarks(thisPageBookmark);
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Bookmark removed", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Bookmark removed", Toast.LENGTH_SHORT).show();
} else { }
else {
thisPageBookmarkMenuButton.setIcon(R.drawable.ic_bookmark_true_accent_24dp); thisPageBookmarkMenuButton.setIcon(R.drawable.ic_bookmark_true_accent_24dp);
toggleTopicToBookmarks(thisPageBookmark); toggleTopicToBookmarks(thisPageBookmark);
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Bookmark added", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Bookmark added", Toast.LENGTH_SHORT).show();
@ -581,14 +594,16 @@ public abstract class BaseActivity extends AppCompatActivity {
protected void setBoardBookmark(final ImageButton thisPageBookmarkImageButton) { protected void setBoardBookmark(final ImageButton thisPageBookmarkImageButton) {
if (thisPageBookmark.matchExists(boardsBookmarked)) { if (thisPageBookmark.matchExists(boardsBookmarked)) {
thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_true_accent_24dp); thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_true_accent_24dp);
} else { }
else {
thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_false_accent_24dp); thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_false_accent_24dp);
} }
thisPageBookmarkImageButton.setOnClickListener(view -> { thisPageBookmarkImageButton.setOnClickListener(view -> {
if (thisPageBookmark.matchExists(boardsBookmarked)) { if (thisPageBookmark.matchExists(boardsBookmarked)) {
thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_false_accent_24dp); thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_false_accent_24dp);
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Bookmark removed", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Bookmark removed", Toast.LENGTH_SHORT).show();
} else { }
else {
thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_true_accent_24dp); thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_true_accent_24dp);
Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Bookmark added", Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), "Bookmark added", Toast.LENGTH_SHORT).show();
} }
@ -602,7 +617,8 @@ public abstract class BaseActivity extends AppCompatActivity {
loadSavedBookmarks(); loadSavedBookmarks();
if (thisPageBookmark.matchExists(boardsBookmarked)) { if (thisPageBookmark.matchExists(boardsBookmarked)) {
thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_true_accent_24dp); thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_true_accent_24dp);
} else { }
else {
thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_false_accent_24dp); thisPageBookmarkImageButton.setImageResource(R.drawable.ic_bookmark_false_accent_24dp);
} }
} }
@ -627,7 +643,8 @@ public abstract class BaseActivity extends AppCompatActivity {
if (bookmark.matchExists(boardsBookmarked)) { if (bookmark.matchExists(boardsBookmarked)) {
boardsBookmarked.remove(bookmark.findIndex(boardsBookmarked)); boardsBookmarked.remove(bookmark.findIndex(boardsBookmarked));
FirebaseMessaging.getInstance().unsubscribeFromTopic("b" + bookmark.getId()); FirebaseMessaging.getInstance().unsubscribeFromTopic("b" + bookmark.getId());
} else { }
else {
boardsBookmarked.add(new Bookmark(bookmark.getTitle(), bookmark.getId(), true)); boardsBookmarked.add(new Bookmark(bookmark.getTitle(), bookmark.getId(), true));
FirebaseMessaging.getInstance().subscribeToTopic("b" + bookmark.getId()); FirebaseMessaging.getInstance().subscribeToTopic("b" + bookmark.getId());
} }
@ -639,7 +656,8 @@ public abstract class BaseActivity extends AppCompatActivity {
if (bookmark.matchExists(topicsBookmarked)) { if (bookmark.matchExists(topicsBookmarked)) {
topicsBookmarked.remove(bookmark.findIndex(topicsBookmarked)); topicsBookmarked.remove(bookmark.findIndex(topicsBookmarked));
FirebaseMessaging.getInstance().unsubscribeFromTopic(bookmark.getId()); FirebaseMessaging.getInstance().unsubscribeFromTopic(bookmark.getId());
} else { }
else {
topicsBookmarked.add(new Bookmark(bookmark.getTitle(), bookmark.getId(), true)); topicsBookmarked.add(new Bookmark(bookmark.getTitle(), bookmark.getId(), true));
FirebaseMessaging.getInstance().subscribeToTopic(bookmark.getId()); FirebaseMessaging.getInstance().subscribeToTopic(bookmark.getId());
} }
@ -676,7 +694,8 @@ public abstract class BaseActivity extends AppCompatActivity {
FirebaseMessaging.getInstance().unsubscribeFromTopic(bookmark.getId()); FirebaseMessaging.getInstance().unsubscribeFromTopic(bookmark.getId());
return topicsBookmarked.get(bookmark.findIndex(topicsBookmarked)).isNotificationsEnabled(); return topicsBookmarked.get(bookmark.findIndex(topicsBookmarked)).isNotificationsEnabled();
} else if (bookmark.matchExists(boardsBookmarked)) { }
else if (bookmark.matchExists(boardsBookmarked)) {
boardsBookmarked.get(bookmark.findIndex(boardsBookmarked)).toggleNotificationsEnabled(); boardsBookmarked.get(bookmark.findIndex(boardsBookmarked)).toggleNotificationsEnabled();
updateBoardBookmarks(); updateBoardBookmarks();
@ -686,7 +705,8 @@ public abstract class BaseActivity extends AppCompatActivity {
FirebaseMessaging.getInstance().unsubscribeFromTopic("b" + bookmark.getId()); FirebaseMessaging.getInstance().unsubscribeFromTopic("b" + bookmark.getId());
return boardsBookmarked.get(bookmark.findIndex(boardsBookmarked)).isNotificationsEnabled(); return boardsBookmarked.get(bookmark.findIndex(boardsBookmarked)).isNotificationsEnabled();
} else }
else
Timber.w("No bookmark match exists!"); Timber.w("No bookmark match exists!");
return false; return false;
} }
@ -855,8 +875,8 @@ public abstract class BaseActivity extends AppCompatActivity {
privacyPolicyTextView.setTextColor(ContextCompat.getColor(this, R.color.primary_text)); privacyPolicyTextView.setTextColor(ContextCompat.getColor(this, R.color.primary_text));
SpannableConfiguration configuration = SpannableConfiguration.builder(this).linkResolver(new LinkResolverDef()).build(); SpannableConfiguration configuration = SpannableConfiguration.builder(this).linkResolver(new LinkResolverDef()).build();
String privacyPolicy = AssetUtils.readFileToText(BaseActivity.this,"PRIVACY.md"); String privacyPolicy = AssetUtils.readFileToText(BaseActivity.this, "PRIVACY.md");
if(privacyPolicy!=null){ if (privacyPolicy != null) {
Markwon.setMarkdown(privacyPolicyTextView, configuration, privacyPolicy); Markwon.setMarkdown(privacyPolicyTextView, configuration, privacyPolicy);
AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyle); AlertDialog.Builder builder = new AlertDialog.Builder(this, R.style.AppCompatAlertDialogStyle);
builder.setView(privacyPolicyTextView); builder.setView(privacyPolicyTextView);
@ -943,7 +963,8 @@ public abstract class BaseActivity extends AppCompatActivity {
dialogProgressText.setText(getString(R.string.upload_failed)); dialogProgressText.setText(getString(R.string.upload_failed));
uploadsProgressDialog.show(); uploadsProgressDialog.show();
} else { }
else {
//Empty buttons are needed, they are updated with correct values in the receiver //Empty buttons are needed, they are updated with correct values in the receiver
uploadsProgressDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "placeholder", (progressDialog, progressWhich) -> { uploadsProgressDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "placeholder", (progressDialog, progressWhich) -> {
}); });
@ -954,7 +975,8 @@ public abstract class BaseActivity extends AppCompatActivity {
//UploadsReceiver.setDialogDisplay(uploadsProgressDialog, dialogUploadID, retryIntent); //UploadsReceiver.setDialogDisplay(uploadsProgressDialog, dialogUploadID, retryIntent);
uploadsProgressDialog.show(); uploadsProgressDialog.show();
} }
} else { }
else {
UploadsReceiver.setDialogDisplay(uploadsProgressDialog, dialogUploadID, null); UploadsReceiver.setDialogDisplay(uploadsProgressDialog, dialogUploadID, null);
//UploadsReceiver.setDialogDisplay(uploadsProgressDialog, dialogUploadID, retryIntent); //UploadsReceiver.setDialogDisplay(uploadsProgressDialog, dialogUploadID, retryIntent);
uploadsProgressDialog.show(); uploadsProgressDialog.show();

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

@ -46,6 +46,7 @@ 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.settings.SettingsActivity.DISPLAY_RELATIVE_TIME;
// TODO: Replace MultiDexApplication with Application after KitKat support is dropped // TODO: Replace MultiDexApplication with Application after KitKat support is dropped
@ -63,6 +64,7 @@ public class BaseApplication extends MultiDexApplication {
private SessionManager sessionManager; private SessionManager sessionManager;
private boolean displayRelativeTime; private boolean displayRelativeTime;
private boolean displayCompactTabs;
//Display Metrics //Display Metrics
private static float widthDp; private static float widthDp;
@ -105,10 +107,11 @@ public class BaseApplication extends MultiDexApplication {
setDisplayMetrics(); setDisplayMetrics();
displayRelativeTime = settingsSharedPrefs.getBoolean(DISPLAY_RELATIVE_TIME, true); displayRelativeTime = settingsSharedPrefs.getBoolean(DISPLAY_RELATIVE_TIME, true);
displayCompactTabs = settingsSharedPrefs.getBoolean(DISPLAY_COMPACT_TABS, true);
} }
private void initFirebase(SharedPreferences settingsSharedPrefs){ private void initFirebase(SharedPreferences settingsSharedPrefs) {
if (settingsSharedPrefs.getBoolean(getString(R.string.pref_privacy_crashlytics_enable_key), false)){ if (settingsSharedPrefs.getBoolean(getString(R.string.pref_privacy_crashlytics_enable_key), false)) {
Timber.i("Starting app with Firebase Crashlytics enabled."); Timber.i("Starting app with Firebase Crashlytics enabled.");
setFirebaseCrashlyticsEnabled(true); setFirebaseCrashlyticsEnabled(true);
} }
@ -127,7 +130,7 @@ public class BaseApplication extends MultiDexApplication {
Timber.i("Starting app with Firebase Analytics disabled."); Timber.i("Starting app with Firebase Analytics disabled.");
} }
private void initOkHttp(PersistentCookieJar cookieJar){ private void initOkHttp(PersistentCookieJar cookieJar) {
OkHttpClient.Builder builder = new OkHttpClient.Builder() OkHttpClient.Builder builder = new OkHttpClient.Builder()
.cookieJar(cookieJar) .cookieJar(cookieJar)
.addInterceptor(chain -> { .addInterceptor(chain -> {
@ -165,7 +168,7 @@ public class BaseApplication extends MultiDexApplication {
client = builder.build(); client = builder.build();
} }
private void initDrawerImageLoader(){ private void initDrawerImageLoader() {
DrawerImageLoader.init(new AbstractDrawerImageLoader() { DrawerImageLoader.init(new AbstractDrawerImageLoader() {
@Override @Override
public void set(ImageView imageView, Uri uri, Drawable placeholder, String tag) { public void set(ImageView imageView, Uri uri, Drawable placeholder, String tag) {
@ -179,7 +182,7 @@ public class BaseApplication extends MultiDexApplication {
@Override @Override
public Drawable placeholder(Context ctx, String tag) { public Drawable placeholder(Context ctx, String tag) {
if (DrawerImageLoader.Tags.PROFILE.name().equals(tag)){ if (DrawerImageLoader.Tags.PROFILE.name().equals(tag)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
return ContextCompat.getDrawable(BaseApplication.getInstance(), R.drawable.ic_default_user_avatar); return ContextCompat.getDrawable(BaseApplication.getInstance(), R.drawable.ic_default_user_avatar);
else { // Just for KitKats else { // Just for KitKats
@ -194,7 +197,7 @@ public class BaseApplication extends MultiDexApplication {
}); });
} }
private void setDisplayMetrics(){ private void setDisplayMetrics() {
DisplayMetrics displayMetrics = getApplicationContext().getResources().getDisplayMetrics(); DisplayMetrics displayMetrics = getApplicationContext().getResources().getDisplayMetrics();
widthPxl = displayMetrics.widthPixels; widthPxl = displayMetrics.widthPixels;
@ -233,6 +236,10 @@ public class BaseApplication extends MultiDexApplication {
return displayRelativeTime; return displayRelativeTime;
} }
public boolean isDisplayCompactTabsEnabled() {
return displayCompactTabs;
}
//-------------------- Firebase -------------------- //-------------------- Firebase --------------------
public void logFirebaseAnalyticsEvent(String event, Bundle params) { public void logFirebaseAnalyticsEvent(String event, Bundle params) {
@ -244,7 +251,7 @@ public class BaseApplication extends MultiDexApplication {
if (!enabled) if (!enabled)
firebaseAnalytics.resetAnalyticsData(); firebaseAnalytics.resetAnalyticsData();
if(enabled) if (enabled)
Timber.i("Firebase Analytics enabled."); Timber.i("Firebase Analytics enabled.");
else else
Timber.i("Firebase Analytics disabled."); Timber.i("Firebase Analytics disabled.");
@ -252,14 +259,14 @@ public class BaseApplication extends MultiDexApplication {
public void setFirebaseCrashlyticsEnabled(boolean enable) { public void setFirebaseCrashlyticsEnabled(boolean enable) {
FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(enable); FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(enable);
if(enable){ if (enable) {
crashReportingTree = new CrashReportingTree(); crashReportingTree = new CrashReportingTree();
Timber.plant(crashReportingTree); Timber.plant(crashReportingTree);
Timber.i("CrashReporting tree planted."); Timber.i("CrashReporting tree planted.");
Timber.i("Firebase Crashlytics enabled."); Timber.i("Firebase Crashlytics enabled.");
} }
else{ else {
if(crashReportingTree!=null) { if (crashReportingTree != null) {
Timber.uproot(crashReportingTree); Timber.uproot(crashReportingTree);
Timber.i("CrashReporting tree uprooted."); Timber.i("CrashReporting tree uprooted.");
} }
@ -267,7 +274,7 @@ public class BaseApplication extends MultiDexApplication {
} }
} }
public static String getFirebaseProjectId(){ public static String getFirebaseProjectId() {
return firebaseProjectId; return firebaseProjectId;
} }
} }

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

@ -46,5 +46,6 @@ public abstract class BaseFragment extends Fragment {
* the activity that contains it, to allow communication upon interaction, * the activity that contains it, to allow communication upon interaction,
* between the fragment and the activity/ other fragments * between the fragment and the activity/ other fragments
*/ */
public interface FragmentInteractionListener {} public interface FragmentInteractionListener {
}
} }

2
app/src/main/java/gr/thmmy/mthmmy/model/Bookmark.java

@ -28,7 +28,7 @@ public class Bookmark implements java.io.Serializable {
return isNotificationsEnabled; return isNotificationsEnabled;
} }
public void toggleNotificationsEnabled(){ public void toggleNotificationsEnabled() {
this.isNotificationsEnabled = !this.isNotificationsEnabled; this.isNotificationsEnabled = !this.isNotificationsEnabled;
} }

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

@ -57,11 +57,11 @@ public class Download {
return hasSubCategory; return hasSubCategory;
} }
public String getFileName(){ public String getFileName() {
return fileName; return fileName;
} }
public void setFileName(String fileName){ public void setFileName(String fileName) {
this.fileName = fileName; this.fileName = fileName;
} }
} }

3
app/src/main/java/gr/thmmy/mthmmy/model/Poll.java

@ -91,8 +91,7 @@ public class Poll extends TopicItem {
/** /**
* Constructor for entry with unknown number of votes * Constructor for entry with unknown number of votes
* *
* @param entryName * @param entryName The name of the entry
* The name of the entry
*/ */
public Entry(String entryName) { public Entry(String entryName) {
this.entryName = entryName; this.entryName = entryName;

6
app/src/main/java/gr/thmmy/mthmmy/model/Post.java

@ -81,7 +81,8 @@ public class Post extends TopicItem {
* Constructor for active user's posts. All variables are declared final, once assigned they * Constructor for active user's posts. All variables are declared final, once assigned they
* can not change. Parameters notated as {@link Nullable} can either pass null or empty * can not change. Parameters notated as {@link Nullable} can either pass null or empty
* (strings/ArrayList). * (strings/ArrayList).
* @param thumbnailUrl author's thumbnail url *
* @param thumbnailUrl author's thumbnail url
* @param author author's username * @param author author's username
* @param subject post's subject * @param subject post's subject
* @param content post itself * @param content post itself
@ -139,7 +140,8 @@ public class Post extends TopicItem {
* Constructor for deleted user's posts. All variables are declared final, once assigned they * Constructor for deleted user's posts. All variables are declared final, once assigned they
* can not change. Parameters notated as {@link Nullable} can either pass null or empty * can not change. Parameters notated as {@link Nullable} can either pass null or empty
* (strings/ArrayList). * (strings/ArrayList).
* @param thumbnailUrl author's thumbnail url *
* @param thumbnailUrl author's thumbnail url
* @param author author's username * @param author author's username
* @param subject post's subject * @param subject post's subject
* @param content post itself * @param content post itself

12
app/src/main/java/gr/thmmy/mthmmy/model/PostNotification.java

@ -30,12 +30,12 @@ public class PostNotification {
* Constructor specifying all class variables necessary to summarize this post. All variables * Constructor specifying all class variables necessary to summarize this post. All variables
* are declared final, once assigned they cannot change. * are declared final, once assigned they cannot change.
* *
* @param postId this post's id * @param postId this post's id
* @param topicId this post's topicId * @param topicId this post's topicId
* @param topicTitle this post's topicTitle * @param topicTitle this post's topicTitle
* @param poster username of this post's author * @param poster username of this post's author
* @param boardId one of this post's boardIds (-1 if it is a topic notification) * @param boardId one of this post's boardIds (-1 if it is a topic notification)
* @param boardTitle one of this post's boardTitles (null if it is a topic notification) * @param boardTitle one of this post's boardTitles (null if it is a topic notification)
*/ */
public PostNotification(int postId, int topicId, String topicTitle, String poster, int boardId, String boardTitle) { public PostNotification(int postId, int topicId, String topicTitle, String poster, int boardId, String boardTitle) {
this.postId = postId; this.postId = postId;

2
app/src/main/java/gr/thmmy/mthmmy/model/ThmmyFile.java

@ -21,7 +21,7 @@ public class ThmmyFile {
*/ */
public ThmmyFile(URL fileUrl, String fileName, String fileInfo) { public ThmmyFile(URL fileUrl, String fileName, String fileInfo) {
this.fileUrl = fileUrl; this.fileUrl = fileUrl;
if(fileName!=null) if (fileName != null)
this.fileName = fileName; this.fileName = fileName;
else else
this.fileName = URLUtil.guessFileName(fileUrl.toString(), null, null); this.fileName = URLUtil.guessFileName(fileUrl.toString(), null, null);

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

@ -153,7 +153,8 @@ public class ThmmyPage {
else if (uriString.contains(";sa=statPanel")) else if (uriString.contains(";sa=statPanel"))
return PageCategory.PROFILE_STATS; return PageCategory.PROFILE_STATS;
else return PageCategory.PROFILE_SUMMARY; else return PageCategory.PROFILE_SUMMARY;
} else if (uriString.contains("action=unread")) }
else if (uriString.contains("action=unread"))
return PageCategory.UNREAD_POSTS; return PageCategory.UNREAD_POSTS;
else if (uriString.contains("action=tpmod;dl=item")) else if (uriString.contains("action=tpmod;dl=item"))
return PageCategory.DOWNLOADS_FILE; return PageCategory.DOWNLOADS_FILE;
@ -185,17 +186,19 @@ public class ThmmyPage {
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; }
else return null;
} }
return null; return null;
} }
/** /**
* This method gets a VALID topic url and strips it off any unnecessary stuff (e.g. wap2). * This method gets a VALID topic url and strips it off any unnecessary stuff (e.g. wap2).
*
* @param topicUrl a valid topic url * @param topicUrl a valid topic url
* @return sanitized topic url * @return sanitized topic url
*/ */
public static String sanitizeTopicUrl(String topicUrl) { public static String sanitizeTopicUrl(String topicUrl) {
return topicUrl.replace("action=printpage;","").replace("wap2",""); return topicUrl.replace("action=printpage;", "").replace("wap2", "");
} }
} }

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

@ -24,7 +24,7 @@ import static gr.thmmy.mthmmy.utils.FileUtils.getMimeType;
public class DownloadHelper { public class DownloadHelper {
public static final File SAVE_DIR = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); public static final File SAVE_DIR = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
public static void enqueueDownload(ThmmyFile thmmyFile){ public static void enqueueDownload(ThmmyFile thmmyFile) {
Context applicationContext = BaseApplication.getInstance().getApplicationContext(); Context applicationContext = BaseApplication.getInstance().getApplicationContext();
Toast.makeText(applicationContext, "Download started!", Toast.LENGTH_SHORT).show(); Toast.makeText(applicationContext, "Download started!", Toast.LENGTH_SHORT).show();
@ -32,11 +32,11 @@ public class DownloadHelper {
String fileName = renameFileIfExists(thmmyFile.getFilename()); String fileName = renameFileIfExists(thmmyFile.getFilename());
Uri downloadURI = Uri.parse(thmmyFile.getFileUrl().toString()); Uri downloadURI = Uri.parse(thmmyFile.getFileUrl().toString());
DownloadManager downloadManager = (DownloadManager)applicationContext.getSystemService(Context.DOWNLOAD_SERVICE); DownloadManager downloadManager = (DownloadManager) applicationContext.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(downloadURI); DownloadManager.Request request = new DownloadManager.Request(downloadURI);
Cookie thmmyCookie = BaseApplication.getInstance().getSessionManager().getThmmyCookie(); Cookie thmmyCookie = BaseApplication.getInstance().getSessionManager().getThmmyCookie();
if(thmmyCookie!=null) if (thmmyCookie != null)
request.addRequestHeader("Cookie", thmmyCookie.name() + "=" + thmmyCookie.value()); request.addRequestHeader("Cookie", thmmyCookie.name() + "=" + thmmyCookie.value());
request.setTitle(fileName); request.setTitle(fileName);
request.setMimeType(getMimeType(fileName)); request.setMimeType(getMimeType(fileName));
@ -63,7 +63,8 @@ public class DownloadHelper {
if (tokens.length != 2) { if (tokens.length != 2) {
Timber.w("Couldn't get file extension..."); Timber.w("Couldn't get file extension...");
nameFormat = originalFileName + "(%d)"; nameFormat = originalFileName + "(%d)";
} else }
else
nameFormat = tokens[0] + "-%d." + tokens[1]; nameFormat = tokens[0] + "-%d." + tokens[1];
for (int i = 1; ; i++) { for (int i = 1; ; i++) {

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

@ -63,12 +63,12 @@ public class NotificationService extends FirebaseMessagingService {
int boardId = -1; int boardId = -1;
String boardTitle = null; String boardTitle = null;
int topicId = Integer.parseInt(json.getString("topicId")); int topicId = Integer.parseInt(json.getString("topicId"));
if(remoteMessage.getFrom().contains("b")){ if (remoteMessage.getFrom().contains("b")) {
Timber.i("FCM BOARD type message detected."); Timber.i("FCM BOARD type message detected.");
SharedPreferences bookmarksFile = getSharedPreferences(BOOKMARKS_SHARED_PREFS, Context.MODE_PRIVATE); SharedPreferences bookmarksFile = getSharedPreferences(BOOKMARKS_SHARED_PREFS, Context.MODE_PRIVATE);
String bookmarkedTopicsString = bookmarksFile.getString(BOOKMARKED_TOPICS_KEY, null); String bookmarkedTopicsString = bookmarksFile.getString(BOOKMARKED_TOPICS_KEY, null);
if (bookmarkedTopicsString != null && matchExistsById(Bookmark.stringToArrayList(bookmarkedTopicsString), topicId)){ if (bookmarkedTopicsString != null && matchExistsById(Bookmark.stringToArrayList(bookmarkedTopicsString), topicId)) {
Timber.i("Board notification suppressed (already subscribed to topic)."); Timber.i("Board notification suppressed (already subscribed to topic).");
return; return;
} }
@ -76,12 +76,12 @@ public class NotificationService extends FirebaseMessagingService {
boardId = Integer.parseInt(json.getString("boardId")); boardId = Integer.parseInt(json.getString("boardId"));
String bookmarkedBoardsString = bookmarksFile.getString(BOOKMARKED_BOARDS_KEY, null); String bookmarkedBoardsString = bookmarksFile.getString(BOOKMARKED_BOARDS_KEY, null);
if (bookmarkedBoardsString != null){ if (bookmarkedBoardsString != null) {
ArrayList<Bookmark> boardBookmarks = Bookmark.stringToArrayList(bookmarkedBoardsString); ArrayList<Bookmark> boardBookmarks = Bookmark.stringToArrayList(bookmarkedBoardsString);
ArrayList<Integer> subBoardIds = getSubBoardIds(json.getString("boardIds"), boardId); ArrayList<Integer> subBoardIds = getSubBoardIds(json.getString("boardIds"), boardId);
//TODO: Also suppress if user has chosen to be notified only for direct children of boardId && !subBoardIds.isEmpty() //TODO: Also suppress if user has chosen to be notified only for direct children of boardId && !subBoardIds.isEmpty()
for(int subId:subBoardIds){ for (int subId : subBoardIds) {
if(matchExistsById(boardBookmarks, subId)){ if (matchExistsById(boardBookmarks, subId)) {
Timber.i("Board notification suppressed (already subscribed to a subBoard)."); Timber.i("Board notification suppressed (already subscribed to a subBoard).");
return; return;
} }
@ -98,7 +98,8 @@ public class NotificationService extends FirebaseMessagingService {
String poster = json.getString("poster"); String poster = json.getString("poster");
sendNotification(new PostNotification(postId, topicId, topicTitle, poster, boardId, boardTitle)); sendNotification(new PostNotification(postId, topicId, topicTitle, poster, boardId, boardTitle));
} else }
else
Timber.i("Notification suppressed (own userID)."); Timber.i("Notification suppressed (own userID).");
} catch (JSONException e) { } catch (JSONException e) {
Timber.e(e, "JSON Exception"); Timber.e(e, "JSON Exception");
@ -106,17 +107,17 @@ public class NotificationService extends FirebaseMessagingService {
} }
} }
private static ArrayList<Integer> getSubBoardIds(String boardIdsString, int boardId){ private static ArrayList<Integer> getSubBoardIds(String boardIdsString, int boardId) {
ArrayList<Integer> subBoardIds = new ArrayList<>(); ArrayList<Integer> subBoardIds = new ArrayList<>();
Pattern p = Pattern.compile("(\\d+)"); Pattern p = Pattern.compile("(\\d+)");
Matcher m = p.matcher(boardIdsString); Matcher m = p.matcher(boardIdsString);
boolean boardIdfound=false; boolean boardIdfound = false;
while (m.find()){ while (m.find()) {
int subBoardId = Integer.parseInt(m.group()); int subBoardId = Integer.parseInt(m.group());
if(boardIdfound) if (boardIdfound)
subBoardIds.add(subBoardId); subBoardIds.add(subBoardId);
else if(boardId==subBoardId) else if (boardId == subBoardId)
boardIdfound=true; boardIdfound = true;
} }
return subBoardIds; return subBoardIds;
} }
@ -154,7 +155,8 @@ public class NotificationService extends FirebaseMessagingService {
if (notificationsVibrateEnabled) { if (notificationsVibrateEnabled) {
if (notificationDefaultValues != -1) { if (notificationDefaultValues != -1) {
notificationDefaultValues |= Notification.DEFAULT_VIBRATE; notificationDefaultValues |= Notification.DEFAULT_VIBRATE;
} else { }
else {
notificationDefaultValues = Notification.DEFAULT_VIBRATE; notificationDefaultValues = Notification.DEFAULT_VIBRATE;
} }
@ -162,7 +164,8 @@ public class NotificationService extends FirebaseMessagingService {
if (notificationSoundUri == null) { if (notificationSoundUri == null) {
if (notificationDefaultValues != -1) { if (notificationDefaultValues != -1) {
notificationDefaultValues = Notification.DEFAULT_SOUND; notificationDefaultValues = Notification.DEFAULT_SOUND;
} else { }
else {
notificationDefaultValues |= Notification.DEFAULT_SOUND; notificationDefaultValues |= Notification.DEFAULT_SOUND;
} }
} }
@ -180,15 +183,15 @@ public class NotificationService extends FirebaseMessagingService {
int notificationId; int notificationId;
String contentText; String contentText;
if(isTopicNotification){ if (isTopicNotification) {
notificationId = postNotification.getTopicId(); notificationId = postNotification.getTopicId();
contentText = "New post by " + postNotification.getPoster(); contentText = "New post by " + postNotification.getPoster();
} }
else{ else {
// Using Cantor pairing function (plus the minus sign) for id uniqueness // Using Cantor pairing function (plus the minus sign) for id uniqueness
int k1 = postNotification.getTopicId(); int k1 = postNotification.getTopicId();
int k2 = postNotification.getBoardId(); int k2 = postNotification.getBoardId();
notificationId = -(((k1+k2)*(k1+k2+1))/2+k2); notificationId = -(((k1 + k2) * (k1 + k2 + 1)) / 2 + k2);
contentText = "New post in \"" + postNotification.getTopicTitle() + "\""; contentText = "New post in \"" + postNotification.getTopicTitle() + "\"";
} }
@ -198,7 +201,7 @@ public class NotificationService extends FirebaseMessagingService {
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();
@ -217,7 +220,7 @@ public class NotificationService extends FirebaseMessagingService {
.setGroup(GROUP_KEY) .setGroup(GROUP_KEY)
.addExtras(notificationExtras); .addExtras(notificationExtras);
if(isTopicNotification) if (isTopicNotification)
notificationBuilder.setContentTitle(postNotification.getTopicTitle()); notificationBuilder.setContentTitle(postNotification.getTopicTitle());
else else
@ -262,7 +265,7 @@ public class NotificationService extends FirebaseMessagingService {
// Since Android Oreo notification channel is needed. // Since Android Oreo notification channel is needed.
if (buildVersion >= Build.VERSION_CODES.O && notificationManager.getNotificationChannel(CHANNEL_ID) == null) if (buildVersion >= Build.VERSION_CODES.O && notificationManager.getNotificationChannel(CHANNEL_ID) == null)
notificationManager.createNotificationChannel(new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH)); notificationManager.createNotificationChannel(new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH));
notificationManager.notify(NEW_POST_TAG, notificationId, notificationBuilder.build()); notificationManager.notify(NEW_POST_TAG, notificationId, notificationBuilder.build());

15
app/src/main/java/gr/thmmy/mthmmy/services/UploadsReceiver.java

@ -87,7 +87,7 @@ public class UploadsReceiver extends UploadServiceBroadcastReceiver {
@Override @Override
public void onProgress(Context context, UploadInfo uploadInfo) { public void onProgress(Context context, UploadInfo uploadInfo) {
Timber.i("Upload in progress (id: %s)",uploadInfo.getUploadId()); Timber.i("Upload in progress (id: %s)", uploadInfo.getUploadId());
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP &&
uploadInfo.getUploadId().equals(dialogUploadID) && uploadInfo.getUploadId().equals(dialogUploadID) &&
uploadProgressDialog != null) { uploadProgressDialog != null) {
@ -127,7 +127,7 @@ public class UploadsReceiver extends UploadServiceBroadcastReceiver {
@Override @Override
public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse, public void onError(Context context, UploadInfo uploadInfo, ServerResponse serverResponse,
Exception exception) { Exception exception) {
Timber.i("Error while uploading (id: %s)",uploadInfo.getUploadId()); Timber.i("Error while uploading (id: %s)", uploadInfo.getUploadId());
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP &&
uploadInfo.getUploadId().equals(dialogUploadID) && uploadInfo.getUploadId().equals(dialogUploadID) &&
uploadProgressDialog != null) { uploadProgressDialog != null) {
@ -162,7 +162,8 @@ public class UploadsReceiver extends UploadServiceBroadcastReceiver {
uploadProgressDialog.dismiss(); uploadProgressDialog.dismiss();
} }
} }
} else { }
else {
cancelNotification(context, uploadInfo.getNotificationID()); cancelNotification(context, uploadInfo.getNotificationID());
Intent combinedActionsIntent = new Intent(UploadsReceiver.ACTION_COMBINED_UPLOAD); Intent combinedActionsIntent = new Intent(UploadsReceiver.ACTION_COMBINED_UPLOAD);
combinedActionsIntent.putExtra(UploadsReceiver.UPLOAD_ID_KEY, uploadInfo.getUploadId()); combinedActionsIntent.putExtra(UploadsReceiver.UPLOAD_ID_KEY, uploadInfo.getUploadId());
@ -183,15 +184,15 @@ public class UploadsReceiver extends UploadServiceBroadcastReceiver {
} }
String response = serverResponse.getBodyAsString(); String response = serverResponse.getBodyAsString();
if(response.contains("Η προσθήκη του αρχείου ήταν επιτυχημένη.")||response.contains("The upload was successful.")){ if (response.contains("Η προσθήκη του αρχείου ήταν επιτυχημένη.") || response.contains("The upload was successful.")) {
Timber.i("Upload completed successfully (id: %s)",uploadInfo.getUploadId()); Timber.i("Upload completed successfully (id: %s)", uploadInfo.getUploadId());
Toast.makeText(context.getApplicationContext(), "Upload completed successfully", Toast.LENGTH_SHORT).show(); Toast.makeText(context.getApplicationContext(), "Upload completed successfully", Toast.LENGTH_SHORT).show();
BaseApplication.getInstance().logFirebaseAnalyticsEvent("file_upload", null); BaseApplication.getInstance().logFirebaseAnalyticsEvent("file_upload", null);
} }
else { else {
MultipartUploadException multipartUploadException = new MultipartUploadException(response); MultipartUploadException multipartUploadException = new MultipartUploadException(response);
Timber.e(multipartUploadException); Timber.e(multipartUploadException);
onError(context,uploadInfo,serverResponse,multipartUploadException); onError(context, uploadInfo, serverResponse, multipartUploadException);
} }
if (storage == null) { if (storage == null) {
@ -224,7 +225,7 @@ public class UploadsReceiver extends UploadServiceBroadcastReceiver {
//UploadsReceiver.multipartUploadRetryIntent = multipartUploadRetryIntent; //UploadsReceiver.multipartUploadRetryIntent = multipartUploadRetryIntent;
} }
private void cancelNotification(Context context, int notificationId){ private void cancelNotification(Context context, int notificationId) {
NotificationManager notificationManager = (NotificationManager) context.getApplicationContext(). NotificationManager notificationManager = (NotificationManager) context.getApplicationContext().
getSystemService(Context.NOTIFICATION_SERVICE); getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) if (notificationManager != null)

3
app/src/main/java/gr/thmmy/mthmmy/session/InvalidSessionException.java

@ -1,7 +1,8 @@
package gr.thmmy.mthmmy.session; package gr.thmmy.mthmmy.session;
public class InvalidSessionException extends RuntimeException { public class InvalidSessionException extends RuntimeException {
public InvalidSessionException() {} public InvalidSessionException() {
}
public InvalidSessionException(String message) { public InvalidSessionException(String message) {
super(message); super(message);

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

@ -28,7 +28,7 @@ public class LogoutTask extends NetworkTask<Void> {
Keep in mind, server changes sesc at will over time for a given session! Keep in mind, server changes sesc at will over time for a given session!
*/ */
Parcel<Void> parcel = executeInBackground(indexUrl.toString()); Parcel<Void> parcel = executeInBackground(indexUrl.toString());
if(parcel.getResultCode() == NetworkResultCodes.SUCCESSFUL) if (parcel.getResultCode() == NetworkResultCodes.SUCCESSFUL)
return executeInBackground(logoutLink); // Now we will attempt to logout return executeInBackground(logoutLink); // Now we will attempt to logout
else return parcel; else return parcel;
} }
@ -36,14 +36,14 @@ public class LogoutTask extends NetworkTask<Void> {
@Override @Override
protected Void performTask(Document document, Response response) { protected Void performTask(Document document, Response response) {
try { try {
if(logoutLink==null) if (logoutLink == null)
logoutLink = extractLogoutLink(document); logoutLink = extractLogoutLink(document);
else { // Just for logging purposes else { // Just for logging purposes
Elements sessionVerificationFailed = document.select("td:containsOwn(Session " + Elements sessionVerificationFailed = document.select("td:containsOwn(Session " +
"verification failed. Please try logging out and back in again, and then try " + "verification failed. Please try logging out and back in again, and then try " +
"again.), td:containsOwn(Η επαλήθευση συνόδου απέτυχε. Παρακαλούμε κάντε " + "again.), td:containsOwn(Η επαλήθευση συνόδου απέτυχε. Παρακαλούμε κάντε " +
"αποσύνδεση, επανασύνδεση και ξαναδοκιμάστε.)"); "αποσύνδεση, επανασύνδεση και ξαναδοκιμάστε.)");
if(!sessionVerificationFailed.isEmpty()){ if (!sessionVerificationFailed.isEmpty()) {
Timber.i("Logout failed (invalid session)"); Timber.i("Logout failed (invalid session)");
throw new InvalidSessionException(); throw new InvalidSessionException();
} }
@ -73,7 +73,7 @@ public class LogoutTask extends NetworkTask<Void> {
return NetworkResultCodes.SUCCESSFUL; return NetworkResultCodes.SUCCESSFUL;
} }
private String extractLogoutLink(Document document){ private String extractLogoutLink(Document document) {
Elements logoutLink = document.select("a[href^=" + baseLogoutLink + "]"); Elements logoutLink = document.select("a[href^=" + baseLogoutLink + "]");
if (!logoutLink.isEmpty()) { if (!logoutLink.isEmpty()) {

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

@ -22,7 +22,7 @@ public class MarkAsReadTask extends NetworkTask<Void> {
@Override @Override
protected Parcel<Void> doInBackground(String... input) { protected Parcel<Void> doInBackground(String... input) {
Parcel<Void> parcel = executeInBackground(unreadUrl.toString()); Parcel<Void> parcel = executeInBackground(unreadUrl.toString());
if(parcel.getResultCode() == NetworkResultCodes.SUCCESSFUL) if (parcel.getResultCode() == NetworkResultCodes.SUCCESSFUL)
return executeInBackground(markAsReadLink); return executeInBackground(markAsReadLink);
else return parcel; else return parcel;
} }
@ -34,9 +34,9 @@ public class MarkAsReadTask extends NetworkTask<Void> {
"verification failed. Please try logging out and back in again, and then try " + "verification failed. Please try logging out and back in again, and then try " +
"again.), td:containsOwn(Η επαλήθευση συνόδου απέτυχε. Παρακαλούμε κάντε " + "again.), td:containsOwn(Η επαλήθευση συνόδου απέτυχε. Παρακαλούμε κάντε " +
"αποσύνδεση, επανασύνδεση και ξαναδοκιμάστε.)"); "αποσύνδεση, επανασύνδεση και ξαναδοκιμάστε.)");
if(!sessionVerificationFailed.isEmpty()) if (!sessionVerificationFailed.isEmpty())
throw new InvalidSessionException(); throw new InvalidSessionException();
if(markAsReadLink==null) if (markAsReadLink == null)
markAsReadLink = extractMarkAsReadLink(document); markAsReadLink = extractMarkAsReadLink(document);
} catch (InvalidSessionException ise) { } catch (InvalidSessionException ise) {
@ -52,7 +52,7 @@ public class MarkAsReadTask extends NetworkTask<Void> {
return NetworkResultCodes.SUCCESSFUL; return NetworkResultCodes.SUCCESSFUL;
} }
private String extractMarkAsReadLink(Document document){ private String extractMarkAsReadLink(Document document) {
Elements markAllAsReadLink = document.select("a[href^=" + baseMarkAllAsReadLink + "]"); Elements markAllAsReadLink = document.select("a[href^=" + baseMarkAllAsReadLink + "]");
if (!markAllAsReadLink.isEmpty()) { if (!markAllAsReadLink.isEmpty()) {

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

@ -125,7 +125,8 @@ public class SessionManager {
editor.apply(); editor.apply();
return SUCCESS; return SUCCESS;
} else { }
else {
Timber.i("Login failed."); Timber.i("Login failed.");
//Investigate login failure //Investigate login failure
@ -156,7 +157,7 @@ public class SessionManager {
Timber.i("Login InterruptedIOException"); //users cancels LoginTask Timber.i("Login InterruptedIOException"); //users cancels LoginTask
return CANCELLED; return CANCELLED;
} catch (IOException e) { } catch (IOException e) {
Timber.w(e ,"Login IOException"); Timber.w(e, "Login IOException");
return CONNECTION_ERROR; return CONNECTION_ERROR;
} catch (Exception e) { } catch (Exception e) {
Timber.e(e, "Login Exception (other)"); Timber.e(e, "Login Exception (other)");
@ -203,8 +204,8 @@ public class SessionManager {
public Cookie getThmmyCookie() { public Cookie getThmmyCookie() {
List<Cookie> cookieList = cookieJar.loadForRequest(indexUrl); List<Cookie> cookieList = cookieJar.loadForRequest(indexUrl);
for(Cookie cookie: cookieList) { for (Cookie cookie : cookieList) {
if(cookie.name().equals("THMMYgrC00ki3")) if (cookie.name().equals("THMMYgrC00ki3"))
return cookie; return cookie;
} }
return null; return null;
@ -225,8 +226,8 @@ public class SessionManager {
//------------------------------------ OTHER ------------------------------------------- //------------------------------------ OTHER -------------------------------------------
private boolean validateRetrievedCookies() { private boolean validateRetrievedCookies() {
List<Cookie> cookieList = cookieJar.loadForRequest(indexUrl); List<Cookie> cookieList = cookieJar.loadForRequest(indexUrl);
for(Cookie cookie: cookieList) { for (Cookie cookie : cookieList) {
if(cookie.name().equals("THMMYgrC00ki3")) if (cookie.name().equals("THMMYgrC00ki3"))
return true; return true;
} }
return false; return false;
@ -246,7 +247,7 @@ public class SessionManager {
cookiePersistor.saveAll(cookieList); cookiePersistor.saveAll(cookieList);
} }
private void setLoginScreenAsDefault(boolean b){ private void setLoginScreenAsDefault(boolean b) {
sessionSharedPrefs.edit().putBoolean(LOGIN_SCREEN_AS_DEFAULT, b).apply(); sessionSharedPrefs.edit().putBoolean(LOGIN_SCREEN_AS_DEFAULT, b).apply();
} }
@ -263,7 +264,8 @@ public class SessionManager {
Matcher matcher = pattern.matcher(txt); Matcher matcher = pattern.matcher(txt);
if (matcher.find()) if (matcher.find())
userName = matcher.group(1); userName = matcher.group(1);
} else { }
else {
//Helios_Multi and SMF_oneBlue //Helios_Multi and SMF_oneBlue
user = doc.select("td.smalltext[width=100%] b"); user = doc.select("td.smalltext[width=100%] b");
if (user.size() == 1) if (user.size() == 1)
@ -279,12 +281,12 @@ public class SessionManager {
if (userName != null && !userName.isEmpty()) if (userName != null && !userName.isEmpty())
return userName; return userName;
Timber.e(new ParseException("Parsing failed(username extraction)"),"ParseException"); Timber.e(new ParseException("Parsing failed(username extraction)"), "ParseException");
return "User"; //return a default username return "User"; //return a default username
} }
private int extractUserId(@NonNull Document doc) { private int extractUserId(@NonNull Document doc) {
try{ try {
Elements elements = doc.select("a:containsOwn(Εμφάνιση των μηνυμάτων σας), a:containsOwn(Show own posts)"); Elements elements = doc.select("a:containsOwn(Εμφάνιση των μηνυμάτων σας), a:containsOwn(Show own posts)");
if (elements.size() == 1) { if (elements.size() == 1) {
String link = elements.first().attr("href"); String link = elements.first().attr("href");
@ -295,9 +297,9 @@ public class SessionManager {
return Integer.parseInt(matcher.group(1)); return Integer.parseInt(matcher.group(1));
} }
} catch (Exception e) { } catch (Exception e) {
Timber.e(new ParseException("Parsing failed(user id extraction)"),"ParseException"); Timber.e(new ParseException("Parsing failed(user id extraction)"), "ParseException");
} }
Timber.e(new ParseException("Parsing failed(user id extraction)"),"ParseException"); Timber.e(new ParseException("Parsing failed(user id extraction)"), "ParseException");
return -1; return -1;
} }

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

@ -10,8 +10,8 @@ import static android.text.format.DateUtils.YEAR_IN_MILLIS;
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;
private static final long DECADE_IN_MILLIS = 10*YEAR_IN_MILLIS; private static final long DECADE_IN_MILLIS = 10 * YEAR_IN_MILLIS;
@VisibleForTesting @VisibleForTesting
public static String getRelativeTimeSpanString(long time) { public static String getRelativeTimeSpanString(long time) {
@ -21,51 +21,55 @@ public class DateTimeUtils {
long duration = Math.abs(now - time); long duration = Math.abs(now - time);
String format; String format;
long count, mod; long count, mod;
if(duration < 45*SECOND_IN_MILLIS) if (duration < 45 * SECOND_IN_MILLIS)
return "just now"; return "just now";
else if (duration < 45*MINUTE_IN_MILLIS) { else if (duration < 45 * MINUTE_IN_MILLIS) {
count = duration/MINUTE_IN_MILLIS; count = duration / MINUTE_IN_MILLIS;
mod = duration % MINUTE_IN_MILLIS; mod = duration % MINUTE_IN_MILLIS;
if(mod >= 30*SECOND_IN_MILLIS) if (mod >= 30 * SECOND_IN_MILLIS)
count += 1; count += 1;
format = "%dm"; format = "%dm";
} else if (duration < 22*HOUR_IN_MILLIS) { }
count = duration/HOUR_IN_MILLIS; else if (duration < 22 * HOUR_IN_MILLIS) {
count = duration / HOUR_IN_MILLIS;
format = "%dh"; format = "%dh";
mod = (duration%HOUR_IN_MILLIS)/MINUTE_IN_MILLIS; mod = (duration % HOUR_IN_MILLIS) / MINUTE_IN_MILLIS;
if(count<3 && mod>9 && mod<51){ if (count < 3 && mod > 9 && mod < 51) {
if(count==0) if (count == 0)
format = mod +"m"; format = mod + "m";
else else
format = format + " " + mod +"m"; format = format + " " + mod + "m";
} }
else if(mod >= 30) else if (mod >= 30)
count += 1; count += 1;
} else if (duration < 26*DAY_IN_MILLIS) { }
count = duration/DAY_IN_MILLIS; else if (duration < 26 * DAY_IN_MILLIS) {
count = duration / DAY_IN_MILLIS;
format = "%dd"; format = "%dd";
mod = duration % DAY_IN_MILLIS; mod = duration % DAY_IN_MILLIS;
if(mod >= 12*HOUR_IN_MILLIS) if (mod >= 12 * HOUR_IN_MILLIS)
count += 1; count += 1;
} else if (duration < 320*DAY_IN_MILLIS) { }
count = duration/MONTH_IN_MILLIS; else if (duration < 320 * DAY_IN_MILLIS) {
count = duration / MONTH_IN_MILLIS;
format = "%d month"; format = "%d month";
mod = duration % MONTH_IN_MILLIS; mod = duration % MONTH_IN_MILLIS;
if(mod >= 15*DAY_IN_MILLIS) if (mod >= 15 * DAY_IN_MILLIS)
count += 1; count += 1;
if(count>1) if (count > 1)
format = format + 's'; format = format + 's';
} else if (duration < DECADE_IN_MILLIS) { }
count = duration/YEAR_IN_MILLIS; else if (duration < DECADE_IN_MILLIS) {
count = duration / YEAR_IN_MILLIS;
format = "%d year"; format = "%d year";
mod = duration % YEAR_IN_MILLIS; mod = duration % YEAR_IN_MILLIS;
if(mod >= 183*DAY_IN_MILLIS) if (mod >= 183 * DAY_IN_MILLIS)
count += 1; count += 1;
if(count>1) if (count > 1)
format = format + 's'; format = format + 's';
} }
else else
return past ? "a long time ago": "in the distant future"; return past ? "a long time ago" : "in the distant future";
format = past ? format : "in " + format; format = past ? format : "in " + format;
return String.format(format, (int) count); return String.format(format, (int) count);

5
app/src/main/java/gr/thmmy/mthmmy/utils/ExternalAsyncTask.java

@ -52,7 +52,8 @@ public abstract class ExternalAsyncTask<U, V> extends AsyncTask<U, Void, V> {
this.onTaskFinishedListener = onTaskFinishedListener; this.onTaskFinishedListener = onTaskFinishedListener;
} }
public ExternalAsyncTask() { } public ExternalAsyncTask() {
}
public void setOnTaskStartedListener(OnTaskStartedListener onTaskStartedListener) { public void setOnTaskStartedListener(OnTaskStartedListener onTaskStartedListener) {
this.onTaskStartedListener = onTaskStartedListener; this.onTaskStartedListener = onTaskStartedListener;
@ -78,7 +79,7 @@ public abstract class ExternalAsyncTask<U, V> extends AsyncTask<U, Void, V> {
void onTaskFinished(V result); void onTaskFinished(V result);
} }
public boolean isRunning(){ public boolean isRunning() {
return getStatus() == AsyncTask.Status.RUNNING; return getStatus() == AsyncTask.Status.RUNNING;
} }
} }

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

@ -41,7 +41,8 @@ public class FileUtils {
} }
if (filename.toLowerCase().endsWith(".tar.gz")) { if (filename.toLowerCase().endsWith(".tar.gz")) {
fileExtension = filename.substring(filename.length() - 7); fileExtension = filename.substring(filename.length() - 7);
} else { }
else {
fileExtension = filename.substring(filename.lastIndexOf(".")); fileExtension = filename.substring(filename.lastIndexOf("."));
} }

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

@ -25,13 +25,15 @@ import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME; import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
public class HTMLUtils { public class HTMLUtils {
private HTMLUtils() {} private HTMLUtils() {
}
public static SpannableStringBuilder getSpannableFromHtml(Activity activity, String html) { public static SpannableStringBuilder getSpannableFromHtml(Activity activity, String html) {
CharSequence sequence; CharSequence sequence;
if (Build.VERSION.SDK_INT >= 24) { if (Build.VERSION.SDK_INT >= 24) {
sequence = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY); sequence = Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY);
} else { }
else {
//noinspection deprecation //noinspection deprecation
sequence = Html.fromHtml(html); sequence = Html.fromHtml(html);
} }
@ -59,7 +61,8 @@ public class HTMLUtils {
intent.putExtras(extras); intent.putExtras(extras);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent); context.startActivity(intent);
} else if (target.is(ThmmyPage.PageCategory.PROFILE)) { }
else if (target.is(ThmmyPage.PageCategory.PROFILE)) {
Intent intent = new Intent(context, ProfileActivity.class); Intent intent = new Intent(context, ProfileActivity.class);
Bundle extras = new Bundle(); Bundle extras = new Bundle();
extras.putString(BUNDLE_PROFILE_URL, span.getURL()); extras.putString(BUNDLE_PROFILE_URL, span.getURL());
@ -68,7 +71,8 @@ public class HTMLUtils {
intent.putExtras(extras); intent.putExtras(extras);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent); context.startActivity(intent);
} else if (target.is(ThmmyPage.PageCategory.INDEX)) { }
else if (target.is(ThmmyPage.PageCategory.INDEX)) {
Intent intent = new Intent(context, MainActivity.class); Intent intent = new Intent(context, MainActivity.class);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent); context.startActivity(intent);

6
app/src/main/java/gr/thmmy/mthmmy/utils/LaunchType.java

@ -24,11 +24,13 @@ public class LaunchType {
if (currentVersionCode == savedVersionCode) { if (currentVersionCode == savedVersionCode) {
//This is just a normal run //This is just a normal run
return LAUNCH_TYPE.NORMAL_LAUNCH; return LAUNCH_TYPE.NORMAL_LAUNCH;
} else if (savedVersionCode == notThere) { }
else if (savedVersionCode == notThere) {
//Updates the shared preferences with the current version code //Updates the shared preferences with the current version code
prefs.edit().putInt(PREF_VERSION_CODE_KEY, currentVersionCode).apply(); prefs.edit().putInt(PREF_VERSION_CODE_KEY, currentVersionCode).apply();
return LAUNCH_TYPE.FIRST_LAUNCH_EVER; return LAUNCH_TYPE.FIRST_LAUNCH_EVER;
} else if (currentVersionCode > savedVersionCode) { }
else if (currentVersionCode > savedVersionCode) {
//Updates the shared preferences with the current version code //Updates the shared preferences with the current version code
prefs.edit().putInt(PREF_VERSION_CODE_KEY, currentVersionCode).apply(); prefs.edit().putInt(PREF_VERSION_CODE_KEY, currentVersionCode).apply();
return LAUNCH_TYPE.FIRST_LAUNCH_AFTER_UPDATE; return LAUNCH_TYPE.FIRST_LAUNCH_AFTER_UPDATE;

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

@ -86,7 +86,7 @@ public class TakePhoto {
File imageFolder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) + File imageFolder = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM) +
File.separator + "mTHMMY"); File.separator + "mTHMMY");
if (!imageFolder.exists()&&!imageFolder.mkdirs()) { if (!imageFolder.exists() && !imageFolder.mkdirs()) {
Timber.w("Photos folder build returned false in %s", TakePhoto.class.getSimpleName()); Timber.w("Photos folder build returned false in %s", TakePhoto.class.getSimpleName());
Toast.makeText(context, "Couldn't create photos directory", Toast.LENGTH_SHORT).show(); Toast.makeText(context, "Couldn't create photos directory", Toast.LENGTH_SHORT).show();
return null; return null;

3
app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReporter.java

@ -13,7 +13,8 @@ import gr.thmmy.mthmmy.utils.parsing.ParseHelpers;
public class CrashReporter { public class CrashReporter {
private static final int STRING_BATCH_LENGTH = 250; private static final int STRING_BATCH_LENGTH = 250;
private CrashReporter() {} private CrashReporter() {
}
public static void reportForumInfo(Document document) { public static void reportForumInfo(Document document) {
ParseHelpers.Theme theme = ParseHelpers.parseTheme(document); ParseHelpers.Theme theme = ParseHelpers.parseTheme(document);

9
app/src/main/java/gr/thmmy/mthmmy/utils/crashreporting/CrashReportingTree.java

@ -9,7 +9,8 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics;
import timber.log.Timber.DebugTree; import timber.log.Timber.DebugTree;
public class CrashReportingTree extends DebugTree { public class CrashReportingTree extends DebugTree {
private FirebaseCrashlytics firebaseCrashlytics; private FirebaseCrashlytics firebaseCrashlytics;
public CrashReportingTree() { public CrashReportingTree() {
super(); super();
firebaseCrashlytics = FirebaseCrashlytics.getInstance(); firebaseCrashlytics = FirebaseCrashlytics.getInstance();
@ -27,15 +28,15 @@ public class CrashReportingTree extends DebugTree {
level = 'I'; level = 'I';
else if (priority == Log.WARN) else if (priority == Log.WARN)
level = 'W'; level = 'W';
else if(priority == Log.ERROR) else if (priority == Log.ERROR)
level = 'E'; level = 'E';
else else
level = 'A'; level = 'A';
firebaseCrashlytics.log(level + "/" + tag + ": " + message); firebaseCrashlytics.log(level + "/" + tag + ": " + message);
if(priority == Log.ERROR) { if (priority == Log.ERROR) {
if (t!=null) if (t != null)
firebaseCrashlytics.recordException(t); firebaseCrashlytics.recordException(t);
else else
firebaseCrashlytics.recordException(new Exception(message)); firebaseCrashlytics.recordException(new Exception(message));

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

@ -36,7 +36,8 @@ public abstract class NetworkTask<T> extends ExternalAsyncTask<String, Parcel<T>
this.onNetworkTaskFinishedListener = onNetworkTaskFinishedListener; this.onNetworkTaskFinishedListener = onNetworkTaskFinishedListener;
} }
public NetworkTask() {} public NetworkTask() {
}
@Override @Override
protected Parcel<T> doInBackground(String... input) { protected Parcel<T> doInBackground(String... input) {
@ -85,7 +86,7 @@ public abstract class NetworkTask<T> extends ExternalAsyncTask<String, Parcel<T>
// BaseApplication.getInstance().getSessionManager().clearSessionData(); // BaseApplication.getInstance().getSessionManager().clearSessionData();
// BaseApplication.getInstance().getSessionManager().guestLogin(); // BaseApplication.getInstance().getSessionManager().guestLogin();
return new Parcel<>(SessionManager.INVALID_SESSION, null); return new Parcel<>(SessionManager.INVALID_SESSION, null);
}catch (Exception e) { } catch (Exception e) {
Timber.e(e); Timber.e(e);
return new Parcel<>(NetworkResultCodes.PERFORM_TASK_ERROR, null); return new Parcel<>(NetworkResultCodes.PERFORM_TASK_ERROR, null);
} }

5
app/src/main/java/gr/thmmy/mthmmy/utils/parsing/NewParseTask.java

@ -17,7 +17,8 @@ public abstract class NewParseTask<T> extends NetworkTask<T> {
super(onTaskStartedListener, onParseTaskFinishedListener); super(onTaskStartedListener, onParseTaskFinishedListener);
} }
public NewParseTask() {} public NewParseTask() {
}
@Override @Override
protected final T performTask(Document document, Response response) { protected final T performTask(Document document, Response response) {
@ -30,5 +31,5 @@ public abstract class NewParseTask<T> extends NetworkTask<T> {
} }
} }
protected abstract T parse (Document document, Response response) throws ParseException; protected abstract T parse(Document document, Response response) throws ParseException;
} }

3
app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseException.java

@ -4,7 +4,8 @@ package gr.thmmy.mthmmy.utils.parsing;
* Use ParseException for errors while parsing. * Use ParseException for errors while parsing.
*/ */
public class ParseException extends RuntimeException { public class ParseException extends RuntimeException {
public ParseException() {} public ParseException() {
}
public ParseException(String message) { public ParseException(String message) {
super(message); super(message);

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

@ -56,7 +56,8 @@ public class ParseHelpers {
if (welcomingGuest != null && welcomingGuest.text().contains("Welcome")) if (welcomingGuest != null && welcomingGuest.text().contains("Welcome"))
return ENGLISH; return ENGLISH;
return PAGE_INCOMPLETE; return PAGE_INCOMPLETE;
} else if (welcoming.text().contains("Καλώς ορίσατε")) return GREEK; }
else if (welcoming.text().contains("Καλώς ορίσατε")) return GREEK;
else if (welcoming.text().contains("Hey")) return ENGLISH; else if (welcoming.text().contains("Hey")) return ENGLISH;
else return UNKNOWN_LANGUAGE; else return UNKNOWN_LANGUAGE;
} }
@ -72,7 +73,7 @@ public class ParseHelpers {
public static Theme parseTheme(Document page) { public static Theme parseTheme(Document page) {
Element stylesheet = page.select("link[rel=stylesheet]").first(); Element stylesheet = page.select("link[rel=stylesheet]").first();
if(stylesheet!=null){ if (stylesheet != null) {
if (stylesheet.attr("href").contains("scribbles2")) if (stylesheet.attr("href").contains("scribbles2"))
return Theme.SCRIBBLES2; return Theme.SCRIBBLES2;
else if (stylesheet.attr("href").contains("helios_multi")) else if (stylesheet.attr("href").contains("helios_multi"))
@ -168,7 +169,7 @@ public class ParseHelpers {
+ "https://img.youtube.com/vi/" + "https://img.youtube.com/vi/"
+ videoId + videoId
+ "/default.jpg');\"></a></div>" + "/default.jpg');\"></a></div>"
); );
++counter; ++counter;
} }
return fixed; return fixed;

7
app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ParseTask.java

@ -21,14 +21,17 @@ import timber.log.Timber;
*/ */
public abstract class ParseTask extends AsyncTask<String, Void, ParseTask.ResultCode> { public abstract class ParseTask extends AsyncTask<String, Void, ParseTask.ResultCode> {
protected String url; protected String url;
public enum ResultCode { public enum ResultCode {
SUCCESS, PARSING_ERROR, NETWORK_ERROR, OTHER_ERROR SUCCESS, PARSING_ERROR, NETWORK_ERROR, OTHER_ERROR
} }
protected abstract void parse (Document document) throws ParseException; protected abstract void parse(Document document) throws ParseException;
protected abstract void postExecution(ParseTask.ResultCode result); //ResultCode.NETWORK_ERROR is handled automatically protected abstract void postExecution(ParseTask.ResultCode result); //ResultCode.NETWORK_ERROR is handled automatically
protected void postParsing (){} protected void postParsing() {
}
protected Request prepareRequest(String... params) { protected Request prepareRequest(String... params) {
url = params[0]; url = params[0];

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

@ -5,6 +5,8 @@ import androidx.annotation.VisibleForTesting;
import org.joda.time.DateTime; import org.joda.time.DateTime;
import org.joda.time.DateTimeUtils; import org.joda.time.DateTimeUtils;
import org.joda.time.DateTimeZone; import org.joda.time.DateTimeZone;
import org.joda.time.IllegalInstantException;
import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter; import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.DateTimeFormatterBuilder; import org.joda.time.format.DateTimeFormatterBuilder;
@ -39,9 +41,10 @@ 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);
String originalDateTime = thmmyDateTime; String originalDateTime = thmmyDateTime;
DateTimeZone dtz = getDtz(); DateTimeZone dtz = getDtz();
@ -50,61 +53,70 @@ public class ThmmyDateTimeParser {
thmmyDateTime = purifyTodayDateTime(thmmyDateTime); thmmyDateTime = purifyTodayDateTime(thmmyDateTime);
// Add today's date for the first two cases // Add today's date for the first two cases
if(thmmyDateTime.charAt(2)==':') if (thmmyDateTime.charAt(2) == ':')
thmmyDateTime = (new DateTime()).toString("MMMM d, Y, ") + thmmyDateTime; thmmyDateTime = (new DateTime()).toString("MMMM d, Y, ") + thmmyDateTime;
// Don't even ask // Don't even ask
if(thmmyDateTime.contains("am")) if (thmmyDateTime.contains("am"))
thmmyDateTime = thmmyDateTime.replaceAll("\\s00:"," 12:"); thmmyDateTime = thmmyDateTime.replaceAll("\\s00:", " 12:");
// For the stupid format 23:54:12 pm // For the stupid format 23:54:12 pm
Matcher matcher = pattern.matcher(thmmyDateTime); Matcher matcher = pattern.matcher(thmmyDateTime);
if (matcher.find()) if (matcher.find())
thmmyDateTime = thmmyDateTime.replaceAll("\\spm",""); thmmyDateTime = thmmyDateTime.replaceAll("\\spm", "");
DateTime dateTime; DateTime dateTime;
try{ LocalDateTime localDateTime;
dateTime=formatter.withZone(dtz).withLocale(englishLocale).parseDateTime(thmmyDateTime); try {
} localDateTime = formatter.withLocale(englishLocale).parseLocalDateTime(thmmyDateTime);
catch (IllegalArgumentException e1){ } catch (IllegalArgumentException e1) {
Timber.v("Parsing DateTime %s using English Locale failed.", thmmyDateTime); Timber.v("Parsing DateTime %s using English Locale failed.", thmmyDateTime);
try{ try {
DateFormatSymbols dfs = DateTimeUtils.getDateFormatSymbols(greekLocale); DateFormatSymbols dfs = DateTimeUtils.getDateFormatSymbols(greekLocale);
thmmyDateTime = thmmyDateTime.replace("am",dfs.getAmPmStrings()[0]); thmmyDateTime = thmmyDateTime.replace("am", dfs.getAmPmStrings()[0]);
thmmyDateTime = thmmyDateTime.replace("pm",dfs.getAmPmStrings()[1]); thmmyDateTime = thmmyDateTime.replace("pm", dfs.getAmPmStrings()[1]);
Timber.v("Attempting to parse DateTime %s using Greek Locale...", thmmyDateTime); Timber.v("Attempting to parse DateTime %s using Greek Locale...", thmmyDateTime);
dateTime=formatter.withZone(dtz).withLocale(greekLocale).parseDateTime(thmmyDateTime); localDateTime = formatter.withLocale(greekLocale).parseLocalDateTime(thmmyDateTime);
} } catch (IllegalArgumentException e2) {
catch (IllegalArgumentException e2){ Timber.v("Parsing DateTime %s using Greek Locale failed too.", thmmyDateTime);
Timber.d("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 %s to timestamp!", originalDateTime);
return null; return null;
} }
} }
// Ensure DST time overlaps/ gaps are handled properly
try{
// For autumn overlaps
dateTime = localDateTime.toDateTime(dtz).withEarlierOffsetAtOverlap();
} catch (IllegalInstantException e2) {
// For spring gaps
dateTime = localDateTime.plusHours(1).toDateTime(dtz);
}
String timestamp = Long.toString(dateTime.getMillis()); String timestamp = Long.toString(dateTime.getMillis());
Timber.v("DateTime %s was converted to %s, or %s", originalDateTime, timestamp, dateTime.toString()); Timber.v("DateTime %s was converted to %s, or %s", originalDateTime, timestamp, dateTime.toString());
return timestamp; return timestamp;
} }
public static String simplifyDateTime(String dateTime){ public static String simplifyDateTime(String dateTime) {
return removeSeconds(purifyTodayDateTime(dateTime)); return removeSeconds(purifyTodayDateTime(dateTime));
} }
// Converts e.g. Today at 12:16:48 -> 12:16:48, but October 03, 2019, 16:40:18 remains as is // Converts e.g. Today at 12:16:48 -> 12:16:48, but October 03, 2019, 16:40:18 remains as is
@VisibleForTesting @VisibleForTesting
static String purifyTodayDateTime(String dateTime){ static String purifyTodayDateTime(String dateTime) {
return dateTime.replaceAll("(Today at |Σήμερα στις )(.+)", "$2"); return dateTime.replaceAll("(Today at |Σήμερα στις )(.+)", "$2");
} }
// Converts e.g. 12:16:48 -> 12:16, October 03, 2019, 16:40:18 -> 12:16 October 03, 2019, 16:40 // Converts e.g. 12:16:48 -> 12:16, October 03, 2019, 16:40:18 -> 12:16 October 03, 2019, 16:40
private static String removeSeconds(String dateTime){ private static String removeSeconds(String dateTime) {
return dateTime.replaceAll("(.*):\\d+($|\\s.*)", "$1$2"); return dateTime.replaceAll("(.*):\\d+($|\\s.*)", "$1$2");
} }
@VisibleForTesting @VisibleForTesting
private static DateTimeZone getDtz(){ private static DateTimeZone getDtz() {
if(!BaseApplication.getInstance().getSessionManager().isLoggedIn()) if (!BaseApplication.getInstance().getSessionManager().isLoggedIn())
return DateTimeZone.forID("Europe/Athens"); return DateTimeZone.forID("Europe/Athens");
else else
return DateTimeZone.getDefault(); return DateTimeZone.getDefault();

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

@ -138,7 +138,8 @@ public class ThmmyParser {
if (separatorIndex > 0) { if (separatorIndex > 0) {
attribute = startTag.substring(separatorIndex); attribute = startTag.substring(separatorIndex);
name = startTag.substring(0, separatorIndex); name = startTag.substring(0, separatorIndex);
} else }
else
name = startTag; name = startTag;
if (name.startsWith("/")) { if (name.startsWith("/")) {
@ -177,7 +178,8 @@ public class ThmmyParser {
attribute = fullAttribute.substring(1, equalsIndex); attribute = fullAttribute.substring(1, equalsIndex);
attributeValue = fullAttribute.substring(equalsIndex + 2, fullAttribute.length() - 1); attributeValue = fullAttribute.substring(equalsIndex + 2, fullAttribute.length() - 1);
name = startTag.substring(0, separatorIndex); name = startTag.substring(0, separatorIndex);
} else }
else
name = startTag; name = startTag;
if (name.startsWith("/")) { if (name.startsWith("/")) {

2
app/src/main/java/gr/thmmy/mthmmy/utils/ui/CenterVerticalSpan.java

@ -15,7 +15,7 @@ public class CenterVerticalSpan extends ReplacementSpan {
} }
@Override @Override
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom,@NonNull Paint paint) { public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
text = text.subSequence(start, end); text = text.subSequence(start, end);
Rect charSize = new Rect(); Rect charSize = new Rect();
paint.getTextBounds(text.toString(), 0, 1, charSize); paint.getTextBounds(text.toString(), 0, 1, charSize);

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

@ -20,7 +20,7 @@ import timber.log.Timber;
import static android.content.Context.CLIPBOARD_SERVICE; 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"};
private Context context; private Context context;
@ -32,7 +32,7 @@ public class ImageDownloadDialogBuilder extends AlertDialog.Builder{
this.imageURL = imageURL; this.imageURL = imageURL;
setItems(colors, (dialog, which) -> { setItems(colors, (dialog, which) -> {
if(which == 0) if (which == 0)
copyUrlToClipboard(); copyUrlToClipboard();
else { else {
try { try {
@ -46,11 +46,11 @@ public class ImageDownloadDialogBuilder extends AlertDialog.Builder{
}); });
} }
private void copyUrlToClipboard(){ private void copyUrlToClipboard() {
ClipboardManager clipboard = (ClipboardManager) BaseApplication.getInstance().getSystemService(CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) BaseApplication.getInstance().getSystemService(CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("ReactiveWebViewCopiedText", imageURL); ClipData clip = ClipData.newPlainText("ReactiveWebViewCopiedText", imageURL);
clipboard.setPrimaryClip(clip); clipboard.setPrimaryClip(clip);
Toast.makeText(BaseApplication.getInstance().getApplicationContext(),context.getString(R.string.link_copied_msg),Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), context.getString(R.string.link_copied_msg), Toast.LENGTH_SHORT).show();
} }
private BaseActivity getBaseActivity() { private BaseActivity getBaseActivity() {
@ -58,7 +58,7 @@ public class ImageDownloadDialogBuilder extends AlertDialog.Builder{
while (baseActivityContext instanceof ContextWrapper) { while (baseActivityContext instanceof ContextWrapper) {
if (context instanceof BaseActivity) if (context instanceof BaseActivity)
return (BaseActivity) context; return (BaseActivity) context;
baseActivityContext = ((ContextWrapper)context).getBaseContext(); baseActivityContext = ((ContextWrapper) context).getBaseContext();
} }
return null; return null;
} }

3
app/src/main/java/gr/thmmy/mthmmy/utils/ui/ScrollAwareFABBehavior.java

@ -45,7 +45,8 @@ public class ScrollAwareFABBehavior extends CoordinatorLayout.Behavior<FloatingA
fab.setVisibility(View.INVISIBLE); fab.setVisibility(View.INVISIBLE);
} }
}); });
} else if (child.getTag() != null && (boolean) child.getTag() && (dyConsumed < 0 || }
else if (child.getTag() != null && (boolean) child.getTag() && (dyConsumed < 0 ||
!target.canScrollVertically(-1) && dyUnconsumed < -50)) { !target.canScrollVertically(-1) && dyUnconsumed < -50)) {
child.show(new FloatingActionButton.OnVisibilityChangedListener() { child.show(new FloatingActionButton.OnVisibilityChangedListener() {
@Override @Override

3
app/src/main/java/gr/thmmy/mthmmy/utils/ui/ScrollAwareLinearBehavior.java

@ -45,7 +45,8 @@ public class ScrollAwareLinearBehavior extends CoordinatorLayout.Behavior<View>
if (bottomNavBar.getVisibility() == View.VISIBLE && (dyConsumed > 0 if (bottomNavBar.getVisibility() == View.VISIBLE && (dyConsumed > 0
|| (!target.canScrollVertically(-1) && dyConsumed == 0 && dyUnconsumed > 50))) { || (!target.canScrollVertically(-1) && dyConsumed == 0 && dyUnconsumed > 50))) {
hide(bottomNavBar); hide(bottomNavBar);
} else if (bottomNavBar.getVisibility() == View.INVISIBLE && (dyConsumed < 0 }
else if (bottomNavBar.getVisibility() == View.INVISIBLE && (dyConsumed < 0
|| (!target.canScrollVertically(-1) && dyConsumed == 0 && dyUnconsumed < -50))) { || (!target.canScrollVertically(-1) && dyConsumed == 0 && dyUnconsumed < -50))) {
show(bottomNavBar); show(bottomNavBar);
} }

3
app/src/main/java/gr/thmmy/mthmmy/viewmodel/ShoutboxViewModel.java

@ -28,7 +28,8 @@ public class ShoutboxViewModel extends ViewModel {
} }
public void sendShout(String shout) { public void sendShout(String shout) {
if (shoutboxMutableLiveData.getValue() == null) throw new IllegalStateException("Shoutbox task has not finished yet!"); if (shoutboxMutableLiveData.getValue() == null)
throw new IllegalStateException("Shoutbox task has not finished yet!");
Shoutbox shoutbox = shoutboxMutableLiveData.getValue(); Shoutbox shoutbox = shoutboxMutableLiveData.getValue();
new SendShoutTask(onSendShoutTaskStarted, onSendShoutTaskFinished) new SendShoutTask(onSendShoutTaskStarted, onSendShoutTaskFinished)
.execute(shoutbox.getSendShoutUrl(), shout, shoutbox.getSc(), .execute(shoutbox.getSendShoutUrl(), shout, shoutbox.getSc(),

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

@ -100,7 +100,8 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
} }
public void reloadPage() { public void reloadPage() {
if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); if (topicUrl == null)
throw new NullPointerException("No topic task has been requested yet!");
Timber.i("Reloading page"); Timber.i("Reloading page");
loadUrl(topicUrl); loadUrl(topicUrl);
} }
@ -110,13 +111,15 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
* in the url before refreshing * in the url before refreshing
*/ */
public void resetPage() { public void resetPage() {
if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); if (topicUrl == null)
throw new NullPointerException("No topic task has been requested yet!");
Timber.i("Resetting page"); Timber.i("Resetting page");
loadUrl(ParseHelpers.getBaseURL(topicUrl) + "." + String.valueOf(currentPageIndex * 15)); loadUrl(ParseHelpers.getBaseURL(topicUrl) + "." + String.valueOf(currentPageIndex * 15));
} }
public void resetPageThen(Runnable runnable) { public void resetPageThen(Runnable runnable) {
if (topicUrl == null) throw new NullPointerException("No topic task has been requested yet!"); if (topicUrl == null)
throw new NullPointerException("No topic task has been requested yet!");
Timber.i("Resetting page"); Timber.i("Resetting page");
stopLoading(); stopLoading();
currentTopicTask = new TopicTask(topicTaskObserver, result -> { currentTopicTask = new TopicTask(topicTaskObserver, result -> {
@ -134,18 +137,21 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
Timber.i("Changing to page " + pageRequested + 1); Timber.i("Changing to page " + pageRequested + 1);
loadUrl(ParseHelpers.getBaseURL(topicUrl) + "." + pageRequested * 15); loadUrl(ParseHelpers.getBaseURL(topicUrl) + "." + pageRequested * 15);
pageIndicatorIndex.setValue(pageRequested + 1); pageIndicatorIndex.setValue(pageRequested + 1);
} else { }
else {
stopLoading(); stopLoading();
} }
} }
public boolean submitVote(LinearLayout optionsLayout) { public boolean submitVote(LinearLayout optionsLayout) {
if (topicItems.getValue() == null) throw new NullPointerException("Topic task has not finished yet!"); if (topicItems.getValue() == null)
throw new NullPointerException("Topic task has not finished yet!");
ArrayList<Integer> votes = new ArrayList<>(); ArrayList<Integer> votes = new ArrayList<>();
if (optionsLayout.getChildAt(0) instanceof RadioGroup) { if (optionsLayout.getChildAt(0) instanceof RadioGroup) {
RadioGroup optionsRadioGroup = (RadioGroup) optionsLayout.getChildAt(0); RadioGroup optionsRadioGroup = (RadioGroup) optionsLayout.getChildAt(0);
votes.add(optionsRadioGroup.getCheckedRadioButtonId()); votes.add(optionsRadioGroup.getCheckedRadioButtonId());
} else if (optionsLayout.getChildAt(0) instanceof CheckBox) { }
else if (optionsLayout.getChildAt(0) instanceof CheckBox) {
for (int i = 0; i < optionsLayout.getChildCount(); i++) { for (int i = 0; i < optionsLayout.getChildCount(); i++) {
CheckBox checkBox = (CheckBox) optionsLayout.getChildAt(i); CheckBox checkBox = (CheckBox) optionsLayout.getChildAt(i);
if (checkBox.isChecked()) if (checkBox.isChecked())
@ -164,7 +170,8 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
} }
public void removeVote() { public void removeVote() {
if (topicItems.getValue() == null) throw new NullPointerException("Topic task has not finished yet!"); if (topicItems.getValue() == null)
throw new NullPointerException("Topic task has not finished yet!");
RemoveVoteTask removeVoteTask = new RemoveVoteTask(); RemoveVoteTask removeVoteTask = new RemoveVoteTask();
removeVoteTask.setOnTaskStartedListener(removeVoteTaskStartedListener); removeVoteTask.setOnTaskStartedListener(removeVoteTaskStartedListener);
removeVoteTask.setOnNetworkTaskFinishedListener(removeVoteTaskFinishedListener); removeVoteTask.setOnNetworkTaskFinishedListener(removeVoteTaskFinishedListener);
@ -308,14 +315,15 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
throw new NullPointerException("No page has been loaded yet!"); throw new NullPointerException("No page has been loaded yet!");
int oldIndicatorIndex = this.pageIndicatorIndex.getValue(); int oldIndicatorIndex = this.pageIndicatorIndex.getValue();
this.pageIndicatorIndex.setValue(pageIndicatorIndex); this.pageIndicatorIndex.setValue(pageIndicatorIndex);
if (changePage && oldIndicatorIndex != this.pageIndicatorIndex.getValue()) loadPageIndicated(); if (changePage && oldIndicatorIndex != this.pageIndicatorIndex.getValue())
loadPageIndicated();
} }
// <-------------Just getters, setters and helper methods below here----------------> // <-------------Just getters, setters and helper methods below here---------------->
public int getTopicId() { public int getTopicId() {
if (pageTopicId.getValue() == null) if (pageTopicId.getValue() == null)
throw new NullPointerException("No page has been loaded yet!"); throw new NullPointerException("No page has been loaded yet!");
return pageTopicId.getValue(); return pageTopicId.getValue();
} }
@ -461,12 +469,12 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
} }
public int getCurrentPageIndex() { public int getCurrentPageIndex() {
if (currentPageIndex == 0) throw new NullPointerException("No page has been loaded yet!"); if (currentPageIndex == 0) throw new NullPointerException("No page has been loaded yet!");
return currentPageIndex; return currentPageIndex;
} }
public int getPageCount() { public int getPageCount() {
if (pageCount == 0) throw new NullPointerException("No page has been loaded yet!"); if (pageCount == 0) throw new NullPointerException("No page has been loaded yet!");
return pageCount; return pageCount;
} }
@ -484,7 +492,7 @@ public class TopicViewModel extends BaseViewModel implements TopicTask.OnTopicTa
public int postCount() { public int postCount() {
if (topicItems.getValue() == null) if (topicItems.getValue() == null)
throw new NullPointerException("No page has been loaded yet!"); throw new NullPointerException("No page has been loaded yet!");
return topicItems.getValue().size(); return topicItems.getValue().size();
} }
} }

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

@ -41,7 +41,7 @@ public class ReactiveWebView extends WebView {
init(); init();
} }
private void init(){ private void init() {
setOnLongClickListener(); setOnLongClickListener();
this.setVerticalScrollBarEnabled(false); this.setVerticalScrollBarEnabled(false);
} }
@ -53,7 +53,7 @@ public class ReactiveWebView extends WebView {
downTime = event.getEventTime(); downTime = event.getEventTime();
break; break;
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_UP:
if(event.getEventTime() - downTime <= MAX_TOUCH_DURATION) if (event.getEventTime() - downTime <= MAX_TOUCH_DURATION)
performClick(); performClick();
break; break;
default: default:
@ -65,27 +65,27 @@ public class ReactiveWebView extends WebView {
@Override @Override
public boolean performClick() { public boolean performClick() {
WebView.HitTestResult result = this.getHitTestResult(); WebView.HitTestResult result = this.getHitTestResult();
if(result.getType() == WebView.HitTestResult.IMAGE_TYPE){ if (result.getType() == WebView.HitTestResult.IMAGE_TYPE) {
String imageURL = result.getExtra(); String imageURL = result.getExtra();
displayPhotoViewImage(context, imageURL); displayPhotoViewImage(context, imageURL);
} }
return super.performClick(); return super.performClick();
} }
private void setOnLongClickListener(){ private void setOnLongClickListener() {
this.setOnLongClickListener(v -> { this.setOnLongClickListener(v -> {
HitTestResult result = ReactiveWebView.this.getHitTestResult(); HitTestResult result = ReactiveWebView.this.getHitTestResult();
if(result.getType() == HitTestResult.SRC_ANCHOR_TYPE) if (result.getType() == HitTestResult.SRC_ANCHOR_TYPE)
copyUrlToClipboard(result.getExtra()); copyUrlToClipboard(result.getExtra());
else if(result.getType() == WebView.HitTestResult.IMAGE_TYPE) { else if (result.getType() == WebView.HitTestResult.IMAGE_TYPE) {
String imageURL = result.getExtra(); String imageURL = result.getExtra();
showImageDownloadDialog(imageURL); showImageDownloadDialog(imageURL);
} }
else if(result.getType() == HitTestResult.SRC_IMAGE_ANCHOR_TYPE) { else if (result.getType() == HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
final String imageURL = result.getExtra(); final String imageURL = result.getExtra();
Uri uri = Uri.parse(imageURL); Uri uri = Uri.parse(imageURL);
String videoId = uri.getQueryParameter(VIDEO_ID_PARAMETER); String videoId = uri.getQueryParameter(VIDEO_ID_PARAMETER);
if (videoId!=null) if (videoId != null)
copyUrlToClipboard("https://www.youtube.com/watch?v=" + videoId); copyUrlToClipboard("https://www.youtube.com/watch?v=" + videoId);
else else
showImageDownloadDialog(imageURL); showImageDownloadDialog(imageURL);
@ -94,14 +94,14 @@ public class ReactiveWebView extends WebView {
}); });
} }
private void copyUrlToClipboard(String urlToCopy){ private void copyUrlToClipboard(String urlToCopy) {
ClipboardManager clipboard = (ClipboardManager) BaseApplication.getInstance().getSystemService(CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) BaseApplication.getInstance().getSystemService(CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("ReactiveWebViewCopiedText", urlToCopy); ClipData clip = ClipData.newPlainText("ReactiveWebViewCopiedText", urlToCopy);
clipboard.setPrimaryClip(clip); clipboard.setPrimaryClip(clip);
Toast.makeText(BaseApplication.getInstance().getApplicationContext(),context.getString(R.string.link_copied_msg),Toast.LENGTH_SHORT).show(); Toast.makeText(BaseApplication.getInstance().getApplicationContext(), context.getString(R.string.link_copied_msg), Toast.LENGTH_SHORT).show();
} }
private void showImageDownloadDialog(String imageURL){ private void showImageDownloadDialog(String imageURL) {
ImageDownloadDialogBuilder builder = new ImageDownloadDialogBuilder(context, imageURL); ImageDownloadDialogBuilder builder = new ImageDownloadDialogBuilder(context, imageURL);
builder.show(); builder.show();
} }

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

@ -67,6 +67,7 @@ public class RelativeTimeTextView extends TextView {
* Sets the reference time for this view. At any moment, the view will render a relative time period relative to the time set here. * Sets the reference time for this view. At any moment, the view will render a relative time period relative to the time set here.
* <p/> * <p/>
* This value can also be set with the XML attribute {@code reference_time} * This value can also be set with the XML attribute {@code reference_time}
*
* @param referenceTime The timestamp (in milliseconds since epoch) that will be the reference point for this view. * @param referenceTime The timestamp (in milliseconds since epoch) that will be the reference point for this view.
*/ */
public void setReferenceTime(long referenceTime) { public void setReferenceTime(long referenceTime) {
@ -120,13 +121,14 @@ public class RelativeTimeTextView extends TextView {
super.onVisibilityChanged(changedView, visibility); super.onVisibilityChanged(changedView, visibility);
if (visibility == GONE || visibility == INVISIBLE) { if (visibility == GONE || visibility == INVISIBLE) {
stopTaskForPeriodicallyUpdatingRelativeTime(); stopTaskForPeriodicallyUpdatingRelativeTime();
} else { }
else {
startTaskForPeriodicallyUpdatingRelativeTime(); startTaskForPeriodicallyUpdatingRelativeTime();
} }
} }
private void startTaskForPeriodicallyUpdatingRelativeTime() { private void startTaskForPeriodicallyUpdatingRelativeTime() {
if(mUpdateTimeTask.isDetached()) initUpdateTimeTask(); if (mUpdateTimeTask.isDetached()) initUpdateTimeTask();
mHandler.post(mUpdateTimeTask); mHandler.post(mUpdateTimeTask);
isUpdateTaskRunning = true; isUpdateTaskRunning = true;
} }
@ -136,7 +138,7 @@ public class RelativeTimeTextView extends TextView {
} }
private void stopTaskForPeriodicallyUpdatingRelativeTime() { private void stopTaskForPeriodicallyUpdatingRelativeTime() {
if(isUpdateTaskRunning) { if (isUpdateTaskRunning) {
mUpdateTimeTask.detach(); mUpdateTimeTask.detach();
mHandler.removeCallbacks(mUpdateTimeTask); mHandler.removeCallbacks(mUpdateTimeTask);
isUpdateTaskRunning = false; isUpdateTaskRunning = false;
@ -158,7 +160,7 @@ public class RelativeTimeTextView extends TextView {
return; return;
} }
SavedState ss = (SavedState)state; SavedState ss = (SavedState) state;
mReferenceTime = ss.referenceTime; mReferenceTime = ss.referenceTime;
super.onRestoreInstanceState(ss.getSuperState()); super.onRestoreInstanceState(ss.getSuperState());
} }
@ -219,9 +221,11 @@ public class RelativeTimeTextView extends TextView {
long interval = INITIAL_UPDATE_INTERVAL; long interval = INITIAL_UPDATE_INTERVAL;
if (difference > DateUtils.WEEK_IN_MILLIS) { if (difference > DateUtils.WEEK_IN_MILLIS) {
interval = DateUtils.WEEK_IN_MILLIS; interval = DateUtils.WEEK_IN_MILLIS;
} else if (difference > DateUtils.DAY_IN_MILLIS) { }
else if (difference > DateUtils.DAY_IN_MILLIS) {
interval = DateUtils.DAY_IN_MILLIS; interval = DateUtils.DAY_IN_MILLIS;
} else if (difference > DateUtils.HOUR_IN_MILLIS) { }
else if (difference > DateUtils.HOUR_IN_MILLIS) {
interval = DateUtils.HOUR_IN_MILLIS; interval = DateUtils.HOUR_IN_MILLIS;
} }
rttv.updateTextDisplay(); rttv.updateTextDisplay();

1
app/src/main/java/gr/thmmy/mthmmy/views/ToggledBackgroundButton.java

@ -1,4 +1,5 @@
package gr.thmmy.mthmmy.views; package gr.thmmy.mthmmy.views;
import android.content.Context; import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;

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

@ -85,7 +85,8 @@ public class EditorView extends LinearLayout implements EmojiInputField {
if (!emojiKeyboard.isVisible()) { if (!emojiKeyboard.isVisible()) {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT); imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
} else { }
else {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(getWindowToken(), 0); imm.hideSoftInputFromWindow(getWindowToken(), 0);
requestEditTextFocus(); requestEditTextFocus();
@ -128,244 +129,246 @@ public class EditorView extends LinearLayout implements EmojiInputField {
getResources().getDimension(R.dimen.editor_format_button_margin_between); getResources().getDimension(R.dimen.editor_format_button_margin_between);
int columns = (int) Math.floor(displayMetrics.widthPixels / itemWidth); int columns = (int) Math.floor(displayMetrics.widthPixels / itemWidth);
formatButtonsRecyclerview.setLayoutManager(new GridLayoutManager(context, columns)); formatButtonsRecyclerview.setLayoutManager(new GridLayoutManager(context, columns));
formatButtonsRecyclerview.setAdapter( formatButtonsRecyclerview.setAdapter(
new FormatButtonsAdapter( new FormatButtonsAdapter(
(view, drawableId) -> { (view, drawableId) -> {
boolean hadTextSelection; boolean hadTextSelection;
switch (drawableId) { switch (drawableId) {
case R.drawable.ic_format_bold: case R.drawable.ic_format_bold:
hadTextSelection = editText.hasSelection(); hadTextSelection = editText.hasSelection();
getText().insert(editText.getSelectionStart(), "[b]"); getText().insert(editText.getSelectionStart(), "[b]");
getText().insert(editText.getSelectionEnd(), "[/b]"); getText().insert(editText.getSelectionEnd(), "[/b]");
editText.setSelection( editText.setSelection(
hadTextSelection hadTextSelection
? editText.getSelectionEnd() ? editText.getSelectionEnd()
: editText.getSelectionStart() - 4); : editText.getSelectionStart() - 4);
break; break;
case R.drawable.ic_format_italic: case R.drawable.ic_format_italic:
hadTextSelection = editText.hasSelection(); hadTextSelection = editText.hasSelection();
getText().insert(editText.getSelectionStart(), "[i]"); getText().insert(editText.getSelectionStart(), "[i]");
getText().insert(editText.getSelectionEnd(), "[/i]"); getText().insert(editText.getSelectionEnd(), "[/i]");
editText.setSelection( editText.setSelection(
hadTextSelection hadTextSelection
? editText.getSelectionEnd() ? editText.getSelectionEnd()
: editText.getSelectionStart() - 4); : editText.getSelectionStart() - 4);
break; break;
case R.drawable.ic_format_underlined: case R.drawable.ic_format_underlined:
hadTextSelection = editText.hasSelection(); hadTextSelection = editText.hasSelection();
getText().insert(editText.getSelectionStart(), "[u]"); getText().insert(editText.getSelectionStart(), "[u]");
getText().insert(editText.getSelectionEnd(), "[/u]"); getText().insert(editText.getSelectionEnd(), "[/u]");
editText.setSelection( editText.setSelection(
hadTextSelection hadTextSelection
? editText.getSelectionEnd() ? editText.getSelectionEnd()
: editText.getSelectionStart() - 4); : editText.getSelectionStart() - 4);
break; break;
case R.drawable.ic_strikethrough_s: case R.drawable.ic_strikethrough_s:
hadTextSelection = editText.hasSelection(); hadTextSelection = editText.hasSelection();
getText().insert(editText.getSelectionStart(), "[s]"); getText().insert(editText.getSelectionStart(), "[s]");
getText().insert(editText.getSelectionEnd(), "[/s]"); getText().insert(editText.getSelectionEnd(), "[/s]");
editText.setSelection( editText.setSelection(
hadTextSelection hadTextSelection
? editText.getSelectionEnd() ? editText.getSelectionEnd()
: editText.getSelectionStart() - 4); : editText.getSelectionStart() - 4);
break; break;
case R.drawable.ic_format_color_text: case R.drawable.ic_format_color_text:
int selectionStart = editText.getSelectionStart(); int selectionStart = editText.getSelectionStart();
int selectionEnd = editText.getSelectionEnd(); int selectionEnd = editText.getSelectionEnd();
PopupWindow popupWindow = new PopupWindow(view.getContext()); PopupWindow popupWindow = new PopupWindow(view.getContext());
popupWindow.setHeight(LayoutParams.WRAP_CONTENT); popupWindow.setHeight(LayoutParams.WRAP_CONTENT);
popupWindow.setWidth(LayoutParams.WRAP_CONTENT); popupWindow.setWidth(LayoutParams.WRAP_CONTENT);
popupWindow.setFocusable(true); popupWindow.setFocusable(true);
ScrollView colorPickerScrollview = ScrollView colorPickerScrollview =
(ScrollView) (ScrollView)
LayoutInflater.from(context) LayoutInflater.from(context)
.inflate(R.layout.editor_view_color_picker, null); .inflate(R.layout.editor_view_color_picker, null);
LinearLayout colorPicker = (LinearLayout) colorPickerScrollview.getChildAt(0); LinearLayout colorPicker = (LinearLayout) colorPickerScrollview.getChildAt(0);
popupWindow.setContentView(colorPickerScrollview); popupWindow.setContentView(colorPickerScrollview);
for (int i = 0; i < colorPicker.getChildCount(); i++) { for (int i = 0; i < colorPicker.getChildCount(); i++) {
TextView child = (TextView) colorPicker.getChildAt(i); TextView child = (TextView) colorPicker.getChildAt(i);
child.setOnClickListener( child.setOnClickListener(
v -> { v -> {
boolean hadTextSelection2 = editText.hasSelection(); boolean hadTextSelection2 = editText.hasSelection();
getText() getText()
.insert( .insert(
editText.getSelectionStart(), editText.getSelectionStart(),
"[color=" + colors.get(v.getId()) + "]"); "[color=" + colors.get(v.getId()) + "]");
getText().insert(editText.getSelectionEnd(), "[/color]"); getText().insert(editText.getSelectionEnd(), "[/color]");
editText.setSelection( editText.setSelection(
hadTextSelection2 hadTextSelection2
? editText.getSelectionEnd() ? editText.getSelectionEnd()
: editText.getSelectionStart() - 8); : editText.getSelectionStart() - 8);
popupWindow.dismiss(); popupWindow.dismiss();
}); });
} }
popupWindow.showAsDropDown(view); popupWindow.showAsDropDown(view);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
new AsyncTask<Void, Void, Void>() { new AsyncTask<Void, Void, Void>() {
@Override @Override
protected Void doInBackground(Void... voids) { protected Void doInBackground(Void... voids) {
try { try {
Thread.sleep(100); Thread.sleep(100);
} catch (InterruptedException e) { } catch (InterruptedException e) {
Timber.e(e); Timber.e(e);
} }
return null; return null;
} }
@Override @Override
protected void onPostExecute(Void aVoid) { protected void onPostExecute(Void aVoid) {
editText.setSelection(selectionStart, selectionEnd); editText.setSelection(selectionStart, selectionEnd);
} }
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); }.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();
getText().insert(editText.getSelectionStart(), "[size=10pt]"); getText().insert(editText.getSelectionStart(), "[size=10pt]");
getText().insert(editText.getSelectionEnd(), "[/size]"); getText().insert(editText.getSelectionEnd(), "[/size]");
editText.setSelection( editText.setSelection(
hadTextSelection hadTextSelection
? editText.getSelectionEnd() ? editText.getSelectionEnd()
: editText.getSelectionStart() - 7); : editText.getSelectionStart() - 7);
break; break;
case R.drawable.ic_text_format: case R.drawable.ic_text_format:
hadTextSelection = editText.hasSelection(); hadTextSelection = editText.hasSelection();
getText().insert(editText.getSelectionStart(), "[font=Verdana]"); getText().insert(editText.getSelectionStart(), "[font=Verdana]");
getText().insert(editText.getSelectionEnd(), "[/font]"); getText().insert(editText.getSelectionEnd(), "[/font]");
editText.setSelection( editText.setSelection(
hadTextSelection hadTextSelection
? editText.getSelectionEnd() ? editText.getSelectionEnd()
: editText.getSelectionStart() - 7); : editText.getSelectionStart() - 7);
break; break;
case R.drawable.ic_format_list_bulleted: case R.drawable.ic_format_list_bulleted:
hadTextSelection = editText.hasSelection(); hadTextSelection = editText.hasSelection();
getText().insert(editText.getSelectionStart(), "[list]\n[li]"); getText().insert(editText.getSelectionStart(), "[list]\n[li]");
getText().insert(editText.getSelectionEnd(), "[/li]\n[li][/li]\n[/list]"); getText().insert(editText.getSelectionEnd(), "[/li]\n[li][/li]\n[/list]");
editText.setSelection( editText.setSelection(
hadTextSelection hadTextSelection
? editText.getSelectionEnd() - 13 ? editText.getSelectionEnd() - 13
: editText.getSelectionStart() - 23); : editText.getSelectionStart() - 23);
break; break;
case R.drawable.ic_format_align_left: case R.drawable.ic_format_align_left:
hadTextSelection = editText.hasSelection(); hadTextSelection = editText.hasSelection();
getText().insert(editText.getSelectionStart(), "[left]"); getText().insert(editText.getSelectionStart(), "[left]");
getText().insert(editText.getSelectionEnd(), "[/left]"); getText().insert(editText.getSelectionEnd(), "[/left]");
editText.setSelection( editText.setSelection(
hadTextSelection hadTextSelection
? editText.getSelectionEnd() ? editText.getSelectionEnd()
: editText.getSelectionStart() - 7); : editText.getSelectionStart() - 7);
break; break;
case R.drawable.ic_format_align_center: case R.drawable.ic_format_align_center:
hadTextSelection = editText.hasSelection(); hadTextSelection = editText.hasSelection();
getText().insert(editText.getSelectionStart(), "[center]"); getText().insert(editText.getSelectionStart(), "[center]");
getText().insert(editText.getSelectionEnd(), "[/center]"); getText().insert(editText.getSelectionEnd(), "[/center]");
editText.setSelection( editText.setSelection(
hadTextSelection hadTextSelection
? editText.getSelectionEnd() ? editText.getSelectionEnd()
: editText.getSelectionStart() - 9); : editText.getSelectionStart() - 9);
break; break;
case R.drawable.ic_format_align_right: case R.drawable.ic_format_align_right:
hadTextSelection = editText.hasSelection(); hadTextSelection = editText.hasSelection();
getText().insert(editText.getSelectionStart(), "[right]"); getText().insert(editText.getSelectionStart(), "[right]");
getText().insert(editText.getSelectionEnd(), "[/right]"); getText().insert(editText.getSelectionEnd(), "[/right]");
editText.setSelection( editText.setSelection(
hadTextSelection hadTextSelection
? editText.getSelectionEnd() ? editText.getSelectionEnd()
: editText.getSelectionStart() - 8); : editText.getSelectionStart() - 8);
break; break;
case R.drawable.ic_insert_link: case R.drawable.ic_insert_link:
LinearLayout dialogBody = LinearLayout dialogBody =
(LinearLayout) (LinearLayout)
LayoutInflater.from(context).inflate(R.layout.dialog_create_link, null); LayoutInflater.from(context).inflate(R.layout.dialog_create_link, null);
TextInputLayout linkUrl = dialogBody.findViewById(R.id.link_url_input); TextInputLayout linkUrl = dialogBody.findViewById(R.id.link_url_input);
linkUrl.setOnClickListener(view1 -> linkUrl.setError(null)); linkUrl.setOnClickListener(view1 -> linkUrl.setError(null));
TextInputLayout linkText = dialogBody.findViewById(R.id.link_text_input); TextInputLayout linkText = dialogBody.findViewById(R.id.link_text_input);
linkText.setOnClickListener(view2 -> linkText.setError(null)); linkText.setOnClickListener(view2 -> linkText.setError(null));
hadTextSelection = editText.hasSelection(); hadTextSelection = editText.hasSelection();
int start = editText.getSelectionStart(), end = editText.getSelectionEnd(); int start = editText.getSelectionStart(), end = editText.getSelectionEnd();
if (editText.hasSelection()) { if (editText.hasSelection()) {
linkText linkText
.getEditText() .getEditText()
.setText( .setText(
editText editText
.getText() .getText()
.toString() .toString()
.substring( .substring(
editText.getSelectionStart(), editText.getSelectionEnd())); editText.getSelectionStart(), editText.getSelectionEnd()));
} }
AlertDialog linkDialog = AlertDialog linkDialog =
new AlertDialog.Builder(context, R.style.AppTheme_Dark_Dialog) new AlertDialog.Builder(context, R.style.AppTheme_Dark_Dialog)
.setTitle(R.string.dialog_create_link_title) .setTitle(R.string.dialog_create_link_title)
.setView(dialogBody) .setView(dialogBody)
.setPositiveButton(R.string.ok, null) .setPositiveButton(R.string.ok, null)
.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss()) .setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss())
.create(); .create();
linkDialog.setOnShowListener( linkDialog.setOnShowListener(
dialogInterface -> { dialogInterface -> {
Button button = linkDialog.getButton(AlertDialog.BUTTON_POSITIVE); Button button = linkDialog.getButton(AlertDialog.BUTTON_POSITIVE);
button.setOnClickListener( button.setOnClickListener(
view12 -> { view12 -> {
if (TextUtils.isEmpty( if (TextUtils.isEmpty(
Objects.requireNonNull(linkUrl.getEditText()) Objects.requireNonNull(linkUrl.getEditText())
.getText() .getText()
.toString())) { .toString())) {
linkUrl.setError(context.getString(R.string.input_field_required)); linkUrl.setError(context.getString(R.string.input_field_required));
return; return;
} }
if (hadTextSelection) editText.getText().delete(start, end); if (hadTextSelection)
if (!TextUtils.isEmpty(linkText.getEditText().getText())) { editText.getText().delete(start, end);
getText() if (!TextUtils.isEmpty(linkText.getEditText().getText())) {
.insert( getText()
editText.getSelectionStart(), .insert(
"[url=" editText.getSelectionStart(),
+ linkUrl.getEditText().getText().toString() "[url="
+ "]" + linkUrl.getEditText().getText().toString()
+ linkText.getEditText().getText().toString() + "]"
+ "[/url]"); + linkText.getEditText().getText().toString()
} else + "[/url]");
getText() }
.insert( else
editText.getSelectionStart(), getText()
"[url]" .insert(
+ linkUrl.getEditText().getText().toString() editText.getSelectionStart(),
+ "[/url]"); "[url]"
linkDialog.dismiss(); + linkUrl.getEditText().getText().toString()
}); + "[/url]");
}); linkDialog.dismiss();
linkDialog.show(); });
break; });
case R.drawable.ic_format_quote: linkDialog.show();
hadTextSelection = editText.hasSelection(); break;
getText().insert(editText.getSelectionStart(), "[quote]"); case R.drawable.ic_format_quote:
getText().insert(editText.getSelectionEnd(), "[/quote]"); hadTextSelection = editText.hasSelection();
editText.setSelection( getText().insert(editText.getSelectionStart(), "[quote]");
hadTextSelection getText().insert(editText.getSelectionEnd(), "[/quote]");
? editText.getSelectionEnd() editText.setSelection(
: editText.getSelectionStart() - 8); hadTextSelection
break; ? editText.getSelectionEnd()
case R.drawable.ic_code: : editText.getSelectionStart() - 8);
hadTextSelection = editText.hasSelection(); break;
getText().insert(editText.getSelectionStart(), "[code]"); case R.drawable.ic_code:
getText().insert(editText.getSelectionEnd(), "[/code]"); hadTextSelection = editText.hasSelection();
editText.setSelection( getText().insert(editText.getSelectionStart(), "[code]");
hadTextSelection getText().insert(editText.getSelectionEnd(), "[/code]");
? editText.getSelectionEnd() editText.setSelection(
: editText.getSelectionStart() - 7); hadTextSelection
break; ? editText.getSelectionEnd()
case R.drawable.ic_functions: : editText.getSelectionStart() - 7);
hadTextSelection = editText.hasSelection(); break;
getText().insert(editText.getSelectionStart(), "[tex]"); case R.drawable.ic_functions:
getText().insert(editText.getSelectionEnd(), "[/tex]"); hadTextSelection = editText.hasSelection();
editText.setSelection( getText().insert(editText.getSelectionStart(), "[tex]");
hadTextSelection getText().insert(editText.getSelectionEnd(), "[/tex]");
? editText.getSelectionEnd() editText.setSelection(
: editText.getSelectionStart() - 6); hadTextSelection
break; ? editText.getSelectionEnd()
default: : editText.getSelectionStart() - 6);
throw new IllegalArgumentException("Unknown format button click"); break;
} default:
})); throw new IllegalArgumentException("Unknown format button click");
}
}));
emojiButton.setOnClickListener(view -> { emojiButton.setOnClickListener(view -> {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE); InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
@ -402,7 +405,8 @@ public class EditorView extends LinearLayout implements EmojiInputField {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Activity.INPUT_METHOD_SERVICE); InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Activity.INPUT_METHOD_SERVICE);
if (imm != null) if (imm != null)
imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT); imm.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
} else { }
else {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Activity.INPUT_METHOD_SERVICE); InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Activity.INPUT_METHOD_SERVICE);
if (imm != null) if (imm != null)
imm.hideSoftInputFromWindow(getWindowToken(), 0); imm.hideSoftInputFromWindow(getWindowToken(), 0);
@ -414,19 +418,20 @@ public class EditorView extends LinearLayout implements EmojiInputField {
if (b) { if (b) {
emojiKeyboard.onEmojiInputFieldFocused(EditorView.this); emojiKeyboard.onEmojiInputFieldFocused(EditorView.this);
showMarkdown(); showMarkdown();
} else hideMarkdown(); }
else hideMarkdown();
}); });
editText.setOnFocusChangeListener((view, b) -> { editText.setOnFocusChangeListener((view, b) -> {
if (b) { if (b) {
emojiKeyboard.onEmojiInputFieldFocused(EditorView.this); emojiKeyboard.onEmojiInputFieldFocused(EditorView.this);
showMarkdown(); showMarkdown();
} else hideMarkdown(); }
else hideMarkdown();
}); });
} }
/** /**
* Animates the hiding of the markdown options. * Animates the hiding of the markdown options.
*
*/ */
public void hideMarkdown() { public void hideMarkdown() {
if (formatButtonsRecyclerview.getVisibility() == GONE) return; if (formatButtonsRecyclerview.getVisibility() == GONE) return;
@ -459,7 +464,6 @@ public class EditorView extends LinearLayout implements EmojiInputField {
/** /**
* Animates the showing of the markdown options. * Animates the showing of the markdown options.
*
*/ */
public void showMarkdown() { public void showMarkdown() {
if (formatButtonsRecyclerview.getVisibility() == VISIBLE) return; if (formatButtonsRecyclerview.getVisibility() == VISIBLE) return;
@ -523,7 +527,8 @@ public class EditorView extends LinearLayout implements EmojiInputField {
public void onKeyboardVisibilityChange(boolean visible) { public void onKeyboardVisibilityChange(boolean visible) {
if (visible) { if (visible) {
emojiButton.setImageResource(R.drawable.ic_keyboard_24dp); emojiButton.setImageResource(R.drawable.ic_keyboard_24dp);
} else { }
else {
emojiButton.setImageResource(R.drawable.ic_tag_faces_24dp); emojiButton.setImageResource(R.drawable.ic_tag_faces_24dp);
} }
} }

1
app/src/main/java/gr/thmmy/mthmmy/views/editorview/EmojiInputField.java

@ -4,5 +4,6 @@ import android.view.inputmethod.InputConnection;
public interface EmojiInputField { public interface EmojiInputField {
void onKeyboardVisibilityChange(boolean visible); void onKeyboardVisibilityChange(boolean visible);
InputConnection getInputConnection(); InputConnection getInputConnection();
} }

9
app/src/main/java/gr/thmmy/mthmmy/views/editorview/FormatButtonsAdapter.java

@ -14,10 +14,10 @@ public class FormatButtonsAdapter extends RecyclerView.Adapter<FormatButtonsAdap
private OnFormatButtonClickListener listener; private OnFormatButtonClickListener listener;
public static final int[] FORMAT_BUTTON_IDS = {R.drawable.ic_format_bold, R.drawable.ic_format_italic, public static final int[] FORMAT_BUTTON_IDS = {R.drawable.ic_format_bold, R.drawable.ic_format_italic,
R.drawable.ic_format_underlined, R.drawable.ic_strikethrough_s, R.drawable.ic_format_color_text, R.drawable.ic_format_underlined, R.drawable.ic_strikethrough_s, R.drawable.ic_format_color_text,
R.drawable.ic_format_size, R.drawable.ic_text_format, R.drawable.ic_format_list_bulleted, R.drawable.ic_format_size, R.drawable.ic_text_format, R.drawable.ic_format_list_bulleted,
R.drawable.ic_format_align_left, R.drawable.ic_format_align_center, R.drawable.ic_format_align_right, R.drawable.ic_format_align_left, R.drawable.ic_format_align_center, R.drawable.ic_format_align_right,
R.drawable.ic_insert_link, R.drawable.ic_format_quote, R.drawable.ic_code, R.drawable.ic_functions}; R.drawable.ic_insert_link, R.drawable.ic_format_quote, R.drawable.ic_code, R.drawable.ic_functions};
public FormatButtonsAdapter(OnFormatButtonClickListener listener) { public FormatButtonsAdapter(OnFormatButtonClickListener listener) {
this.listener = listener; this.listener = listener;
@ -45,6 +45,7 @@ public class FormatButtonsAdapter extends RecyclerView.Adapter<FormatButtonsAdap
static class FormatButtonViewHolder extends RecyclerView.ViewHolder { static class FormatButtonViewHolder extends RecyclerView.ViewHolder {
AppCompatImageButton formatButton; AppCompatImageButton formatButton;
FormatButtonViewHolder(AppCompatImageButton formatButton) { FormatButtonViewHolder(AppCompatImageButton formatButton) {
super(formatButton); super(formatButton);
this.formatButton = formatButton; this.formatButton = formatButton;

4
app/src/main/java/gr/thmmy/mthmmy/views/editorview/IEmojiKeyboard.java

@ -8,24 +8,28 @@ public interface IEmojiKeyboard {
/** /**
* Check if keyboard is visible * Check if keyboard is visible
*
* @return true, if {@link EmojiKeyboard#getVisibility()} returns View.VISIBLE, otherwise false * @return true, if {@link EmojiKeyboard#getVisibility()} returns View.VISIBLE, otherwise false
*/ */
boolean isVisible(); boolean isVisible();
/** /**
* Callback to the keyboard when {@link EditorView#emojiButton} is clicked * Callback to the keyboard when {@link EditorView#emojiButton} is clicked
*
* @return whether the keyboard became visible or not * @return whether the keyboard became visible or not
*/ */
boolean onEmojiButtonToggle(); boolean onEmojiButtonToggle();
/** /**
* Callback to create input connection with {@link EmojiInputField} * Callback to create input connection with {@link EmojiInputField}
*
* @param emojiInputField the connected input field * @param emojiInputField the connected input field
*/ */
void onEmojiInputFieldFocused(EmojiInputField emojiInputField); void onEmojiInputFieldFocused(EmojiInputField emojiInputField);
/** /**
* Persist a set of all input fields to update all of them when visibility changes * Persist a set of all input fields to update all of them when visibility changes
*
* @param emojiInputField the input field to be added * @param emojiInputField the input field to be added
*/ */
void registerEmojiInputField(EmojiInputField emojiInputField); void registerEmojiInputField(EmojiInputField emojiInputField);

2
app/src/main/res/anim/push_left_in.xml

@ -3,6 +3,6 @@
<translate <translate
android:duration="500" android:duration="500"
android:fromXDelta="100%p" android:fromXDelta="100%p"
android:toXDelta="0"/> android:toXDelta="0" />
</set> </set>

2
app/src/main/res/anim/push_left_out.xml

@ -3,5 +3,5 @@
<translate <translate
android:duration="500" android:duration="500"
android:fromXDelta="0" android:fromXDelta="0"
android:toXDelta="-100%p"/> android:toXDelta="-100%p" />
</set> </set>

2
app/src/main/res/anim/push_right_in.xml

@ -3,6 +3,6 @@
<translate <translate
android:duration="500" android:duration="500"
android:fromXDelta="-100%p" android:fromXDelta="-100%p"
android:toXDelta="0"/> android:toXDelta="0" />
</set> </set>

2
app/src/main/res/anim/push_right_out.xml

@ -3,6 +3,6 @@
<translate <translate
android:duration="500" android:duration="500"
android:fromXDelta="0" android:fromXDelta="0"
android:toXDelta="100%p"/> android:toXDelta="100%p" />
</set> </set>

8
app/src/main/res/drawable/guest_button_border_bg.xml

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@null"/> <solid android:color="@null" />
<stroke <stroke
android:width="1dip" android:width="1dip"
android:color="@color/accent"/> android:color="@color/accent" />
<corners android:radius="5dip"/> <corners android:radius="5dip" />
<padding <padding
android:bottom="0dip" android:bottom="0dip"
android:left="0dip" android:left="0dip"
android:right="0dip" android:right="0dip"
android:top="0dip"/> android:top="0dip" />
</shape> </shape>

13
app/src/main/res/drawable/ic_access_time_white_24dp.xml

@ -1,5 +1,10 @@
<vector android:height="24dp" android:tint="#FFFFFF" <vector android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0" android:tint="#FFFFFF"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android"> android:viewportHeight="24.0"
<path android:fillColor="#FF000000" android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/> android:viewportWidth="24.0"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android">
<path
android:fillColor="#FF000000"
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8zM12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z" />
</vector> </vector>

10
app/src/main/res/drawable/ic_add_fab.xml

@ -1,9 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" <vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp" android:width="24dp"
android:height="24dp" android:height="24dp"
android:viewportWidth="24.0" android:viewportWidth="24.0"
android:viewportHeight="24.0"> android:viewportHeight="24.0">
<path <path
android:fillColor="#FFFFFF" android:fillColor="#FFFFFF"
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/> android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z" />
</vector> </vector>

13
app/src/main/res/drawable/ic_announcement.xml

@ -1,7 +1,12 @@
<vector android:height="24dp" android:viewportHeight="297" <vector android:height="24dp"
android:viewportWidth="297" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android" android:viewportHeight="297"
android:viewportWidth="297"
android:width="24dp"
xmlns:android="http://schemas.android.com/apk/res/android"
android:tint="#FFFFFF"> android:tint="#FFFFFF">
<path android:fillColor="#FF000000" <path
android:fillColor="#FF000000"
android:pathData="M282.82,107.559h-25.792V10.025c0,-4.056 -2.443,-7.711 -6.19,-9.261c-3.745,-1.555 -8.059,-0.693 -10.925,2.177C195.46,47.434 157.039,68.643 132.635,78.6C106.33,89.333 90.261,89.635 90.159,89.637H14.18c-5.536,0 -10.023,4.488 -10.023,10.024v89.631c0,5.536 4.487,10.023 10.023,10.023h10.2l37.887,91.497c1.551,3.746 5.206,6.189 9.261,6.189h55.538c0.006,-0.001 0.012,-0.001 0.02,0c5.536,0 10.023,-4.488 10.023,-10.023c0,-1.588 -0.37,-3.09 -1.025,-4.424l-33.809,-81.646c22.4,4.443 73.884,21.285 137.641,85.1c1.917,1.921 4.483,2.939 7.094,2.939c0.055,0 0.109,0 0.164,0c5.468,-0.079 9.877,-4.536 9.877,-10.023c0,-0.214 -0.006,-0.428 -0.02,-0.639l-0.002,-96.896h25.792c5.536,0 10.023,-4.488 10.023,-10.024v-53.779C292.844,112.048 288.356,107.559 282.82,107.559zM24.204,109.683h55.932v69.584H24.204V109.683zM78.226,276.952l-31.139,-75.196h33.839l31.138,75.196H78.226zM100.183,180.201v-71.452c20.889,-3.123 72.28,-16.674 136.797,-75.301v84.121v0.015v53.779c0,0.008 0,0.017 0,0.025l0.002,84.111C172.466,196.876 121.072,183.326 100.183,180.201zM272.796,161.34h-15.768v-33.732h15.768V161.34z" android:pathData="M282.82,107.559h-25.792V10.025c0,-4.056 -2.443,-7.711 -6.19,-9.261c-3.745,-1.555 -8.059,-0.693 -10.925,2.177C195.46,47.434 157.039,68.643 132.635,78.6C106.33,89.333 90.261,89.635 90.159,89.637H14.18c-5.536,0 -10.023,4.488 -10.023,10.024v89.631c0,5.536 4.487,10.023 10.023,10.023h10.2l37.887,91.497c1.551,3.746 5.206,6.189 9.261,6.189h55.538c0.006,-0.001 0.012,-0.001 0.02,0c5.536,0 10.023,-4.488 10.023,-10.023c0,-1.588 -0.37,-3.09 -1.025,-4.424l-33.809,-81.646c22.4,4.443 73.884,21.285 137.641,85.1c1.917,1.921 4.483,2.939 7.094,2.939c0.055,0 0.109,0 0.164,0c5.468,-0.079 9.877,-4.536 9.877,-10.023c0,-0.214 -0.006,-0.428 -0.02,-0.639l-0.002,-96.896h25.792c5.536,0 10.023,-4.488 10.023,-10.024v-53.779C292.844,112.048 288.356,107.559 282.82,107.559zM24.204,109.683h55.932v69.584H24.204V109.683zM78.226,276.952l-31.139,-75.196h33.839l31.138,75.196H78.226zM100.183,180.201v-71.452c20.889,-3.123 72.28,-16.674 136.797,-75.301v84.121v0.015v53.779c0,0.008 0,0.017 0,0.025l0.002,84.111C172.466,196.876 121.072,183.326 100.183,180.201zM272.796,161.34h-15.768v-33.732h15.768V161.34z"
android:strokeColor="#000000" android:strokeWidth="1"/> android:strokeColor="#000000"
android:strokeWidth="1" />
</vector> </vector>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save