Browse Source

Version 1.3.3

master v1.3.3
Ezerous 7 years ago
parent
commit
4f2a19c672
  1. 4
      .gitignore
  2. 38
      .gitlab-ci.yml
  3. 2
      VERSION
  4. 37
      app/build.gradle
  5. 42
      app/src/debug/google-services.json
  6. 1
      app/src/main/AndroidManifest.xml
  7. 42
      app/src/main/assets/apache_libraries.html
  8. 2
      app/src/main/assets/mit_libraries.html
  9. 51
      app/src/main/java/gr/thmmy/mthmmy/activities/AboutActivity.java
  10. 4
      app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java
  11. 2
      app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java
  12. 19
      app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java
  13. 2
      app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadAdapter.java
  14. 8
      app/src/main/java/gr/thmmy/mthmmy/activities/main/unread/UnreadFragment.java
  15. 27
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java
  16. 7
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java
  17. 14
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsFragment.java
  18. 86
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java
  19. 233
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/Posting.java
  20. 241
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java
  21. 131
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
  22. 57
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAnimations.java
  23. 3
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java
  24. 50
      app/src/main/java/gr/thmmy/mthmmy/base/BaseActivity.java
  25. 26
      app/src/main/java/gr/thmmy/mthmmy/services/DownloadService.java
  26. 7
      app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareFABBehavior.java
  27. 7
      app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareLinearBehavior.java
  28. 12
      app/src/main/res/layout-v21/activity_topic_post_row.xml
  29. 83
      app/src/main/res/layout/activity_about.xml
  30. 14
      app/src/main/res/layout/activity_board_sub_board.xml
  31. 14
      app/src/main/res/layout/activity_board_topic.xml
  32. 12
      app/src/main/res/layout/activity_topic_post_row.xml
  33. 17
      app/src/main/res/layout/activity_topic_quick_reply_row.xml
  34. 13
      app/src/main/res/layout/fragment_forum_board_row.xml
  35. 14
      app/src/main/res/layout/fragment_latest_posts_empty_message.xml
  36. 2
      app/src/main/res/layout/fragment_recent_row.xml
  37. 11
      app/src/main/res/layout/fragment_unread_mark_read_row.xml
  38. 2
      app/src/main/res/layout/fragment_unread_row.xml
  39. 4
      app/src/main/res/values/strings.xml
  40. 3
      build.gradle
  41. 4
      gradle/wrapper/gradle-wrapper.properties

4
.gitignore

@ -46,5 +46,5 @@ captures/
### Android Patch ### ### Android Patch ###
gen-external-apklibs gen-external-apklibs
# Google Services (release build) # Google Services JSON
app/src/release/google-services.json google-services.json

38
.gitlab-ci.yml

@ -2,30 +2,38 @@ image: openjdk:8-jdk
variables: variables:
ANDROID_TARGET_SDK: "26" ANDROID_TARGET_SDK: "26"
ANDROID_BUILD_TOOLS: "26.0.1" ANDROID_BUILD_TOOLS: "27.0.0"
ANDROID_SDK_TOOLS: "25.2.5" ANDROID_SDK_TOOLS_REV: "3859397"
before_script: before_script:
- apt-get --quiet update --yes - apt-get --quiet update --yes
- apt-get --quiet install --yes wget tar unzip lib32stdc++6 lib32z1 - apt-get --quiet install --yes wget unzip lib32stdc++6 lib32z1
- wget --quiet --output-document=android-sdk.zip https://dl.google.com/android/repository/tools_r${ANDROID_SDK_TOOLS}-linux.zip - mkdir $HOME/.android # for sdkmanager configs
- unzip android-sdk.zip -d android-sdk-linux - echo 'count=0' > $HOME/.android/repositories.cfg # avoid warning
- echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter android-${ANDROID_TARGET_SDK} - wget --quiet --output-document=android-sdk.zip https://dl.google.com/android/repository/sdk-tools-linux-${ANDROID_SDK_TOOLS_REV}.zip
- echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter platform-tools - mkdir $PWD/android-sdk-linux
- echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter build-tools-${ANDROID_BUILD_TOOLS} - unzip -qq android-sdk.zip -d $PWD/android-sdk-linux
- echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter extra-android-m2repository
- echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter extra-google-google_play_services
- echo y | android-sdk-linux/tools/android --silent update sdk --no-ui --all --filter extra-google-m2repository
- export ANDROID_HOME=$PWD/android-sdk-linux - export ANDROID_HOME=$PWD/android-sdk-linux
- export PATH=$PATH:$PWD/android-sdk-linux/platform-tools/ - echo y | $ANDROID_HOME/tools/bin/sdkmanager --update > /dev/null
- echo y | $ANDROID_HOME/tools/bin/sdkmanager 'tools' > /dev/null
- echo y | $ANDROID_HOME/tools/bin/sdkmanager 'platform-tools' > /dev/null
- echo y | $ANDROID_HOME/tools/bin/sdkmanager 'build-tools;'$ANDROID_BUILD_TOOLS > /dev/null
- echo y | $ANDROID_HOME/tools/bin/sdkmanager 'platforms;android-'$ANDROID_TARGET_SDK > /dev/null
- echo y | $ANDROID_HOME/tools/bin/sdkmanager 'extras;android;m2repository' > /dev/null
- echo y | $ANDROID_HOME/tools/bin/sdkmanager 'extras;google;google_play_services' > /dev/null
- echo y | $ANDROID_HOME/tools/bin/sdkmanager 'extras;google;m2repository' > /dev/null
- chmod +x ./gradlew - chmod +x ./gradlew
build_develop: stages:
- build
build:
stage: build
script: script:
- ./gradlew assembleDebug - ./gradlew assembleDebug > /dev/null
except: except:
- master - master
artifacts: artifacts:
name: "${CI_BUILD_NAME}" name: "${CI_BUILD_NAME}"
paths: paths:
- app/build/outputs/apk - app/build/outputs/

2
VERSION

@ -1 +1 @@
1.3.2 1.3.3

37
app/build.gradle

@ -2,15 +2,15 @@ apply plugin: 'com.android.application'
android { android {
compileSdkVersion 26 compileSdkVersion 26
buildToolsVersion "26.0.1" buildToolsVersion "27.0.0"
defaultConfig { defaultConfig {
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
applicationId "gr.thmmy.mthmmy" applicationId "gr.thmmy.mthmmy"
minSdkVersion 19 minSdkVersion 19
targetSdkVersion 26 targetSdkVersion 26
versionCode 10 versionCode 11
versionName "1.3.2" versionName "1.3.3"
archivesBaseName = "mTHMMY-v$versionName" archivesBaseName = "mTHMMY-v$versionName"
} }
@ -19,35 +19,38 @@ android {
minifyEnabled true minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
/*debug { debug {
def date = new Date().format('ddMMyy_HH'); def date = new Date().format('ddMMyy_HHmmss')
archivesBaseName = archivesBaseName + "-$date" archivesBaseName = archivesBaseName + "-$date"
}*/ }
} }
} }
dependencies { dependencies {
compile fileTree(dir: 'libs', include: ['*.jar']) compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:26.0.0' compile 'com.android.support:appcompat-v7:26.1.0'
compile 'com.android.support:design:26.0.0' compile 'com.android.support:design:26.1.0'
compile 'com.android.support:support-v4:26.0.0' compile 'com.android.support:support-v4:26.1.0'
compile 'com.android.support:cardview-v7:26.0.0' compile 'com.android.support:cardview-v7:26.1.0'
compile 'com.android.support:recyclerview-v7:26.0.0' compile 'com.android.support:recyclerview-v7:26.1.0'
compile 'com.google.firebase:firebase-crash:10.2.6' compile 'com.google.firebase:firebase-crash:11.4.2'
compile 'com.squareup.okhttp3:okhttp:3.8.0' compile 'com.squareup.okhttp3:okhttp:3.9.0'
compile 'com.squareup.picasso:picasso:2.5.2' compile 'com.squareup.picasso:picasso:2.5.2'
compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0' compile 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
compile 'org.jsoup:jsoup:1.10.2' compile 'org.jsoup:jsoup:1.10.3'
compile 'com.github.franmontiel:PersistentCookieJar:v1.0.1' compile 'com.github.franmontiel:PersistentCookieJar:v1.0.1'
compile 'com.github.PhilJay:MPAndroidChart:v3.0.2' compile 'com.github.PhilJay:MPAndroidChart:v3.0.2'
compile('com.mikepenz:materialdrawer:5.9.2@aar') { compile('com.mikepenz:materialdrawer:5.9.3@aar') {
transitive = true transitive = true
} }
compile 'com.mikepenz:fontawesome-typeface:4.7.0.0@aar' compile 'com.mikepenz:fontawesome-typeface:4.7.0.0@aar'
compile 'com.mikepenz:google-material-typeface:3.0.1.2.original@aar'
compile 'pl.droidsonroids.gif:android-gif-drawable:1.2.7' compile 'pl.droidsonroids.gif:android-gif-drawable:1.2.7'
compile 'com.bignerdranch.android:expandablerecyclerview:3.0.0-RC1' //TODO: Deprecated - needs replacement! compile 'com.bignerdranch.android:expandablerecyclerview:3.0.0-RC1' //TODO: Deprecated - needs replacement!
compile 'me.zhanghai.android.materialprogressbar:library:1.4.1' compile 'me.zhanghai.android.materialprogressbar:library:1.4.2'
compile 'com.jakewharton.timber:timber:4.5.1' compile 'com.jakewharton.timber:timber:4.5.1'
} }
apply plugin: 'com.google.gms.google-services' if (getGradle().getStartParameter().getTaskRequests().toString().contains("Release")){
apply plugin: 'com.google.gms.google-services'
}

42
app/src/debug/google-services.json

@ -1,42 +0,0 @@
{
"project_info": {
"project_number": "934432863001",
"firebase_url": "https://mthmmy-debug.firebaseio.com",
"project_id": "mthmmy-debug",
"storage_bucket": "mthmmy-debug.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:934432863001:android:088be0537ff6b292",
"android_client_info": {
"package_name": "gr.thmmy.mthmmy"
}
},
"oauth_client": [
{
"client_id": "934432863001-d5oocs1vdi0pcepesi55a41p7enphfcv.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyD4-gwVcb2Rc8zeT8l1v2Lg1DU0QgfGtk8"
}
],
"services": {
"analytics_service": {
"status": 1
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 2
}
}
}
],
"configuration_version": "1"
}

1
app/src/main/AndroidManifest.xml

@ -7,6 +7,7 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<application <application
android:name=".base.BaseApplication" android:name=".base.BaseApplication"

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

@ -38,27 +38,27 @@
<body> <body>
<ul> <ul>
<li> <li>
<h5><a href="https://square.github.io/okhttp/">OkHttp</a>&nbsp;v3.8.0 (Copyright ©2016 Square, Inc.)</h5> <h5><a href="https://square.github.io/okhttp/">OkHttp</a>&nbsp;v3.9.0 (Copyright ©2016 Square, Inc.)</h5>
</li> </li>
<li> <li>
<h5><a href="https://square.github.io/picasso/">Picasso</a>&nbsp;v2.5.2 (Copyright ©2013 Square, Inc.)</h5> <h5><a href="https://square.github.io/picasso/">Picasso</a>&nbsp;v2.5.2 (Copyright ©2013 Square, Inc.)</h5>
</li> </li>
<li> <li>
<h5><a href="https://github.com/franmontiel/PersistentCookieJar">PersistentCookieJar</a>&nbsp;v1.0.1 (Copyright ©2016 Francisco José Montiel Navarro)</h5> <h5><a href="https://github.com/franmontiel/PersistentCookieJar">PersistentCookieJar</a>&nbsp;v1.0.1 (Copyright ©2016 Francisco José Montiel Navarro)</h5>
</li> </li>
<li> <li>
<h5><a href="https://github.com/PhilJay/MPAndroidChart">MPAndroidChart</a>&nbsp;v3.0.2 (Copyright ©2016 Philipp Jahoda)</h5> <h5><a href="https://github.com/PhilJay/MPAndroidChart">MPAndroidChart</a>&nbsp;v3.0.2 (Copyright ©2016 Philipp Jahoda)</h5>
</li> </li>
<li> <li>
<h5><a href="https://github.com/mikepenz/MaterialDrawer">MaterialDrawer</a>&nbsp;v5.9.2 (Copyright ©2016 Mike Penz)</h5> <h5><a href="https://github.com/mikepenz/MaterialDrawer">MaterialDrawer</a>&nbsp;v5.9.3 (Copyright ©2016 Mike Penz)</h5>
</li> </li>
<li> <li>
<h5><a href="https://github.com/mikepenz/Android-Iconics/tree/develop/fontawesome-typeface-library">Fontawesome Typeface Library</a>&nbsp;v4.7.0.0 (Copyright ©2016 Mike Penz)</h5> <h5><a href="https://github.com/mikepenz/Android-Iconics">Android-Iconics</a>&nbsp;v2.9.5 (Copyright ©2016 Mike Penz)</h5>
</li> </li>
<li> <li>
<h5><a href="https://github.com/DreaminginCodeZH/MaterialProgressBar">MaterialProgressBar</a>&nbsp;v1.4.1 (Copyright ©2015 Zhang Hai)</h5> <h5><a href="https://github.com/DreaminginCodeZH/MaterialProgressBar">MaterialProgressBar</a>&nbsp;v1.4.2 (Copyright ©2015 Zhang Hai)</h5>
</li> </li>
</ul> </ul>

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

@ -39,7 +39,7 @@
<body> <body>
<ul> <ul>
<li> <li>
<h5><a href="https://jsoup.org//">jsoup</a>&nbsp;v1.10.2 (Copyright ©2009-2017, Jonathan Hedley &lt;jonathan@hedley.net&gt;)</h5> <h5><a href="https://jsoup.org//">jsoup</a>&nbsp;v1.10.3 (Copyright ©2009-2017, Jonathan Hedley &lt;jonathan@hedley.net&gt;)</h5>
</li> </li>
<li> <li>
<h5><a href="https://github.com/koral--/android-gif-drawable">android-gif-drawable</a>&nbsp;v1.2.7 (Copyright ©2016 Karol Wrótniak, Droids on Roids)</h5> <h5><a href="https://github.com/koral--/android-gif-drawable">android-gif-drawable</a>&nbsp;v1.2.7 (Copyright ©2016 Karol Wrótniak, Droids on Roids)</h5>

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

