Browse Source

support not supporting html tags in polls

pull/61/merge
oogee 6 years ago
parent
commit
9b22f1da6a
  1. 5
      app/src/main/java/gr/thmmy/mthmmy/activities/TestActivity.java
  2. 38
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicAdapter.java
  3. 19
      app/src/main/java/gr/thmmy/mthmmy/utils/HTMLUtils.java
  4. 65
      app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyParser.java

5
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 androidx.appcompat.app.AppCompatActivity;
import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.utils.parsing.BBParser; import gr.thmmy.mthmmy.utils.parsing.ThmmyParser;
import timber.log.Timber;
import android.os.Bundle; import android.os.Bundle;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
@ -17,7 +16,7 @@ public class TestActivity extends AppCompatActivity {
setContentView(R.layout.activity_test); setContentView(R.layout.activity_test);
String bb = "[b]An [i]elep[u]hant[/i][/b] swi[/u]ms in [s]the[/s] tree"; 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 bbRaw = findViewById(R.id.bb_raw);
TextView bb2Text = findViewById(R.id.bb2text); TextView bb2Text = findViewById(R.id.bb2text);

38
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.ThmmyPage;
import gr.thmmy.mthmmy.model.TopicItem; import gr.thmmy.mthmmy.model.TopicItem;
import gr.thmmy.mthmmy.utils.CircleTransform; import gr.thmmy.mthmmy.utils.CircleTransform;
import gr.thmmy.mthmmy.utils.parsing.ThmmyParser;
import gr.thmmy.mthmmy.utils.parsing.ParseHelpers; import gr.thmmy.mthmmy.utils.parsing.ParseHelpers;
import gr.thmmy.mthmmy.viewmodel.TopicViewModel; import gr.thmmy.mthmmy.viewmodel.TopicViewModel;
import timber.log.Timber; import timber.log.Timber;
@ -166,9 +167,34 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
Poll poll = (Poll) topicItems.get(position); Poll poll = (Poll) topicItems.get(position);
Poll.Entry[] entries = poll.getEntries(); Poll.Entry[] entries = poll.getEntries();
PollViewHolder holder = (PollViewHolder) currentHolder; 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.question.setText(poll.getQuestion());
holder.optionsLayout.removeAllViews(); holder.optionsLayout.removeAllViews();
holder.errorTooManySelected.setVisibility(View.GONE); holder.errorTextview.setVisibility(View.GONE);
if (poll.getAvailableVoteCount() > 1) { if (poll.getAvailableVoteCount() > 1) {
for (Poll.Entry entry : entries) { for (Poll.Entry entry : entries) {
LinearLayout container = new LinearLayout(context); LinearLayout container = new LinearLayout(context);
@ -183,6 +209,7 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
//noinspection deprecation //noinspection deprecation
label.setText(Html.fromHtml(entry.getEntryName())); label.setText(Html.fromHtml(entry.getEntryName()));
} }
label.setText(ThmmyParser.html2span(context, entry.getEntryName()));
checkBox.setTextColor(context.getResources().getColor(R.color.primary_text)); checkBox.setTextColor(context.getResources().getColor(R.color.primary_text));
container.addView(checkBox); container.addView(checkBox);
container.addView(label); container.addView(label);
@ -202,6 +229,7 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
//noinspection deprecation //noinspection deprecation
radioButton.setText(Html.fromHtml(entries[i].getEntryName())); radioButton.setText(Html.fromHtml(entries[i].getEntryName()));
} }
radioButton.setText(ThmmyParser.html2span(context, entries[i].getEntryName()));
radioButton.setTextColor(context.getResources().getColor(R.color.primary_text)); radioButton.setTextColor(context.getResources().getColor(R.color.primary_text));
radioGroup.addView(radioButton); radioGroup.addView(radioButton);
} }
@ -261,10 +289,10 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
if (poll.getPollFormUrl() != null) { if (poll.getPollFormUrl() != null) {
holder.submitButton.setOnClickListener(v -> { holder.submitButton.setOnClickListener(v -> {
if (!viewModel.submitVote(holder.optionsLayout)) { if (!viewModel.submitVote(holder.optionsLayout)) {
holder.errorTooManySelected.setText(context.getResources() holder.errorTextview.setText(context.getResources()
.getQuantityString(R.plurals.error_too_many_checked, poll.getAvailableVoteCount(), .getQuantityString(R.plurals.error_too_many_checked, poll.getAvailableVoteCount(),
poll.getAvailableVoteCount())); poll.getAvailableVoteCount()));
holder.errorTooManySelected.setVisibility(View.VISIBLE); holder.errorTextview.setVisibility(View.VISIBLE);
} }
}); });
holder.submitButton.setVisibility(View.VISIBLE); holder.submitButton.setVisibility(View.VISIBLE);
@ -754,7 +782,7 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
} }
static class PollViewHolder extends RecyclerView.ViewHolder { static class PollViewHolder extends RecyclerView.ViewHolder {
final TextView question, errorTooManySelected; final TextView question, errorTextview;
final LinearLayout optionsLayout; final LinearLayout optionsLayout;
final AppCompatButton submitButton; final AppCompatButton submitButton;
final AppCompatButton removeVotesButton, showPollResultsButton, hidePollResultsButton; final AppCompatButton removeVotesButton, showPollResultsButton, hidePollResultsButton;
@ -769,7 +797,7 @@ class TopicAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
removeVotesButton = itemView.findViewById(R.id.remove_vote_button); removeVotesButton = itemView.findViewById(R.id.remove_vote_button);
showPollResultsButton = itemView.findViewById(R.id.show_poll_results_button); showPollResultsButton = itemView.findViewById(R.id.show_poll_results_button);
hidePollResultsButton = itemView.findViewById(R.id.show_poll_options_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); voteChart = itemView.findViewById(R.id.vote_chart);
} }
} }

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

