package com.troy.xifan.util;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.URLSpan;
import android.text.util.Linkify;
import android.widget.TextView;
import com.troy.xifan.App;
import com.troy.xifan.R;
import com.troy.xifan.config.Constants;
import com.troy.xifan.view.ClickLinkMovementMethod;
import com.troy.xifan.view.VerticalImageSpan;
import com.troy.xifan.view.XiFanClickableSpan;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.util.regex.Pattern.compile;
/**
* Created by chenlongfei on 2016/11/25.
*/
public final class PatternUtils {
// #话题#
public static final String REGEX_TOPIC = "#[\\p{Print}\\p{InCJKUnifiedIdeographs}&&[^#]]+#";
// [表情]
public static final String REGEX_EMOTION = "\\[(\\S+?)\\]";
// url
public static final String REGEX_URL =
"http[s]?://[a-zA-Z0-9+&@#/%?=~_\\\\-|!:,\\\\.;]*[a-zA-Z0-9+&@#/%=~_|]";
// @人
public static final String REGEX_AT = "@[\\w\\p{InCJKUnifiedIdeographs}-]{1,26}";
//user link
public static final String REGEX_USER_LINK =
"@<a href=\"http://fanfou.com/(.*?)\" class=\"former\">(.*?)</a>";
public static final Pattern PATTERN_TOPIC = compile(REGEX_TOPIC);
public static final Pattern PATTERN_URL = compile(REGEX_URL);
public static final Pattern PATTERN_AT = compile(REGEX_AT);
public static final String SCHEME_TOPIC =
Constants.Router.SCHEME + Constants.Router.TREND_STATUSES + "?keyword=";
public static final String SCHEME_URL =
Constants.Router.SCHEME + Constants.Router.BROWSER + "?url=";
public static final String SCHEME_AT =
Constants.Router.SCHEME + Constants.Router.PROFILE + "?userid=";
private PatternUtils() {
}
public static String extractToken(String regex, String responseData) {
Pattern pattern = compile(regex);
Matcher matcher = pattern.matcher(responseData);
if (matcher.find() && matcher.groupCount() >= 1) {
return matcher.group(1);
} else {
throw new RuntimeException("Can't extract token,responseData is" + responseData);
}
}
//将@用户提取出来
private static Map<String, String> findAtUser(String sourceText) {
Map<String, String> userMap = new HashMap<>();
Pattern pattern = Pattern.compile(REGEX_USER_LINK);
Matcher matcher = pattern.matcher(sourceText);
while (matcher.find()) {
String userId = matcher.group(1);
String userName = matcher.group(2);
userMap.put(userName, userId);
}
return userMap;
}
private static void linkifyUsers(Spannable spannable, final Map<String, String> userMap) {
Linkify.MatchFilter filter = new Linkify.MatchFilter() {
@Override
public final boolean acceptMatch(final CharSequence s, final int start, final int end) {
String name = s.subSequence(start + 1, end).toString().trim();
return userMap.containsKey(name);
}
};
Linkify.TransformFilter transformFilter = new Linkify.TransformFilter() {
@Override
public String transformUrl(Matcher matcher, String value) {
String userName = value.subSequence(1, value.length()).toString().trim();
String userId = userMap.get(userName);
return userId;
}
};
Linkify.addLinks(spannable, PATTERN_AT, SCHEME_AT, filter, transformFilter);
}
private static void linkifyTopic(Spannable spannable) {
Linkify.TransformFilter transformFilter = new Linkify.TransformFilter() {
@Override
public String transformUrl(Matcher matcher, String value) {
return value.replace("#", "");
}
};
Linkify.addLinks(spannable, PATTERN_TOPIC, SCHEME_TOPIC, null, transformFilter);
}
private static void linkifyUrl(Spannable spannable) {
Linkify.TransformFilter transformFilter = new Linkify.TransformFilter() {
@Override
public String transformUrl(Matcher matcher, String value) {
return value;
}
};
Linkify.addLinks(spannable, PATTERN_URL, SCHEME_URL, null, transformFilter);
}
/**
* 格式化微博文本
* 感谢 http://melodyxxx.com/2016/12/04/use_spannablestring_format_weibo/
*
* @param context 上下文
* @param source 源文本
* @param textView 目标 TextView
* @return SpannableStringBuilder
*/
public static SpannableStringBuilder formatWeiBoContent(Context context, String source,
TextView textView) {
// 获取到 TextView 的文字大小,后面的 ImageSpan 需要用到该值
int textSize = (int) textView.getTextSize();
// 若要部分 SpannableString 可点击,需要如下设置
textView.setMovementMethod(ClickLinkMovementMethod.getInstance());
textView.setFocusable(false);
textView.setClickable(false);
textView.setLongClickable(false);
String content = Html.fromHtml(source).toString();
// 将要格式化的 String 构建成一个 SpannableStringBuilder
final SpannableStringBuilder value = new SpannableStringBuilder(content);
Map<String, String> userMap = findAtUser(source);
// 使用正则匹配@用户
linkifyUsers(value, userMap);
// 使用正则匹配话题
linkifyTopic(value);
// 使用正则匹配链接
linkifyUrl(value);
// 获取上面到所有 addLinks 后的匹配部分(这里一个匹配项被封装成了一个 URLSpan 对象)
URLSpan[] urlSpans = value.getSpans(0, value.length(), URLSpan.class);
// 遍历所有的 URLSpan
for (final URLSpan urlSpan : urlSpans) {
// 自定义的匹配部分的点击效果
XiFanClickableSpan clickSpan = new XiFanClickableSpan(urlSpan);
// 话题
if (urlSpan.getURL().startsWith(SCHEME_TOPIC)) {
int start = value.getSpanStart(urlSpan);
int end = value.getSpanEnd(urlSpan);
value.removeSpan(urlSpan);
// 格式化话题部分文本
value.setSpan(clickSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
// @用户
if (urlSpan.getURL().startsWith(SCHEME_AT)) {
int start = value.getSpanStart(urlSpan);
int end = value.getSpanEnd(urlSpan);
value.removeSpan(urlSpan);
// 格式化@用户部分文本
value.setSpan(clickSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
// 链接
if (urlSpan.getURL().startsWith(SCHEME_URL)) {
int start = value.getSpanStart(urlSpan);
int end = value.getSpanEnd(urlSpan);
value.removeSpan(urlSpan);
SpannableStringBuilder urlSpannableString =
getUrlTextSpannableString(context, urlSpan.getURL(), textSize);
value.replace(start, end, urlSpannableString);
// 格式化链接部分文本
value.setSpan(clickSpan, start, start + urlSpannableString.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
return value;
}
private static SpannableStringBuilder getUrlTextSpannableString(Context context, String source,
int size) {
SpannableStringBuilder builder = new SpannableStringBuilder(source);
String prefix = " ";
builder.replace(0, prefix.length(), prefix);
Drawable drawable = context.getResources().getDrawable(R.mipmap.ic_status_link);
drawable.setBounds(0, 0, size, size);
builder.setSpan(new VerticalImageSpan(drawable), prefix.length(), source.length(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
builder.append(App.getInstance().getString(R.string.text_url_link));
return builder;
}
}