Skip to content
This repository has been archived by the owner on Feb 25, 2022. It is now read-only.

Commit

Permalink
Support h tag
Browse files Browse the repository at this point in the history
  • Loading branch information
seven332 committed Feb 23, 2020
1 parent 6ee9b79 commit a099830
Show file tree
Hide file tree
Showing 7 changed files with 188 additions and 34 deletions.
174 changes: 166 additions & 8 deletions app/src/main/java/com/hippo/nimingban/client/ac/data/ACItemUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,39 @@

package com.hippo.nimingban.client.ac.data;

import android.graphics.Color;
import android.support.annotation.Nullable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.BackgroundColorSpan;
import android.text.style.ForegroundColorSpan;
import android.text.style.URLSpan;

import android.widget.TextView;
import com.hippo.nimingban.client.ReferenceSpan;
import com.hippo.nimingban.client.ac.ACUrl;
import com.hippo.nimingban.client.data.ACSite;
import com.hippo.nimingban.util.Settings;
import com.hippo.text.Html;
import com.hippo.yorozuya.StringUtils;

import org.xml.sax.Attributes;
import org.xml.sax.XMLReader;

import java.security.MessageDigest;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.xml.sax.Attributes;
import org.xml.sax.XMLReader;

public final class ACItemUtils {
private ACItemUtils() {}

private static final Pattern REFERENCE_PATTERN = Pattern.compile(">>?(?:No.)?(\\d+)");
private static final Pattern URL_PATTERN = Pattern.compile("(http|https)://[a-z0-9A-Z%-]+(\\.[a-z0-9A-Z%-]+)+(:\\d{1,5})?(/[a-zA-Z0-9-_~:#@!&',;=%/\\*\\.\\?\\+\\$\\[\\]\\(\\)]+)?/?");
private static final Pattern AC_PATTERN = Pattern.compile("ac\\d+");
private static final Pattern HIDE_PATTERN = Pattern.compile("\\[h](.+?)\\[/h]");

private static final String NO_TITLE = "无标题";
private static final String NO_NAME = "无名氏";
Expand All @@ -59,8 +60,35 @@ private ACItemUtils() {}

private static final byte[] IV = new byte[] {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF};

private static final String NMB_HIDE_TAG = "nmb-hide";
private static final String NMB_HIDE_TAG_LEFT = "<" + NMB_HIDE_TAG + ">";
private static final String NMB_HIDE_TAG_RIGHT = "</" + NMB_HIDE_TAG + ">";

private static final ACHtmlTagHandler AC_HTML_TAG_HANDLER = new ACHtmlTagHandler();

private static String replaceBracketsH(String content) {
Matcher m = HIDE_PATTERN.matcher(content);

int lastEnd = 0;
StringBuilder sb = null;

while (m.find()) {
if (sb == null) sb = new StringBuilder(content.length());
sb.append(content, lastEnd, m.start());
sb.append(NMB_HIDE_TAG_LEFT);
sb.append(m.group(1));
sb.append(NMB_HIDE_TAG_RIGHT);
lastEnd = m.end();
}

if (sb != null) {
sb.append(content.substring(lastEnd));
return sb.toString();
} else {
return content;
}
}

public static CharSequence handleReference(CharSequence content) {
Matcher m = REFERENCE_PATTERN.matcher(content);

Expand Down Expand Up @@ -146,6 +174,7 @@ public static CharSequence handleAcUrl(CharSequence content) {
}

public static CharSequence generateContent(String content) {
content = replaceBracketsH(content);
CharSequence charSequence;
charSequence = Html.fromHtml(content, null, AC_HTML_TAG_HANDLER);
charSequence = handleReference(charSequence);
Expand Down Expand Up @@ -260,7 +289,7 @@ public boolean handleTag(boolean opening, String tag,
// Add ac nmb host
String href = attributes.getValue("", "href");
if (!href.startsWith("http")) {
if (href.startsWith("/")){
if (href.startsWith("/")) {
href = ACUrl.getHost() + href;
} else {
href = ACUrl.getHost() + '/' + href;
Expand All @@ -277,11 +306,27 @@ public boolean handleTag(boolean opening, String tag,
Href h = (Href) obj;
if (h.mHref != null) {
output.setSpan(new URLSpan(h.mHref), where, len,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
}
return true;
} else if (tag.equalsIgnoreCase(NMB_HIDE_TAG)) {
if (opening) {
int len = output.length();
output.setSpan(new Hide(), len, len, Spannable.SPAN_MARK_MARK);
} else {
int len = output.length();
Object obj = getLast(output, Hide.class);
int where = output.getSpanStart(obj);

output.removeSpan(obj);

if (where != len) {
output.setSpan(new HideSpan(where, len), where, len, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
return true;
} else {
return false;
}
Expand Down Expand Up @@ -309,4 +354,117 @@ public Href(String href) {
mHref = href;
}
}

public static void setContentText(TextView tv, CharSequence text) {
tv.setText(updateContentText(text, tv.getTextColors().getDefaultColor()));
}

public static CharSequence updateContentText(CharSequence text, int hideColor) {
if (text instanceof Spanned) {
Spanned spanned = (Spanned) text;
ACItemUtils.HideSpan[] hideSpans = spanned.getSpans(0, spanned.length(), ACItemUtils.HideSpan.class);
for (ACItemUtils.HideSpan hideSpan : hideSpans) {
spanned = hideSpan.update(spanned, hideColor);
}
text = spanned;
}
return text;
}


private static class Hide {
public Hide() { }
}

public static class HideSpan {

public final int start;
public final int end;
public boolean hidden;
public BackgroundColorSpan hideSpan1;
public final ForegroundColorSpan hideSpan2;

public HideSpan(int start, int end) {
this.start = start;
this.end = end;
this.hidden = true;
this.hideSpan2 = new ForegroundColorSpan(Color.TRANSPARENT);
}

private BackgroundColorSpan updateHideSpan1(int hideColor) {
if (hideSpan1 != null && hideSpan1.getBackgroundColor() == hideColor) return null;
BackgroundColorSpan oldHideSpan = hideSpan1;
hideSpan1 = new BackgroundColorSpan(hideColor);
return oldHideSpan;
}

private Spanned checkTextView(TextView tv) {
CharSequence text = tv.getText();
if (!(text instanceof Spanned)) return null;
return (Spanned) text;
}

public Spanned update(Spanned spanned, int hideColor) {
if (spanned.getSpanStart(this) == -1) return spanned;

ACItemUtils.Text text = new ACItemUtils.Text(spanned);

BackgroundColorSpan oldHideSpan = updateHideSpan1(hideColor);
if (oldHideSpan != null) text.removeSpan(oldHideSpan);

if (hidden) {
text.setSpan(hideSpan1, start, end);
text.setSpan(hideSpan2, start, end);
} else {
text.removeSpan(hideSpan1);
text.removeSpan(hideSpan2);
}

return text.getText();
}

public void update(TextView tv) {
Spanned spanned = checkTextView(tv);
if (spanned == null) return;

CharSequence text = update(spanned, tv.getTextColors().getDefaultColor());

if (text != spanned) tv.setText(text);
}

public void toggle(TextView tv) {
Spanned spanned = checkTextView(tv);
if (spanned == null) return;

hidden = !hidden;

update(tv);
}
}

private static class Text {
private final Spanned spanned;
private Spannable spannable;

Text(Spanned spanned) {
this.spanned = spanned;
if (spanned instanceof Spannable) spannable = (Spannable) spanned;
}

void removeSpan(Object what) {
if (spannable == null && spanned.getSpanStart(what) != -1)
spannable = new SpannableString(spanned);
if (spannable != null) spannable.removeSpan(what);
}

void setSpan(Object what, int start, int end) {
if (spannable == null && (spanned.getSpanStart(what) != start || spanned.getSpanEnd(what) != end))
spannable = new SpannableString(spanned);
if (spannable != null) spannable.setSpan(what, start, end, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}

Spanned getText() {
return spannable != null ? spannable : spanned;
}
}
}
6 changes: 2 additions & 4 deletions app/src/main/java/com/hippo/nimingban/ui/FeedActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator;
import com.h6ah4i.android.widget.advrecyclerview.animator.SwipeDismissItemAnimator;
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager;
Expand All @@ -47,6 +46,7 @@
import com.hippo.nimingban.R;
import com.hippo.nimingban.client.NMBClient;
import com.hippo.nimingban.client.NMBRequest;
import com.hippo.nimingban.client.ac.data.ACItemUtils;
import com.hippo.nimingban.client.data.ACSite;
import com.hippo.nimingban.client.data.Post;
import com.hippo.nimingban.client.data.Site;
Expand All @@ -63,12 +63,10 @@
import com.hippo.yorozuya.NumberUtils;
import com.hippo.yorozuya.ObjectUtils;
import com.hippo.yorozuya.ResourcesUtils;

import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import jp.wasabeef.recyclerview.animators.SlideInUpAnimator;

public final class FeedActivity extends TranslucentActivity implements EasyRecyclerView.OnItemClickListener {
Expand Down Expand Up @@ -371,7 +369,7 @@ public void onBindViewHolder(FeedHolder holder, int i) {
holder.leftText.setText(post.getNMBDisplayUsername());
holder.centerText.setText("No." + post.getNMBId());
holder.rightText.setText(ReadableTime.getDisplayTime(post.getNMBTime()));
holder.content.setText(post.getNMBDisplayContent());
ACItemUtils.setContentText(holder.content, post.getNMBDisplayContent());

String thumbKey = post.getNMBThumbKey();
String thumbUrl = post.getNMBThumbUrl();
Expand Down
6 changes: 2 additions & 4 deletions app/src/main/java/com/hippo/nimingban/ui/ListActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.hippo.app.CheckBoxDialogBuilder;
import com.hippo.drawerlayout.DrawerLayout;
import com.hippo.easyrecyclerview.EasyRecyclerView;
Expand All @@ -70,6 +69,7 @@
import com.hippo.nimingban.client.Notice;
import com.hippo.nimingban.client.UpdateHelper;
import com.hippo.nimingban.client.ac.ACUrl;
import com.hippo.nimingban.client.ac.data.ACItemUtils;
import com.hippo.nimingban.client.data.ACSite;
import com.hippo.nimingban.client.data.CommonPost;
import com.hippo.nimingban.client.data.DisplayForum;
Expand Down Expand Up @@ -108,7 +108,6 @@
import com.hippo.yorozuya.Messenger;
import com.hippo.yorozuya.ObjectUtils;
import com.hippo.yorozuya.ResourcesUtils;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.MalformedURLException;
Expand All @@ -118,7 +117,6 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import jp.wasabeef.recyclerview.animators.SlideInUpAnimator;

public final class ListActivity extends AbsActivity
Expand Down Expand Up @@ -1159,7 +1157,7 @@ public void onBindViewHolder(ListHolder holder, int position) {
holder.centerText.setText("No." + post.getNMBId());
}
holder.rightText.setText(ReadableTime.getDisplayTime(post.getNMBTime()));
holder.content.setText(post.getNMBDisplayContent());
ACItemUtils.setContentText(holder.content, post.getNMBDisplayContent());
holder.bottomText.setText(post.getNMBReplyDisplayCount());

View bottom = holder.bottom;
Expand Down
6 changes: 2 additions & 4 deletions app/src/main/java/com/hippo/nimingban/ui/SearchActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.hippo.easyrecyclerview.EasyRecyclerView;
import com.hippo.easyrecyclerview.MarginItemDecoration;
import com.hippo.easyrecyclerview.RawMarginItemDecoration;
Expand All @@ -36,6 +35,7 @@
import com.hippo.nimingban.R;
import com.hippo.nimingban.client.NMBClient;
import com.hippo.nimingban.client.NMBRequest;
import com.hippo.nimingban.client.ac.data.ACItemUtils;
import com.hippo.nimingban.client.ac.data.ACSearchItem;
import com.hippo.nimingban.client.data.ACSite;
import com.hippo.nimingban.util.PostIgnoreUtils;
Expand All @@ -49,12 +49,10 @@
import com.hippo.yorozuya.LayoutUtils;
import com.hippo.yorozuya.Messenger;
import com.hippo.yorozuya.ResourcesUtils;

import java.lang.ref.WeakReference;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import jp.wasabeef.recyclerview.animators.SlideInUpAnimator;

public class SearchActivity extends TranslucentActivity implements EasyRecyclerView.OnItemClickListener {
Expand Down Expand Up @@ -325,7 +323,7 @@ public void onBindViewHolder(SearchHolder holder, int position) {
holder.leftText.setText(item.getNMBDisplayUsername());
holder.centerText.setText("No." + item.getNMBId());
holder.rightText.setText(ReadableTime.getDisplayTime(item.getNMBTime()));
holder.content.setText(item.getNMBDisplayContent());
ACItemUtils.setContentText(holder.content, item.getNMBDisplayContent());

String thumbKey = item.getNMBThumbKey();
String thumbUrl = item.getNMBThumbUrl();
Expand Down
Loading

0 comments on commit a099830

Please sign in to comment.