@ -1,6 +1,7 @@
package gr.thmmy.mthmmy.utils; package gr.thmmy.mthmmy.utils;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Build; import android.os.Build;
@ -12,6 +13,7 @@ import android.text.style.URLSpan;
import android.view.View; import android.view.View;
import gr.thmmy.mthmmy.activities.board.BoardActivity; 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.activities.profile.ProfileActivity;
import gr.thmmy.mthmmy.model.ThmmyPage; import gr.thmmy.mthmmy.model.ThmmyPage;
@ -41,7 +43,7 @@ public class HTMLUtils {
return strBuilder; 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 start = strBuilder.getSpanStart(span);
int end = strBuilder.getSpanEnd(span); int end = strBuilder.getSpanEnd(span);
int flags = strBuilder.getSpanFlags(span); int flags = strBuilder.getSpanFlags(span);
@ -50,24 +52,27 @@ public class HTMLUtils {
public void onClick(View view) { public void onClick(View view) {
ThmmyPage.PageCategory target = ThmmyPage.resolvePageCategory(Uri.parse(span.getURL())); ThmmyPage.PageCategory target = ThmmyPage.resolvePageCategory(Uri.parse(span.getURL()));
if (target.is(ThmmyPage.PageCategory.BOARD)) { 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(); Bundle extras = new Bundle();
extras.putString(BUNDLE_BOARD_URL, span.getURL()); extras.putString(BUNDLE_BOARD_URL, span.getURL());
extras.putString(BUNDLE_BOARD_TITLE, ""); extras.putString(BUNDLE_BOARD_TITLE, "");
intent.putExtras(extras); intent.putExtras(extras);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
activity.getApplicationContext().startActivity(intent); context.startActivity(intent);
} else if (target.is(ThmmyPage.PageCategory.PROFILE)) { } 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(); Bundle extras = new Bundle();
extras.putString(BUNDLE_PROFILE_URL, span.getURL()); extras.putString(BUNDLE_PROFILE_URL, span.getURL());
extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, ""); extras.putString(BUNDLE_PROFILE_THUMBNAIL_URL, "");
extras.putString(BUNDLE_PROFILE_USERNAME, ""); extras.putString(BUNDLE_PROFILE_USERNAME, "");
intent.putExtras(extras); intent.putExtras(extras);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK); intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
activity.getApplicationContext().startActivity(intent); context.startActivity(intent);
} else if (target.is(ThmmyPage.PageCategory.INDEX)) } else if (target.is(ThmmyPage.PageCategory.INDEX)) {
activity.finish(); Intent intent = new Intent(context, MainActivity.class);
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
} }
}; };
strBuilder.setSpan(clickable, start, end, flags); strBuilder.setSpan(clickable, start, end, flags);

65
app/src/main/java/gr/thmmy/mthmmy/utils/parsing/BBParser.java → app/src/main/java/gr/thmmy/mthmmy/utils/parsing/ThmmyParser.java