@ -53,28 +53,33 @@ public class AboutActivity extends BaseActivity {
trollGif = findViewById(R.id.trollPicFrame); trollGif = findViewById(R.id.trollPicFrame);
TextView tv = findViewById(R.id.version); TextView tv = findViewById(R.id.version);
if (tv != null) if (tv != null) {
tv.setText(getString(R.string.version, versionName)); if (BuildConfig.DEBUG)
tv.setText(getString(R.string.version, versionName + "-debug"));
tv.setOnClickListener(new View.OnClickListener() { else
@Override tv.setText(getString(R.string.version, versionName));
public void onClick(View view) {
if (mVersionLastPressedTime + TIME_INTERVAL > System.currentTimeMillis()) {
if (mVersionPressedCounter == TIMES_TO_PRESS) { tv.setOnClickListener(new View.OnClickListener() {
appBar.setVisibility(View.INVISIBLE); @Override
mainContent.setVisibility(View.INVISIBLE); public void onClick(View view) {
trollGif.setVisibility(View.VISIBLE); if (mVersionLastPressedTime + TIME_INTERVAL > System.currentTimeMillis()) {
drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); if (mVersionPressedCounter == TIMES_TO_PRESS) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); appBar.setVisibility(View.INVISIBLE);
mainContent.setVisibility(View.INVISIBLE);
trollGif.setVisibility(View.VISIBLE);
drawer.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
mVersionLastPressedTime = System.currentTimeMillis();
++mVersionPressedCounter;
} else {
mVersionLastPressedTime = System.currentTimeMillis();
mVersionPressedCounter = 0;
} }
mVersionLastPressedTime = System.currentTimeMillis();
++mVersionPressedCounter;
} else {
mVersionLastPressedTime = System.currentTimeMillis();
mVersionPressedCounter = 0;
} }
} });
}); }
} }
@ -95,7 +100,8 @@ public class AboutActivity extends BaseActivity {
.setView(webView) .setView(webView)
.setPositiveButton(android.R.string.ok, null) .setPositiveButton(android.R.string.ok, null)
.show(); .show();
alertDialog.getWindow().setLayout(width, height); if(alertDialog.getWindow()!=null)
alertDialog.getWindow().setLayout(width, height);
} }
public void displayMITLibraries(View v) { public void displayMITLibraries(View v) {
@ -109,7 +115,8 @@ public class AboutActivity extends BaseActivity {
.setView(webView) .setView(webView)
.setPositiveButton(android.R.string.ok, null) .setPositiveButton(android.R.string.ok, null)
.show(); .show();
alertDialog.getWindow().setLayout(width, height); if(alertDialog.getWindow()!=null)
alertDialog.getWindow().setLayout(width, height);
} }
} }

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

