display text and markdown content

This commit is contained in:
Akinwale Ariwodola 2020-05-14 03:36:46 +01:00
parent df4785fb5f
commit 6bed7bfd2f
6 changed files with 229 additions and 32 deletions

View file

@ -79,6 +79,7 @@ dependencies {
implementation 'com.hbb20:ccp:2.3.8' implementation 'com.hbb20:ccp:2.3.8'
implementation 'com.github.chrisbanes:PhotoView:2.3.0' implementation 'com.github.chrisbanes:PhotoView:2.3.0'
implementation 'com.atlassian.commonmark:commonmark:0.14.0'
compileOnly 'org.projectlombok:lombok:1.18.10' compileOnly 'org.projectlombok:lombok:1.18.10'
annotationProcessor 'org.projectlombok:lombok:1.18.10' annotationProcessor 'org.projectlombok:lombok:1.18.10'

View file

@ -20,6 +20,10 @@ import android.text.format.DateUtils;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.WindowManager; import android.view.WindowManager;
import android.webkit.WebResourceRequest;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
@ -48,6 +52,9 @@ import com.google.android.flexbox.FlexboxLayoutManager;
import com.google.android.material.button.MaterialButton; import com.google.android.material.button.MaterialButton;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
@ -56,6 +63,7 @@ import java.math.BigDecimal;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
@ -74,6 +82,7 @@ import io.lbry.browser.model.LbryFile;
import io.lbry.browser.model.Tag; import io.lbry.browser.model.Tag;
import io.lbry.browser.model.lbryinc.Reward; import io.lbry.browser.model.lbryinc.Reward;
import io.lbry.browser.model.lbryinc.Subscription; import io.lbry.browser.model.lbryinc.Subscription;
import io.lbry.browser.tasks.ReadTextFileTask;
import io.lbry.browser.tasks.claim.ClaimListResultHandler; import io.lbry.browser.tasks.claim.ClaimListResultHandler;
import io.lbry.browser.tasks.claim.ClaimSearchTask; import io.lbry.browser.tasks.claim.ClaimSearchTask;
import io.lbry.browser.tasks.file.DeleteFileTask; import io.lbry.browser.tasks.file.DeleteFileTask;
@ -161,6 +170,7 @@ public class FileViewActivity extends AppCompatActivity {
loadFile(); loadFile();
} }
} }
setContentView(R.layout.activity_file_view); setContentView(R.layout.activity_file_view);
checkIsFileComplete(); checkIsFileComplete();
@ -218,6 +228,14 @@ public class FileViewActivity extends AppCompatActivity {
walletBalanceListeners.remove(listener); walletBalanceListeners.remove(listener);
} }
private void initWebView() {
WebView webView = findViewById(R.id.file_view_webview);
webView.setWebViewClient(new LbryWebViewClient(this));
WebSettings webSettings = webView.getSettings();
webSettings.setAllowFileAccess(true);
webSettings.setJavaScriptEnabled(true);
}
private void logUrlEvent(String url) { private void logUrlEvent(String url) {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString("uri", url); bundle.putString("uri", url);
@ -466,6 +484,8 @@ public class FileViewActivity extends AppCompatActivity {
} }
private void initUi() { private void initUi() {
initWebView();
findViewById(R.id.file_view_title_area).setOnClickListener(new View.OnClickListener() { findViewById(R.id.file_view_title_area).setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
@ -788,10 +808,10 @@ public class FileViewActivity extends AppCompatActivity {
findViewById(R.id.file_view_fee_container).setVisibility(View.VISIBLE); findViewById(R.id.file_view_fee_container).setVisibility(View.VISIBLE);
((TextView) findViewById(R.id.file_view_fee)).setText(Helper.shortCurrencyFormat(Helper.parseDouble(fee.getAmount(), 0))); ((TextView) findViewById(R.id.file_view_fee)).setText(Helper.shortCurrencyFormat(Helper.parseDouble(fee.getAmount(), 0)));
} }
} }
findViewById(R.id.file_view_icon_follow_unfollow).setVisibility(claim.getSigningChannel() != null ? View.VISIBLE : View.GONE);
MaterialButton mainActionButton = findViewById(R.id.file_view_main_action_button); MaterialButton mainActionButton = findViewById(R.id.file_view_main_action_button);
if (claim.isPlayable()) { if (claim.isPlayable()) {
mainActionButton.setText(R.string.play); mainActionButton.setText(R.string.play);
@ -801,9 +821,11 @@ public class FileViewActivity extends AppCompatActivity {
mainActionButton.setText(R.string.download); mainActionButton.setText(R.string.download);
} }
if (claim.isFree() && (claim.isPlayable() || claim.isViewable())) { if (claim.isFree()) {
if (claim.isPlayable() || (claim.isViewable() && Lbry.SDK_READY)) {
onMainActionButtonClicked(); onMainActionButtonClicked();
} }
}
loadRelatedContent(); loadRelatedContent();
} }
@ -1008,40 +1030,98 @@ public class FileViewActivity extends AppCompatActivity {
handled = true; handled = true;
} else if (claim.isViewable()) { } else if (claim.isViewable()) {
// check type and display // check type and display
boolean fileExists = false;
LbryFile claimFile = claim.getFile();
Uri fileUri = null;
if (claimFile != null && !Helper.isNullOrEmpty(claimFile.getDownloadPath())) {
File file = new File(claimFile.getDownloadPath());
fileUri = Uri.fromFile(file);
fileExists = file.exists();
}
if (!fileExists) {
showError(getString(R.string.claim_file_not_found, claimFile != null ? claimFile.getDownloadPath() : ""));
} else if (fileUri != null) {
if (mediaType.startsWith("image")) { if (mediaType.startsWith("image")) {
// display the image // display the image
View container = findViewById(R.id.file_view_imageviewer_container); View container = findViewById(R.id.file_view_imageviewer_container);
PhotoView photoView = findViewById(R.id.file_view_imageviewer); PhotoView photoView = findViewById(R.id.file_view_imageviewer);
boolean fileExists = false;
LbryFile claimFile = claim.getFile();
if (claimFile != null && !Helper.isNullOrEmpty(claimFile.getDownloadPath())) {
File file = new File(claimFile.getDownloadPath());
fileExists = file.exists();
if (fileExists) {
Uri fileUri = Uri.fromFile(file);
Glide.with(getApplicationContext()).load(fileUri).centerInside().into(photoView); Glide.with(getApplicationContext()).load(fileUri).centerInside().into(photoView);
hideFloatingWalletBalance(); hideFloatingWalletBalance();
container.setVisibility(View.VISIBLE); container.setVisibility(View.VISIBLE);
}
}
if (!fileExists) {
showError(getString(R.string.claim_file_not_found, claimFile != null ? claimFile.getDownloadPath() : ""));
}
} else if (mediaType.startsWith("text")) { } else if (mediaType.startsWith("text")) {
// show browser (and parse markdown too) // show web view (and parse markdown too)
View container = findViewById(R.id.file_view_webview_container);
WebView webView = findViewById(R.id.file_view_webview);
if (Arrays.asList("text/markdown", "text/md").contains(mediaType.toLowerCase())) {
loadMarkdownFromFile(claimFile.getDownloadPath());
} else {
webView.loadUrl(fileUri.toString());
}
hideFloatingWalletBalance();
container.setVisibility(View.VISIBLE);
} }
handled = true; handled = true;
} }
} }
}
if (!handled) { if (!handled) {
showUnsupportedView(); showUnsupportedView();
} }
} }
private void loadMarkdownFromFile(String filePath) {
ReadTextFileTask task = new ReadTextFileTask(filePath, new ReadTextFileTask.ReadTextFileHandler() {
@Override
public void onSuccess(String text) {
String html = buildMarkdownHtml(text);
WebView webView = findViewById(R.id.file_view_webview);
webView.loadData(html, "text/html", "utf-8");
}
@Override
public void onError(Exception error) {
showError(error.getMessage());
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private String buildMarkdownHtml(String markdown) {
Parser parser = Parser.builder().build();
Node document = parser.parse(markdown);
HtmlRenderer renderer = HtmlRenderer.builder().build();
String markdownHtml = renderer.render(document);
return "<!doctype html>\n" +
" <html>\n" +
" <head>\n" +
" <meta charset=\"utf-8\"/>\n" +
" <meta name=\"viewport\" content=\"width=device-width, user-scalable=no\"/>\n" +
" <style type=\"text/css\">\n" +
" @font-face {\n" +
" font-family: 'Inter';\n" +
" src: url('file:///android_res/font/inter_regular.otf');\n" +
" font-weight: normal;\n" +
" }\n" +
" @font-face {\n" +
" font-family: 'Inter';\n" +
" src: url('file:///android_res/font/inter_bold.otf');\n" +
" font-weight: bold;\n" +
" }\n" +
" body { font-family: 'Inter', sans-serif; margin: 16px }\n" +
" img { width: 100%; }\n" +
" </style>\n" +
" </head>\n" +
" <body>\n" +
" <div id=\"content\">\n" +
markdownHtml +
" </div>\n" +
" </body>\n" +
" </html>";
}
public void showError(String message) { public void showError(String message) {
Snackbar.make(findViewById(R.id.file_view_claim_display_area), message, Snackbar.LENGTH_LONG). Snackbar.make(findViewById(R.id.file_view_claim_display_area), message, Snackbar.LENGTH_LONG).
setTextColor(Color.WHITE). setTextColor(Color.WHITE).
@ -1113,6 +1193,14 @@ public class FileViewActivity extends AppCompatActivity {
if (isImageViewerVisible()) { if (isImageViewerVisible()) {
findViewById(R.id.file_view_imageviewer_container).setVisibility(View.GONE); findViewById(R.id.file_view_imageviewer_container).setVisibility(View.GONE);
restoreMainActionButton();
showFloatingWalletBalance();
return;
}
if (isWebViewVisible()) {
findViewById(R.id.file_view_webview_container).setVisibility(View.GONE);
restoreMainActionButton();
showFloatingWalletBalance();
return; return;
} }
@ -1127,14 +1215,17 @@ public class FileViewActivity extends AppCompatActivity {
} }
private boolean isWebViewVisible() { private boolean isWebViewVisible() {
return false; return findViewById(R.id.file_view_webview_container).getVisibility() == View.VISIBLE;
} }
protected void onUserLeaveHint() { protected void onUserLeaveHint() {
if (stopServiceReceived) { if (stopServiceReceived ||
claim == null ||
!claim.isPlayable()) {
return; return;
} }
if (startingShareActivity) { if (startingShareActivity) {
// share activity triggered this, so reset the flag at this point // share activity triggered this, so reset the flag at this point
new Handler().postDelayed(new Runnable() { new Handler().postDelayed(new Runnable() {
@ -1145,6 +1236,7 @@ public class FileViewActivity extends AppCompatActivity {
}, 1000); }, 1000);
return; return;
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !MainActivity.mainActive) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !MainActivity.mainActive) {
PictureInPictureParams params = new PictureInPictureParams.Builder().build(); PictureInPictureParams params = new PictureInPictureParams.Builder().build();
enterPictureInPictureMode(params); enterPictureInPictureMode(params);
@ -1432,6 +1524,9 @@ public class FileViewActivity extends AppCompatActivity {
private void hideFloatingWalletBalance() { private void hideFloatingWalletBalance() {
findViewById(R.id.floating_balance_main_container).setVisibility(View.GONE); findViewById(R.id.floating_balance_main_container).setVisibility(View.GONE);
} }
private void showFloatingWalletBalance() {
findViewById(R.id.floating_balance_main_container).setVisibility(View.VISIBLE);
}
private void onDownloadAborted() { private void onDownloadAborted() {
downloadInProgress = false; downloadInProgress = false;
@ -1451,4 +1546,20 @@ public class FileViewActivity extends AppCompatActivity {
findViewById(R.id.file_view_main_action_loading).setVisibility(View.INVISIBLE); findViewById(R.id.file_view_main_action_loading).setVisibility(View.INVISIBLE);
findViewById(R.id.file_view_main_action_button).setVisibility(View.VISIBLE); findViewById(R.id.file_view_main_action_button).setVisibility(View.VISIBLE);
} }
private static class LbryWebViewClient extends WebViewClient {
private Context context;
public LbryWebViewClient(Context context) {
this.context = context;
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
Uri url = request.getUrl();
if (context != null) {
Intent intent = new Intent(Intent.ACTION_VIEW, url);
context.startActivity(intent);
}
return true;
}
}
} }

View file

@ -20,6 +20,7 @@ import com.google.firebase.analytics.FirebaseAnalytics;
import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage; import com.google.firebase.messaging.RemoteMessage;
import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.lbrysdk.LbrynetService; import io.lbry.lbrysdk.LbrynetService;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@ -61,7 +62,7 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
if (firebaseAnalytics != null) { if (firebaseAnalytics != null) {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putString("name", name); bundle.putString("name", name);
firebaseAnalytics.logEvent("lbry_notification_receive", bundle); firebaseAnalytics.logEvent(LbryAnalytics.EVENT_LBRY_NOTIFICATION_RECEIVE, bundle);
} }
sendNotification(title, body, type, url, name, contentTitle, channelUrl, publishTime); sendNotification(title, body, type, url, name, contentTitle, channelUrl, publishTime);

View file

@ -315,6 +315,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
}); });
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
checkNotificationOpenIntent(getIntent());
setContentView(R.layout.activity_main); setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar); Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
@ -441,6 +442,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
protected void onNewIntent(Intent intent) { protected void onNewIntent(Intent intent) {
super.onNewIntent(intent); super.onNewIntent(intent);
checkUrlIntent(intent); checkUrlIntent(intent);
checkNotificationOpenIntent(intent);
} }
public void addSdkStatusListener(SdkStatusListener listener) { public void addSdkStatusListener(SdkStatusListener listener) {
@ -1837,6 +1839,22 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
return false; return false;
} }
private void checkNotificationOpenIntent(Intent intent) {
if (intent != null) {
String notificationName = intent.getStringExtra("notification_name");
if (notificationName != null) {
logNotificationOpen(notificationName);
}
}
}
private void logNotificationOpen(String name) {
Bundle bundle = new Bundle();
bundle.putString("name", name);
LbryAnalytics.logEvent(LbryAnalytics.EVENT_LBRY_NOTIFICATION_OPEN, bundle);
}
private void registerServiceActionsReceiver() { private void registerServiceActionsReceiver() {
IntentFilter intentFilter = new IntentFilter(); IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(LbrynetService.LBRY_SDK_SERVICE_STARTED); intentFilter.addAction(LbrynetService.LBRY_SDK_SERVICE_STARTED);

View file

@ -0,0 +1,55 @@
package io.lbry.browser.tasks;
import android.os.AsyncTask;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.Buffer;
import io.lbry.browser.utils.Helper;
public class ReadTextFileTask extends AsyncTask<Void, Void, String> {
private String filePath;
private Exception error;
private ReadTextFileHandler handler;
public ReadTextFileTask(String filePath, ReadTextFileHandler handler) {
this.filePath = filePath;
this.handler = handler;
}
protected String doInBackground(Void... params) {
StringBuilder sb = new StringBuilder();
BufferedReader reader = null;
try {
reader = new BufferedReader(new InputStreamReader(new FileInputStream(filePath)));
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line).append("\n");
}
} catch (IOException ex) {
error = ex;
return null;
} finally {
Helper.closeCloseable(reader);
}
return sb.toString();
}
protected void onPostExecute(String text) {
if (handler != null) {
if (!Helper.isNull(text)) {
handler.onSuccess(text);
} else {
handler.onError(error);
}
}
}
public interface ReadTextFileHandler {
void onSuccess(String text);
void onError(Exception error);
}
}

View file

@ -624,6 +624,17 @@
android:layout_height="match_parent" /> android:layout_height="match_parent" />
</RelativeLayout> </RelativeLayout>
<RelativeLayout
android:id="@+id/file_view_webview_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<WebView
android:id="@+id/file_view_webview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
<include layout="@layout/floating_wallet_balance" /> <include layout="@layout/floating_wallet_balance" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>