package eu.fiskur.markdownview; import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; import android.net.Uri; import android.os.Build; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.webkit.WebChromeClient; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import android.widget.RelativeLayout; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; public class MarkdownView extends RelativeLayout { private static final String TAG = MarkdownView.class.getSimpleName(); private WebView webView; private WebSettings webSettings; private MarkdownWebViewClient webViewClient; private OnProgressChangedListener onProgressChangedListener; public interface OnProgressChangedListener { void onChanged(int progress); } private static final String MARKDOWN_MARKUP_TEMPLATE = "<!doctype html>\n" + "<html>\n" + "<head>\n" + " <meta charset=\"utf-8\"/>\n" + " <title>Marked in the browser</title>\n" + " <link rel=\"stylesheet\" href=\"./githubmarkdown.css\">\n" + " <script src=\"./marked.js\"></script>\n" + " <script src=\"./markdown.js\"></script>\n" + "</head>\n" + "<body>\n" + " <div id=\"content\" class=\"markdown-body\"></div>\n" + " <div class=\"footer\">" + " <h4 class=\"visit\"><a href='%s'>페이지 방문하기</a></h4>" + " </div>\n" + " <script>\n" + " document.getElementById('content').innerHTML =\n" + " marked('%s');\n" + " </script>" + "</body>\n" + "</html>"; public MarkdownView(Context context) { super(context); setup(); } public MarkdownView(Context context, AttributeSet attrs) { super(context, attrs); setup(); readAttributes(context, attrs); } public MarkdownView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); setup(); readAttributes(context, attrs); } private void readAttributes(Context context, AttributeSet attrs){ TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MarkdownView, 0, 0); int rawFileId; int stringId; try { rawFileId = typedArray.getResourceId(R.styleable.MarkdownView_rawFile, -1); stringId = typedArray.getResourceId(R.styleable.MarkdownView_markdown, -1); }finally{ typedArray.recycle(); } if(rawFileId != -1 && stringId != -1){ Log.e(TAG, "Cannot set both raw file and string resource xml attributes"); return; } if(rawFileId != -1){ showMarkdown(rawFileId); } if(stringId != -1){ showMarkdown(getResources().getString(stringId)); } } private void setup(){ LayoutInflater.from(getContext()).inflate(R.layout.markdown_view, this); webView = (WebView) findViewById(R.id.markdown_web_view); webSettings = webView.getSettings(); webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE); webSettings.setJavaScriptEnabled(true); //To handle web links: webViewClient = new MarkdownWebViewClient(getContext()); webView.setWebViewClient(webViewClient); webView.setWebChromeClient(new WebChromeClient() { @Override public void onProgressChanged(WebView view, int newProgress) { if (onProgressChangedListener != null) { onProgressChangedListener.onChanged(newProgress); } } }); allowGestures(false); } public void setOnProgressChangedListener(OnProgressChangedListener onProgressChangedListener) { this.onProgressChangedListener = onProgressChangedListener; } public void setOnLoadingCompleteAction(Runnable completeAction) { webViewClient.setOnLoadingCompleteAction(completeAction); } public void setOnOverrideUrlAction(MarkdownWebViewClient.OnOverrideUrlListener onOverrideUrlListener, Runnable fallbackAction) { webViewClient.setOnOverrideUrlAction(onOverrideUrlListener, fallbackAction); } public void showMarkdown(String markdown){ showMarkdown("#", markdown); } public void showMarkdown(String link, String markdown){ if(markdown == null || markdown.isEmpty()){ return; } markdown = markdown.replace("\n", "\\n"); webView.loadDataWithBaseURL("file:///android_asset/", String.format(MARKDOWN_MARKUP_TEMPLATE, link, markdown), "text/html", "utf-8", null); } public void showMarkdown(int rawFileId){ StringBuffer sb = new StringBuffer(); BufferedReader reader = null; InputStreamReader isr = null; try { isr = new InputStreamReader(getContext().getResources().openRawResource(rawFileId)); reader = new BufferedReader(isr); String line; while ((line = reader.readLine()) != null) { sb.append(line + "\n"); } } catch (IOException e) { Log.e(TAG, e.toString()); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) {} } if(isr != null){ try { isr.close(); } catch (IOException e) {} } } showMarkdown(sb.toString()); } //Off by default public void allowGestures(boolean allowGestures){ if(allowGestures){ webSettings.setBuiltInZoomControls(true); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { webSettings.setDisplayZoomControls(false); } }else{ webSettings.setBuiltInZoomControls(false); } } private static class MarkdownWebViewClient extends WebViewClient { private final Context context; private Runnable completeAction; private OnOverrideUrlListener onOverrideUrlListener; private Runnable fallbackAction; public interface OnOverrideUrlListener { void onUrl(String url); } MarkdownWebViewClient(Context context) { this.context = context; } void setOnLoadingCompleteAction(Runnable completeAction) { this.completeAction = completeAction; } void setOnOverrideUrlAction(OnOverrideUrlListener onOverrideUrlListener, Runnable fallbackAction) { this.onOverrideUrlListener = onOverrideUrlListener; this.fallbackAction = fallbackAction; } @Override public void onPageFinished(WebView view, String url) { if (completeAction != null) { completeAction.run(); } } @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (onOverrideUrlListener == null) { Intent intent= new Intent(Intent.ACTION_VIEW, Uri.parse(url)); context.startActivity(intent); } else { try { onOverrideUrlListener.onUrl(url); } catch (ActivityNotFoundException e) { fallbackAction.run(); } } return true; } } }