@ -125,7 +125,7 @@ public class ForumFragment extends BaseFragment {
}); });
CustomRecyclerView recyclerView = rootView.findViewById(R.id.list); CustomRecyclerView recyclerView = rootView.findViewById(R.id.list);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(rootView.findViewById(R.id.list).getContext()); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(recyclerView.getContext());
recyclerView.setLayoutManager(linearLayoutManager); recyclerView.setLayoutManager(linearLayoutManager);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
linearLayoutManager.getOrientation()); linearLayoutManager.getOrientation());
@ -133,6 +133,8 @@ public class ForumFragment extends BaseFragment {
recyclerView.setAdapter(forumAdapter); recyclerView.setAdapter(forumAdapter);
swipeRefreshLayout = rootView.findViewById(R.id.swiperefresh); swipeRefreshLayout = rootView.findViewById(R.id.swiperefresh);
swipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.primary);
swipeRefreshLayout.setColorSchemeResources(R.color.accent);
swipeRefreshLayout.setOnRefreshListener( swipeRefreshLayout.setOnRefreshListener(
new SwipeRefreshLayout.OnRefreshListener() { new SwipeRefreshLayout.OnRefreshListener() {
@Override @Override

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

@ -43,7 +43,7 @@ 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) {
holder.mTitleView.setText(recentList.get(position).getSubject()); holder.mTitleView.setText(recentList.get(position).getSubject());
holder.mDateTimeView.setText(recentList.get(position).getDateTimeModified()); holder.mDateTimeView.setText(recentList.get(position).getDateTimeModified());
holder.mUserView.setText(context.getString(R.string.byUser, recentList.get(position).getLastUser())); holder.mUserView.setText(recentList.get(position).getLastUser());
holder.topic = recentList.get(position); holder.topic = recentList.get(position);

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

@ -99,7 +99,7 @@ public class RecentFragment extends BaseFragment {
recentAdapter = new RecentAdapter(getActivity(), topicSummaries, fragmentInteractionListener); recentAdapter = new RecentAdapter(getActivity(), topicSummaries, fragmentInteractionListener);
CustomRecyclerView recyclerView = rootView.findViewById(R.id.list); CustomRecyclerView recyclerView = rootView.findViewById(R.id.list);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(rootView.findViewById(R.id.list).getContext()); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(recyclerView.getContext());
recyclerView.setLayoutManager(linearLayoutManager); recyclerView.setLayoutManager(linearLayoutManager);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
linearLayoutManager.getOrientation()); linearLayoutManager.getOrientation());
@ -107,6 +107,8 @@ public class RecentFragment extends BaseFragment {
recyclerView.setAdapter(recentAdapter); recyclerView.setAdapter(recentAdapter);
swipeRefreshLayout = rootView.findViewById(R.id.swiperefresh); swipeRefreshLayout = rootView.findViewById(R.id.swiperefresh);
swipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.primary);
swipeRefreshLayout.setColorSchemeResources(R.color.accent);
swipeRefreshLayout.setOnRefreshListener( swipeRefreshLayout.setOnRefreshListener(
new SwipeRefreshLayout.OnRefreshListener() { new SwipeRefreshLayout.OnRefreshListener() {
@Override @Override
@ -161,11 +163,20 @@ public class RecentFragment extends BaseFragment {
throw new ParseException("Parsing failed (lastUser)"); throw new ParseException("Parsing failed (lastUser)");
String dateTime = recent.get(i + 2).text(); String dateTime = recent.get(i + 2).text();
pattern = Pattern.compile("\\[(.*)\\]"); pattern = Pattern.compile("\\[(.*)]");
matcher = pattern.matcher(dateTime); matcher = pattern.matcher(dateTime);
if (matcher.find()) if (matcher.find()) {
dateTime = matcher.group(1); dateTime = matcher.group(1);
else if (dateTime.contains(" am") || dateTime.contains(" pm") ||
dateTime.contains(" πμ") || dateTime.contains(" μμ")) {
dateTime = dateTime.replaceAll(":[0-5][0-9] ", " ");
} else {
dateTime=dateTime.substring(0,dateTime.lastIndexOf(":"));
}
if (!dateTime.contains(",")) {
dateTime = dateTime.replaceAll(".+? ([0-9])", "$1");
}
} else
throw new ParseException("Parsing failed (dateTime)"); throw new ParseException("Parsing failed (dateTime)");
topicSummaries.add(new TopicSummary(link, title, lastUser, dateTime)); topicSummaries.add(new TopicSummary(link, title, lastUser, dateTime));

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

@ -67,7 +67,7 @@ class UnreadAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
viewHolder.mTitleView.setText(unreadList.get(holder.getAdapterPosition()).getSubject()); viewHolder.mTitleView.setText(unreadList.get(holder.getAdapterPosition()).getSubject());
viewHolder.mDateTimeView.setText(unreadList.get(holder.getAdapterPosition()).getDateTimeModified()); viewHolder.mDateTimeView.setText(unreadList.get(holder.getAdapterPosition()).getDateTimeModified());
viewHolder.mUserView.setText(context.getString(R.string.byUser, unreadList.get(position).getLastUser())); viewHolder.mUserView.setText(unreadList.get(position).getLastUser());
viewHolder.topic = unreadList.get(holder.getAdapterPosition()); viewHolder.topic = unreadList.get(holder.getAdapterPosition());

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

@ -111,7 +111,7 @@ public class UnreadFragment extends BaseFragment {
}); });
CustomRecyclerView recyclerView = rootView.findViewById(R.id.list); CustomRecyclerView recyclerView = rootView.findViewById(R.id.list);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(rootView.findViewById(R.id.list).getContext()); LinearLayoutManager linearLayoutManager = new LinearLayoutManager(recyclerView.getContext());
recyclerView.setLayoutManager(linearLayoutManager); recyclerView.setLayoutManager(linearLayoutManager);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
linearLayoutManager.getOrientation()); linearLayoutManager.getOrientation());
@ -119,6 +119,8 @@ public class UnreadFragment extends BaseFragment {
recyclerView.setAdapter(unreadAdapter); recyclerView.setAdapter(unreadAdapter);
swipeRefreshLayout = rootView.findViewById(R.id.swiperefresh); swipeRefreshLayout = rootView.findViewById(R.id.swiperefresh);
swipeRefreshLayout.setProgressBackgroundColorSchemeResource(R.color.primary);
swipeRefreshLayout.setColorSchemeResources(R.color.accent);
swipeRefreshLayout.setOnRefreshListener( swipeRefreshLayout.setOnRefreshListener(
new SwipeRefreshLayout.OnRefreshListener() { new SwipeRefreshLayout.OnRefreshListener() {
@Override @Override
@ -172,6 +174,10 @@ public class UnreadFragment extends BaseFragment {
dateTime = dateTime.substring(0, dateTime.indexOf("<br>")); dateTime = dateTime.substring(0, dateTime.indexOf("<br>"));
dateTime = dateTime.replace("<b>", ""); dateTime = dateTime.replace("<b>", "");
dateTime = dateTime.replace("</b>", ""); dateTime = dateTime.replace("</b>", "");
dateTime = dateTime.replaceAll(":[0-5][0-9] ", " ");
if (!dateTime.contains(",")) {
dateTime = dateTime.replaceAll(".+? ([0-9])", "$1");
}
topicSummaries.add(new TopicSummary(link, title, lastUser, dateTime)); topicSummaries.add(new TopicSummary(link, title, lastUser, dateTime));
} }

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

@ -172,7 +172,7 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
ThmmyPage.PageCategory target = ThmmyPage.resolvePageCategory(Uri.parse(profileUrl)); ThmmyPage.PageCategory target = ThmmyPage.resolvePageCategory(Uri.parse(profileUrl));
if (!target.is(ThmmyPage.PageCategory.PROFILE)) { if (!target.is(ThmmyPage.PageCategory.PROFILE)) {
Timber.e("Bundle came with a non profile url!\nUrl:\n%s" , profileUrl); Timber.e("Bundle came with a non profile url!\nUrl:\n%s", profileUrl);
Toast.makeText(this, "An error has occurred\n Aborting.", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "An error has occurred\n Aborting.", Toast.LENGTH_SHORT).show();
finish(); finish();
} }
@ -217,6 +217,7 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
//Class variables //Class variables
Document profilePage; Document profilePage;
Spannable usernameSpan; Spannable usernameSpan;
Boolean isOnline = false;
protected void onPreExecute() { protected void onPreExecute() {
progressBar.setVisibility(ProgressBar.VISIBLE); progressBar.setVisibility(ProgressBar.VISIBLE);
@ -261,13 +262,17 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
usernameSpan.setSpan(new RelativeSizeSpan(0.45f) usernameSpan.setSpan(new RelativeSizeSpan(0.45f)
, 0, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); , 0, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
if (contentsTable.toString().contains("Online") if (contentsTable.toString().contains("Online")
|| contentsTable.toString().contains("Συνδεδεμένος")) { || contentsTable.toString().contains("Συνδεδεμένος")) {
usernameSpan.setSpan(new ForegroundColorSpan(Color.parseColor("#4CAF50")) isOnline = true;
, 0, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } else {
} else isOnline = false;
usernameSpan.setSpan(new ForegroundColorSpan(Color.GRAY) /*usernameSpan.setSpan(new ForegroundColorSpan(Color.GRAY)
, 0, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); , 0, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);*/
}
usernameSpan.setSpan(new ForegroundColorSpan(Color.parseColor("#26A69A"))
, 2, usernameSpan.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
} }
return true; return true;
} catch (SSLHandshakeException e) { } catch (SSLHandshakeException e) {
@ -290,8 +295,14 @@ public class ProfileActivity extends BaseActivity implements LatestPostsFragment
if (pmFAB.getVisibility() != View.GONE) pmFAB.setEnabled(true); if (pmFAB.getVisibility() != View.GONE) pmFAB.setEnabled(true);
progressBar.setVisibility(ProgressBar.INVISIBLE); progressBar.setVisibility(ProgressBar.INVISIBLE);
if (usernameSpan != null) usernameView.setText(usernameSpan); if (usernameSpan != null) {
else if (usernameView.getText() != username) usernameView.setText(username); if (isOnline) {
usernameView.setTextColor(Color.parseColor("#4CAF50"));
} else {
usernameView.setTextColor(Color.GRAY);
}
usernameView.setText(usernameSpan);
} else if (usernameView.getText() != username) usernameView.setText(username);
if (thumbnailUrl != null && !Objects.equals(thumbnailUrl, "")) if (thumbnailUrl != null && !Objects.equals(thumbnailUrl, ""))
//noinspection ConstantConditions //noinspection ConstantConditions
Picasso.with(getApplicationContext()) Picasso.with(getApplicationContext())

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

@ -21,6 +21,7 @@ import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
* specified {@link LatestPostsFragment.LatestPostsFragmentInteractionListener}. * specified {@link LatestPostsFragment.LatestPostsFragmentInteractionListener}.
*/ */
class LatestPostsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { class LatestPostsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final int VIEW_TYPE_EMPTY = -1;
private final int VIEW_TYPE_ITEM = 0; private final int VIEW_TYPE_ITEM = 0;
private final int VIEW_TYPE_LOADING = 1; private final int VIEW_TYPE_LOADING = 1;
final private LatestPostsFragment.LatestPostsFragmentInteractionListener interactionListener; final private LatestPostsFragment.LatestPostsFragmentInteractionListener interactionListener;
@ -38,11 +39,17 @@ class LatestPostsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
if (parsedTopicSummaries.get(position) == null && position == 0) return VIEW_TYPE_EMPTY;
return parsedTopicSummaries.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM; return parsedTopicSummaries.get(position) == null ? VIEW_TYPE_LOADING : VIEW_TYPE_ITEM;
} }
@Override @Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == VIEW_TYPE_EMPTY) {
View view = LayoutInflater.from(parent.getContext()).
inflate(R.layout.fragment_latest_posts_empty_message, parent, false);
return new RecyclerView.ViewHolder(view){};
}
if (viewType == VIEW_TYPE_ITEM) { if (viewType == VIEW_TYPE_ITEM) {
View view = LayoutInflater.from(parent.getContext()). View view = LayoutInflater.from(parent.getContext()).
inflate(R.layout.fragment_latest_posts_row, parent, false); inflate(R.layout.fragment_latest_posts_row, parent, false);

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

@ -50,6 +50,7 @@ public class LatestPostsFragment extends BaseFragment implements LatestPostsAdap
private LatestPostsTask profileLatestPostsTask; private LatestPostsTask profileLatestPostsTask;
private MaterialProgressBar progressBar; private MaterialProgressBar progressBar;
private boolean isLoadingMore; private boolean isLoadingMore;
private boolean userHasPosts = true;
private static final int visibleThreshold = 5; private static final int visibleThreshold = 5;
private int lastVisibleItem, totalItemCount; private int lastVisibleItem, totalItemCount;
@ -100,7 +101,8 @@ public class LatestPostsFragment extends BaseFragment implements LatestPostsAdap
totalItemCount = layoutManager.getItemCount(); totalItemCount = layoutManager.getItemCount();
lastVisibleItem = layoutManager.findLastVisibleItemPosition(); lastVisibleItem = layoutManager.findLastVisibleItemPosition();
if (!isLoadingMore && totalItemCount <= (lastVisibleItem + visibleThreshold)) { if (userHasPosts && !isLoadingMore &&
totalItemCount <= (lastVisibleItem + visibleThreshold)) {
isLoadingMore = true; isLoadingMore = true;
onLoadMore(); onLoadMore();
} }
@ -126,7 +128,7 @@ public class LatestPostsFragment extends BaseFragment implements LatestPostsAdap
@Override @Override
public void onActivityCreated(Bundle savedInstanceState) { public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
if (parsedTopicSummaries.isEmpty()) { if (parsedTopicSummaries.isEmpty() && userHasPosts) {
profileLatestPostsTask = new LatestPostsTask(); profileLatestPostsTask = new LatestPostsTask();
profileLatestPostsTask.execute(profileUrl + ";sa=showPosts"); profileLatestPostsTask.execute(profileUrl + ";sa=showPosts");
pagesLoaded = 1; pagesLoaded = 1;
@ -186,6 +188,7 @@ public class LatestPostsFragment extends BaseFragment implements LatestPostsAdap
//TODO: better parse error handling (ParseException etc.) //TODO: better parse error handling (ParseException etc.)
private boolean parseLatestPosts(Document latestPostsPage) { private boolean parseLatestPosts(Document latestPostsPage) {
//td:contains( Sorry, no matches were found)
Elements latestPostsRows = latestPostsPage. Elements latestPostsRows = latestPostsPage.
select("td:has(table:Contains(Show Posts)):not([style]) > table"); select("td:has(table:Contains(Show Posts)):not([style]) > table");
if (latestPostsRows.isEmpty()) { if (latestPostsRows.isEmpty()) {
@ -197,6 +200,13 @@ public class LatestPostsFragment extends BaseFragment implements LatestPostsAdap
parsedTopicSummaries.remove(parsedTopicSummaries.size() - 1); parsedTopicSummaries.remove(parsedTopicSummaries.size() - 1);
} }
if (!latestPostsRows.select("td:contains(Sorry, no matches were found)").isEmpty() ||
!latestPostsRows.select("td:contains(Δυστυχώς δεν βρέθηκε τίποτα)").isEmpty()){
userHasPosts = false;
parsedTopicSummaries.add(null);
return true;
}
for (Element row : latestPostsRows) { for (Element row : latestPostsRows) {
String pTopicUrl, pTopicTitle, pDateTime, pPost; String pTopicUrl, pTopicTitle, pDateTime, pPost;
if (Integer.parseInt(row.attr("cellpadding")) == 4) { if (Integer.parseInt(row.attr("cellpadding")) == 4) {

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

@ -56,6 +56,7 @@ public class StatsFragment extends Fragment {
private MaterialProgressBar progressBar; private MaterialProgressBar progressBar;
private boolean haveParsed = false; private boolean haveParsed = false;
private boolean userHasPosts = true;
private String generalStatisticsTitle = "", generalStatistics = "", postingActivityByTimeTitle = "", mostPopularBoardsByPostsTitle = "", mostPopularBoardsByActivityTitle = ""; private String generalStatisticsTitle = "", generalStatistics = "", postingActivityByTimeTitle = "", mostPopularBoardsByPostsTitle = "", mostPopularBoardsByActivityTitle = "";
final private List<Entry> postingActivityByTime = new ArrayList<>(); final private List<Entry> postingActivityByTime = new ArrayList<>();
final private List<BarEntry> mostPopularBoardsByPosts = new ArrayList<>(), mostPopularBoardsByActivity = new ArrayList<>(); final private List<BarEntry> mostPopularBoardsByPosts = new ArrayList<>(), mostPopularBoardsByActivity = new ArrayList<>();
@ -123,6 +124,7 @@ public class StatsFragment extends Fragment {
* as String parameter!</p> * as String parameter!</p>
*/ */
private class ProfileStatsTask extends AsyncTask<String, Void, Boolean> { private class ProfileStatsTask extends AsyncTask<String, Void, Boolean> {
@Override @Override
protected void onPreExecute() { protected void onPreExecute() {
progressBar.setVisibility(ProgressBar.VISIBLE); progressBar.setVisibility(ProgressBar.VISIBLE);
@ -160,14 +162,23 @@ public class StatsFragment extends Fragment {
} }
private boolean parseStats(Document statsPage) { private boolean parseStats(Document statsPage) {
//Doesn't go through all the parsing if this user has no posts
if (!statsPage.select("td:contains(No posts to speak of!)").isEmpty()) {
userHasPosts = false;
}
if (!statsPage.select("td:contains(Δεν υπάρχει καμία αποστολή μηνύματος!)").isEmpty()) {
userHasPosts = false;
}
if (statsPage.select("table.bordercolor[align]>tbody>tr").size() != 6) if (statsPage.select("table.bordercolor[align]>tbody>tr").size() != 6)
return false; return false;
{ {
Elements titleRows = statsPage.select("table.bordercolor[align]>tbody>tr.titlebg"); Elements titleRows = statsPage.select("table.bordercolor[align]>tbody>tr.titlebg");
generalStatisticsTitle = titleRows.first().text(); generalStatisticsTitle = titleRows.first().text();
postingActivityByTimeTitle = titleRows.get(1).text(); if (userHasPosts) {
mostPopularBoardsByPostsTitle = titleRows.last().select("td").first().text(); postingActivityByTimeTitle = titleRows.get(1).text();
mostPopularBoardsByActivityTitle = titleRows.last().select("td").last().text(); mostPopularBoardsByPostsTitle = titleRows.last().select("td").first().text();
mostPopularBoardsByActivityTitle = titleRows.last().select("td").last().text();
}
} }
{ {
Elements statsRows = statsPage.select("table.bordercolor[align]>tbody>tr:not(.titlebg)"); Elements statsRows = statsPage.select("table.bordercolor[align]>tbody>tr:not(.titlebg)");
@ -177,39 +188,41 @@ public class StatsFragment extends Fragment {
generalStatistics += generalStatisticsRow.text() + "\n"; generalStatistics += generalStatisticsRow.text() + "\n";
generalStatistics = generalStatistics.trim(); generalStatistics = generalStatistics.trim();
} }
{ if (userHasPosts) {
Elements postingActivityByTimeCols = statsRows.get(1).select(">td").last() {
.select("tr").first().select("td[width=4%]"); Elements postingActivityByTimeCols = statsRows.get(1).select(">td").last()
int i = -1; .select("tr").first().select("td[width=4%]");
for (Element postingActivityByTimeColumn : postingActivityByTimeCols) { int i = -1;
postingActivityByTime.add(new Entry(++i, Float.parseFloat(postingActivityByTimeColumn for (Element postingActivityByTimeColumn : postingActivityByTimeCols) {
.select("img").first().attr("height")))); postingActivityByTime.add(new Entry(++i, Float.parseFloat(postingActivityByTimeColumn
.select("img").first().attr("height"))));
}
} }
} {
{ Elements mostPopularBoardsByPostsRows = statsRows.last().select(">td").get(1)
Elements mostPopularBoardsByPostsRows = statsRows.last().select(">td").get(1) .select(">table>tbody>tr");
.select(">table>tbody>tr"); int i = mostPopularBoardsByPostsRows.size();
int i = mostPopularBoardsByPostsRows.size(); for (Element mostPopularBoardsByPostsRow : mostPopularBoardsByPostsRows) {
for (Element mostPopularBoardsByPostsRow : mostPopularBoardsByPostsRows) { Elements dataCols = mostPopularBoardsByPostsRow.select("td");
Elements dataCols = mostPopularBoardsByPostsRow.select("td"); mostPopularBoardsByPosts.add(new BarEntry(--i,
mostPopularBoardsByPosts.add(new BarEntry(--i, Integer.parseInt(dataCols.last().text())));
Integer.parseInt(dataCols.last().text()))); mostPopularBoardsByPostsLabels.add(dataCols.first().text());
mostPopularBoardsByPostsLabels.add(dataCols.first().text()); }
Collections.reverse(mostPopularBoardsByPostsLabels);
} }
Collections.reverse(mostPopularBoardsByPostsLabels); {
} Elements mostPopularBoardsByActivityRows = statsRows.last().select(">td").last()
{ .select(">table>tbody>tr");
Elements mostPopularBoardsByActivityRows = statsRows.last().select(">td").last() int i = mostPopularBoardsByActivityRows.size();
.select(">table>tbody>tr"); for (Element mostPopularBoardsByActivityRow : mostPopularBoardsByActivityRows) {
int i = mostPopularBoardsByActivityRows.size(); Elements dataCols = mostPopularBoardsByActivityRow.select("td");
for (Element mostPopularBoardsByActivityRow : mostPopularBoardsByActivityRows) { String tmp = dataCols.last().text();
Elements dataCols = mostPopularBoardsByActivityRow.select("td"); mostPopularBoardsByActivity.add(new BarEntry(--i,
String tmp = dataCols.last().text(); Float.parseFloat(tmp.substring(0, tmp.indexOf("%")))));
mostPopularBoardsByActivity.add(new BarEntry(--i, mostPopularBoardsByActivityLabels.add(dataCols.first().text());
Float.parseFloat(tmp.substring(0, tmp.indexOf("%"))))); }
mostPopularBoardsByActivityLabels.add(dataCols.first().text()); Collections.reverse(mostPopularBoardsByActivityLabels);
} }
Collections.reverse(mostPopularBoardsByActivityLabels);
} }
} }
return true; return true;
@ -221,6 +234,13 @@ public class StatsFragment extends Fragment {
.setText(generalStatisticsTitle); .setText(generalStatisticsTitle);
((TextView) mainContent.findViewById(R.id.general_statistics)) ((TextView) mainContent.findViewById(R.id.general_statistics))
.setText(generalStatistics); .setText(generalStatistics);
if (!userHasPosts) {
mainContent.removeViews(2, mainContent.getChildCount() - 2);
//mainContent.removeViews(2, 6);
return;
}
((TextView) mainContent.findViewById(R.id.posting_activity_by_time_title)) ((TextView) mainContent.findViewById(R.id.posting_activity_by_time_title))
.setText(postingActivityByTimeTitle); .setText(postingActivityByTimeTitle);

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

@ -1,14 +1,9 @@
package gr.thmmy.mthmmy.activities.topic; package gr.thmmy.mthmmy.activities.topic;
import android.util.Log;
import org.jsoup.Jsoup; import org.jsoup.Jsoup;
import org.jsoup.nodes.Document; import org.jsoup.nodes.Document;
import java.io.IOException; import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import okhttp3.Response; import okhttp3.Response;
import timber.log.Timber; import timber.log.Timber;
@ -86,232 +81,4 @@ class Posting {
} }
return REPLY_STATUS.SUCCESSFUL; return REPLY_STATUS.SUCCESSFUL;
} }
/**
* This is a fucked up method.. Just don't waste your time here unless you have suicidal
* tendencies.
*
* @param html the html string to be transformed to BBcode
* @return the BBcode string
*/
static String htmlToBBcode(String html) {
Log.d("Cancer", html);
Map<String, String> bbMap = new HashMap<>();
Map<String, String> smileysMap1 = new HashMap<>();
Map<String, String> smileysMap2 = new HashMap<>();
smileysMap1.put("Smiley", ":)");
smileysMap1.put("Wink", ";)");
smileysMap1.put("Cheesy", ":D");
smileysMap1.put("Grin", ";D");
smileysMap1.put("Angry", ">:(");
smileysMap1.put("Sad", ":(");
smileysMap1.put("Shocked", ":o");
smileysMap1.put("Cool", "8))");
smileysMap1.put("Huh", ":???:");
smileysMap1.put("Roll Eyes", "::)");
smileysMap1.put("Tongue", ":P");
smileysMap1.put("Embarrassed", ":-[");
smileysMap1.put("Lips Sealed", ":-X");
smileysMap1.put("Kiss", ":-*");
smileysMap1.put("Cry", ":'(");
smileysMap1.put("heart", "<3");
smileysMap1.put("kleidaria", "^locked^");
smileysMap1.put("roll_over", "^rollover^");
smileysMap1.put("redface", "^redface^");
smileysMap1.put("confused", "^confused^");
smileysMap1.put("innocent", "^innocent^");
smileysMap1.put("sleep", "^sleep^");
smileysMap1.put("lips_sealed", "^sealed^");
smileysMap1.put("cool", "^cool^");
smileysMap1.put("crazy", "^crazy^");
smileysMap1.put("mad", "^mad^");
smileysMap1.put("wav", "^wav^");
smileysMap1.put("BinkyBaby", "^binkybaby^");
smileysMap1.put("DontKnow", "^dontknow^");
smileysMap1.put("angry4", ":angry4:");
smileysMap1.put("angryAndHot", "^angryhot^");
smileysMap1.put("angry", "^angry^");
smileysMap1.put("bang_head", "^banghead^");
smileysMap1.put("CryBaby", "^crybaby^");
smileysMap1.put("Hello", "^hello^");
smileysMap1.put("jerk", "^jerk^");
smileysMap1.put("NoNo", "^nono^");
smileysMap1.put("NotWorthy", "^notworthy^");
smileysMap1.put("Off-topic", "^off-topic^");
smileysMap1.put("Puke", "^puke^");
smileysMap1.put("Shout", "^shout^");
smileysMap1.put("Slurp", "^slurp^");
smileysMap1.put("SuperConfused", "^superconfused^");
smileysMap1.put("SuperInnocent", "^superinnocent^");
smileysMap1.put("CellPhone", "^cellPhone^");
smileysMap1.put("Idiot", "^idiot^");
smileysMap1.put("Knuppel", "^knuppel^");
smileysMap1.put("TickedOff", "^tickedOff^");
smileysMap1.put("Peace", "^peace^");
smileysMap1.put("Suspicious", "^suspicious^");
smileysMap1.put("Caffine", "^caffine^");
smileysMap1.put("argue", "^argue^");
smileysMap1.put("banned2", "^banned2^");
smileysMap1.put("banned", "^banned^");
smileysMap1.put("bath", "^bath^");
smileysMap1.put("beg", "^beg^");
smileysMap1.put("bluescreen", "^bluescreen^");
smileysMap1.put("boil", "^boil^");
smileysMap1.put("bye", "^bye^");
smileysMap1.put("callmerip", "^callmerip^");
smileysMap1.put("carnaval", "^carnaval^");
smileysMap1.put("clap", "^clap^");
smileysMap1.put("coffepot", "^coffepot^");
smileysMap1.put("crap", "^crap^");
smileysMap1.put("curses", "^curses^");
smileysMap1.put("funny", "^funny^");
smileysMap1.put("guitar", "^guitar^");
smileysMap1.put("kissy", "^kissy^");
smileysMap1.put("band", "^band^");
smileysMap1.put("ivres", "^ivres^");
smileysMap1.put("kaloe", "^kaloe^");
smileysMap1.put("kremala", "^kremala^");
smileysMap1.put("moon", "^moon^");
smileysMap1.put("mopping", "^mopping^");
smileysMap1.put("mountza", "^mountza^");
smileysMap1.put("pcsleep", "^pcsleep^");
smileysMap1.put("pinokio", "^pinokio^");
smileysMap1.put("poke", "^poke^");
smileysMap1.put("seestars", "^seestars^");
smileysMap1.put("sfyri", "^sfyri^");
smileysMap1.put("spam", "^spam^");
smileysMap1.put("super", "^super^");
smileysMap1.put("tafos", "^tafos^");
smileysMap1.put("tomato", "^tomato^");
smileysMap1.put("ytold", "^ytold^");
smileysMap1.put("beer", "^beer^");
smileysMap1.put("ο fritz!!!", "^fritz^");
smileysMap1.put("o Wade!!!", "^wade^");
smileysMap1.put("bonjour", "^hat^");
smileysMap1.put("bonjour2", "^miss^");
smileysMap1.put("question", "^que^");
smileysMap1.put("shifty", "^shifty^");
smileysMap1.put("shy", "^shy^");
smileysMap1.put("music_listenning", "^music_listen^");
smileysMap1.put("bag_face", "^bagface^");
smileysMap1.put("rotation", "^rotate^");
smileysMap1.put("love", "^love^");
smileysMap1.put("speech", "^speech^");
smileysMap1.put("shocked", "^shocked^");
smileysMap1.put("extremely_shocked", "^ex_shocked^");
smileysMap1.put("smurf", "^smurf^");
smileysMap1.put("monster", "^monster^");
smileysMap1.put("pig", "^pig^");
smileysMap1.put("lol", "^lol^");
smileysMap2.put("Police", "^Police^");
smileysMap2.put("foyska", "^fouska^");
smileysMap2.put("nista", "^nysta^");
smileysMap2.put("10_7_3", "^sfinaki^");
smileysMap2.put("yu", "^yue^");
smileysMap2.put("a-eatpaper", "^eatpaper^");
smileysMap2.put("lypi", "^lypi^");
smileysMap2.put("megashok1wq", "^aytoxeir^");
smileysMap2.put("victory", "^victory^");
smileysMap2.put("filarakia", "^filarakia^");
smileysMap2.put("rofl", "^rolfmao^");
smileysMap2.put("locked", "^lock^");
smileysMap2.put("facepalm", "^facepalm^");
//html stuff on the beginning
bbMap.put("<link rel=.+\">\n ", "");
//quotes and code headers
bbMap.put("\\s*?<div class=\"quoteheader\">(.*?(\\n))*?.*?<\\/div>", "");
bbMap.put("\\s*?<div class=\"codeheader\">(.*?(\\n))+?.*?<\\/div>", "");
bbMap.put("\\s*?<div class=\"quote\">(.*?(\\n))+?.*?<\\/div>", "");
bbMap.put("<br>", "\\\n");
//Non-breaking space
bbMap.put("&nbsp;", " ");
//bold
bbMap.put("\\s*?<b>([\\S\\s]+?)<\\/b>", "\\[b\\]$1\\[/b\\]");
//italics
bbMap.put("\\s*?<i>([\\S\\s]+?)<\\/i>", "\\[i\\]$1\\[/i\\]");
//underline
bbMap.put("\\s*?<span style=\"text-decoration: underline;\">([\\S\\s]+?)<\\/span>", "\\[u\\]$1\\[/u\\]");
//deleted
bbMap.put("\\s*?<del>([\\S\\s]+?)<\\/del>", "\\[s\\]$1\\[/s\\]");
//text color
bbMap.put("\\s*?<span style=\"color: (.+?);\">([\\S\\s]+?)<\\/span>", "\\[color=$1\\]$2\\[/color\\]");
//glow
bbMap.put("\\s*?<span style=\"background-color: (.+?);\">([\\S\\s]+?)<\\/span>", "\\[glow=$1,2,300\\]$2\\[/glow\\]");
//shadow
bbMap.put("\\s*?<span style=\"text-shadow: (.+?) (.+?)\">([\\S\\s]+?)<\\/span>", "\\[shadow=$1,$2\\]$3\\[/shadow\\]");
//running text
bbMap.put("\\s*?<marquee>\n ([\\S\\s]+?)\n <\\/marquee>", "\\[move\\]$1\\[/move\\]");
//alignment
bbMap.put("\\s*?<div align=\"center\">\n ([\\S\\s]+?)\n <\\/div>", "\\[center\\]$1\\[/center\\]");
bbMap.put("\\s*?<div style=\"text-align: (.+?);\">\n ([\\S\\s]+?)\n <\\/div>", "\\[$1\\]$2\\[/$1\\]");
//preformated
bbMap.put("\\s*?<pre>([\\S\\s]+?)<\\/pre>", "\\[pre\\]$1\\[/pre\\]");
//horizontal rule
bbMap.put("\\s*?<hr>", "\\[hr\\]");
//resize
bbMap.put("\\s*?<span style=\"font-size: (.+?);(.+?)\">([\\S\\s]+?)<\\/span>", "\\[size=$1\\]$3\\[/size\\]");
//font
bbMap.put("\\s*?<span style=\"font-family: (.+?);\">([\\S\\s]+?)<\\/span>", "\\[font=$1\\]$2\\[/font\\]");
//lists
bbMap.put("\\s+<li>(.+?)<\\/li>", "\\[li\\]$1\\[/li\\]");
bbMap.put("\n\\s+<ul style=\"margin-top: 0; margin-bottom: 0;\">([\\S\\s]+?)\n\\s+<\\/ul>",
"\\[list\\]\n$1\n\\[/list\\]");
//latex code
bbMap.put("\\s*?<img src=\".+?eq=([\\S\\s]+?)\" .+?\">", "\\[tex\\]$1\\[/tex\\]");
//code
bbMap.put("\\s*?<div class=\"code\">((.*?(\\n))+?.*?)<\\/div>", "\\[code\\]$1\\[/code\\]");
//teletype
bbMap.put("\\s*?<tt>([\\S\\s]+?)<\\/tt>", "\\[tt\\]$1\\[/tt\\]");
//superscript/subscript
bbMap.put("\\s*?<sub>([\\S\\s]+?)<\\/sub>", "\\[sub\\]$1\\[/sub\\]");
bbMap.put("\\s*?<sup>([\\S\\s]+?)<\\/sup>", "\\[sup\\]$1\\[/sup\\]");
//tables
bbMap.put("\\s*?<td.+?>([\\S\\s]+?)<\\/td>", "\\[td\\]$1\\[/td\\]");
bbMap.put("<tr>([\\S\\s]+?)\n <\\/tr>", "\\[tr\\]$1\\[/tr\\]");
bbMap.put("\\s*?<table style=\"(.+?)\">\n <tbody>\n ([\\S\\s]+?)\n <\\/tbody>\n <\\/table>"
, "\\[table\\]$2\\[/table\\]");
//videos
bbMap.put("\\s*?<div class=\"yt\">.+?watch\\?v=(.+?)\"((.|\\n)*?)/div>\n",
"[youtube]https://www.youtube.com/watch?v=$1[/youtube]");
//ftp
bbMap.put("<a href=\"ftp:(.+?)\" .+?>([\\S\\s]+?)<\\/a>", "\\[fpt=ftp:$1\\]$2\\[/ftp\\]");
//mailto
bbMap.put("\\s*?<a href=\"mailto:(.+?)\">([\\S\\s]+?)<\\/a>", "\\[email\\]$2\\[/email\\]");
//links
bbMap.put("\\s*?<a href=\"(.+?)\" .+?>([\\S\\s]+?)</a>", "\\[url=$1\\]$2\\[/url\\]");
//smileys
for (Map.Entry entry : smileysMap1.entrySet()) {
bbMap.put("\n <img src=\"(.+?)//www.thmmy.gr/smf/Smileys/default_dither/(.+?) alt=\""
+ entry.getKey().toString() + "\" .+?\">", entry.getValue().toString());
}
for (Map.Entry entry : smileysMap2.entrySet()) { //Those that have empty alt tag
bbMap.put("\n <img src=\"(.+?)//www.thmmy.gr/smf/Smileys/default_dither/"
+ entry.getKey().toString() + ".gif\" .+?\">", entry.getValue().toString());
}
bbMap.put("\n <img src=\"(.+?)//www.thmmy.gr/smf/Smileys/default_dither/undecided.gif\" alt=\"Undecided\" border=\"0\">"
, Matcher.quoteReplacement(":-\\"));
//html stuff on the end
bbMap.put("\n</div>", "");
for (Map.Entry entry : bbMap.entrySet()) {
html = html.replaceAll(entry.getKey().toString(), entry.getValue().toString());
}
//img need to be done last or it messes up everything else
html = html.replaceAll("\\s+<img src=\"(.+?)\" .+? width=\"(.+?)\" .+? height=\"(.+?)\" .+?>",
"\\[img width=$2 height=$3\\]$1\\[/img\\]");
html = html.replaceAll("\\s+<img src=\"(.+?)\" .+? height=\"(.+?)\" .+? width=\"(.+?)\" .+?>",
"\\[img height=$2 width=$3\\]$1\\[/img\\]");
html = html.replaceAll("\\s+<img src=\"(.+?)\" .+? width=\"(.+?)\" .+?>", "\\[img width=$2\\]$1\\[/img\\]");
html = html.replaceAll("\\s+<img src=\"(.+?)\" .+? height=\"(.+?)\" .+?>", "\\[img height=$2\\]$1\\[/img\\]");
html = html.replaceAll("\\s+<img src=\"(.+?)\".+?>", "\\[img\\]$1\\[/img\\]");
Log.d("Cancer", html);
return html;
}
} }

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

@ -65,13 +65,14 @@ import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_
import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus; import static gr.thmmy.mthmmy.activities.topic.Posting.replyStatus;
/** /**
* Activity for topics. When creating an Intent of this activity you need to bundle a <b>String</b> * Activity for parsing and rendering topics. When creating an Intent of this activity you need to
* containing this topics's url using the key {@link #BUNDLE_TOPIC_URL} and a <b>String</b> containing * bundle a <b>String</b> containing this topic's url using the key {@link #BUNDLE_TOPIC_URL}.
* this topic's title using the key {@link #BUNDLE_TOPIC_TITLE}. * You can also bundle a <b>String</b> containing this topic's title, if its available, using the
* key {@link #BUNDLE_TOPIC_TITLE} for faster title rendering.
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public class TopicActivity extends BaseActivity { public class TopicActivity extends BaseActivity {
//Class variables //Activity's variables
/** /**
* The key to use when putting topic's url String to {@link TopicActivity}'s Bundle. * The key to use when putting topic's url String to {@link TopicActivity}'s Bundle.
*/ */
@ -81,46 +82,110 @@ public class TopicActivity extends BaseActivity {
*/ */
public static final String BUNDLE_TOPIC_TITLE = "TOPIC_TITLE"; public static final String BUNDLE_TOPIC_TITLE = "TOPIC_TITLE";
private static TopicTask topicTask; private static TopicTask topicTask;
//About posts private MaterialProgressBar progressBar;
private TextView toolbarTitle;
/**
* Holds this topic's base url. For example a topic with url similar to
* "https://www.thmmy.gr/smf/index.php?topic=1.15;topicseen" or
* "https://www.thmmy.gr/smf/index.php?topic=1.msg1#msg1"
* has the base url "https://www.thmmy.gr/smf/index.php?topic=1"
*/
private static String base_url = "";
/**
* Holds this topic's title. At first this gets the value of the topic title that came with
* bundle and is rendered in the toolbar while parsing this topic. Later, after topic's parsing
* is done, it gets the value of {@link #parsedTitle} if bundle title and parsed title differ.
*/
private String topicTitle;
/**
* Holds this topic's title as parsed from the html source. If this (parsed) title is different
* than the one that came with activity's bundle then the parsed title is preferred over the
* bundle one and gets rendered in the toolbar.
*/
private String parsedTitle;
private RecyclerView recyclerView;
/**
* Holds the url of this page
*/
private String loadedPageUrl = "";
/**
* Becomes true after user has posted in this topic and the page is being reloaded and false
* when topic's reloading is done
*/
private boolean reloadingPage = false;
//Posts related
private TopicAdapter topicAdapter; private TopicAdapter topicAdapter;
/**
* Holds a list of this topic's posts
*/
private ArrayList<Post> postsList; private ArrayList<Post> postsList;
/**
* Gets assigned to {@link #postFocus} when there is no post focus information in the url
*/
private static final int NO_POST_FOCUS = -1; private static final int NO_POST_FOCUS = -1;
/**
* Holds the index of the post that has focus
*/
private int postFocus = NO_POST_FOCUS; private int postFocus = NO_POST_FOCUS;
/**
* Holds the position in the {@link #postsList} of the post with focus
*/
private static int postFocusPosition = 0; private static int postFocusPosition = 0;
//Reply //Reply related
private FloatingActionButton replyFAB; private FloatingActionButton replyFAB;
/**
* Holds this topic's reply url
*/
private String replyPageUrl = null; private String replyPageUrl = null;
//Topic's pages //Topic's pages related
/**
* Holds current page's index (starting from 1, not 0)
*/
private int thisPage = 1; private int thisPage = 1;
/**
* Holds this topic's number of pages
*/
private int numberOfPages = 1; private int numberOfPages = 1;
/**
* Holds a list of this topic's pages urls
*/
private final SparseArray<String> pagesUrls = new SparseArray<>(); private final SparseArray<String> pagesUrls = new SparseArray<>();
//Page select //Page select related
/**
* Used for handling bottom navigation bar's buttons long click user interactions
*/
private final Handler repeatUpdateHandler = new Handler(); private final Handler repeatUpdateHandler = new Handler();
/**
* Holds the initial time delay before a click on bottom navigation bar is considered long
*/
private final long INITIAL_DELAY = 500; private final long INITIAL_DELAY = 500;
private boolean autoIncrement = false; private boolean autoIncrement = false;
private boolean autoDecrement = false; private boolean autoDecrement = false;
/**
* Holds the number of pages to be added or subtracted from current page on each step while a
* long click is held in either next or previous buttons
*/
private static final int SMALL_STEP = 1; private static final int SMALL_STEP = 1;
/**
* Holds the number of pages to be added or subtracted from current page on each step while a
* long click is held in either first or last buttons
*/
private static final int LARGE_STEP = 10; private static final int LARGE_STEP = 10;
/**
* Holds the value (index) of the page to be requested when a user interaction with bottom
* navigation bar occurs
*/
private Integer pageRequestValue; private Integer pageRequestValue;
//Bottom navigation graphics //Bottom navigation bar graphics related
private LinearLayout bottomNavBar; private LinearLayout bottomNavBar;
private ImageButton firstPage; private ImageButton firstPage;
private ImageButton previousPage; private ImageButton previousPage;
private TextView pageIndicator; private TextView pageIndicator;
private ImageButton nextPage; private ImageButton nextPage;
private ImageButton lastPage; private ImageButton lastPage;
//Topic's info //Topic's info related
private SpannableStringBuilder topicTreeAndMods = new SpannableStringBuilder("Loading..."), private SpannableStringBuilder topicTreeAndMods = new SpannableStringBuilder("Loading..."),
topicViewers = new SpannableStringBuilder("Loading..."); topicViewers = new SpannableStringBuilder("Loading...");
//Other variables
private MaterialProgressBar progressBar;
private TextView toolbarTitle;
private static String base_url = "";
private String topicTitle;
private String parsedTitle;
private RecyclerView recyclerView;
private String loadedPageUrl = "";
private boolean reloadingPage = false;
@Override @Override
@ -149,6 +214,7 @@ public class TopicActivity extends BaseActivity {
toolbarTitle.setMarqueeRepeatLimit(-1); toolbarTitle.setMarqueeRepeatLimit(-1);
toolbarTitle.setText(topicTitle); toolbarTitle.setText(topicTitle);
toolbarTitle.setSelected(true); toolbarTitle.setSelected(true);
toolbarTitle.setEnabled(false);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
if (getSupportActionBar() != null) { if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@ -171,6 +237,7 @@ public class TopicActivity extends BaseActivity {
new View.OnTouchListener() { new View.OnTouchListener() {
@Override @Override
public boolean onTouch(View v, MotionEvent event) { public boolean onTouch(View v, MotionEvent event) {
v.performClick();
return topicTask != null && topicTask.getStatus() == AsyncTask.Status.RUNNING; return topicTask != null && topicTask.getStatus() == AsyncTask.Status.RUNNING;
} }
} }
@ -179,7 +246,7 @@ public class TopicActivity extends BaseActivity {
CustomLinearLayoutManager layoutManager = new CustomLinearLayoutManager( CustomLinearLayoutManager layoutManager = new CustomLinearLayoutManager(
getApplicationContext(), loadedPageUrl); getApplicationContext(), loadedPageUrl);
recyclerView.setLayoutManager(layoutManager); recyclerView.setLayoutManager(layoutManager);
topicAdapter = new TopicAdapter(this, postsList, topicTask); topicAdapter = new TopicAdapter(this, postsList, base_url, topicTask);
recyclerView.setAdapter(topicAdapter); recyclerView.setAdapter(topicAdapter);
replyFAB = findViewById(R.id.topic_fab); replyFAB = findViewById(R.id.topic_fab);
@ -191,12 +258,8 @@ public class TopicActivity extends BaseActivity {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
if (sessionManager.isLoggedIn()) { if (sessionManager.isLoggedIn()) {
postsList.add(null); PrepareForReply prepareForReply = new PrepareForReply();
topicAdapter.notifyItemInserted(postsList.size()); prepareForReply.execute(topicAdapter.getToQuoteList());
topicAdapter.prepareForReply(new ReplyTask(), topicTitle, loadedPageUrl);
replyFAB.hide();
bottomNavBar.setVisibility(View.GONE);
recyclerView.scrollToPosition(postsList.size() - 1);
} }
} }
}); });
@ -464,12 +527,10 @@ public class TopicActivity extends BaseActivity {
//------------------------------------BOTTOM NAV BAR METHODS END------------------------------------ //------------------------------------BOTTOM NAV BAR METHODS END------------------------------------
/** /**
* An {@link AsyncTask} that handles asynchronous fetching of a topic page and parsing it's * An {@link AsyncTask} that handles asynchronous fetching of this topic page and parsing of it's
* data. {@link AsyncTask#onPostExecute(Object) OnPostExecute} method calls {@link RecyclerView#swapAdapter} * data.
* to build graphics. * <p>TopicTask's {@link AsyncTask#execute execute} method needs a topic's url as String
* <p> * parameter.</p>
* <p>Calling TopicTask's {@link AsyncTask#execute execute} method needs to have profile's url
* as String parameter!</p>
*/ */
class TopicTask extends AsyncTask<String, Void, Integer> { class TopicTask extends AsyncTask<String, Void, Integer> {
private static final int SUCCESS = 0; private static final int SUCCESS = 0;
@ -477,6 +538,8 @@ public class TopicActivity extends BaseActivity {
private static final int OTHER_ERROR = 2; private static final int OTHER_ERROR = 2;
private static final int SAME_PAGE = 3; private static final int SAME_PAGE = 3;
ArrayList<Post> localPostsList;
@Override @Override
protected void onPreExecute() { protected void onPreExecute() {
progressBar.setVisibility(ProgressBar.VISIBLE); progressBar.setVisibility(ProgressBar.VISIBLE);
@ -530,7 +593,15 @@ public class TopicActivity extends BaseActivity {
try { try {
Response response = client.newCall(request).execute(); Response response = client.newCall(request).execute();
document = Jsoup.parse(response.body().string()); document = Jsoup.parse(response.body().string());
parse(document); localPostsList = parse(document);
//Finds the position of the focused message if present
for (int i = 0; i < localPostsList.size(); ++i) {
if (localPostsList.get(i).getPostIndex() == postFocus) {
postFocusPosition = i;
break;
}
}
return SUCCESS; return SUCCESS;
} catch (IOException e) { } catch (IOException e) {
Timber.i(e, "IO Exception"); Timber.i(e, "IO Exception");
@ -542,14 +613,6 @@ public class TopicActivity extends BaseActivity {
} }
protected void onPostExecute(Integer parseResult) { protected void onPostExecute(Integer parseResult) {
//Finds the position of the focused message if present
for (int i = 0; i < postsList.size(); ++i) {
if (postsList.get(i).getPostIndex() == postFocus) {
postFocusPosition = i;
break;
}
}
switch (parseResult) { switch (parseResult) {
case SUCCESS: case SUCCESS:
if (topicTitle == null || Objects.equals(topicTitle, "") if (topicTitle == null || Objects.equals(topicTitle, "")
@ -560,12 +623,19 @@ public class TopicActivity extends BaseActivity {
invalidateOptionsMenu(); invalidateOptionsMenu();
} }
if (!(postsList.isEmpty() || postsList.size() == 0)) {
recyclerView.getRecycledViewPool().clear(); //Avoid inconsistency detected bug
postsList.clear();
topicAdapter.notifyItemRangeRemoved(0, postsList.size() - 1);
}
postsList.addAll(localPostsList);
topicAdapter.notifyItemRangeInserted(0, postsList.size());
progressBar.setVisibility(ProgressBar.INVISIBLE); progressBar.setVisibility(ProgressBar.INVISIBLE);
recyclerView.getRecycledViewPool().clear(); //Avoid inconsistency detected bug
if (replyPageUrl == null) { if (replyPageUrl == null) {
replyFAB.hide(); replyFAB.hide();
topicAdapter.customNotifyDataSetChanged(new TopicTask(), false); topicAdapter.resetTopic(base_url, new TopicTask(), false);
} else topicAdapter.customNotifyDataSetChanged(new TopicTask(), true); } else topicAdapter.resetTopic(base_url, new TopicTask(), true);
if (replyFAB.getVisibility() != View.GONE) replyFAB.setEnabled(true); if (replyFAB.getVisibility() != View.GONE) replyFAB.setEnabled(true);
@ -582,8 +652,8 @@ public class TopicActivity extends BaseActivity {
progressBar.setVisibility(ProgressBar.INVISIBLE); progressBar.setVisibility(ProgressBar.INVISIBLE);
if (replyPageUrl == null) { if (replyPageUrl == null) {
replyFAB.hide(); replyFAB.hide();
topicAdapter.customNotifyDataSetChanged(new TopicTask(), false); topicAdapter.resetTopic(base_url, new TopicTask(), false);
} else topicAdapter.customNotifyDataSetChanged(new TopicTask(), true); } else topicAdapter.resetTopic(base_url, new TopicTask(), true);
if (replyFAB.getVisibility() != View.GONE) replyFAB.setEnabled(true); if (replyFAB.getVisibility() != View.GONE) replyFAB.setEnabled(true);
paginationEnabled(true); paginationEnabled(true);
Toast.makeText(TopicActivity.this, "That's the same page.", Toast.LENGTH_SHORT).show(); Toast.makeText(TopicActivity.this, "That's the same page.", Toast.LENGTH_SHORT).show();
@ -604,7 +674,7 @@ public class TopicActivity extends BaseActivity {
* @param topic {@link Document} object containing this topic's source code * @param topic {@link Document} object containing this topic's source code
* @see org.jsoup.Jsoup Jsoup * @see org.jsoup.Jsoup Jsoup
*/ */
private void parse(Document topic) { private ArrayList<Post> parse(Document topic) {
ParseHelpers.Language language = ParseHelpers.Language.getLanguage(topic); ParseHelpers.Language language = ParseHelpers.Language.getLanguage(topic);
//Finds topic's tree, mods and users viewing //Finds topic's tree, mods and users viewing
@ -646,11 +716,7 @@ public class TopicActivity extends BaseActivity {
} }
} }
postsList.clear(); return TopicParser.parseTopic(topic, language);
int oldSize = postsList.size();
topicAdapter.notifyItemRangeRemoved(0, oldSize);
recyclerView.getRecycledViewPool().clear(); //Avoid inconsistency detected bug
postsList.addAll(TopicParser.parseTopic(topic, language));
} }
private void makeLinkClickable(SpannableStringBuilder strBuilder, final URLSpan span) { private void makeLinkClickable(SpannableStringBuilder strBuilder, final URLSpan span) {
@ -703,23 +769,25 @@ public class TopicActivity extends BaseActivity {
} }
} }
class ReplyTask extends AsyncTask<String, Void, Boolean> { class PrepareForReply extends AsyncTask<ArrayList<Integer>, Void, Boolean> {
String numReplies, seqnum, sc, topic, buildedQuotes = "";
@Override @Override
protected void onPreExecute() { protected void onPreExecute() {
progressBar.setVisibility(ProgressBar.VISIBLE); progressBar.setVisibility(ProgressBar.VISIBLE);
paginationEnabled(false); paginationEnabled(false);
replyFAB.setEnabled(false); replyFAB.setEnabled(false);
replyFAB.hide();
bottomNavBar.setVisibility(View.GONE);
} }
@Override @Override
protected Boolean doInBackground(String... message) { protected Boolean doInBackground(ArrayList<Integer>... quoteList) {
Document document; Document document;
String numReplies, seqnum, sc, topic;
Request request = new Request.Builder() Request request = new Request.Builder()
.url(replyPageUrl + ";wap2") .url(replyPageUrl + ";wap2")
.build(); .build();
try { try {
Response response = client.newCall(request).execute(); Response response = client.newCall(request).execute();
document = Jsoup.parse(response.body().string()); document = Jsoup.parse(response.body().string());
@ -728,22 +796,61 @@ public class TopicActivity extends BaseActivity {
seqnum = document.select("input[name=seqnum]").first().attr("value"); seqnum = document.select("input[name=seqnum]").first().attr("value");
sc = document.select("input[name=sc]").first().attr("value"); sc = document.select("input[name=sc]").first().attr("value");
topic = document.select("input[name=topic]").first().attr("value"); topic = document.select("input[name=topic]").first().attr("value");
} catch (IOException e) { } catch (IOException | Selector.SelectorParseException e) {
Timber.e(e, "Post failed."); Timber.e(e, "Prepare failed.");
return false;
} catch (Selector.SelectorParseException e) {
Timber.e(e, "Post failed.");
return false; return false;
} }
for (Integer quotePosition : quoteList[0]) {
request = new Request.Builder()
.url("https://www.thmmy.gr/smf/index.php?action=quotefast;quote=" +
postsList.get(quotePosition).getPostIndex() +
";" + "sesc=" + sc + ";xml")
.build();
try {
Response response = client.newCall(request).execute();
String body = response.body().string();
buildedQuotes += body.substring(body.indexOf("<quote>") + 7, body.indexOf("</quote>"));
buildedQuotes += "\n\n";
} catch (IOException | Selector.SelectorParseException e) {
Timber.e(e, "Quote building failed.");
return false;
}
}
return true;
}
@Override
protected void onPostExecute(Boolean result) {
postsList.add(null);
topicAdapter.notifyItemInserted(postsList.size());
topicAdapter.prepareForReply(new ReplyTask(), topicTitle, numReplies, seqnum, sc,
topic, buildedQuotes);
recyclerView.scrollToPosition(postsList.size() - 1);
progressBar.setVisibility(ProgressBar.GONE);
}
}
class ReplyTask extends AsyncTask<String, Void, Boolean> {
@Override
protected void onPreExecute() {
progressBar.setVisibility(ProgressBar.VISIBLE);
paginationEnabled(false);
replyFAB.setEnabled(false);
}
@Override
protected Boolean doInBackground(String... args) {
RequestBody postBody = new MultipartBody.Builder() RequestBody postBody = new MultipartBody.Builder()
.setType(MultipartBody.FORM) .setType(MultipartBody.FORM)
.addFormDataPart("message", message[1]) .addFormDataPart("message", args[1])
.addFormDataPart("num_replies", numReplies) .addFormDataPart("num_replies", args[2])
.addFormDataPart("seqnum", seqnum) .addFormDataPart("seqnum", args[3])
.addFormDataPart("sc", sc) .addFormDataPart("sc", args[4])
.addFormDataPart("subject", message[0]) .addFormDataPart("subject", args[0])
.addFormDataPart("topic", topic) .addFormDataPart("topic", args[5])
.build(); .build();
Request post = new Request.Builder() Request post = new Request.Builder()

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

@ -10,10 +10,8 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.res.ResourcesCompat; import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.widget.AppCompatImageButton; import android.support.v7.widget.AppCompatImageButton;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.text.Editable; import android.text.Editable;
import android.text.TextUtils; import android.text.TextUtils;
@ -26,7 +24,6 @@ import android.webkit.WebResourceRequest;
import android.webkit.WebView; import android.webkit.WebView;
import android.webkit.WebViewClient; import android.webkit.WebViewClient;
import android.widget.EditText; import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
@ -35,14 +32,8 @@ import android.widget.TextView;
import com.squareup.picasso.Picasso; import com.squareup.picasso.Picasso;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Objects; import java.util.Objects;
import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.R;
@ -61,7 +52,9 @@ import static gr.thmmy.mthmmy.activities.board.BoardActivity.BUNDLE_BOARD_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL; import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_THUMBNAIL_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL; import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_URL;
import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME; import static gr.thmmy.mthmmy.activities.profile.ProfileActivity.BUNDLE_PROFILE_USERNAME;
import static gr.thmmy.mthmmy.activities.topic.Posting.htmlToBBcode; import static gr.thmmy.mthmmy.activities.topic.TopicActivity.BUNDLE_TOPIC_URL;
import static gr.thmmy.mthmmy.activities.topic.TopicParser.USER_COLOR_WHITE;
import static gr.thmmy.mthmmy.activities.topic.TopicParser.USER_COLOR_YELLOW;
import static gr.thmmy.mthmmy.base.BaseActivity.getSessionManager; import static gr.thmmy.mthmmy.base.BaseActivity.getSessionManager;
/** /**
@ -74,6 +67,7 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static int THUMBNAIL_SIZE; private static int THUMBNAIL_SIZE;
private final Context context; private final Context context;
private String topicTitle; private String topicTitle;
private String baseUrl;
private final ArrayList<Integer> toQuoteList = new ArrayList<>(); private final ArrayList<Integer> toQuoteList = new ArrayList<>();
private final List<Post> postsList; private final List<Post> postsList;
/** /**
@ -98,16 +92,18 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final String[] replyDataHolder = new String[2]; private final String[] replyDataHolder = new String[2];
private final int replySubject = 0, replyText = 1; private final int replySubject = 0, replyText = 1;
private String loadedPageUrl = ""; private String numReplies, seqnum, sc, topic, buildedQuotes;
private boolean canReply = false; private boolean canReply = false;
/** /**
* @param context the context of the {@link RecyclerView} * @param context the context of the {@link RecyclerView}
* @param postsList List of {@link Post} objects to use * @param postsList List of {@link Post} objects to use
*/ */
TopicAdapter(Context context, List<Post> postsList, TopicActivity.TopicTask topicTask) { TopicAdapter(Context context, List<Post> postsList, String baseUrl,
TopicActivity.TopicTask topicTask) {
this.context = context; this.context = context;
this.postsList = postsList; this.postsList = postsList;
this.baseUrl = baseUrl;
THUMBNAIL_SIZE = (int) context.getResources().getDimension(R.dimen.thumbnail_size); THUMBNAIL_SIZE = (int) context.getResources().getDimension(R.dimen.thumbnail_size);
for (int i = 0; i < postsList.size(); ++i) { for (int i = 0; i < postsList.size(); ++i) {
@ -117,10 +113,19 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
this.topicTask = topicTask; this.topicTask = topicTask;
} }
void prepareForReply(TopicActivity.ReplyTask replyTask, String topicTitle, String loadedPageUrl) { ArrayList<Integer> getToQuoteList(){
return toQuoteList;
}
void prepareForReply(TopicActivity.ReplyTask replyTask, String topicTitle, String numReplies,
String seqnum, String sc, String topic, String buildedQuotes) {
this.replyTask = replyTask; this.replyTask = replyTask;
this.topicTitle = topicTitle; this.topicTitle = topicTitle;
this.loadedPageUrl = loadedPageUrl; this.numReplies = numReplies;
this.seqnum = seqnum;
this.sc = sc;
this.topic = topic;
this.buildedQuotes = buildedQuotes;
} }
@Override @Override
@ -158,12 +163,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
//Default post subject //Default post subject
replyDataHolder[replySubject] = "Re: " + topicTitle; replyDataHolder[replySubject] = "Re: " + topicTitle;
//Build quotes //Build quotes
String quotes = ""; if (!Objects.equals(buildedQuotes, ""))
for (int quotePosition : toQuoteList) { replyDataHolder[replyText] = buildedQuotes;
quotes += buildQuote(quotePosition);
}
if (!Objects.equals(quotes, ""))
replyDataHolder[replyText] = htmlToBBcode(quotes);
return new QuickReplyViewHolder(view, new CustomEditTextListener(replySubject), return new QuickReplyViewHolder(view, new CustomEditTextListener(replySubject),
new CustomEditTextListener(replyText)); new CustomEditTextListener(replyText));
} }
@ -309,6 +310,11 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
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) {
holder.username.setTextColor(mUserColor);
} else {
holder.username.setTextColor(USER_COLOR_WHITE);
}
if (mNumberOfStars > 0) { if (mNumberOfStars > 0) {
holder.stars.setTypeface(Typeface.createFromAsset(context.getAssets() holder.stars.setTypeface(Typeface.createFromAsset(context.getAssets()
, "fonts/fontawesome-webfont.ttf")); , "fonts/fontawesome-webfont.ttf"));
@ -396,7 +402,7 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
TopicAnimations.animateUserExtraInfoVisibility(holder.username, TopicAnimations.animateUserExtraInfoVisibility(holder.username,
holder.subject, Color.parseColor("#FFFFFF"), holder.subject, Color.parseColor("#FFFFFF"),
Color.parseColor("#757575"), v); Color.parseColor("#757575"), (LinearLayout) v);
} }
}); });
} else { } else {
@ -460,7 +466,7 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (holder.quickReply.getText().toString().isEmpty()) return; if (holder.quickReply.getText().toString().isEmpty()) return;
holder.submitButton.setEnabled(false); holder.submitButton.setEnabled(false);
replyTask.execute(holder.quickReplySubject.getText().toString(), replyTask.execute(holder.quickReplySubject.getText().toString(),
holder.quickReply.getText().toString()); holder.quickReply.getText().toString(), numReplies, seqnum, sc, topic);
holder.quickReplySubject.getText().clear(); holder.quickReplySubject.getText().clear();
holder.quickReplySubject.setText("Re: " + topicTitle); holder.quickReplySubject.setText("Re: " + topicTitle);
@ -471,7 +477,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
} }
} }
void customNotifyDataSetChanged(TopicActivity.TopicTask topicTask, boolean canReply) { void resetTopic(String baseUrl, TopicActivity.TopicTask topicTask, boolean canReply) {
this.baseUrl = baseUrl;
this.topicTask = topicTask; this.topicTask = topicTask;
this.canReply = canReply; this.canReply = canReply;
viewProperties.clear(); viewProperties.clear();
@ -479,8 +486,6 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
//Initializes properties, array's values will be false by default //Initializes properties, array's values will be false by default
viewProperties.add(new boolean[3]); viewProperties.add(new boolean[3]);
} }
notifyItemRangeInserted(0, postsList.size());
//notifyDataSetChanged();
} }
@Override @Override
@ -492,9 +497,7 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
* Custom {@link RecyclerView.ViewHolder} implementation * Custom {@link RecyclerView.ViewHolder} implementation
*/ */
private class PostViewHolder extends RecyclerView.ViewHolder { private class PostViewHolder extends RecyclerView.ViewHolder {
final CardView cardView;
final LinearLayout cardChildLinear; final LinearLayout cardChildLinear;
final FrameLayout postDateAndNumber;
final TextView postDate, postNum, username, subject; final TextView postDate, postNum, username, subject;
final ImageView thumbnail; final ImageView thumbnail;
final public WebView post; final public WebView post;
@ -510,9 +513,7 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
super(view); super(view);
//Initializes layout's graphic elements //Initializes layout's graphic elements
//Standard stuff //Standard stuff
cardView = view.findViewById(R.id.card_view);
cardChildLinear = view.findViewById(R.id.card_child_linear); cardChildLinear = view.findViewById(R.id.card_child_linear);
postDateAndNumber = view.findViewById(R.id.post_date_and_number_exp);
postDate = view.findViewById(R.id.post_date); postDate = view.findViewById(R.id.post_date);
postNum = view.findViewById(R.id.post_number); postNum = view.findViewById(R.id.post_number);
thumbnail = view.findViewById(R.id.thumbnail); thumbnail = view.findViewById(R.id.thumbnail);
@ -544,7 +545,6 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
final TextView username; final TextView username;
final EditText quickReply, quickReplySubject; final EditText quickReply, quickReplySubject;
final AppCompatImageButton submitButton; final AppCompatImageButton submitButton;
final CustomEditTextListener replySubject, replyText;
QuickReplyViewHolder(View quickReply, CustomEditTextListener replySubject QuickReplyViewHolder(View quickReply, CustomEditTextListener replySubject
, CustomEditTextListener replyText) { , CustomEditTextListener replyText) {
@ -552,10 +552,8 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
thumbnail = quickReply.findViewById(R.id.thumbnail); thumbnail = quickReply.findViewById(R.id.thumbnail);
username = quickReply.findViewById(R.id.username); username = quickReply.findViewById(R.id.username);
this.quickReply = quickReply.findViewById(R.id.quick_reply_text); this.quickReply = quickReply.findViewById(R.id.quick_reply_text);
this.replyText = replyText;
this.quickReply.addTextChangedListener(replyText); this.quickReply.addTextChangedListener(replyText);
quickReplySubject = quickReply.findViewById(R.id.quick_reply_subject); quickReplySubject = quickReply.findViewById(R.id.quick_reply_subject);
this.replySubject = replySubject;
quickReplySubject.addTextChangedListener(replySubject); quickReplySubject.addTextChangedListener(replySubject);
submitButton = quickReply.findViewById(R.id.quick_reply_submit); submitButton = quickReply.findViewById(R.id.quick_reply_submit);
} }
@ -589,7 +587,7 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (target.is(ThmmyPage.PageCategory.TOPIC)) { if (target.is(ThmmyPage.PageCategory.TOPIC)) {
//This url points to a topic //This url points to a topic
//Checks if this is the current topic //Checks if this is the current topic
/*if (Objects.equals(uriString.substring(0, uriString.lastIndexOf(".")), base_url)) { if (Objects.equals(uriString.substring(0, uriString.lastIndexOf(".")), baseUrl)) {
//Gets uri's targeted message's index number //Gets uri's targeted message's index number
String msgIndexReq = uriString.substring(uriString.indexOf("msg") + 3); String msgIndexReq = uriString.substring(uriString.indexOf("msg") + 3);
if (msgIndexReq.contains("#")) if (msgIndexReq.contains("#"))
@ -604,9 +602,16 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
return true; return true;
} }
} }
}*/
topicTask.execute(uri.toString()); topicTask.execute(uri.toString());
}
Intent intent = new Intent(context, TopicActivity.class);
Bundle extras = new Bundle();
extras.putString(BUNDLE_TOPIC_URL, uriString);
intent.putExtras(extras);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
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);
@ -660,62 +665,6 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
} }
} }
@Nullable
private String buildQuote(int quotePosition) {
Date postDate = null;
{
String date = postsList.get(quotePosition).getPostDate();
if (date != null) {
DateFormat format = new SimpleDateFormat("MMMM d, yyyy, h:m:s a", Locale.ENGLISH);
date = date.replace("Ιανουαρίου", "January");
date = date.replace("Φεβρουαρίου", "February");
date = date.replace("Μαρτίου", "March");
date = date.replace("Απριλίου", "April");
date = date.replace("Μαΐου", "May");
date = date.replace("Ιουνίου", "June");
date = date.replace("Ιουλίου", "July");
date = date.replace("Αυγούστου", "August");
date = date.replace("Σεπτεμβρίου", "September");
date = date.replace("Οκτωβρίου", "October");
date = date.replace("Νοεμβρίου", "November");
date = date.replace("Δεκεμβρίου", "December");
if (date.contains("Today")) {
date = date.replace("Today at",
Calendar.getInstance().getDisplayName(Calendar.MONTH,
Calendar.LONG, Locale.ENGLISH)
+ " " + Calendar.getInstance().get(Calendar.DAY_OF_MONTH)
+ ", " + Calendar.getInstance().get(Calendar.YEAR) + ",");
} else if (date.contains("Σήμερα")) {
date = date.replace("Σήμερα στις",
Calendar.getInstance().getDisplayName(Calendar.MONTH,
Calendar.LONG, Locale.ENGLISH)
+ " " + Calendar.getInstance().get(Calendar.DAY_OF_MONTH)
+ ", " + Calendar.getInstance().get(Calendar.YEAR) + ",");
if (date.contains("πμ")) date = date.replace("πμ", "am");
if (date.contains("μμ")) date = date.replace("μμ", "pm");
}
try {
postDate = format.parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
if (postsList.get(quotePosition).getPostIndex() != 0) {
if (postDate != null) {
return "[quote author=" + postsList.get(quotePosition).getAuthor()
+ " link=topic=" + ThmmyPage.getTopicId(loadedPageUrl) + ".msg"
+ postsList.get(quotePosition).getPostIndex()
+ "#msg" + postsList.get(quotePosition).getPostIndex()
+ " date=" + postDate.getTime() / 1000 + "]"
+ "\n" + postsList.get(quotePosition).getContent()
+ "\n" + "[/quote]" + "\n\n";
}
}
return null;
}
/** /**
* Returns a String with a single FontAwesome typeface character corresponding to this file's * Returns a String with a single FontAwesome typeface character corresponding to this file's
* extension. * extension.

57
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAnimations.java

@ -4,68 +4,67 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorListenerAdapter;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
class TopicAnimations { class TopicAnimations {
//--------------------------USER'S INFO VISIBILITY CHANGE ANIMATION METHOD--------------------------
/** /**
* Method that animates view's visibility changes for user's extra info * Method that animates view's visibility changes for user's extra info
*/ */
static void animateUserExtraInfoVisibility(TextView username, TextView subject, static void animateUserExtraInfoVisibility(final TextView username, final TextView subject,
int expandedColor, int collapsedColor, int expandedColor, final int collapsedColor,
final View userExtra) { final LinearLayout userExtraInfo) {
//If the view is gone fade it in //If the view is currently gone it fades it in
if (userExtra.getVisibility() == View.GONE) { if (userExtraInfo.getVisibility() == View.GONE) {
userExtra.clearAnimation(); userExtraInfo.clearAnimation();
userExtra.setVisibility(View.VISIBLE); userExtraInfo.setVisibility(View.VISIBLE);
userExtra.setAlpha(0.0f); userExtraInfo.setAlpha(0.0f);
// Start the animation //Animation start
userExtra.animate() userExtraInfo.animate()
.alpha(1.0f) .alpha(1.0f)
.setDuration(300) .setDuration(300)
.setListener(new AnimatorListenerAdapter() { .setListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation); super.onAnimationEnd(animation);
userExtra.setVisibility(View.VISIBLE); userExtraInfo.setVisibility(View.VISIBLE);
} }
}); });
//Show full username //Shows full username
username.setMaxLines(Integer.MAX_VALUE); //As in the android sourcecode username.setMaxLines(Integer.MAX_VALUE); //As in the android sourcecode
username.setEllipsize(null); username.setEllipsize(null);
//Show full subject //Shows full subject
subject.setTextColor(expandedColor); subject.setTextColor(expandedColor);
subject.setMaxLines(Integer.MAX_VALUE); //As in the android sourcecode subject.setMaxLines(Integer.MAX_VALUE); //As in the android sourcecode
subject.setEllipsize(null); subject.setEllipsize(null);
} }
//If the view is visible fade it out //If the view is currently visible then it fades it out
else { else {
userExtra.clearAnimation(); userExtraInfo.clearAnimation();
// Start the animation //Animation start
userExtra.animate() userExtraInfo.animate()
.alpha(0.0f) .alpha(0.0f)
.setDuration(300) .setDuration(300)
.setListener(new AnimatorListenerAdapter() { .setListener(new AnimatorListenerAdapter() {
@Override @Override
public void onAnimationEnd(Animator animation) { public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation); super.onAnimationEnd(animation);
userExtra.setVisibility(View.GONE); userExtraInfo.setVisibility(View.GONE);
}
});
username.setMaxLines(1); //As in the android sourcecode //Ellipsizes username
username.setEllipsize(TextUtils.TruncateAt.END); username.setMaxLines(1); //As in the android sourcecode
username.setEllipsize(TextUtils.TruncateAt.END);
subject.setTextColor(collapsedColor); //Ellipsizes subject
subject.setMaxLines(1); //As in the android sourcecode subject.setTextColor(collapsedColor);
subject.setEllipsize(TextUtils.TruncateAt.END); subject.setMaxLines(1); //As in the android sourcecode
subject.setEllipsize(TextUtils.TruncateAt.END);
}
});
} }
} }
//------------------------POST'S INFO VISIBILITY CHANGE ANIMATION METHOD END------------------------
} }

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

@ -35,7 +35,8 @@ class TopicParser {
private static final int USER_COLOR_GREEN = Color.parseColor("#4CAF50"); private static final int USER_COLOR_GREEN = Color.parseColor("#4CAF50");
private static final int USER_COLOR_BLUE = Color.parseColor("#536DFE"); private static final int USER_COLOR_BLUE = Color.parseColor("#536DFE");
static final int USER_COLOR_PINK = Color.parseColor("#FF4081"); static final int USER_COLOR_PINK = Color.parseColor("#FF4081");
private static final int USER_COLOR_YELLOW = Color.parseColor("#FFEB3B"); static final int USER_COLOR_YELLOW = Color.parseColor("#FFEB3B");
static final int USER_COLOR_WHITE = Color.WHITE;
/** /**
* Returns users currently viewing this topic. * Returns users currently viewing this topic.

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

@ -20,6 +20,7 @@ import android.widget.ImageButton;
import android.widget.Toast; import android.widget.Toast;
import com.mikepenz.fontawesome_typeface_library.FontAwesome; import com.mikepenz.fontawesome_typeface_library.FontAwesome;
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
import com.mikepenz.iconics.IconicsDrawable; import com.mikepenz.iconics.IconicsDrawable;
import com.mikepenz.materialdrawer.AccountHeader; import com.mikepenz.materialdrawer.AccountHeader;
import com.mikepenz.materialdrawer.AccountHeaderBuilder; import com.mikepenz.materialdrawer.AccountHeaderBuilder;
@ -156,27 +157,27 @@ public abstract class BaseActivity extends AppCompatActivity {
//Drawer Icons //Drawer Icons
homeIcon = new IconicsDrawable(this) homeIcon = new IconicsDrawable(this)
.icon(FontAwesome.Icon.faw_home) .icon(GoogleMaterial.Icon.gmd_home)
.color(primaryColor); .color(primaryColor);
homeIconSelected = new IconicsDrawable(this) homeIconSelected = new IconicsDrawable(this)
.icon(FontAwesome.Icon.faw_home) .icon(GoogleMaterial.Icon.gmd_home)
.color(selectedSecondaryColor); .color(selectedSecondaryColor);
downloadsIcon = new IconicsDrawable(this) bookmarksIcon = new IconicsDrawable(this)
.icon(FontAwesome.Icon.faw_download) .icon(GoogleMaterial.Icon.gmd_bookmark)
.color(primaryColor); .color(primaryColor);
downloadsIconSelected = new IconicsDrawable(this) bookmarksIconSelected = new IconicsDrawable(this)
.icon(FontAwesome.Icon.faw_download) .icon(GoogleMaterial.Icon.gmd_bookmark)
.color(selectedSecondaryColor); .color(selectedSecondaryColor);
bookmarksIcon = new IconicsDrawable(this) downloadsIcon = new IconicsDrawable(this)
.icon(FontAwesome.Icon.faw_bookmark) .icon(GoogleMaterial.Icon.gmd_file_download)
.color(primaryColor); .color(primaryColor);
bookmarksIconSelected = new IconicsDrawable(this) downloadsIconSelected = new IconicsDrawable(this)
.icon(FontAwesome.Icon.faw_bookmark) .icon(GoogleMaterial.Icon.gmd_file_download)
.color(selectedSecondaryColor); .color(selectedSecondaryColor);
loginIcon = new IconicsDrawable(this) loginIcon = new IconicsDrawable(this)
@ -188,11 +189,11 @@ public abstract class BaseActivity extends AppCompatActivity {
.color(primaryColor); .color(primaryColor);
aboutIcon = new IconicsDrawable(this) aboutIcon = new IconicsDrawable(this)
.icon(FontAwesome.Icon.faw_info_circle) .icon(GoogleMaterial.Icon.gmd_info)
.color(primaryColor); .color(primaryColor);
aboutIconSelected = new IconicsDrawable(this) aboutIconSelected = new IconicsDrawable(this)
.icon(FontAwesome.Icon.faw_info_circle) .icon(GoogleMaterial.Icon.gmd_info)
.color(selectedSecondaryColor); .color(selectedSecondaryColor);
//Drawer Items //Drawer Items
@ -358,14 +359,15 @@ public abstract class BaseActivity extends AppCompatActivity {
{ {
drawer.removeItem(DOWNLOADS_ID); drawer.removeItem(DOWNLOADS_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()).withIcon(new IconicsDrawable(this) profileDrawerItem.withName(sessionManager.getUsername());
.icon(FontAwesome.Icon.faw_user) setDefaultAvatar();
.paddingDp(10)
.color(ContextCompat.getColor(this, R.color.primary_light))
.backgroundColor(ContextCompat.getColor(this, R.color.primary)));
} else { } else {
loginLogoutItem.withName(R.string.logout).withIcon(logoutIcon); //Swap login with logout loginLogoutItem.withName(R.string.logout).withIcon(logoutIcon); //Swap login with logout
profileDrawerItem.withName(sessionManager.getUsername()).withIcon(sessionManager.getAvatarLink()); profileDrawerItem.withName(sessionManager.getUsername());
if(sessionManager.hasAvatar())
profileDrawerItem.withIcon(sessionManager.getAvatarLink());
else
setDefaultAvatar();
} }
accountHeader.updateProfile(profileDrawerItem); accountHeader.updateProfile(profileDrawerItem);
drawer.updateItem(loginLogoutItem); drawer.updateItem(loginLogoutItem);
@ -373,6 +375,13 @@ public abstract class BaseActivity extends AppCompatActivity {
} }
} }
private void setDefaultAvatar() {
profileDrawerItem.withIcon(new IconicsDrawable(this)
.icon(FontAwesome.Icon.faw_user)
.paddingDp(10)
.color(ContextCompat.getColor(this, R.color.primary_light))
.backgroundColor(ContextCompat.getColor(this, R.color.primary)));
}
//-------------------------------------------LOGOUT------------------------------------------------- //-------------------------------------------LOGOUT-------------------------------------------------
@ -402,6 +411,11 @@ public abstract class BaseActivity extends AppCompatActivity {
if (mainActivity != null) if (mainActivity != null)
mainActivity.updateTabs(); mainActivity.updateTabs();
progressDialog.dismiss(); progressDialog.dismiss();
//if (BaseActivity.this instanceof TopicActivity){
Intent intent = new Intent(BaseActivity.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
//}
} }
} }
//-----------------------------------------LOGOUT END----------------------------------------------- //-----------------------------------------LOGOUT END-----------------------------------------------

26
app/src/main/java/gr/thmmy/mthmmy/services/DownloadService.java

@ -1,11 +1,13 @@
package gr.thmmy.mthmmy.services; package gr.thmmy.mthmmy.services;
import android.app.DownloadManager;
import android.app.IntentService; import android.app.IntentService;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.os.Environment; import android.os.Environment;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.webkit.MimeTypeMap;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -107,7 +109,7 @@ public class DownloadService extends IntentService {
Response response = client.newCall(request).execute(); Response response = client.newCall(request).execute();
String contentDisposition = response.headers("Content-Disposition").toString(); //check if link provides an attachment String contentDisposition = response.headers("Content-Disposition").toString(); //check if link provides an attachment
if (contentDisposition.contains("attachment")){ if (contentDisposition.contains("attachment")) {
fileName = contentDisposition.split("\"")[1]; fileName = contentDisposition.split("\"")[1];
File dirPath = new File(SAVE_DIR); File dirPath = new File(SAVE_DIR);
@ -141,7 +143,7 @@ public class DownloadService extends IntentService {
fileName = file.getName(); fileName = file.getName();
Timber.v("Started saving file %s" , fileName); Timber.v("Started saving file %s", fileName);
sendNotification(downloadId, STARTED, fileName); sendNotification(downloadId, STARTED, fileName);
sink = Okio.buffer(Okio.sink(file)); sink = Okio.buffer(Okio.sink(file));
@ -149,6 +151,12 @@ public class DownloadService extends IntentService {
sink.flush(); sink.flush();
Timber.i("Download OK!"); Timber.i("Download OK!");
sendNotification(downloadId, COMPLETED, fileName); sendNotification(downloadId, COMPLETED, fileName);
// Register download
DownloadManager mManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
long length = file.length();
mManager.addCompletedDownload(fileName, "edo mporei na mpei ena description", false, getMimeType(file), SAVE_DIR +File.separator+ fileName, length, false);
} else } else
Timber.e("No attachment in response!"); Timber.e("No attachment in response!");
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
@ -203,4 +211,18 @@ public class DownloadService extends IntentService {
} }
@NonNull
static String getMimeType(@NonNull File file) {
String type = null;
final String url = file.toString();
final String extension = MimeTypeMap.getFileExtensionFromUrl(url);
if (extension != null) {
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
}
if (type == null) {
type = ""; // fallback type. You might set it to */*
}
return type;
}
} }

7
app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareFABBehavior.java

@ -34,8 +34,8 @@ public class ScrollAwareFABBehavior extends CoordinatorLayout.Behavior<FloatingA
final int dxUnconsumed, final int dyUnconsumed, int type) { final int dxUnconsumed, final int dyUnconsumed, int type) {
super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed,
dyUnconsumed, type); dyUnconsumed, type);
if ((dyConsumed > 0 || (!target.canScrollVertically(-1) && dyConsumed == 0 if (child.getVisibility() == View.VISIBLE && (dyConsumed > 0
&& dyUnconsumed < 40)) && child.getVisibility() == View.VISIBLE) { || (!target.canScrollVertically(-1) && dyConsumed == 0 && dyUnconsumed > 50))) {
child.hide(new FloatingActionButton.OnVisibilityChangedListener() { child.hide(new FloatingActionButton.OnVisibilityChangedListener() {
@Override @Override
public void onHidden(FloatingActionButton fab) { public void onHidden(FloatingActionButton fab) {
@ -43,7 +43,8 @@ public class ScrollAwareFABBehavior extends CoordinatorLayout.Behavior<FloatingA
fab.setVisibility(View.INVISIBLE); fab.setVisibility(View.INVISIBLE);
} }
}); });
} else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) { } else if (child.getVisibility() == View.INVISIBLE && (dyConsumed < 0
|| (!target.canScrollVertically(-1) && dyConsumed == 0 && dyUnconsumed < -50))) {
child.show(); child.show();
} }
} }

7
app/src/main/java/gr/thmmy/mthmmy/utils/ScrollAwareLinearBehavior.java

@ -37,10 +37,11 @@ public class ScrollAwareLinearBehavior extends CoordinatorLayout.Behavior<View>
int dxUnconsumed, int dyUnconsumed, int type) { int dxUnconsumed, int dyUnconsumed, int type) {
super.onNestedScroll(coordinatorLayout, bottomNavBar, target, dxConsumed, dyConsumed, super.onNestedScroll(coordinatorLayout, bottomNavBar, target, dxConsumed, dyConsumed,
dxUnconsumed, dyUnconsumed, type); dxUnconsumed, dyUnconsumed, type);
if ((dyConsumed > 0 || (!target.canScrollVertically(-1) && dyConsumed == 0 if (bottomNavBar.getVisibility() == View.VISIBLE && (dyConsumed > 0
&& dyUnconsumed < 40)) && bottomNavBar.getVisibility() == View.VISIBLE) { || (!target.canScrollVertically(-1) && dyConsumed == 0 && dyUnconsumed > 50))) {
hide(bottomNavBar); hide(bottomNavBar);
} else if (dyConsumed < 0 && bottomNavBar.getVisibility() != View.VISIBLE) { } else if (bottomNavBar.getVisibility() == View.INVISIBLE && (dyConsumed < 0
|| (!target.canScrollVertically(-1) && dyConsumed == 0 && dyUnconsumed < -50))) {
show(bottomNavBar); show(bottomNavBar);
} }
} }

12
app/src/main/res/layout-v21/activity_topic_post_row.xml

@ -37,6 +37,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:paddingLeft="16dp" android:paddingLeft="16dp"
android:paddingRight="16dp" android:paddingRight="16dp"
android:paddingTop="16dp"> android:paddingTop="16dp">
@ -94,6 +95,7 @@
android:background="@color/card_background" android:background="@color/card_background"
android:clickable="true" android:clickable="true"
android:contentDescription="@string/post_quote_button" android:contentDescription="@string/post_quote_button"
android:focusable="true"
android:src="@drawable/ic_format_quote_unchecked" /> android:src="@drawable/ic_format_quote_unchecked" />
</LinearLayout> </LinearLayout>
@ -102,6 +104,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:orientation="vertical" android:orientation="vertical"
android:paddingLeft="16dp" android:paddingLeft="16dp"
android:paddingRight="16dp" android:paddingRight="16dp"
@ -174,8 +177,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="start" android:gravity="start"
android:text="" android:text=""
android:textColor="@color/card_expand_text_color" android:textColor="@color/accent"
android:textSize="10sp" /> android:textSize="11sp" />
<TextView <TextView
android:id="@+id/post_number" android:id="@+id/post_number"
@ -183,8 +186,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="end" android:gravity="end"
android:text="" android:text=""
android:textColor="@color/card_expand_text_color" android:textColor="@color/accent"
android:textSize="10sp" /> android:textSize="11sp" />
</FrameLayout> </FrameLayout>
@ -212,6 +215,7 @@
android:layout_marginRight="16dp" android:layout_marginRight="16dp"
android:background="@color/card_background" android:background="@color/card_background"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:text="@string/post" /> android:text="@string/post" />
</FrameLayout> </FrameLayout>

83
app/src/main/res/layout/activity_about.xml

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_content" android:id="@+id/main_content"
@ -21,8 +20,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize" android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary" android:background="?attr/colorPrimary"
app:popupTheme="@style/ToolbarTheme"> app:popupTheme="@style/ToolbarTheme" />
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout> </android.support.design.widget.AppBarLayout>
@ -30,11 +28,10 @@
android:id="@+id/scrollview" android:id="@+id/scrollview"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" android:background="@color/primary_light"
android:background="@color/background"> app:layout_behavior="@string/appbar_scrolling_view_behavior">
<RelativeLayout <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -44,19 +41,15 @@
android:paddingTop="@dimen/activity_vertical_margin" android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.eternalpixels.toinfinity.Info"> tools:context="com.eternalpixels.toinfinity.Info">
<ImageView
<pl.droidsonroids.gif.GifImageView
android:id="@+id/logoView" android:id="@+id/logoView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentTop="true" android:layout_margin="15dp"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:layout_marginTop="20dp" android:layout_alignParentTop="true"
android:layout_marginBottom="20dp" android:src="@mipmap/ic_launcher"
android:contentDescription="@string/logo" android:contentDescription="@string/logo" />
android:src="@drawable/logo_animated"
/>
<TextView <TextView
android:id="@+id/version" android:id="@+id/version"
@ -65,73 +58,74 @@
android:layout_below="@+id/logoView" android:layout_below="@+id/logoView"
android:layout_centerHorizontal="true" android:layout_centerHorizontal="true"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/accent" android:textColor="@color/accent"
android:textStyle="italic"/> android:textStyle="italic" />
<TextView <TextView
android:id="@+id/open_source_header" android:id="@+id/open_source_header"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@+id/version"
android:layout_marginTop="20dp" android:layout_marginTop="20dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/open_source" android:text="@string/open_source"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@color/accent" android:textColor="@color/accent"
android:layout_below="@+id/version"
android:layout_alignParentStart="true"
android:textStyle="bold" /> android:textStyle="bold" />
<TextView <TextView
android:id="@+id/open_source_text" android:id="@+id/open_source_text"
android:layout_below="@+id/open_source_header"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@+id/open_source_header"
android:autoLink="web" android:autoLink="web"
android:text="@string/open_source_text" android:text="@string/open_source_text"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/iron" android:textColor="@color/iron" />
android:layout_alignParentStart="true" />
<TextView <TextView
android:id="@+id/libraries_header" android:id="@+id/libraries_header"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@+id/open_source_text"
android:layout_marginTop="20dp" android:layout_marginTop="20dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/libraries" android:text="@string/libraries"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@color/accent" android:textColor="@color/accent"
android:layout_below="@+id/open_source_text"
android:layout_alignParentStart="true"
android:textStyle="bold" /> android:textStyle="bold" />
<TextView <TextView
android:id="@+id/libraries_text" android:id="@+id/libraries_text"
android:layout_below="@+id/libraries_header"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@+id/libraries_header"
android:text="@string/libraries_text" android:text="@string/libraries_text"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/iron" android:textColor="@color/iron" />
android:layout_alignParentStart="true" />
<TextView <TextView
android:layout_below="@+id/libraries_text" android:id="@+id/apache_libs"
android:onClick="displayApacheLibraries"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/apache_v2_0_libraries"
android:id="@+id/apache_libs"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_below="@+id/libraries_text"
android:onClick="displayApacheLibraries"
android:text="@string/apache_v2_0_libraries"
android:textColor="@color/accent" /> android:textColor="@color/accent" />
<TextView <TextView
android:id="@+id/mit_libs" android:id="@+id/mit_libs"
android:onClick="displayMITLibraries"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/the_mit_libraries"
android:layout_below="@+id/apache_libs"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_below="@+id/apache_libs"
android:onClick="displayMITLibraries"
android:text="@string/the_mit_libraries"
android:textColor="@color/accent" /> android:textColor="@color/accent" />
@ -139,24 +133,24 @@
android:id="@+id/contact_header" android:id="@+id/contact_header"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@+id/mit_libs"
android:layout_marginTop="20dp" android:layout_marginTop="20dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="@string/contact" android:text="@string/contact"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@color/accent" android:textColor="@color/accent"
android:layout_below="@+id/mit_libs"
android:layout_alignParentStart="true"
android:textStyle="bold" /> android:textStyle="bold" />
<TextView <TextView
android:id="@+id/contact_text" android:id="@+id/contact_text"
android:layout_below="@+id/contact_header"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_below="@+id/contact_header"
android:autoLink="email|web" android:autoLink="email|web"
android:text="@string/contact_text" android:text="@string/contact_text"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="@color/iron" android:textColor="@color/iron" />
android:layout_alignParentStart="true" />
</RelativeLayout> </RelativeLayout>
</ScrollView> </ScrollView>
@ -175,7 +169,6 @@
android:layout_gravity="center" android:layout_gravity="center"
android:contentDescription="@string/trollPic" android:contentDescription="@string/trollPic"
android:foregroundGravity="center" android:foregroundGravity="center"
android:src="@drawable/fun" android:src="@drawable/fun" />
/>
</FrameLayout> </FrameLayout>
</android.support.design.widget.CoordinatorLayout> </android.support.design.widget.CoordinatorLayout>

14
app/src/main/res/layout/activity_board_sub_board.xml

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/card_background" android:background="@color/card_background"
@ -33,7 +32,7 @@
android:paddingBottom="2dp" android:paddingBottom="2dp"
android:text="@string/child_board_title" android:text="@string/child_board_title"
android:textColor="@color/accent" android:textColor="@color/accent"
android:textSize="22sp"/> android:textSize="22sp" />
<ImageButton <ImageButton
android:id="@+id/child_board_expand_collapse_button" android:id="@+id/child_board_expand_collapse_button"
@ -41,7 +40,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@null" android:background="@null"
android:contentDescription="@string/child_board_button" android:contentDescription="@string/child_board_button"
android:src="@drawable/ic_arrow_drop_down"/> android:src="@drawable/ic_arrow_drop_down" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
@ -61,7 +60,7 @@
android:text="@string/child_board_mods" android:text="@string/child_board_mods"
android:textColor="@color/secondary_text" android:textColor="@color/secondary_text"
android:textSize="12sp" android:textSize="12sp"
android:textStyle="italic"/> android:textStyle="italic" />
<TextView <TextView
android:id="@+id/child_board_stats" android:id="@+id/child_board_stats"
@ -71,7 +70,7 @@
android:layout_marginTop="1dp" android:layout_marginTop="1dp"
android:text="@string/child_board_stats" android:text="@string/child_board_stats"
android:textColor="@color/secondary_text" android:textColor="@color/secondary_text"
android:textSize="12sp"/> android:textSize="12sp" />
<TextView <TextView
android:id="@+id/child_board_last_post" android:id="@+id/child_board_last_post"
@ -80,9 +79,10 @@
android:layout_marginBottom="1dp" android:layout_marginBottom="1dp"
android:layout_marginTop="1dp" android:layout_marginTop="1dp"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:text="@string/child_board_last_post" android:text="@string/child_board_last_post"
android:textColor="@color/primary_text" android:textColor="@color/primary_text"
android:textSize="12sp"/> android:textSize="12sp" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

14
app/src/main/res/layout/activity_board_topic.xml

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/topic_row_linear" android:id="@+id/topic_row_linear"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -27,7 +26,7 @@
android:paddingBottom="2dp" android:paddingBottom="2dp"
android:text="@string/topic_subject" android:text="@string/topic_subject"
android:textColor="@color/primary_text" android:textColor="@color/primary_text"
android:textSize="18sp"/> android:textSize="18sp" />
<ImageButton <ImageButton
android:id="@+id/topic_expand_collapse_button" android:id="@+id/topic_expand_collapse_button"
@ -35,7 +34,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@null" android:background="@null"
android:contentDescription="@string/child_board_button" android:contentDescription="@string/child_board_button"
android:src="@drawable/ic_arrow_drop_down"/> android:src="@drawable/ic_arrow_drop_down" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
@ -54,7 +53,7 @@
android:layout_marginTop="1dp" android:layout_marginTop="1dp"
android:text="@string/topic_started_by" android:text="@string/topic_started_by"
android:textColor="@color/secondary_text" android:textColor="@color/secondary_text"
android:textSize="12sp"/> android:textSize="12sp" />
<TextView <TextView
android:id="@+id/topic_stats" android:id="@+id/topic_stats"
@ -64,7 +63,7 @@
android:layout_marginTop="1dp" android:layout_marginTop="1dp"
android:text="@string/topic_stats" android:text="@string/topic_stats"
android:textColor="@color/secondary_text" android:textColor="@color/secondary_text"
android:textSize="12sp"/> android:textSize="12sp" />
<TextView <TextView
android:id="@+id/topic_last_post" android:id="@+id/topic_last_post"
@ -73,8 +72,9 @@
android:layout_marginBottom="1dp" android:layout_marginBottom="1dp"
android:layout_marginTop="1dp" android:layout_marginTop="1dp"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:text="@string/topic_last_post" android:text="@string/topic_last_post"
android:textColor="@color/primary_text" android:textColor="@color/primary_text"
android:textSize="12sp"/> android:textSize="12sp" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>

12
app/src/main/res/layout/activity_topic_post_row.xml

@ -37,6 +37,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="1" android:layout_weight="1"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:paddingLeft="16dp" android:paddingLeft="16dp"
android:paddingRight="16dp" android:paddingRight="16dp"
android:paddingTop="16dp"> android:paddingTop="16dp">
@ -93,6 +94,7 @@
android:background="@color/card_background" android:background="@color/card_background"
android:clickable="true" android:clickable="true"
android:contentDescription="@string/post_quote_button" android:contentDescription="@string/post_quote_button"
android:focusable="true"
android:src="@drawable/ic_format_quote_unchecked" /> android:src="@drawable/ic_format_quote_unchecked" />
</LinearLayout> </LinearLayout>
@ -101,6 +103,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:orientation="vertical" android:orientation="vertical"
android:paddingLeft="16dp" android:paddingLeft="16dp"
android:paddingRight="16dp" android:paddingRight="16dp"
@ -173,8 +176,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="start" android:gravity="start"
android:text="" android:text=""
android:textColor="@color/card_expand_text_color" android:textColor="@color/accent"
android:textSize="10sp" /> android:textSize="11sp" />
<TextView <TextView
android:id="@+id/post_number" android:id="@+id/post_number"
@ -182,8 +185,8 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="end" android:gravity="end"
android:text="" android:text=""
android:textColor="@color/card_expand_text_color" android:textColor="@color/accent"
android:textSize="10sp" /> android:textSize="11sp" />
</FrameLayout> </FrameLayout>
@ -211,6 +214,7 @@
android:layout_marginRight="16dp" android:layout_marginRight="16dp"
android:background="@color/card_background" android:background="@color/card_background"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:text="@string/post" /> android:text="@string/post" />
</FrameLayout> </FrameLayout>

17
app/src/main/res/layout/activity_topic_quick_reply_row.xml

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -8,8 +7,7 @@
android:paddingEnd="4dp" android:paddingEnd="4dp"
android:paddingStart="4dp"> android:paddingStart="4dp">
<android.support.v7.widget.CardView <android.support.v7.widget.CardView xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view" android:id="@+id/card_view"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
@ -32,6 +30,7 @@
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1" android:layout_weight="1"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:paddingLeft="16dp" android:paddingLeft="16dp"
android:paddingRight="16dp" android:paddingRight="16dp"
android:paddingTop="16dp"> android:paddingTop="16dp">
@ -53,7 +52,7 @@
android:contentDescription="@string/post_thumbnail" android:contentDescription="@string/post_thumbnail"
android:maxHeight="@dimen/thumbnail_size" android:maxHeight="@dimen/thumbnail_size"
android:maxWidth="@dimen/thumbnail_size" android:maxWidth="@dimen/thumbnail_size"
android:src="@drawable/ic_default_user_thumbnail"/> android:src="@drawable/ic_default_user_thumbnail" />
</FrameLayout> </FrameLayout>
<TextView <TextView
@ -66,7 +65,7 @@
android:maxLines="1" android:maxLines="1"
android:text="@string/post_author" android:text="@string/post_author"
android:textColor="@color/primary_text" android:textColor="@color/primary_text"
android:textStyle="bold"/> android:textStyle="bold" />
<EditText <EditText
android:id="@+id/quick_reply_subject" android:id="@+id/quick_reply_subject"
@ -78,7 +77,7 @@
android:inputType="textMultiLine" android:inputType="textMultiLine"
android:maxLength="80" android:maxLength="80"
android:textSize="10sp" android:textSize="10sp"
tools:ignore="SmallSp"/> tools:ignore="SmallSp" />
</RelativeLayout> </RelativeLayout>
<LinearLayout <LinearLayout
@ -99,7 +98,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:hint="@string/quick_reply" android:hint="@string/quick_reply"
android:inputType="textMultiLine"/> android:inputType="textMultiLine" />
</android.support.design.widget.TextInputLayout> </android.support.design.widget.TextInputLayout>
<android.support.v7.widget.AppCompatImageButton <android.support.v7.widget.AppCompatImageButton
@ -111,7 +110,7 @@
android:layout_marginEnd="5dp" android:layout_marginEnd="5dp"
android:background="@color/card_background" android:background="@color/card_background"
android:contentDescription="@string/quick_reply_submit" android:contentDescription="@string/quick_reply_submit"
android:src="@drawable/ic_send"/> android:src="@drawable/ic_send" />
</LinearLayout> </LinearLayout>
</LinearLayout> </LinearLayout>
</android.support.v7.widget.CardView> </android.support.v7.widget.CardView>

13
app/src/main/res/layout/fragment_forum_board_row.xml

@ -2,19 +2,20 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:background="@color/primary_lighter"
android:background="@color/primary_lighter"> android:orientation="vertical">
<TextView <TextView
android:id="@+id/board" android:id="@+id/board"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAppearance="?attr/textAppearanceListItem"
android:textColor="@color/accent"
android:textSize="16sp"
android:background="?attr/selectableItemBackground" android:background="?attr/selectableItemBackground"
android:clickable="true" android:clickable="true"
android:focusable="true"
android:gravity="center_horizontal" android:gravity="center_horizontal"
android:padding="8dp"/> android:padding="8dp"
android:textAppearance="?attr/textAppearanceListItem"
android:textColor="@color/accent"
android:textSize="16sp" />
</LinearLayout> </LinearLayout>

14
app/src/main/res/layout/fragment_latest_posts_empty_message.xml

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textSize="@dimen/big_text"
android:layout_marginTop="8dp"
android:textColor="@color/accent"
android:text="@string/latest_posts_empty_message"/>
</LinearLayout>

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

@ -38,7 +38,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_below="@+id/spacer" android:layout_below="@+id/spacer"
android:textColor="@color/secondary_text"/> android:textColor="@color/accent"/>
<TextView <TextView
android:id="@+id/lastUser" android:id="@+id/lastUser"

11
app/src/main/res/layout/fragment_unread_mark_read_row.xml

@ -2,15 +2,16 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical">
android:paddingEnd="10dp"
android:paddingStart="10dp"
android:paddingTop="7dp">
<TextView <TextView
android:id="@+id/mark_read" android:id="@+id/mark_read"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textAlignment="textEnd" android:paddingEnd="10dp"
android:paddingStart="10dp"
android:paddingTop="7dp"
android:paddingBottom="7dp"
android:textAlignment="center"
android:textColor="@color/accent" /> android:textColor="@color/accent" />
</LinearLayout> </LinearLayout>

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

@ -38,7 +38,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentStart="true" android:layout_alignParentStart="true"
android:layout_below="@+id/spacer" android:layout_below="@+id/spacer"
android:textColor="@color/secondary_text"/> android:textColor="@color/accent"/>
<TextView <TextView
android:id="@+id/lastUser" android:id="@+id/lastUser"

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

@ -18,9 +18,6 @@
<string name="btn_login">LOGIN</string> <string name="btn_login">LOGIN</string>
<string name="btn_continue_as_guest">Don\'t have an account? Continue as guest!</string> <string name="btn_continue_as_guest">Don\'t have an account? Continue as guest!</string>
<!--Main Activity-->
<string name="byUser">by %1$s</string>
<!--Board Activity--> <!--Board Activity-->
<string name="child_board_title">Child Boards</string> <string name="child_board_title">Child Boards</string>
<string name="child_board_button">Exp/Coll</string> <string name="child_board_button">Exp/Coll</string>
@ -51,6 +48,7 @@
<!--Profile Activity--> <!--Profile Activity-->
<string name="username">Username</string> <string name="username">Username</string>
<string name="latest_posts_empty_message">This user has no posts yet</string>
<string name="general_statistics_title">General Statistics</string> <string name="general_statistics_title">General Statistics</string>
<string name="general_statistics">Statistics</string> <string name="general_statistics">Statistics</string>
<string name="posting_activity_by_time_title">Posting Activity</string> <string name="posting_activity_by_time_title">Posting Activity</string>

3
build.gradle

@ -4,9 +4,10 @@ buildscript {
repositories { repositories {
jcenter() jcenter()
maven { url "https://jitpack.io" } maven { url "https://jitpack.io" }
maven { url "https://maven.google.com" }
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.3.3' classpath 'com.android.tools.build:gradle:3.0.0'
classpath 'com.google.gms:google-services:3.1.0' classpath 'com.google.gms:google-services:3.1.0'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files

4
gradle/wrapper/gradle-wrapper.properties

@ -1,6 +1,6 @@
#Wed Mar 08 11:25:21 EET 2017 #Thu Oct 26 11:21:06 EEST 2017
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

Loading…
Cancel
Save