@ -1,11 +1,13 @@
package gr.thmmy.mthmmy.utils.parsing; package gr.thmmy.mthmmy.utils.parsing;
import android.content.Context;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.text.Spannable; import android.text.Spannable;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.style.StrikethroughSpan; import android.text.style.StrikethroughSpan;
import android.text.style.StyleSpan; import android.text.style.StyleSpan;
import android.text.style.URLSpan;
import android.text.style.UnderlineSpan; import android.text.style.UnderlineSpan;
import java.nio.charset.UnsupportedCharsetException; 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.BBTag;
import gr.thmmy.mthmmy.model.HtmlTag; import gr.thmmy.mthmmy.model.HtmlTag;
import gr.thmmy.mthmmy.utils.HTMLUtils;
public class BBParser { public class ThmmyParser {
private static final String[] ALL_TAGS = {"b", "i", "u", "s", "glow", "shadow", "move", "pre", "lefter", 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" "center", "right", "hr", "size", "font", "color", "youtube", "flash", "img", "url"
, "email", "ftp", "table", "tr", "td", "sup", "sub", "tt", "code", "quote", "tex", "list", "li"}; , "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) { public static SpannableStringBuilder bb2span(String bb) {
SpannableStringBuilder builder = new SpannableStringBuilder(bb); SpannableStringBuilder builder = new SpannableStringBuilder(bb);
@ -30,7 +34,7 @@ public class BBParser {
stringIndices.add(i); stringIndices.add(i);
} }
BBTag[] tags = getTags(bb); BBTag[] tags = getBBTags(bb);
for (BBTag tag : tags) { for (BBTag tag : tags) {
int start = stringIndices.indexOf(tag.getStart()); int start = stringIndices.indexOf(tag.getStart());
int end = stringIndices.indexOf(tag.getEnd()); int end = stringIndices.indexOf(tag.getEnd());
@ -65,7 +69,7 @@ public class BBParser {
return builder; return builder;
} }
public static SpannableStringBuilder html2span(String html) { public static SpannableStringBuilder html2span(Context context, String html) {
SpannableStringBuilder builder = new SpannableStringBuilder(html); SpannableStringBuilder builder = new SpannableStringBuilder(html);
// store the original indices of the string // store the original indices of the string
LinkedList<Integer> stringIndices = new LinkedList<>(); LinkedList<Integer> stringIndices = new LinkedList<>();
@ -78,10 +82,35 @@ public class BBParser {
int start = stringIndices.indexOf(tag.getStart()); int start = stringIndices.indexOf(tag.getStart());
int end = stringIndices.indexOf(tag.getEnd()); int end = stringIndices.indexOf(tag.getEnd());
int startTagLength = tag.getName().length() + 2; int startTagLength = tag.getName().length() + 2;
if (tag.getAttributeKey() != null) {
startTagLength += tag.getAttributeKey().length() + tag.getAttributeValue().length() + 4;
}
int endTagLength = tag.getName().length() + 3; int endTagLength = tag.getName().length() + 3;
if (isHtmlTagSupported(tag.getName(), tag.getAttributeKey(), tag.getAttributeValue())) {
switch (tag.getName()) { 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 //remove starting and ending tag and and do the same changes in the list
@ -97,7 +126,7 @@ public class BBParser {
return builder; return builder;
} }
public static BBTag[] getTags(String bb) { public static BBTag[] getBBTags(String bb) {
Pattern bbtagPattern = Pattern.compile("\\[(.+?)\\]"); Pattern bbtagPattern = Pattern.compile("\\[(.+?)\\]");
LinkedList<BBTag> tags = new LinkedList<>(); LinkedList<BBTag> tags = new LinkedList<>();
@ -123,7 +152,7 @@ public class BBParser {
} }
continue; continue;
} }
if (isSupported(name)) if (isBBTagSupported(name))
tags.add(new BBTag(bbMatcher.start(), name, attribute)); tags.add(new BBTag(bbMatcher.start(), name, attribute));
} }
// remove parsed tags with no end tag // remove parsed tags with no end tag
@ -145,8 +174,8 @@ public class BBParser {
if (separatorIndex > 0) { if (separatorIndex > 0) {
String fullAttribute = startTag.substring(separatorIndex); String fullAttribute = startTag.substring(separatorIndex);
int equalsIndex = fullAttribute.indexOf('='); int equalsIndex = fullAttribute.indexOf('=');
attribute = fullAttribute.substring(0, equalsIndex); attribute = fullAttribute.substring(1, equalsIndex);
attributeValue = fullAttribute.substring(equalsIndex); attributeValue = fullAttribute.substring(equalsIndex + 2, fullAttribute.length() - 1);
name = startTag.substring(0, separatorIndex); name = startTag.substring(0, separatorIndex);
} else } else
name = startTag; name = startTag;
@ -162,7 +191,7 @@ public class BBParser {
} }
continue; continue;
} }
if (isHtmlTagSupported(name, attribute, attributeValue)) if (isHtmlTag(name))
tags.add(new HtmlTag(htmlMatcher.start(), name, attribute, attributeValue)); tags.add(new HtmlTag(htmlMatcher.start(), name, attribute, attributeValue));
} }
// remove parsed tags with no end tag // remove parsed tags with no end tag
@ -173,12 +202,20 @@ public class BBParser {
} }
private static boolean isHtmlTagSupported(String name, String attribute, String attributeValue) { 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 isBBTagSupported(String name) {
return name.equals("b") || name.equals("i") || name.equals("u") || name.equals("s");
} }
public static boolean isSupported(String tagName) { public static boolean isHtmlTag(String tagName) {
for (String tag : SUPPORTED_TAGS) for (String tag : ALL_HTML_TAGS)
if (TextUtils.equals(tag, tagName)) return true; if (TextUtils.equals(tag, tagName)) return true;
return false; return false;
} }
public static boolean containsHtml(String s) {
return getHtmlTags(s).length > 0;
}
} }
Loading…
Cancel
Save