From 278d9875c4ca04c71fa3db6a96058545d366b379 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Wed, 17 Oct 2018 12:45:47 +0300 Subject: [PATCH 1/7] bbparser init --- app/build.gradle | 2 +- .../gr/thmmy/mthmmy/session/SessionManager.java | 14 ++++++++------ .../gr/thmmy/mthmmy/utils/parsing/BBParser.java | 12 ++++++++++++ 3 files changed, 21 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java diff --git a/app/build.gradle b/app/build.gradle index 11baff14..a239de87 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -65,7 +65,7 @@ dependencies { implementation 'org.jsoup:jsoup:1.10.3' //TODO: Warning: upgrading from 1.10.3 will break stuff! implementation 'com.github.franmontiel:PersistentCookieJar:v1.0.1' implementation 'com.github.PhilJay:MPAndroidChart:v3.0.3' - implementation("com.mikepenz:materialdrawer:6.0.7@aar") { + implementation("com.mikepenz:materialdrawer:6.1.1@aar") { transitive = true } implementation 'com.mikepenz:fontawesome-typeface:4.7.0.0@aar' diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java index 4811195d..ffb11416 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java +++ b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java @@ -117,16 +117,18 @@ public class SessionManager { setPersistentCookieSession(); //Store cookies //Edit SharedPreferences, save session's data + SharedPreferences.Editor editor = sharedPrefs.edit(); setLoginScreenAsDefault(false); - sharedPrefs.edit().putBoolean(LOGGED_IN, true).apply(); - sharedPrefs.edit().putString(USERNAME, extractUserName(document)).apply(); - sharedPrefs.edit().putInt(USER_ID, extractUserId(document)).apply(); + editor.putBoolean(LOGGED_IN, true); + editor.putString(USERNAME, extractUserName(document)); + editor.putInt(USER_ID, extractUserId(document)); String avatar = extractAvatarLink(document); if (avatar != null) { - sharedPrefs.edit().putBoolean(HAS_AVATAR, true).apply(); - sharedPrefs.edit().putString(AVATAR_LINK, extractAvatarLink(document)).apply(); + editor.putBoolean(HAS_AVATAR, true); + editor.putString(AVATAR_LINK, avatar); } else - sharedPrefs.edit().putBoolean(HAS_AVATAR, false).apply(); + editor.putBoolean(HAS_AVATAR, false); + editor.apply(); sharedPrefs.edit().putString(LOGOUT_LINK, extractLogoutLink(document)).apply(); diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java new file mode 100644 index 00000000..9719eb83 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java @@ -0,0 +1,12 @@ +package gr.thmmy.mthmmy.utils.parsing; + +import android.text.SpannableStringBuilder; +import android.text.SpannedString; + +public class BBParser { + public static final String[] supportedTags = {"b"}; + + public SpannedString bb2span(String bb) { + SpannableStringBuilder builder = new SpannableStringBuilder(bb); + } +} From c9c3e0312353356871268d58826e6b792e518e37 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Wed, 17 Oct 2018 13:14:08 +0300 Subject: [PATCH 2/7] parse tag starts --- .../java/gr/thmmy/mthmmy/model/BBTag.java | 35 +++++++++++++++++++ .../thmmy/mthmmy/session/SessionManager.java | 10 ++---- .../thmmy/mthmmy/utils/parsing/BBParser.java | 33 +++++++++++++++++ 3 files changed, 71 insertions(+), 7 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/model/BBTag.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/BBTag.java b/app/src/main/java/gr/thmmy/mthmmy/model/BBTag.java new file mode 100644 index 00000000..65a183fd --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/model/BBTag.java @@ -0,0 +1,35 @@ +package gr.thmmy.mthmmy.model; + +public class BBTag { + private int start, end; + private String name; + + public BBTag(int start, String name) { + this.start = start; + this.name = name; + } + + public int getStart() { + return start; + } + + public void setStart(int start) { + this.start = start; + } + + public int getEnd() { + return end; + } + + public void setEnd(int end) { + this.end = end; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java index ffb11416..560c7089 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java +++ b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java @@ -123,16 +123,12 @@ public class SessionManager { editor.putString(USERNAME, extractUserName(document)); editor.putInt(USER_ID, extractUserId(document)); String avatar = extractAvatarLink(document); - if (avatar != null) { - editor.putBoolean(HAS_AVATAR, true); + if (avatar != null) editor.putString(AVATAR_LINK, avatar); - } else - editor.putBoolean(HAS_AVATAR, false); + editor.putBoolean(HAS_AVATAR, avatar != null); + editor.putString(LOGOUT_LINK, extractLogoutLink(document)); editor.apply(); - - sharedPrefs.edit().putString(LOGOUT_LINK, extractLogoutLink(document)).apply(); - return SUCCESS; } else { Timber.i("Login failed."); diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java index 9719eb83..1986c1af 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java @@ -2,11 +2,44 @@ package gr.thmmy.mthmmy.utils.parsing; import android.text.SpannableStringBuilder; import android.text.SpannedString; +import android.text.TextUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import gr.thmmy.mthmmy.model.BBTag; +import timber.log.Timber; public class BBParser { public static final String[] supportedTags = {"b"}; public SpannedString bb2span(String bb) { SpannableStringBuilder builder = new SpannableStringBuilder(bb); + BBTag[] tags = getTags(bb); + } + + public BBTag[] getTags(String bb) { + Pattern bbtagPattern = Pattern.compile("[*+]"); + + LinkedList tags = new LinkedList<>(); + String searcingString = bb; + Matcher bbMatcher = bbtagPattern.matcher(searcingString); + while (bbMatcher.find()) { + String name = bbMatcher.group(0); + if (!isSupported(name)) continue; + tags.add(new BBTag(bbMatcher.start(), name)); + searcingString = searcingString.substring(bbMatcher.start() + name.length()); + bbMatcher = bbtagPattern.matcher(searcingString); + } + return tags.toArray(new BBTag[0]); + } + + public boolean isSupported(String tagName) { + for (String tag : supportedTags) + if (TextUtils.equals(tag, tagName)) return true; + return false; } } From ca3281387bb472cfeea9ca61c742b0ea0cc2ad03 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Wed, 17 Oct 2018 13:39:36 +0300 Subject: [PATCH 3/7] progress --- .../thmmy/mthmmy/utils/parsing/BBParser.java | 43 ++++++++++++++----- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java index 1986c1af..18d70d49 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java @@ -1,9 +1,13 @@ package gr.thmmy.mthmmy.utils.parsing; +import android.graphics.Typeface; +import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.SpannedString; import android.text.TextUtils; +import android.text.style.StyleSpan; +import java.nio.charset.UnsupportedCharsetException; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; @@ -14,30 +18,47 @@ import gr.thmmy.mthmmy.model.BBTag; import timber.log.Timber; public class BBParser { - public static final String[] supportedTags = {"b"}; + private static final String[] supportedTags = {"b"}; - public SpannedString bb2span(String bb) { + public static SpannedString bb2span(String bb) { SpannableStringBuilder builder = new SpannableStringBuilder(bb); BBTag[] tags = getTags(bb); + for (BBTag tag : tags) { + switch (tag.getName()) { + case "b": + builder.setSpan(new StyleSpan(Typeface.BOLD), tag.getStart(), tag.getEnd(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + break; + default: + throw new UnsupportedCharsetException("Tag not supported"); + } + } } - public BBTag[] getTags(String bb) { - Pattern bbtagPattern = Pattern.compile("[*+]"); + public static BBTag[] getTags(String bb) { + Pattern bbtagPattern = Pattern.compile("\\[(.+?)\\]"); LinkedList tags = new LinkedList<>(); - String searcingString = bb; - Matcher bbMatcher = bbtagPattern.matcher(searcingString); + Matcher bbMatcher = bbtagPattern.matcher(bb); while (bbMatcher.find()) { String name = bbMatcher.group(0); - if (!isSupported(name)) continue; - tags.add(new BBTag(bbMatcher.start(), name)); - searcingString = searcingString.substring(bbMatcher.start() + name.length()); - bbMatcher = bbtagPattern.matcher(searcingString); + if (name.startsWith("/")) { + //closing tag + name = name.substring(1); + for (int i = tags.size() - 1; i >= 0; i--) { + if (tags.get(i).getName().equals(name)) { + tags.get(i).setEnd(bbMatcher.start()); + break; + } + } + continue; + } + if (isSupported(name)) + tags.add(new BBTag(bbMatcher.start(), name)); } return tags.toArray(new BBTag[0]); } - public boolean isSupported(String tagName) { + public static boolean isSupported(String tagName) { for (String tag : supportedTags) if (TextUtils.equals(tag, tagName)) return true; return false; From 28e2bdfe740883a60a782f59f50a9accbde76510 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Thu, 18 Oct 2018 17:21:47 +0300 Subject: [PATCH 4/7] maybe finish the parse/modify string logic --- app/src/main/AndroidManifest.xml | 22 ++++++--- .../thmmy/mthmmy/activities/TestActivity.java | 28 +++++++++++ .../mthmmy/activities/main/MainActivity.java | 3 ++ .../java/gr/thmmy/mthmmy/model/BBTag.java | 8 ++++ .../thmmy/mthmmy/utils/parsing/BBParser.java | 46 +++++++++++++++++-- app/src/main/res/layout/activity_test.xml | 20 ++++++++ 6 files changed, 116 insertions(+), 11 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/activities/TestActivity.java create mode 100644 app/src/main/res/layout/activity_test.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index eef46aad..cf3aaef0 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -17,11 +17,18 @@ android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> - - - - - + + + + + \ No newline at end of file diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/TestActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/TestActivity.java new file mode 100644 index 00000000..1ac4c05c --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/TestActivity.java @@ -0,0 +1,28 @@ +package gr.thmmy.mthmmy.activities; + +import androidx.appcompat.app.AppCompatActivity; +import gr.thmmy.mthmmy.R; +import gr.thmmy.mthmmy.utils.parsing.BBParser; +import timber.log.Timber; + +import android.os.Bundle; +import android.text.SpannableStringBuilder; +import android.widget.TextView; + +public class TestActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_test); + + String bb = "[b]An [i]elep[u]hant[/i][/b] swi[/u]ms in [s]the[/s] tree"; + SpannableStringBuilder result = BBParser.bb2span(bb); + + TextView bbRaw = findViewById(R.id.bb_raw); + TextView bb2Text = findViewById(R.id.bb2text); + + bbRaw.setText(bb); + bb2Text.setText(result); + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java index 4a64499f..8b0476a0 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/MainActivity.java @@ -19,6 +19,7 @@ import androidx.preference.PreferenceManager; import androidx.viewpager.widget.ViewPager; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.activities.LoginActivity; +import gr.thmmy.mthmmy.activities.TestActivity; import gr.thmmy.mthmmy.activities.board.BoardActivity; import gr.thmmy.mthmmy.activities.downloads.DownloadsActivity; import gr.thmmy.mthmmy.activities.main.forum.ForumFragment; @@ -137,6 +138,8 @@ public class MainActivity extends BaseActivity implements RecentFragment.RecentF , Toast.LENGTH_SHORT).show(); } mBackPressed = System.currentTimeMillis(); + + startActivity(new Intent(this, TestActivity.class)); } @Override diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/BBTag.java b/app/src/main/java/gr/thmmy/mthmmy/model/BBTag.java index 65a183fd..af8db970 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/BBTag.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/BBTag.java @@ -1,5 +1,7 @@ package gr.thmmy.mthmmy.model; +import androidx.annotation.NonNull; + public class BBTag { private int start, end; private String name; @@ -9,6 +11,12 @@ public class BBTag { this.name = name; } + @NonNull + @Override + public String toString() { + return "start:" + start + ",end:" + end + ",name:" + name; + } + public int getStart() { return start; } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java index 18d70d49..89e177c5 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java @@ -5,12 +5,17 @@ import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.SpannedString; import android.text.TextUtils; +import android.text.style.StrikethroughSpan; import android.text.style.StyleSpan; +import android.text.style.UnderlineSpan; + +import org.commonmark.node.Link; import java.nio.charset.UnsupportedCharsetException; import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; +import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -18,20 +23,49 @@ import gr.thmmy.mthmmy.model.BBTag; import timber.log.Timber; public class BBParser { - private static final String[] supportedTags = {"b"}; + private static final String[] supportedTags = {"b", "i", "u", "s"}; - public static SpannedString bb2span(String bb) { + public static SpannableStringBuilder bb2span(String bb) { SpannableStringBuilder builder = new SpannableStringBuilder(bb); + // store the original indices of the string + LinkedList stringIndices = new LinkedList<>(); + for (int i = 0; i < builder.length(); i++) { + stringIndices.add(i); + } + BBTag[] tags = getTags(bb); for (BBTag tag : tags) { + int start = stringIndices.indexOf(tag.getStart()); + int end = stringIndices.indexOf(tag.getEnd()); + int startTagLength = tag.getName().length() + 2; + int endTagLength = tag.getName().length() + 3; switch (tag.getName()) { case "b": - builder.setSpan(new StyleSpan(Typeface.BOLD), tag.getStart(), tag.getEnd(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + builder.setSpan(new StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + break; + case "i": + builder.setSpan(new StyleSpan(Typeface.ITALIC), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + break; + case "u": + builder.setSpan(new UnderlineSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + break; + case "s": + builder.setSpan(new StrikethroughSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); break; default: throw new UnsupportedCharsetException("Tag not supported"); } + //remove starting and ending tag and and do the same changes in the list + builder.delete(start, start + startTagLength); + for (int i = start; i < start + startTagLength; i++) { + stringIndices.remove(start); + } + builder.delete(end - startTagLength, end - startTagLength + endTagLength); + for (int i = end - startTagLength; i < end - startTagLength + endTagLength; i++) { + stringIndices.remove(end - startTagLength); + } } + return builder; } public static BBTag[] getTags(String bb) { @@ -40,7 +74,7 @@ public class BBParser { LinkedList tags = new LinkedList<>(); Matcher bbMatcher = bbtagPattern.matcher(bb); while (bbMatcher.find()) { - String name = bbMatcher.group(0); + String name = bbMatcher.group(1); if (name.startsWith("/")) { //closing tag name = name.substring(1); @@ -55,6 +89,10 @@ public class BBParser { if (isSupported(name)) tags.add(new BBTag(bbMatcher.start(), name)); } + // remove parsed tags with no end tag + for (BBTag bbTag : tags) + if (bbTag.getEnd() == 0) + tags.remove(bbTag); return tags.toArray(new BBTag[0]); } diff --git a/app/src/main/res/layout/activity_test.xml b/app/src/main/res/layout/activity_test.xml new file mode 100644 index 00000000..16accea6 --- /dev/null +++ b/app/src/main/res/layout/activity_test.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file From 546241e98f790fcd9b9d8b58f72acb360bd3aa84 Mon Sep 17 00:00:00 2001 From: Thodoris1999 Date: Mon, 22 Oct 2018 17:42:45 +0300 Subject: [PATCH 5/7] add attribute parsing --- app/src/main/java/gr/thmmy/mthmmy/model/BBTag.java | 12 +++++++++++- .../java/gr/thmmy/mthmmy/utils/parsing/BBParser.java | 12 ++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/BBTag.java b/app/src/main/java/gr/thmmy/mthmmy/model/BBTag.java index af8db970..77504761 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/model/BBTag.java +++ b/app/src/main/java/gr/thmmy/mthmmy/model/BBTag.java @@ -4,13 +4,19 @@ import androidx.annotation.NonNull; public class BBTag { private int start, end; - private String name; + private String name, attribute; public BBTag(int start, String name) { this.start = start; this.name = name; } + public BBTag(int start, String name, String attribute) { + this.start = start; + this.name = name; + this.attribute = attribute; + } + @NonNull @Override public String toString() { @@ -40,4 +46,8 @@ public class BBTag { public void setName(String name) { this.name = name; } + + public String getAttribute() { + return attribute; + } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java index 89e177c5..e596d85f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java @@ -74,7 +74,15 @@ public class BBParser { LinkedList tags = new LinkedList<>(); Matcher bbMatcher = bbtagPattern.matcher(bb); while (bbMatcher.find()) { - String name = bbMatcher.group(1); + String startTag = bbMatcher.group(1); + int separatorIndex = startTag.indexOf('='); + String name, attribute = null; + if (separatorIndex > 0) { + attribute = startTag.substring(separatorIndex); + name = startTag.substring(0, separatorIndex); + } else + name = startTag; + if (name.startsWith("/")) { //closing tag name = name.substring(1); @@ -87,7 +95,7 @@ public class BBParser { continue; } if (isSupported(name)) - tags.add(new BBTag(bbMatcher.start(), name)); + tags.add(new BBTag(bbMatcher.start(), name, attribute)); } // remove parsed tags with no end tag for (BBTag bbTag : tags) From a6578b0830e05c75b1185a519eeecb4f423ffc29 Mon Sep 17 00:00:00 2001 From: oogee Date: Tue, 6 Nov 2018 15:12:53 +0200 Subject: [PATCH 6/7] html2span progress --- .../mthmmy/activities/topic/TopicParser.java | 6 +- .../java/gr/thmmy/mthmmy/model/HtmlTag.java | 58 ++++++++++++ .../thmmy/mthmmy/utils/parsing/BBParser.java | 90 +++++++++++++++++-- 3 files changed, 142 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/gr/thmmy/mthmmy/model/HtmlTag.java diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java index 5a411e12..4ebbba5a 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicParser.java @@ -156,9 +156,9 @@ public class TopicParser { ArrayList parsedPostsList = new ArrayList<>(); -// Poll poll = findPoll(topic); -// if (poll != null) -// parsedPostsList.add(poll); + Poll poll = findPoll(topic); + if (poll != null) + parsedPostsList.add(poll); Elements postRows; diff --git a/app/src/main/java/gr/thmmy/mthmmy/model/HtmlTag.java b/app/src/main/java/gr/thmmy/mthmmy/model/HtmlTag.java new file mode 100644 index 00000000..b7e13021 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/model/HtmlTag.java @@ -0,0 +1,58 @@ +package gr.thmmy.mthmmy.model; + +import androidx.annotation.NonNull; + +public class HtmlTag { + private int start, end; + private String name, attributeKey, attributeValue; + + public HtmlTag(int start, String name) { + this.start = start; + this.name = name; + } + + public HtmlTag(int start, String name, String attributeKey, String attributeValue) { + this.start = start; + this.name = name; + this.attributeKey = attributeKey; + this.attributeValue = attributeValue; + } + + @NonNull + @Override + public String toString() { + return "start:" + start + ",end:" + end + ",name:" + name; + } + + public int getStart() { + return start; + } + + public void setStart(int start) { + this.start = start; + } + + public int getEnd() { + return end; + } + + public void setEnd(int end) { + this.end = end; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getAttributeKey() { + return attributeKey; + } + + public String getAttributeValue() { + return attributeValue; + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java index e596d85f..618366ff 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java @@ -3,27 +3,24 @@ package gr.thmmy.mthmmy.utils.parsing; import android.graphics.Typeface; import android.text.Spannable; import android.text.SpannableStringBuilder; -import android.text.SpannedString; import android.text.TextUtils; import android.text.style.StrikethroughSpan; import android.text.style.StyleSpan; import android.text.style.UnderlineSpan; -import org.commonmark.node.Link; - import java.nio.charset.UnsupportedCharsetException; -import java.util.ArrayList; -import java.util.Arrays; import java.util.LinkedList; -import java.util.function.Predicate; import java.util.regex.Matcher; import java.util.regex.Pattern; import gr.thmmy.mthmmy.model.BBTag; -import timber.log.Timber; +import gr.thmmy.mthmmy.model.HtmlTag; public class BBParser { - private static final String[] supportedTags = {"b", "i", "u", "s"}; + private static final String[] ALL_TAGS = {"b", "i", "u", "s", "glow", "shadow", "move", "pre", "lefter", + "center", "right", "hr", "size", "font", "color", "youtube", "flash", "img", "url" + , "email", "ftp", "table", "tr", "td", "sup", "sub", "tt", "code", "quote", "tex", "list", "li"}; + private static final String[] SUPPORTED_TAGS = {"b", "i", "u", "s"}; public static SpannableStringBuilder bb2span(String bb) { SpannableStringBuilder builder = new SpannableStringBuilder(bb); @@ -68,6 +65,38 @@ public class BBParser { return builder; } + public static SpannableStringBuilder html2span(String html) { + SpannableStringBuilder builder = new SpannableStringBuilder(html); + // store the original indices of the string + LinkedList stringIndices = new LinkedList<>(); + for (int i = 0; i < builder.length(); i++) { + stringIndices.add(i); + } + + HtmlTag[] tags = getHtmlTags(html); + for (HtmlTag tag : tags) { + int start = stringIndices.indexOf(tag.getStart()); + int end = stringIndices.indexOf(tag.getEnd()); + int startTagLength = tag.getName().length() + 2; + int endTagLength = tag.getName().length() + 3; + + switch (tag.getName()) { + + } + + //remove starting and ending tag and and do the same changes in the list + builder.delete(start, start + startTagLength); + for (int i = start; i < start + startTagLength; i++) { + stringIndices.remove(start); + } + builder.delete(end - startTagLength, end - startTagLength + endTagLength); + for (int i = end - startTagLength; i < end - startTagLength + endTagLength; i++) { + stringIndices.remove(end - startTagLength); + } + } + return builder; + } + public static BBTag[] getTags(String bb) { Pattern bbtagPattern = Pattern.compile("\\[(.+?)\\]"); @@ -104,8 +133,51 @@ public class BBParser { return tags.toArray(new BBTag[0]); } + public static HtmlTag[] getHtmlTags(String html) { + Pattern htmlPattern = Pattern.compile("<(.+?)>"); + + LinkedList tags = new LinkedList<>(); + Matcher htmlMatcher = htmlPattern.matcher(html); + while (htmlMatcher.find()) { + String startTag = htmlMatcher.group(1); + int separatorIndex = startTag.indexOf(' '); + String name, attribute = null, attributeValue = null; + if (separatorIndex > 0) { + String fullAttribute = startTag.substring(separatorIndex); + int equalsIndex = fullAttribute.indexOf('='); + attribute = fullAttribute.substring(0, equalsIndex); + attributeValue = fullAttribute.substring(equalsIndex); + name = startTag.substring(0, separatorIndex); + } else + name = startTag; + + if (name.startsWith("/")) { + //closing tag + name = name.substring(1); + for (int i = tags.size() - 1; i >= 0; i--) { + if (tags.get(i).getName().equals(name)) { + tags.get(i).setEnd(htmlMatcher.start()); + break; + } + } + continue; + } + if (isHtmlTagSupported(name, attribute, attributeValue)) + tags.add(new HtmlTag(htmlMatcher.start(), name, attribute, attributeValue)); + } + // remove parsed tags with no end tag + for (HtmlTag htmlTag : tags) + if (htmlTag.getEnd() == 0) + tags.remove(htmlTag); + return tags.toArray(new HtmlTag[0]); + } + + private static boolean isHtmlTagSupported(String name, String attribute, String attributeValue) { + return false; + } + public static boolean isSupported(String tagName) { - for (String tag : supportedTags) + for (String tag : SUPPORTED_TAGS) if (TextUtils.equals(tag, tagName)) return true; return false; } From 9b22f1da6a09336b602ae5c52724ddad79031599 Mon Sep 17 00:00:00 2001 From: oogee Date: Thu, 8 Nov 2018 18:33:34 +0200 Subject: [PATCH 7/7] support not supporting html tags in polls --- .../thmmy/mthmmy/activities/TestActivity.java | 5 +- .../mthmmy/activities/topic/TopicAdapter.java | 38 +++++++++-- .../java/gr/thmmy/mthmmy/utils/HTMLUtils.java | 19 ++++-- .../{BBParser.java => ThmmyParser.java} | 67 ++++++++++++++----- 4 files changed, 99 insertions(+), 30 deletions(-) rename app/src/main/java/gr/thmmy/mthmmy/utils/parsing/{BBParser.java => ThmmyParser.java} (70%) diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/TestActivity.java b/app/src/main/java/gr/thmmy/mthmmy/activities/TestActivity.java index 1ac4c05c..28ba7c77 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/TestActivity.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/TestActivity.java @@ -2,8 +2,7 @@ package gr.thmmy.mthmmy.activities; import androidx.appcompat.app.AppCompatActivity; import gr.thmmy.mthmmy.R; -import gr.thmmy.mthmmy.utils.parsing.BBParser; -import timber.log.Timber; +import gr.thmmy.mthmmy.utils.parsing.ThmmyParser; import android.os.Bundle; import android.text.SpannableStringBuilder; @@ -17,7 +16,7 @@ public class TestActivity extends AppCompatActivity { setContentView(R.layout.activity_test); String bb = "[b]An [i]elep[u]hant[/i][/b] swi[/u]ms in [s]the[/s] tree"; - SpannableStringBuilder result = BBParser.bb2span(bb); + SpannableStringBuilder result = ThmmyParser.bb2span(bb); TextView bbRaw = findViewById(R.id.bb_raw); TextView bb2Text = findViewById(R.id.bb2text); diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java index 1c32ce2d..44658316 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java @@ -66,6 +66,7 @@ import gr.thmmy.mthmmy.model.ThmmyFile; import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.utils.CircleTransform; +import gr.thmmy.mthmmy.utils.parsing.ThmmyParser; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.viewmodel.TopicViewModel; import timber.log.Timber; @@ -166,9 +167,34 @@ class TopicAdapter extends RecyclerView.Adapter { Poll poll = (Poll) topicItems.get(position); Poll.Entry[] entries = poll.getEntries(); PollViewHolder holder = (PollViewHolder) currentHolder; + + boolean pollSupported = true; + for (Poll.Entry entry : entries) { + if (ThmmyParser.containsHtml(entry.getEntryName())) pollSupported = false; + break; + } + if (ThmmyParser.containsHtml(poll.getQuestion())) pollSupported = false; + if (!pollSupported) { + holder.optionsLayout.setVisibility(View.GONE); + holder.voteChart.setVisibility(View.GONE); + holder.removeVotesButton.setVisibility(View.GONE); + holder.showPollResultsButton.setVisibility(View.GONE); + holder.hidePollResultsButton.setVisibility(View.GONE); + // use the submit vote button to open poll on browser + holder.submitButton.setText("Open in browser"); + holder.submitButton.setOnClickListener(v -> { + Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(viewModel.getTopicUrl())); + context.startActivity(browserIntent); + }); + holder.submitButton.setVisibility(View.VISIBLE); + // put a warning instead of a question + holder.question.setText("This topic contains a poll that is not supported in mthmmy"); + return; + } + holder.question.setText(poll.getQuestion()); holder.optionsLayout.removeAllViews(); - holder.errorTooManySelected.setVisibility(View.GONE); + holder.errorTextview.setVisibility(View.GONE); if (poll.getAvailableVoteCount() > 1) { for (Poll.Entry entry : entries) { LinearLayout container = new LinearLayout(context); @@ -183,6 +209,7 @@ class TopicAdapter extends RecyclerView.Adapter { //noinspection deprecation label.setText(Html.fromHtml(entry.getEntryName())); } + label.setText(ThmmyParser.html2span(context, entry.getEntryName())); checkBox.setTextColor(context.getResources().getColor(R.color.primary_text)); container.addView(checkBox); container.addView(label); @@ -202,6 +229,7 @@ class TopicAdapter extends RecyclerView.Adapter { //noinspection deprecation radioButton.setText(Html.fromHtml(entries[i].getEntryName())); } + radioButton.setText(ThmmyParser.html2span(context, entries[i].getEntryName())); radioButton.setTextColor(context.getResources().getColor(R.color.primary_text)); radioGroup.addView(radioButton); } @@ -261,10 +289,10 @@ class TopicAdapter extends RecyclerView.Adapter { if (poll.getPollFormUrl() != null) { holder.submitButton.setOnClickListener(v -> { if (!viewModel.submitVote(holder.optionsLayout)) { - holder.errorTooManySelected.setText(context.getResources() + holder.errorTextview.setText(context.getResources() .getQuantityString(R.plurals.error_too_many_checked, poll.getAvailableVoteCount(), poll.getAvailableVoteCount())); - holder.errorTooManySelected.setVisibility(View.VISIBLE); + holder.errorTextview.setVisibility(View.VISIBLE); } }); holder.submitButton.setVisibility(View.VISIBLE); @@ -754,7 +782,7 @@ class TopicAdapter extends RecyclerView.Adapter { } static class PollViewHolder extends RecyclerView.ViewHolder { - final TextView question, errorTooManySelected; + final TextView question, errorTextview; final LinearLayout optionsLayout; final AppCompatButton submitButton; final AppCompatButton removeVotesButton, showPollResultsButton, hidePollResultsButton; @@ -769,7 +797,7 @@ class TopicAdapter extends RecyclerView.Adapter { removeVotesButton = itemView.findViewById(R.id.remove_vote_button); showPollResultsButton = itemView.findViewById(R.id.show_poll_results_button); hidePollResultsButton = itemView.findViewById(R.id.show_poll_options_button); - errorTooManySelected = itemView.findViewById(R.id.error_too_many_checked); + errorTextview = itemView.findViewById(R.id.error_too_many_checked); voteChart = itemView.findViewById(R.id.vote_chart); } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/HTMLUtils.java b/app/src/main/java/gr/thmmy/mthmmy/utils/HTMLUtils.java index 2713a2a8..8ca4ede6 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/HTMLUtils.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/HTMLUtils.java @@ -1,6 +1,7 @@ package gr.thmmy.mthmmy.utils; import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; @@ -12,6 +13,7 @@ import android.text.style.URLSpan; import android.view.View; import gr.thmmy.mthmmy.activities.board.BoardActivity; +import gr.thmmy.mthmmy.activities.main.MainActivity; import gr.thmmy.mthmmy.activities.profile.ProfileActivity; import gr.thmmy.mthmmy.model.ThmmyPage; @@ -41,7 +43,7 @@ public class HTMLUtils { return strBuilder; } - private static void makeLinkClickable(Activity activity, SpannableStringBuilder strBuilder, final URLSpan span) { + public static void makeLinkClickable(Context context, SpannableStringBuilder strBuilder, final URLSpan span) { int start = strBuilder.getSpanStart(span); int end = strBuilder.getSpanEnd(span); int flags = strBuilder.getSpanFlags(span); @@ -50,24 +52,27 @@ public class HTMLUtils { public void onClick(View view) { ThmmyPage.PageCategory target = ThmmyPage.resolvePageCategory(Uri.parse(span.getURL())); if (target.is(ThmmyPage.PageCategory.BOARD)) { - Intent intent = new Intent(activity.getApplicationContext(), BoardActivity.class); + Intent intent = new Intent(context, BoardActivity.class); Bundle extras = new Bundle(); extras.putString(BUNDLE_BOARD_URL, span.getURL()); extras.putString(BUNDLE_BOARD_TITLE, ""); intent.putExtras(extras); intent.setFlags(FLAG_ACTIVITY_NEW_TASK); - activity.getApplicationContext().startActivity(intent); + context.startActivity(intent); } else if (target.is(ThmmyPage.PageCategory.PROFILE)) { - Intent intent = new Intent(activity.getApplicationContext(), ProfileActivity.class); + Intent intent = new Intent(context, ProfileActivity.class); Bundle extras = new Bundle(); extras.putString(BUNDLE_PROFILE_URL, span.getURL()); extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, ""); extras.putString(BUNDLE_PROFILE_USERNAME, ""); intent.putExtras(extras); intent.setFlags(FLAG_ACTIVITY_NEW_TASK); - activity.getApplicationContext().startActivity(intent); - } else if (target.is(ThmmyPage.PageCategory.INDEX)) - activity.finish(); + context.startActivity(intent); + } else if (target.is(ThmmyPage.PageCategory.INDEX)) { + Intent intent = new Intent(context, MainActivity.class); + intent.setFlags(FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + } } }; strBuilder.setSpan(clickable, start, end, flags); diff --git a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyParser.java similarity index 70% rename from app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java rename to app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyParser.java index 618366ff..f900290f 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java +++ b/app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyParser.java @@ -1,11 +1,13 @@ package gr.thmmy.mthmmy.utils.parsing; +import android.content.Context; import android.graphics.Typeface; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextUtils; import android.text.style.StrikethroughSpan; import android.text.style.StyleSpan; +import android.text.style.URLSpan; import android.text.style.UnderlineSpan; import java.nio.charset.UnsupportedCharsetException; @@ -15,12 +17,14 @@ import java.util.regex.Pattern; import gr.thmmy.mthmmy.model.BBTag; import gr.thmmy.mthmmy.model.HtmlTag; +import gr.thmmy.mthmmy.utils.HTMLUtils; -public class BBParser { - private static final String[] ALL_TAGS = {"b", "i", "u", "s", "glow", "shadow", "move", "pre", "lefter", +public class ThmmyParser { + private static final String[] ALL_BB_TAGS = {"b", "i", "u", "s", "glow", "shadow", "move", "pre", "lefter", "center", "right", "hr", "size", "font", "color", "youtube", "flash", "img", "url" , "email", "ftp", "table", "tr", "td", "sup", "sub", "tt", "code", "quote", "tex", "list", "li"}; - private static final String[] SUPPORTED_TAGS = {"b", "i", "u", "s"}; + private static final String[] ALL_HTML_TAGS = {"b", "br", "span", "i", "div", "del", "marquee", "pre", + "hr", "embed", "noembed", "a", "img", "table", "tr", "td", "sup", "sub", "tt", "pre", "ul", "li"}; public static SpannableStringBuilder bb2span(String bb) { SpannableStringBuilder builder = new SpannableStringBuilder(bb); @@ -30,7 +34,7 @@ public class BBParser { stringIndices.add(i); } - BBTag[] tags = getTags(bb); + BBTag[] tags = getBBTags(bb); for (BBTag tag : tags) { int start = stringIndices.indexOf(tag.getStart()); int end = stringIndices.indexOf(tag.getEnd()); @@ -65,7 +69,7 @@ public class BBParser { return builder; } - public static SpannableStringBuilder html2span(String html) { + public static SpannableStringBuilder html2span(Context context, String html) { SpannableStringBuilder builder = new SpannableStringBuilder(html); // store the original indices of the string LinkedList stringIndices = new LinkedList<>(); @@ -78,10 +82,35 @@ public class BBParser { int start = stringIndices.indexOf(tag.getStart()); int end = stringIndices.indexOf(tag.getEnd()); int startTagLength = tag.getName().length() + 2; + if (tag.getAttributeKey() != null) { + startTagLength += tag.getAttributeKey().length() + tag.getAttributeValue().length() + 4; + } int endTagLength = tag.getName().length() + 3; - switch (tag.getName()) { - + if (isHtmlTagSupported(tag.getName(), tag.getAttributeKey(), tag.getAttributeValue())) { + switch (tag.getName()) { + case "b": + builder.setSpan(new StyleSpan(Typeface.BOLD), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + break; + case "i": + builder.setSpan(new StyleSpan(Typeface.ITALIC), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + break; + case "span": + if (tag.getAttributeKey().equals("style") && tag.getAttributeValue().equals("text-decoration: underline;")) { + builder.setSpan(new UnderlineSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + break; + case "del": + builder.setSpan(new StrikethroughSpan(), start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + break; + case "a": + URLSpan urlSpan = new URLSpan(tag.getAttributeValue()); + builder.setSpan(urlSpan, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + HTMLUtils.makeLinkClickable(context, builder, urlSpan); + break; + default: + throw new UnsupportedCharsetException("Tag not supported"); + } } //remove starting and ending tag and and do the same changes in the list @@ -97,7 +126,7 @@ public class BBParser { return builder; } - public static BBTag[] getTags(String bb) { + public static BBTag[] getBBTags(String bb) { Pattern bbtagPattern = Pattern.compile("\\[(.+?)\\]"); LinkedList tags = new LinkedList<>(); @@ -123,7 +152,7 @@ public class BBParser { } continue; } - if (isSupported(name)) + if (isBBTagSupported(name)) tags.add(new BBTag(bbMatcher.start(), name, attribute)); } // remove parsed tags with no end tag @@ -145,8 +174,8 @@ public class BBParser { if (separatorIndex > 0) { String fullAttribute = startTag.substring(separatorIndex); int equalsIndex = fullAttribute.indexOf('='); - attribute = fullAttribute.substring(0, equalsIndex); - attributeValue = fullAttribute.substring(equalsIndex); + attribute = fullAttribute.substring(1, equalsIndex); + attributeValue = fullAttribute.substring(equalsIndex + 2, fullAttribute.length() - 1); name = startTag.substring(0, separatorIndex); } else name = startTag; @@ -162,7 +191,7 @@ public class BBParser { } continue; } - if (isHtmlTagSupported(name, attribute, attributeValue)) + if (isHtmlTag(name)) tags.add(new HtmlTag(htmlMatcher.start(), name, attribute, attributeValue)); } // remove parsed tags with no end tag @@ -173,12 +202,20 @@ public class BBParser { } private static boolean isHtmlTagSupported(String name, String attribute, String attributeValue) { - return false; + return name.equals("b") || name.equals("i") || name.equals("span") || name.equals("del") || name.equals("a"); } - public static boolean isSupported(String tagName) { - for (String tag : SUPPORTED_TAGS) + public static boolean isBBTagSupported(String name) { + return name.equals("b") || name.equals("i") || name.equals("u") || name.equals("s"); + } + + public static boolean isHtmlTag(String tagName) { + for (String tag : ALL_HTML_TAGS) if (TextUtils.equals(tag, tagName)) return true; return false; } + + public static boolean containsHtml(String s) { + return getHtmlTags(s).length > 0; + } }