package com.loopeer.codereader.ui.fragment;
import android.annotation.TargetApi;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.AppBarLayout;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.loopeer.codereader.Navigator;
import com.loopeer.codereader.R;
import com.loopeer.codereader.model.DirectoryNode;
import com.loopeer.codereader.ui.loader.CodeFragmentContentLoader;
import com.loopeer.codereader.ui.loader.ILoadHelper;
import com.loopeer.codereader.ui.view.NestedScrollWebView;
import com.loopeer.codereader.utils.BrushMap;
import com.loopeer.codereader.utils.ColorUtils;
import com.loopeer.codereader.utils.DeviceUtils;
import com.loopeer.codereader.utils.FileTypeUtils;
import com.loopeer.codereader.utils.HtmlParser;
import com.todou.markdownj.MarkdownProcessor;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;
import butterknife.BindView;
import rx.Observable;
import rx.Subscriber;
import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
public class CodeReadFragment extends BaseFullscreenFragment implements NestedScrollWebView.ScrollChangeListener {
private static final String TAG = "CodeReadFragment";
@BindView(R.id.web_code_read)
NestedScrollWebView mWebCodeRead;
@BindView(R.id.toolbar)
Toolbar mToolbar;
private DirectoryNode mNode;
private DirectoryNode mRootNode;
private Subscription scrollFinishDelaySubscription;
private boolean mScrollDown = false;
private boolean mOpenFileAfterLoadFinish = false;
private ILoadHelper mCodeContentLoader;
private boolean mOrientationChange;
public static CodeReadFragment newInstance(DirectoryNode node, DirectoryNode root) {
CodeReadFragment codeReadFragment = new CodeReadFragment();
codeReadFragment.mNode = node;
codeReadFragment.mRootNode = root;
return codeReadFragment;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container
, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_code_read, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mCodeContentLoader = new CodeFragmentContentLoader(view);
setupToolbar();
AppCompatActivity activity = (AppCompatActivity) getActivity();
activity.setSupportActionBar(mToolbar);
activity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
activity.getSupportActionBar().setHomeAsUpIndicator(ContextCompat.getDrawable(getContext()
, R.drawable.ic_view_list_white));
mWebCodeRead.setScrollChangeListener(this);
mWebCodeRead.getSettings().setJavaScriptEnabled(true);
mWebCodeRead.getSettings().setSupportZoom(true);
mWebCodeRead.getSettings().setBuiltInZoomControls(true);
mWebCodeRead.setWebViewClient(new WebViewClient() {
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
mCodeContentLoader.showContent();
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
Navigator.startWebActivity(getContext(), url);
return true;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Navigator.startWebActivity(getContext(), String.valueOf(request.getUrl()));
return true;
}
});
mWebCodeRead.setWebChromeClient(new WebChromeClient() {
});
if (Build.VERSION.SDK_INT >= 11) {
((Runnable) () -> mWebCodeRead.getSettings().setDisplayZoomControls(false)).run();
}
openFile();
}
private void setupToolbar() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
return;
AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams) mToolbar.getLayoutParams();
params.height = (int) (DeviceUtils.dpToPx(getActivity(), 56)
+ DeviceUtils.getStatusBarHeight());
mToolbar.setLayoutParams(params);
mToolbar.setPadding(0, DeviceUtils.getStatusBarHeight(), 0, 0);
}
private void openFile() {
if (mCodeContentLoader == null) return;
mCodeContentLoader.showProgress();
mWebCodeRead.clearHistory();
if (mNode == null) {
if (mOpenFileAfterLoadFinish)
mCodeContentLoader.showEmpty(getString(R.string.code_read_no_file_open));
} else if (FileTypeUtils.isImageFileType(mNode.absolutePath)) {
openImageFile();
} else if (FileTypeUtils.isMdFileType(mNode.absolutePath)) {
openMdShowFile();
} else {
openCodeFile();
}
}
private void openImageFile() {
String string = "<html>" +
"<body style=\"background-color:"
+ ColorUtils.getColorString(getContext(), R.color.code_read_background_color)
+ ";margin-top: 40px; margin-bottom: 40px; text-align: center; vertical-align: center;\">"
+ "<img src='file:///" + mNode.absolutePath + "'>"
+ "</body></html>";
mWebCodeRead.loadDataWithBaseURL(null, string
, "text/html"
, "utf-8"
, null);
}
public void openFile(DirectoryNode node) {
mOpenFileAfterLoadFinish = true;
mNode = node;
openFile();
}
protected void openCodeFile() {
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
InputStream stream = null;
try {
stream = new FileInputStream(mNode.absolutePath);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
if (stream == null) {
subscriber.onCompleted();
return;
}
final InputStream finalStream = stream;
String[] names = mNode.name.split("\\.");
String fileTypeName = names[names.length - 1];
if (BrushMap.isBlackFile(fileTypeName)) {
subscriber.onError(new Throwable("Can not open this file!"));
subscriber.onCompleted();
return;
}
String jsFile = BrushMap.getJsFileForExtension(fileTypeName);
if (jsFile == null) {
jsFile = "Txt";
}
StringBuilder sb = new StringBuilder();
StringBuilder localStringBuilder = new StringBuilder();
try {
BufferedReader localBufferedReader = new BufferedReader(
new InputStreamReader(finalStream, "UTF-8"));
for (; ; ) {
String str = localBufferedReader.readLine();
if (str == null) {
break;
}
localStringBuilder.append(str);
localStringBuilder.append("\n");
}
localBufferedReader.close();
sb.append("<pre class='brush: ");
sb.append(jsFile.toLowerCase());
sb.append(";'>");
sb.append(TextUtils.htmlEncode(localStringBuilder.toString()));
sb.append("</pre>");
subscriber.onNext(HtmlParser.buildHtmlContent(getActivity(), sb.toString()
, jsFile, mNode.name));
} catch (OutOfMemoryError e) {
subscriber.onError(e);
} catch (FileNotFoundException e) {
subscriber.onError(e);
} catch (IOException e) {
subscriber.onError(e);
}
subscriber.onCompleted();
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(o -> mWebCodeRead.loadDataWithBaseURL("file:///android_asset/"
, o, "text/html", "UTF-8", ""))
.doOnError(e -> mCodeContentLoader.showEmpty(e.getMessage()))
.onErrorResumeNext(Observable.empty())
.subscribe();
}
protected void openMdShowFile() {
registerSubscription(
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
InputStream stream = null;
try {
stream = new FileInputStream(mNode.absolutePath);
} catch (FileNotFoundException e) {
subscriber.onError(e);
}
if (stream == null)
return;
final InputStream finalStream = stream;
StringBuilder localStringBuilder = new StringBuilder();
try {
BufferedReader localBufferedReader = new BufferedReader(
new InputStreamReader(finalStream, "UTF-8"));
for (; ; ) {
String str = localBufferedReader.readLine();
if (str == null) {
break;
}
localStringBuilder.append(str);
localStringBuilder.append("\n");
}
String textString = localStringBuilder.toString();
if (textString != null) {
MarkdownProcessor m = new MarkdownProcessor(mRootNode.absolutePath);
m.setTextColorString(ColorUtils.getColorString(getContext()
, R.color.text_color_primary));
m.setBackgroundColorString(ColorUtils.getColorString(getContext()
, R.color.code_read_background_color));
m.setCodeBlockColor(ColorUtils.getColorString(getContext()
, R.color.code_block_color));
m.setTableBorderColor(ColorUtils.getColorString(getContext()
, R.color.table_block_border_color));
String html = m.markdown(textString);
subscriber.onNext(html);
}
subscriber.onCompleted();
} catch (OutOfMemoryError e) {
subscriber.onError(e);
} catch (FileNotFoundException e) {
subscriber.onError(e);
} catch (IOException e) {
subscriber.onError(e);
}
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(s -> mWebCodeRead.loadDataWithBaseURL("fake://", s, "text/html"
, "UTF-8", ""))
.doOnError(e -> mCodeContentLoader.showEmpty(e.getMessage()))
.onErrorResumeNext(Observable.empty())
.subscribe()
);
}
@Override
public void onDestroyView() {
super.onDestroyView();
mWebCodeRead.destroy();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mOrientationChange = true;
}
@Override
public void onScrollChanged(int l, int t, int oldl, int oldt) {
if (mOrientationChange) {
mOrientationChange = false;
return;
}
if (scrollFinishDelaySubscription != null && !scrollFinishDelaySubscription.isUnsubscribed()) {
scrollFinishDelaySubscription.unsubscribe();
}
if (t - oldt > 70) {
if (mScrollDown)
return;
mScrollDown = true;
} else if (t - oldt < 0) {
if (!mScrollDown)
return;
mScrollDown = false;
closeFullScreen();
}
if (mScrollDown) {
scrollFinishDelaySubscription = Observable
.timer(500, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(lo -> openFullScreen())
.subscribe();
registerSubscription(scrollFinishDelaySubscription);
}
}
public void updateRootNode(DirectoryNode directoryNode) {
mRootNode = directoryNode;
}
public ILoadHelper getCodeContentLoader() {
return mCodeContentLoader;
}
private void openFullScreen() {
hide();
}
private void closeFullScreen() {
show();
}
}