210 lines
9.4 KiB
Java

package com.fastaccess.provider.timeline;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.v4.content.ContextCompat;
import android.view.HapticFeedbackConstants;
import android.view.WindowManager;
import android.widget.PopupMenu;
import android.widget.TextView;
import com.fastaccess.App;
import com.fastaccess.R;
import com.fastaccess.helper.PrefGetter;
import com.fastaccess.helper.ViewHelper;
import com.fastaccess.provider.scheme.SchemeParser;
import com.fastaccess.provider.timeline.handler.BetterLinkMovementExtended;
import com.fastaccess.provider.timeline.handler.DrawableHandler;
import com.fastaccess.provider.timeline.handler.EmojiHandler;
import com.fastaccess.provider.timeline.handler.ItalicHandler;
import com.fastaccess.provider.timeline.handler.LinkHandler;
import com.fastaccess.provider.timeline.handler.ListsHandler;
import com.fastaccess.provider.timeline.handler.MarginHandler;
import com.fastaccess.provider.timeline.handler.PreTagHandler;
import com.fastaccess.provider.timeline.handler.QouteHandler;
import com.fastaccess.provider.timeline.handler.StrikethroughHandler;
import com.fastaccess.provider.timeline.handler.SubScriptHandler;
import com.fastaccess.provider.timeline.handler.SuperScriptHandler;
import com.fastaccess.provider.timeline.handler.TableHandler;
import com.fastaccess.provider.timeline.handler.UnderlineHandler;
import net.nightwhistler.htmlspanner.HtmlSpanner;
import net.nightwhistler.htmlspanner.handlers.BoldHandler;
/**
* Created by Kosh on 21 Apr 2017, 11:24 PM
*/
public class HtmlHelper {
public static void htmlIntoTextView(@NonNull TextView textView, @NonNull String html) {
registerClickEvent(textView);
textView.setText(initHtml(textView).fromHtml(format(html).toString()));
}
private static void registerClickEvent(@NonNull TextView textView) {
BetterLinkMovementExtended betterLinkMovementMethod = BetterLinkMovementExtended.linkifyHtml(textView);
betterLinkMovementMethod.setOnLinkClickListener((view, url) -> {
SchemeParser.launchUri(view.getContext(), Uri.parse(url));
return true;
});
betterLinkMovementMethod.setOnLinkLongClickListener((view, url) -> {
view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
PopupMenu menu = new PopupMenu(view.getContext(), view);
menu.setOnMenuItemClickListener(menuItem -> {
switch(menuItem.getItemId()) {
case R.id.copy:
ClipboardManager clipboard = (ClipboardManager) view.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("URL", url);
clipboard.setPrimaryClip(clip);
return true;
case R.id.open:
SchemeParser.launchUri(view.getContext(), Uri.parse(url));
return true;
case R.id.open_new_window:
SchemeParser.launchUri(view.getContext(), Uri.parse(url), false, true);
return true;
default:
return false;
}
});
menu.inflate(R.menu.link_popup_menu);
menu.show();
return true;
});
}
private static HtmlSpanner initHtml(@NonNull TextView textView) {
@PrefGetter.ThemeType int theme = PrefGetter.getThemeType();
@ColorInt int windowBackground = getWindowBackground(theme);
Drawable checked = ContextCompat.getDrawable(textView.getContext(), R.drawable.ic_checkbox_small);
Drawable unchecked = ContextCompat.getDrawable(textView.getContext(), R.drawable.ic_checkbox_empty_small);
HtmlSpanner mySpanner = new HtmlSpanner();
mySpanner.setStripExtraWhiteSpace(true);
mySpanner.registerHandler("pre", new PreTagHandler(windowBackground, true, theme));
mySpanner.registerHandler("code", new PreTagHandler(windowBackground, false, theme));
mySpanner.registerHandler("img", new DrawableHandler(textView));
mySpanner.registerHandler("g-emoji", new EmojiHandler());
mySpanner.registerHandler("blockquote", new QouteHandler(windowBackground));
mySpanner.registerHandler("b", new BoldHandler());
mySpanner.registerHandler("strong", new BoldHandler());
mySpanner.registerHandler("i", new ItalicHandler());
mySpanner.registerHandler("em", new ItalicHandler());
mySpanner.registerHandler("ul", new MarginHandler());
mySpanner.registerHandler("ol", new MarginHandler());
mySpanner.registerHandler("li", new ListsHandler(checked, unchecked));
mySpanner.registerHandler("u", new UnderlineHandler());
mySpanner.registerHandler("strike", new StrikethroughHandler());
mySpanner.registerHandler("ins", new UnderlineHandler());
mySpanner.registerHandler("del", new StrikethroughHandler());
mySpanner.registerHandler("sub", new SubScriptHandler());
mySpanner.registerHandler("sup", new SuperScriptHandler());
mySpanner.registerHandler("a", new LinkHandler());
TableHandler tableHandler = new TableHandler();
tableHandler.setTextColor(ViewHelper.generateTextColor(windowBackground));
WindowManager windowManager = (WindowManager) App.getInstance().getSystemService(Context.WINDOW_SERVICE);
Point point = new Point();
windowManager.getDefaultDisplay().getRealSize(point);
tableHandler.setTableWidth((int) (point.x / 1.2));
tableHandler.setTextSize(18.0F);
mySpanner.registerHandler("table", tableHandler);
return mySpanner;
}
@ColorInt private static int getWindowBackground(@PrefGetter.ThemeType int theme) {
switch (theme) {
case PrefGetter.AMLOD:
return Color.parseColor("#0B162A");
case PrefGetter.BLUISH:
return Color.parseColor("#111C2C");
case PrefGetter.DARK:
return Color.parseColor("#22252A");
default:
return Color.parseColor("#EEEEEE");
}
}
private static final String TOGGLE_START = "<span class=\"email-hidden-toggle\">";
private static final String TOGGLE_END = "</span>";
private static final String REPLY_START = "<div class=\"email-quoted-reply\">";
private static final String REPLY_END = "</div>";
private static final String SIGNATURE_START = "<div class=\"email-signature-reply\">";
private static final String SIGNATURE_END = "</div>";
private static final String EMAIL_START = "<div class=\"email-fragment\">";
private static final String EMAIL_END = "</div>";
private static final String HIDDEN_REPLY_START = "<div class=\"email-hidden-reply\" style=\" display:none\">";
private static final String HIDDEN_REPLY_END = "</div>";
private static final String BREAK = "<br>";
private static final String PARAGRAPH_START = "<p>";
private static final String PARAGRAPH_END = "</p>";
//https://github.com/k0shk0sh/GitHubSdk/blob/master/library/src/main/java/com/meisolsson/githubsdk/core/HtmlUtils.java
@NonNull public static CharSequence format(final String html) {
if (html == null || html.length() == 0) return "";
StringBuilder formatted = new StringBuilder(html);
strip(formatted, TOGGLE_START, TOGGLE_END);
strip(formatted, SIGNATURE_START, SIGNATURE_END);
strip(formatted, REPLY_START, REPLY_END);
strip(formatted, HIDDEN_REPLY_START, HIDDEN_REPLY_END);
if (replace(formatted, PARAGRAPH_START, BREAK)) replace(formatted, PARAGRAPH_END, BREAK);
trim(formatted);
return formatted;
}
private static void strip(final StringBuilder input, final String prefix, final String suffix) {
int start = input.indexOf(prefix);
while (start != -1) {
int end = input.indexOf(suffix, start + prefix.length());
if (end == -1)
end = input.length();
input.delete(start, end + suffix.length());
start = input.indexOf(prefix, start);
}
}
private static boolean replace(final StringBuilder input, final String from, final String to) {
int start = input.indexOf(from);
if (start == -1) return false;
final int fromLength = from.length();
final int toLength = to.length();
while (start != -1) {
input.replace(start, start + fromLength, to);
start = input.indexOf(from, start + toLength);
}
return true;
}
private static void trim(final StringBuilder input) {
int length = input.length();
int breakLength = BREAK.length();
while (length > 0) {
if (input.indexOf(BREAK) == 0) input.delete(0, breakLength);
else if (length >= breakLength && input.lastIndexOf(BREAK) == length - breakLength) input.delete(length - breakLength, length);
else if (Character.isWhitespace(input.charAt(0))) input.deleteCharAt(0);
else if (Character.isWhitespace(input.charAt(length - 1))) input.deleteCharAt(length - 1);
else break;
length = input.length();
}
}
}