diff --git a/app/build.gradle b/app/build.gradle
index b2abe1a9..b6a9fdbf 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -86,8 +86,8 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
- __32bitImplementation files('libs/lbrysdk-0.71.0-release__arm.aar')
- __64bitImplementation files('libs/lbrysdk-0.71.0-release__arm64.aar')
+ __32bitImplementation files('libs/lbrysdk-0.72.0-release__arm.aar')
+ __64bitImplementation files('libs/lbrysdk-0.72.0-release__arm64.aar')
}
apply plugin: 'com.google.gms.google-services'
diff --git a/app/libs/lbrysdk-0.71.0-release__arm.aar b/app/libs/lbrysdk-0.72.0-release__arm.aar
similarity index 70%
rename from app/libs/lbrysdk-0.71.0-release__arm.aar
rename to app/libs/lbrysdk-0.72.0-release__arm.aar
index b23902dc..4528d295 100644
Binary files a/app/libs/lbrysdk-0.71.0-release__arm.aar and b/app/libs/lbrysdk-0.72.0-release__arm.aar differ
diff --git a/app/libs/lbrysdk-0.71.0-release__arm64.aar b/app/libs/lbrysdk-0.72.0-release__arm64.aar
similarity index 71%
rename from app/libs/lbrysdk-0.71.0-release__arm64.aar
rename to app/libs/lbrysdk-0.72.0-release__arm64.aar
index 32e37013..c35f7be5 100644
Binary files a/app/libs/lbrysdk-0.71.0-release__arm64.aar and b/app/libs/lbrysdk-0.72.0-release__arm64.aar differ
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index fa041963..b5cb22f8 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -19,6 +19,19 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/io/lbry/browser/FileViewActivity.java b/app/src/main/java/io/lbry/browser/FileViewActivity.java
index 881029b5..628f244f 100644
--- a/app/src/main/java/io/lbry/browser/FileViewActivity.java
+++ b/app/src/main/java/io/lbry/browser/FileViewActivity.java
@@ -1,29 +1,39 @@
package io.lbry.browser;
+import android.annotation.SuppressLint;
import android.app.PictureInPictureParams;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.graphics.Color;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
+import android.service.voice.VoiceInteractionSession;
import android.text.format.DateUtils;
import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.constraintlayout.widget.ConstraintLayout;
+import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.widget.NestedScrollView;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
+import com.bumptech.glide.Glide;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
@@ -34,12 +44,17 @@ import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.util.Util;
import com.google.android.flexbox.FlexboxLayoutManager;
+import com.google.android.material.button.MaterialButton;
import com.google.android.material.snackbar.Snackbar;
import java.math.BigDecimal;
import java.text.DecimalFormat;
+import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
import io.lbry.browser.adapter.ClaimListAdapter;
import io.lbry.browser.adapter.TagListAdapter;
@@ -47,15 +62,22 @@ import io.lbry.browser.dialog.SendTipDialogFragment;
import io.lbry.browser.exceptions.LbryUriException;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.ClaimCacheKey;
+import io.lbry.browser.model.Fee;
import io.lbry.browser.model.File;
import io.lbry.browser.model.Tag;
+import io.lbry.browser.model.lbryinc.Reward;
import io.lbry.browser.tasks.ClaimListResultHandler;
import io.lbry.browser.tasks.ClaimSearchTask;
import io.lbry.browser.tasks.FileListTask;
+import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.tasks.LighthouseSearchTask;
import io.lbry.browser.tasks.ResolveTask;
+import io.lbry.browser.tasks.lbryinc.ClaimRewardTask;
+import io.lbry.browser.tasks.lbryinc.FetchStatCountTask;
+import io.lbry.browser.tasks.lbryinc.LogFileViewTask;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
+import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.LbryUri;
public class FileViewActivity extends AppCompatActivity {
@@ -65,16 +87,23 @@ public class FileViewActivity extends AppCompatActivity {
private static final int SHARE_REQUEST_CODE = 3001;
private static boolean startingShareActivity;
- private SimpleExoPlayer player;
private boolean hasLoadedFirstBalance;
private boolean loadFilePending;
private boolean resolving;
private Claim claim;
+ private String currentUrl;
private ClaimListAdapter relatedContentAdapter;
private File file;
private BroadcastReceiver sdkReceiver;
private Player.EventListener fileViewPlayerListener;
+ private long elapsedDuration = 0;
+ private long totalDuration = 0;
+ private boolean elapsedPlaybackScheduled;
+ private ScheduledExecutorService elapsedPlaybackScheduler;
+ private boolean playbackStarted;
+ private long startTimeMillis;
+
private View buttonShareAction;
private View buttonTipAction;
private View buttonRepostAction;
@@ -118,6 +147,8 @@ public class FileViewActivity extends AppCompatActivity {
}
setContentView(R.layout.activity_file_view);
+ currentUrl = url;
+ logUrlEvent(url);
if (claim == null) {
resolveUrl(url);
}
@@ -127,9 +158,23 @@ public class FileViewActivity extends AppCompatActivity {
fileViewPlayerListener = new Player.EventListener() {
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
- /*if (playbackState == Player.STATE_READY) {
- MainActivity.setNowPlayingClaim(claim, FileViewActivity.this);
- }*/
+ if (playbackState == Player.STATE_READY) {
+ if (totalDuration == 0) {
+ elapsedDuration = MainActivity.appPlayer.getCurrentPosition();
+ totalDuration = MainActivity.appPlayer.getDuration();
+ }
+ if (!playbackStarted) {
+ logPlay(currentUrl, startTimeMillis);
+ playbackStarted = true;
+ }
+ renderTotalDuration();
+ scheduleElapsedPlayback();
+ hideBuffering();
+ } else if (playbackState == Player.STATE_BUFFERING) {
+ showBuffering();
+ } else {
+ hideBuffering();
+ }
}
};
@@ -138,6 +183,12 @@ public class FileViewActivity extends AppCompatActivity {
renderClaim();
}
+ private void logUrlEvent(String url) {
+ Bundle bundle = new Bundle();
+ bundle.putString("uri", url);
+ LbryAnalytics.logEvent(LbryAnalytics.EVENT_OPEN_FILE_PAGE, bundle);
+ }
+
private void checkAndResetNowPlayingClaim() {
if (MainActivity.nowPlayingClaim != null &&
!MainActivity.nowPlayingClaim.getClaimId().equalsIgnoreCase(claim.getClaimId())) {
@@ -164,6 +215,9 @@ public class FileViewActivity extends AppCompatActivity {
return;
}
+ currentUrl = newUrl;
+ logUrlEvent(newUrl);
+ resetViewCount();
ClaimCacheKey key = new ClaimCacheKey();
key.setClaimId(newClaimId);
if (!Helper.isNullOrEmpty(newUrl) && newUrl.contains("#")) {
@@ -230,7 +284,7 @@ public class FileViewActivity extends AppCompatActivity {
}
private String buildLbryTvStreamingUrl() {
- return String.format("https://player.lbry.tv/content/claims/%s/%s/stream", claim.getName(), claim.getClaimId());
+ return String.format("https://cdn.lbryplayer.xyz/content/claims/%s/%s/stream", claim.getName(), claim.getClaimId());
}
private void loadFile() {
@@ -241,7 +295,7 @@ public class FileViewActivity extends AppCompatActivity {
}
loadFilePending = false;
- // TODO: Check if it's paid content and then wait for the user to explicity request the file
+ // TODO: Check if it's paid content and then wait for the user to explicitly request the file
String claimId = claim.getClaimId();
FileListTask task = new FileListTask(claimId, null, new FileListTask.FileListResultHandler() {
@Override
@@ -257,6 +311,7 @@ public class FileViewActivity extends AppCompatActivity {
}
});
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
protected void onResume() {
@@ -266,6 +321,7 @@ public class FileViewActivity extends AppCompatActivity {
private void resolveUrl(String url) {
resolving = true;
+ findViewById(R.id.file_view_claim_display_area).setVisibility(View.INVISIBLE);
View loadingView = findViewById(R.id.file_view_loading_container);
ResolveTask task = new ResolveTask(url, Lbry.LBRY_TV_CONNECTION_STRING, loadingView, new ClaimListResultHandler() {
@Override
@@ -359,6 +415,18 @@ public class FileViewActivity extends AppCompatActivity {
}
});
+ findViewById(R.id.player_toggle_full_screen).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ // check full screen mode
+ if (isInFullscreenMode()) {
+ disableFullScreenMode();
+ } else {
+ enableFullScreenMode();
+ }
+ }
+ });
+
RecyclerView relatedContentList = findViewById(R.id.file_view_related_content_list);
relatedContentList.setNestedScrollingEnabled(false);
LinearLayoutManager llm = new LinearLayoutManager(this);
@@ -370,6 +438,8 @@ public class FileViewActivity extends AppCompatActivity {
return;
}
+ loadViewCount();
+
((NestedScrollView) findViewById(R.id.file_view_scroll_view)).scrollTo(0, 0);
findViewById(R.id.file_view_claim_display_area).setVisibility(View.VISIBLE);
@@ -402,27 +472,58 @@ public class FileViewActivity extends AppCompatActivity {
descTagsList.setAdapter(tagListAdapter);
findViewById(R.id.file_view_tag_area).setVisibility(tags.size() > 0 ? View.VISIBLE : View.GONE);
+ findViewById(R.id.file_view_exoplayer_container).setVisibility(View.GONE);
+ findViewById(R.id.file_view_unsupported_container).setVisibility(View.GONE);
+ findViewById(R.id.file_view_media_meta_container).setVisibility(View.VISIBLE);
+
Claim.GenericMetadata metadata = claim.getValue();
+ if (!Helper.isNullOrEmpty(claim.getThumbnailUrl())) {
+ ImageView thumbnailView = findViewById(R.id.file_view_thumbnail);
+ Glide.with(getApplicationContext()).load(claim.getThumbnailUrl()).centerCrop().into(thumbnailView);
+ } else {
+ // display first x letters of claim name, with random background
+ }
+
+ findViewById(R.id.file_view_main_action_button).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ onMainActionButtonClicked();
+ }
+ });
+ findViewById(R.id.file_view_media_meta_container).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ onMainActionButtonClicked();
+ }
+ });
+
+ boolean isFree = true;
if (metadata instanceof Claim.StreamMetadata) {
Claim.StreamMetadata streamMetadata = (Claim.StreamMetadata) metadata;
long publishTime = streamMetadata.getReleaseTime() > 0 ? streamMetadata.getReleaseTime() * 1000 : claim.getTimestamp() * 1000;
((TextView) findViewById(R.id.file_view_publish_time)).setText(DateUtils.getRelativeTimeSpanString(
publishTime, System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
- // Check the metadata type
- String mediaType = streamMetadata.getSource().getMediaType();
- // Use Exoplayer view if it's video / audio
- if (mediaType.startsWith("audio") || mediaType.startsWith("video")) {
- showExoplayerView();
- playMedia();
- } else if (mediaType.startsWith("text")) {
-
- } else if (mediaType.startsWith("image")) {
-
- } else {
- // unsupported type
- showUnsupportedView();
+ Fee fee = streamMetadata.getFee();
+ if (fee != null && Helper.parseDouble(fee.getAmount(), 0) > 0) {
+ isFree = false;
+ 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)));
}
+
+ MaterialButton mainActionButton = findViewById(R.id.file_view_main_action_button);
+ String mediaType = streamMetadata.getSource().getMediaType();
+ if (mediaType.startsWith("audio") || mediaType.startsWith("video")) {
+ mainActionButton.setText(R.string.play);
+ } else if (mediaType.startsWith("text") || mediaType.startsWith("image")) {
+ mainActionButton.setText(R.string.view);
+ } else {
+ mainActionButton.setText(R.string.download);
+ }
+ }
+
+ if (isFree) {
+ onMainActionButtonClicked();
}
loadRelatedContent();
@@ -451,9 +552,7 @@ public class FileViewActivity extends AppCompatActivity {
}
PlayerView view = findViewById(R.id.file_view_exoplayer_view);
- PlayerControlView controlView = findViewById(R.id.file_view_exoplayer_control_view);
view.setPlayer(MainActivity.appPlayer);
- controlView.setPlayer(MainActivity.appPlayer);
if (MainActivity.nowPlayingClaim != null &&
MainActivity.nowPlayingClaim.getClaimId().equalsIgnoreCase(claim.getClaimId()) &&
@@ -462,6 +561,8 @@ public class FileViewActivity extends AppCompatActivity {
return;
}
+ resetPlayer();
+ showBuffering();
MainActivity.setNowPlayingClaim(claim, FileViewActivity.this);
String userAgent = Util.getUserAgent(this, getString(R.string.app_name));
MediaSource mediaSource = new ProgressiveMediaSource.Factory(
@@ -471,8 +572,81 @@ public class FileViewActivity extends AppCompatActivity {
MainActivity.appPlayer.prepare(mediaSource, true, true);
}
- private void loadViewCount() {
+ private void resetViewCount() {
+ TextView textViewCount = findViewById(R.id.file_view_view_count);
+ Helper.setViewText(textViewCount, null);
+ Helper.setViewVisibility(textViewCount, View.GONE);
+ }
+ private void loadViewCount() {
+ if (claim != null) {
+ FetchStatCountTask task = new FetchStatCountTask(
+ FetchStatCountTask.STAT_VIEW_COUNT, claim.getClaimId(), null, new FetchStatCountTask.FetchStatCountHandler() {
+ @Override
+ public void onSuccess(int count) {
+ try {
+ String displayText = getResources().getQuantityString(R.plurals.view_count, count, NumberFormat.getInstance().format(count));
+ TextView textViewCount = findViewById(R.id.file_view_view_count);
+ Helper.setViewText(textViewCount, displayText);
+ Helper.setViewVisibility(textViewCount, View.VISIBLE);
+ } catch (IllegalStateException ex) {
+ // pass
+ }
+ }
+
+ @Override
+ public void onError(Exception error) {
+ // pass
+ }
+ });
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+ }
+
+ private void onMainActionButtonClicked() {
+ // Check if the claim is free
+ Claim.GenericMetadata metadata = claim.getValue();
+ if (metadata instanceof Claim.StreamMetadata) {
+ Claim.StreamMetadata streamMetadata = (Claim.StreamMetadata) metadata;
+
+ Fee fee = streamMetadata.getFee();
+ if (fee != null && Helper.parseDouble(fee.getAmount(), 0) > 0) {
+ // not free, perform a purchase
+
+ } else {
+ handleMainActionForClaim();
+ }
+ } else {
+ showError(getString(R.string.cannot_view_claim));
+ }
+ }
+
+ private void handleMainActionForClaim() {
+ startTimeMillis = System.currentTimeMillis();
+ Claim.GenericMetadata metadata = claim.getValue();
+ if (metadata instanceof Claim.StreamMetadata) {
+ Claim.StreamMetadata streamMetadata = (Claim.StreamMetadata) metadata;
+ // Check the metadata type
+ String mediaType = streamMetadata.getSource().getMediaType();
+ // Use Exoplayer view if it's video / audio
+ if (mediaType.startsWith("audio") || mediaType.startsWith("video")) {
+ showExoplayerView();
+ playMedia();
+ } else if (mediaType.startsWith("text")) {
+
+ } else if (mediaType.startsWith("image")) {
+
+ } else {
+ // unsupported type
+ showUnsupportedView();
+ }
+ } else {
+ showError(getString(R.string.cannot_view_claim));
+ }
+ }
+
+ private void showError(String message) {
+ Snackbar.make(findViewById(R.id.file_view_claim_display_area), message, Snackbar.LENGTH_LONG).setBackgroundTint(Color.RED).show();
}
private void loadRelatedContent() {
@@ -524,6 +698,11 @@ public class FileViewActivity extends AppCompatActivity {
}
public void onBackPressed() {
+ if (isInFullscreenMode()) {
+ disableFullScreenMode();
+ return;
+ }
+
MainActivity.mainActive = true;
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
@@ -567,16 +746,13 @@ public class FileViewActivity extends AppCompatActivity {
private void renderPictureInPictureMode() {
findViewById(R.id.file_view_scroll_view).setVisibility(View.GONE);
- findViewById(R.id.file_view_exoplayer_control_view).setVisibility(View.GONE);
findViewById(R.id.floating_balance_main_container).setVisibility(View.GONE);
}
private void renderFullMode() {
findViewById(R.id.file_view_scroll_view).setVisibility(View.VISIBLE);
- findViewById(R.id.floating_balance_main_container).setVisibility(View.VISIBLE);
-
- PlayerControlView controlView = findViewById(R.id.file_view_exoplayer_control_view);
- controlView.setPlayer(null);
- controlView.setPlayer(MainActivity.appPlayer);
+ if (!isInFullscreenMode()) {
+ findViewById(R.id.floating_balance_main_container).setVisibility(View.VISIBLE);
+ }
}
@Override
@@ -587,4 +763,151 @@ public class FileViewActivity extends AppCompatActivity {
renderFullMode();
}
}
+
+ @SuppressLint("SourceLockedOrientationActivity")
+ private void enableFullScreenMode() {
+ findViewById(R.id.floating_balance_main_container).setVisibility(View.INVISIBLE);
+
+ View decorView = getWindow().getDecorView();
+ decorView.setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |
+ View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY |
+ View.SYSTEM_UI_FLAG_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
+
+ ConstraintLayout globalLayout = findViewById(R.id.file_view_global_layout);
+ View exoplayerContainer = findViewById(R.id.file_view_exoplayer_container);
+ ((ViewGroup) exoplayerContainer.getParent()).removeView(exoplayerContainer);
+ globalLayout.addView(exoplayerContainer);
+
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ ((ImageView) findViewById(R.id.player_image_full_screen_toggle)).setImageResource(R.drawable.ic_fullscreen_exit);
+ }
+
+ private void disableFullScreenMode() {
+ RelativeLayout mediaContainer = findViewById(R.id.file_view_media_container);
+ View exoplayerContainer = findViewById(R.id.file_view_exoplayer_container);
+ ((ViewGroup) exoplayerContainer.getParent()).removeView(exoplayerContainer);
+ mediaContainer.addView(exoplayerContainer);
+
+ View decorView = getWindow().getDecorView();
+ decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_VISIBLE);
+ setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
+
+ ((ImageView) findViewById(R.id.player_image_full_screen_toggle)).setImageResource(R.drawable.ic_fullscreen);
+ findViewById(R.id.floating_balance_main_container).setVisibility(View.VISIBLE);
+ }
+
+ private boolean isInFullscreenMode() {
+ View exoplayerContainer = findViewById(R.id.file_view_exoplayer_container);
+ return exoplayerContainer.getParent() instanceof ConstraintLayout;
+ }
+
+ private void scheduleElapsedPlayback() {
+ if (!elapsedPlaybackScheduled) {
+ elapsedPlaybackScheduler = Executors.newSingleThreadScheduledExecutor();
+ elapsedPlaybackScheduler.scheduleAtFixedRate(new Runnable() {
+ @Override
+ public void run() {
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (MainActivity.appPlayer != null) {
+ elapsedDuration = MainActivity.appPlayer.getCurrentPosition();
+ renderElapsedDuration();
+ }
+ }
+ });
+ }
+ }, 0, 500, TimeUnit.MILLISECONDS);
+ elapsedPlaybackScheduled = true;
+ }
+ }
+
+ private void resetPlayer() {
+ elapsedDuration = 0;
+ totalDuration = 0;
+ elapsedPlaybackScheduled = false;
+ if (elapsedPlaybackScheduler != null) {
+ elapsedPlaybackScheduler.shutdownNow();
+ elapsedPlaybackScheduler = null;
+ }
+
+ playbackStarted = false;
+ startTimeMillis = 0;
+ }
+
+ private void showBuffering() {
+ findViewById(R.id.player_buffering_progress).setVisibility(View.VISIBLE);
+ }
+
+ private void hideBuffering() {
+ findViewById(R.id.player_buffering_progress).setVisibility(View.INVISIBLE);
+ }
+
+ private void renderElapsedDuration() {
+ Helper.setViewText(findViewById(R.id.player_duration_elapsed), Helper.formatDuration(Double.valueOf(elapsedDuration / 1000.0).longValue()));
+ }
+
+ private void renderTotalDuration() {
+ Helper.setViewText(findViewById(R.id.player_duration_total), Helper.formatDuration(Double.valueOf(totalDuration / 1000.0).longValue()));
+ }
+
+ private void logPlay(String url, long startTimeMillis) {
+ long timeToStartMillis = startTimeMillis > 0 ? System.currentTimeMillis() - startTimeMillis : 0;
+
+ Bundle bundle = new Bundle();
+ bundle.putString("uri", url);
+ bundle.putLong("time_to_start_ms", timeToStartMillis);
+ bundle.putLong("time_to_start_seconds", Double.valueOf(timeToStartMillis / 1000.0).longValue());
+ LbryAnalytics.logEvent(LbryAnalytics.EVENT_PLAY, bundle);
+
+ logFileView(url, timeToStartMillis);
+ }
+
+ private void logFileView(String url, long timeToStart) {
+ if (claim != null) {
+ LogFileViewTask task = new LogFileViewTask(url, claim, timeToStart, new GenericTaskHandler() {
+ @Override
+ public void beforeStart() { }
+
+ @Override
+ public void onSuccess() {
+ claimEligibleRewards();
+ }
+
+ @Override
+ public void onError(Exception error) { }
+ });
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+ }
+
+ private void claimEligibleRewards() {
+ // attempt to claim eligible rewards after viewing or playing a file (fail silently)
+ ClaimRewardTask firstStreamTask = new ClaimRewardTask(Reward.TYPE_FIRST_STREAM, null, null, this, eligibleRewardHandler);
+ ClaimRewardTask dailyViewTask = new ClaimRewardTask(Reward.TYPE_DAILY_VIEW, null, null, this, eligibleRewardHandler);
+ firstStreamTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ dailyViewTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ private ClaimRewardTask.ClaimRewardHandler eligibleRewardHandler = new ClaimRewardTask.ClaimRewardHandler() {
+ @Override
+ public void onSuccess(double amountClaimed, String message) {
+ if (Helper.isNullOrEmpty(message)) {
+ message = getResources().getQuantityString(
+ R.plurals.claim_reward_message,
+ amountClaimed == 1 ? 1 : 2,
+ new DecimalFormat(Helper.LBC_CURRENCY_FORMAT_PATTERN).format(amountClaimed));
+ }
+ Snackbar.make(findViewById(R.id.file_view_global_layout), message, Snackbar.LENGTH_LONG).show();
+ }
+
+ @Override
+ public void onError(Exception error) {
+ // pass
+ }
+ };
}
diff --git a/app/src/main/java/io/lbry/browser/FirstRunActivity.java b/app/src/main/java/io/lbry/browser/FirstRunActivity.java
index 0aa9a0d2..8197fd70 100644
--- a/app/src/main/java/io/lbry/browser/FirstRunActivity.java
+++ b/app/src/main/java/io/lbry/browser/FirstRunActivity.java
@@ -7,7 +7,6 @@ import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
-import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.widget.TextView;
@@ -19,6 +18,7 @@ import androidx.preference.PreferenceManager;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
+import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.Lbryio;
public class FirstRunActivity extends AppCompatActivity {
@@ -60,6 +60,11 @@ public class FirstRunActivity extends AppCompatActivity {
}
}
+ public void onResume() {
+ super.onResume();
+ LbryAnalytics.setCurrentScreen(this, "First Run", "FirstRun");
+ }
+
private void registerAuthReceiver() {
IntentFilter filter = new IntentFilter();
filter.addAction(MainActivity.ACTION_USER_AUTHENTICATION_SUCCESS);
@@ -78,8 +83,13 @@ public class FirstRunActivity extends AppCompatActivity {
}
private void handleAuthenticationSuccess() {
-
// first_auth completed event
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
+ boolean firstAuthCompleted = sp.getBoolean(MainActivity.PREFERENCE_KEY_INTERNAL_FIRST_AUTH_COMPLETED, false);
+ if (!firstAuthCompleted) {
+ LbryAnalytics.logEvent(LbryAnalytics.EVENT_FIRST_USER_AUTH);
+ sp.edit().putBoolean(MainActivity.PREFERENCE_KEY_INTERNAL_FIRST_AUTH_COMPLETED, true).apply();
+ }
findViewById(R.id.welcome_wait_container).setVisibility(View.GONE);
findViewById(R.id.welcome_display).setVisibility(View.VISIBLE);
@@ -96,10 +106,10 @@ public class FirstRunActivity extends AppCompatActivity {
private void finishFirstRun() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
- sp.edit().putBoolean(MainActivity.PREFERENCE_KEY_FIRST_RUN_COMPLETED, true).apply();
+ sp.edit().putBoolean(MainActivity.PREFERENCE_KEY_INTERNAL_FIRST_RUN_COMPLETED, true).apply();
// first_run_completed event
-
+ LbryAnalytics.logEvent(LbryAnalytics.EVENT_FIRST_RUN_COMPLETED);
finish();
}
diff --git a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java
new file mode 100644
index 00000000..42420958
--- /dev/null
+++ b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java
@@ -0,0 +1,160 @@
+package io.lbry.browser;
+
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import androidx.core.app.NotificationCompat;
+import androidx.core.content.ContextCompat;
+import androidx.preference.PreferenceManager;
+
+import android.util.Log;
+
+import com.google.firebase.analytics.FirebaseAnalytics;
+import com.google.firebase.messaging.FirebaseMessagingService;
+import com.google.firebase.messaging.RemoteMessage;
+
+import io.lbry.lbrysdk.LbrynetService;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class LbrynetMessagingService extends FirebaseMessagingService {
+
+ private static final String TAG = "LbrynetMessagingService";
+ private static final String NOTIFICATION_CHANNEL_ID = "io.lbry.browser.LBRY_ENGAGEMENT_CHANNEL";
+ private static final String TYPE_SUBSCRIPTION = "subscription";
+ private static final String TYPE_REWARD = "reward";
+ private static final String TYPE_INTERESTS = "interests";
+ private static final String TYPE_CREATOR = "creator";
+ private FirebaseAnalytics firebaseAnalytics;
+
+ @Override
+ public void onMessageReceived(RemoteMessage remoteMessage) {
+ if (firebaseAnalytics == null) {
+ firebaseAnalytics = FirebaseAnalytics.getInstance(this);
+ }
+
+ Map payload = remoteMessage.getData();
+ if (payload != null) {
+ String type = payload.get("type");
+ String url = payload.get("target");
+ String title = payload.get("title");
+ String body = payload.get("body");
+ String name = payload.get("name"); // notification name
+ String contentTitle = payload.get("content_title");
+ String channelUrl = payload.get("channel_url");
+ //String publishTime = payload.get("publish_time");
+ String publishTime = null;
+
+ if (type != null && getEnabledTypes().indexOf(type) > -1 && body != null && body.trim().length() > 0) {
+ // only log the receive event for valid notifications received
+ if (firebaseAnalytics != null) {
+ Bundle bundle = new Bundle();
+ bundle.putString("name", name);
+ firebaseAnalytics.logEvent("lbry_notification_receive", bundle);
+ }
+
+ sendNotification(title, body, type, url, name, contentTitle, channelUrl, publishTime);
+ }
+ }
+ }
+
+ @Override
+ public void onNewToken(String token) {
+ Log.d(TAG, "Refreshed token: " + token);
+
+ // If you want to send messages to this application instance or
+ // manage this apps subscriptions on the server side, send the
+ // Instance ID token to your app server.
+ sendRegistrationToServer(token);
+ }
+
+ /**
+ * Persist token to third-party servers.
+ *
+ * Modify this method to associate the user's FCM InstanceID token with any server-side account
+ * maintained by your application.
+ *
+ * @param token The new token.
+ */
+ private void sendRegistrationToServer(String token) {
+ // TODO: Implement this method to send token to your app server.
+ }
+
+ /**
+ * Create and show a simple notification containing the received FCM message.
+ *
+ * @param messageBody FCM message body received.
+ */
+ private void sendNotification(String title, String messageBody, String type, String url, String name,
+ String contentTitle, String channelUrl, String publishTime) {
+ //Intent intent = new Intent(this, MainActivity.class);
+ //intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ if (url == null) {
+ if (TYPE_REWARD.equals(type)) {
+ url = "lbry://?rewards";
+ } else {
+ // default to home page
+ url = "lbry://?discover";
+ }
+ }
+
+ Intent launchIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
+ launchIntent.putExtra("notification_name", name);
+ launchIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+ PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, launchIntent, PendingIntent.FLAG_ONE_SHOT);
+
+ Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
+ NotificationCompat.Builder notificationBuilder =
+ new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
+ .setColor(ContextCompat.getColor(this, R.color.lbryGreen))
+ .setSmallIcon(R.drawable.ic_lbry)
+ .setContentTitle(title)
+ .setContentText(messageBody)
+ .setAutoCancel(true)
+ .setSound(defaultSoundUri)
+ .setContentIntent(pendingIntent);
+
+ NotificationManager notificationManager =
+ (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
+
+ // Since android Oreo notification channel is needed.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ NotificationChannel channel = new NotificationChannel(
+ NOTIFICATION_CHANNEL_ID, "LBRY Engagement", NotificationManager.IMPORTANCE_DEFAULT);
+ notificationManager.createNotificationChannel(channel);
+ }
+
+ notificationManager.notify(3, notificationBuilder.build());
+ }
+
+ public List getEnabledTypes() {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
+ List enabledTypes = new ArrayList();
+
+ if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_SUBSCRIPTIONS, true)) {
+ enabledTypes.add(TYPE_SUBSCRIPTION);
+ }
+ if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_REWARDS, true)) {
+ enabledTypes.add(TYPE_REWARD);
+ }
+ if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_CONTENT_INTERESTS, true)) {
+ enabledTypes.add(TYPE_INTERESTS);
+ }
+ if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_CREATOR, true)) {
+ enabledTypes.add(TYPE_CREATOR);
+ }
+
+ return enabledTypes;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java
index 2e40a17a..9aa2f454 100644
--- a/app/src/main/java/io/lbry/browser/MainActivity.java
+++ b/app/src/main/java/io/lbry/browser/MainActivity.java
@@ -34,7 +34,11 @@ import android.widget.Toast;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.ui.PlayerView;
+import com.google.android.gms.tasks.OnCompleteListener;
+import com.google.android.gms.tasks.Task;
import com.google.android.material.snackbar.Snackbar;
+import com.google.firebase.iid.FirebaseInstanceId;
+import com.google.firebase.iid.InstanceIdResult;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
@@ -119,6 +123,7 @@ import io.lbry.browser.ui.wallet.RewardsFragment;
import io.lbry.browser.ui.wallet.WalletFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
+import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.LbryUri;
import io.lbry.browser.utils.Lbryio;
import io.lbry.lbrysdk.LbrynetService;
@@ -136,6 +141,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public static boolean startingSignInFlowActivity = false;
public static boolean mainActive = false;
private boolean enteringPIPMode = false;
+ private String firebaseMessagingToken;
private Map openNavFragments;
private static final Map fragmentClassNavIdMap = new HashMap<>();
@@ -181,6 +187,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public static final String PREFERENCE_KEY_NOTIFICATION_SUBSCRIPTIONS = "io.lbry.browser.preference.notifications.Subscriptions";
public static final String PREFERENCE_KEY_NOTIFICATION_REWARDS = "io.lbry.browser.preference.notifications.Rewards";
public static final String PREFERENCE_KEY_NOTIFICATION_CONTENT_INTERESTS = "io.lbry.browser.preference.notifications.ContentInterests";
+ public static final String PREFERENCE_KEY_NOTIFICATION_CREATOR = "io.lbry.browser.preference.notifications.Creator";
public static final String PREFERENCE_KEY_KEEP_SDK_BACKGROUND = "io.lbry.browser.preference.other.KeepSdkInBackground";
public static final String PREFERENCE_KEY_PARTICIPATE_DATA_NETWORK = "io.lbry.browser.preference.other.ParticipateInDataNetwork";
@@ -190,9 +197,11 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public static final String PREFERENCE_KEY_INTERNAL_WALLET_RECEIVE_ADDRESS = "io.lbry.browser.preference.internal.WalletReceiveAddress";
public static final String PREFERENCE_KEY_INTERNAL_REWARDS_NOT_INTERESTED = "io.lbry.browser.preference.internal.RewardsNotInterested";
+ public static final String PREFERENCE_KEY_INTERNAL_FIRST_RUN_COMPLETED = "io.lbry.browser.preference.internal.FirstRunCompleted";
+ public static final String PREFERENCE_KEY_INTERNAL_FIRST_AUTH_COMPLETED = "io.lbry.browser.preference.internal.FirstAuthCompleted";
+
private final int CHECK_SDK_READY_INTERVAL = 1000;
- public static final String PREFERENCE_KEY_FIRST_RUN_COMPLETED = "io.lbry.browser.Preference.FirstRunCompleted";
public static final String PREFERENCE_KEY_AUTH_TOKEN = "io.lbry.browser.Preference.AuthToken";
public static final String SECURE_VALUE_KEY_SAVED_PASSWORD = "io.lbry.browser.PX";
@@ -273,6 +282,20 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
+ LbryAnalytics.init(this);
+ FirebaseInstanceId.getInstance().getInstanceId().addOnCompleteListener(new OnCompleteListener() {
+ @Override
+ public void onComplete(Task task) {
+ if (!task.isSuccessful()) {
+ return;
+ }
+
+ // Get new Instance ID token
+ firebaseMessagingToken = task.getResult().getToken();
+ android.util.Log.d("#HELP", firebaseMessagingToken);
+ }
+ });
+
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
@@ -504,7 +527,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public static void openFileClaim(Claim claim, Context context) {
Intent intent = new Intent(context, FileViewActivity.class);
intent.putExtra("claimId", claim.getClaimId());
- intent.putExtra("url", claim.getPermanentUrl());
+ intent.putExtra("url", !Helper.isNullOrEmpty(claim.getShortUrl()) ? claim.getShortUrl() : claim.getPermanentUrl());
startingFileViewActivity = true;
context.startActivity(intent);
}
@@ -935,7 +958,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
private void checkFirstRun() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
- boolean firstRunCompleted = sp.getBoolean(PREFERENCE_KEY_FIRST_RUN_COMPLETED, false);
+ boolean firstRunCompleted = sp.getBoolean(PREFERENCE_KEY_INTERNAL_FIRST_RUN_COMPLETED, false);
if (!firstRunCompleted) {
startActivity(new Intent(this, FirstRunActivity.class));
} else if (!appStarted) {
@@ -1004,6 +1027,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public void hideFloatingWalletBalance() {
findViewById(R.id.floating_balance_main_container).setVisibility(View.GONE);
}
+ public void hideFloatingRewardsValue() {
+ findViewById(R.id.floating_reward_container).setVisibility(View.INVISIBLE);
+ }
private void initFloatingWalletBalance() {
findViewById(R.id.floating_balance_container).setOnClickListener(new View.OnClickListener() {
@@ -1455,6 +1481,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
hideActionBar();
lockDrawer();
findViewById(R.id.splash_view).setVisibility(View.VISIBLE);
+ LbryAnalytics.setCurrentScreen(MainActivity.this, "Splash", "Splash");
}
protected Boolean doInBackground(Void... params) {
BufferedReader reader = null;
@@ -1547,6 +1574,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
fetchRewards();
checkUrlIntent(getIntent());
+ LbryAnalytics.logEvent(LbryAnalytics.EVENT_APP_LAUNCH);
appStarted = true;
}
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
@@ -1576,6 +1604,12 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
}
public void showFloatingUnclaimedRewards() {
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
+ boolean notInterestedInRewards = sp.getBoolean(PREFERENCE_KEY_INTERNAL_REWARDS_NOT_INTERESTED, false);
+ if (notInterestedInRewards) {
+ return;
+ }
+
((TextView) findViewById(R.id.floating_reward_value)).setText(Helper.shortCurrencyFormat(Lbryio.totalUnclaimedRewardAmount));
findViewById(R.id.floating_reward_container).setVisibility(View.VISIBLE);
}
diff --git a/app/src/main/java/io/lbry/browser/VerificationActivity.java b/app/src/main/java/io/lbry/browser/VerificationActivity.java
index af6013aa..f616ffce 100644
--- a/app/src/main/java/io/lbry/browser/VerificationActivity.java
+++ b/app/src/main/java/io/lbry/browser/VerificationActivity.java
@@ -18,6 +18,7 @@ import io.lbry.browser.listener.SignInListener;
import io.lbry.browser.listener.WalletSyncListener;
import io.lbry.browser.model.lbryinc.User;
import io.lbry.browser.tasks.lbryinc.FetchCurrentUserTask;
+import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.Lbryio;
public class VerificationActivity extends FragmentActivity implements SignInListener, WalletSyncListener {
@@ -71,6 +72,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList
public void onResume() {
super.onResume();
+ LbryAnalytics.setCurrentScreen(this, "Verification", "Verification");
checkFlow();
}
@@ -123,6 +125,10 @@ public class VerificationActivity extends FragmentActivity implements SignInList
public void onEmailAdded(String email) {
this.email = email;
findViewById(R.id.verification_close_button).setVisibility(View.GONE);
+
+ Bundle bundle = new Bundle();
+ bundle.putString("email", email);
+ LbryAnalytics.logEvent(LbryAnalytics.EVENT_EMAIL_ADDED, bundle);
}
public void onEmailEdit() {
findViewById(R.id.verification_close_button).setVisibility(View.VISIBLE);
@@ -131,6 +137,10 @@ public class VerificationActivity extends FragmentActivity implements SignInList
Snackbar.make(findViewById(R.id.verification_pager), R.string.sign_in_successful, Snackbar.LENGTH_LONG).show();
sendBroadcast(new Intent(MainActivity.ACTION_USER_SIGN_IN_SUCCESS));
+ Bundle bundle = new Bundle();
+ bundle.putString("email", email);
+ LbryAnalytics.logEvent(LbryAnalytics.EVENT_EMAIL_VERIFIED, bundle);
+
if (flow == VERIFICATION_FLOW_SIGN_IN) {
final Intent resultIntent = new Intent();
resultIntent.putExtra("flow", VERIFICATION_FLOW_SIGN_IN);
@@ -206,6 +216,8 @@ public class VerificationActivity extends FragmentActivity implements SignInList
Lbryio.currentUser = user;
if (user.isIdentityVerified() && user.isRewardApproved()) {
// verified for rewards
+ LbryAnalytics.logEvent(LbryAnalytics.EVENT_REWARD_ELIGIBILITY_COMPLETED);
+
setResult(RESULT_OK);
finish();
return;
diff --git a/app/src/main/java/io/lbry/browser/model/Claim.java b/app/src/main/java/io/lbry/browser/model/Claim.java
index cab80fdc..123aa04a 100644
--- a/app/src/main/java/io/lbry/browser/model/Claim.java
+++ b/app/src/main/java/io/lbry/browser/model/Claim.java
@@ -249,6 +249,7 @@ public class Claim {
try {
claim.setClaimId(searchResultObject.getString("claimId"));
claim.setName(searchResultObject.getString("name"));
+ claim.setConfirmations(1);
if (claim.getName().startsWith("@")) {
claimUri.setChannelClaimId(claim.getClaimId());
diff --git a/app/src/main/java/io/lbry/browser/tasks/content/ChannelCreateUpdateTask.java b/app/src/main/java/io/lbry/browser/tasks/ChannelCreateUpdateTask.java
similarity index 97%
rename from app/src/main/java/io/lbry/browser/tasks/content/ChannelCreateUpdateTask.java
rename to app/src/main/java/io/lbry/browser/tasks/ChannelCreateUpdateTask.java
index 3bbd4340..8b9a2ea2 100644
--- a/app/src/main/java/io/lbry/browser/tasks/content/ChannelCreateUpdateTask.java
+++ b/app/src/main/java/io/lbry/browser/tasks/ChannelCreateUpdateTask.java
@@ -1,4 +1,4 @@
-package io.lbry.browser.tasks.content;
+package io.lbry.browser.tasks;
import android.os.AsyncTask;
import android.view.View;
@@ -14,7 +14,6 @@ import java.util.Map;
import io.lbry.browser.exceptions.ApiCallException;
import io.lbry.browser.model.Claim;
-import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
diff --git a/app/src/main/java/io/lbry/browser/tasks/content/ClaimResultHandler.java b/app/src/main/java/io/lbry/browser/tasks/ClaimResultHandler.java
similarity index 81%
rename from app/src/main/java/io/lbry/browser/tasks/content/ClaimResultHandler.java
rename to app/src/main/java/io/lbry/browser/tasks/ClaimResultHandler.java
index 9716686f..deb05445 100644
--- a/app/src/main/java/io/lbry/browser/tasks/content/ClaimResultHandler.java
+++ b/app/src/main/java/io/lbry/browser/tasks/ClaimResultHandler.java
@@ -1,4 +1,4 @@
-package io.lbry.browser.tasks.content;
+package io.lbry.browser.tasks;
import io.lbry.browser.model.Claim;
diff --git a/app/src/main/java/io/lbry/browser/tasks/lbryinc/FetchStatCountTask.java b/app/src/main/java/io/lbry/browser/tasks/lbryinc/FetchStatCountTask.java
new file mode 100644
index 00000000..1f8bb465
--- /dev/null
+++ b/app/src/main/java/io/lbry/browser/tasks/lbryinc/FetchStatCountTask.java
@@ -0,0 +1,73 @@
+package io.lbry.browser.tasks.lbryinc;
+
+import android.os.AsyncTask;
+import android.view.View;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import io.lbry.browser.exceptions.LbryioRequestException;
+import io.lbry.browser.exceptions.LbryioResponseException;
+import io.lbry.browser.utils.Helper;
+import io.lbry.browser.utils.Lbryio;
+
+public class FetchStatCountTask extends AsyncTask {
+ public static final int STAT_VIEW_COUNT = 1;
+ public static final int STAT_SUB_COUNT = 2;
+
+ private String claimId;
+ private int stat;
+ private FetchStatCountHandler handler;
+ private View progressView;
+ private Exception error;
+
+ public FetchStatCountTask(int stat, String claimId, View progressView, FetchStatCountHandler handler) {
+ this.stat = stat;
+ this.claimId = claimId;
+ this.progressView = progressView;
+ this.handler = handler;
+ }
+
+ protected void onPreExecute() {
+ Helper.setViewVisibility(progressView, View.VISIBLE);
+ }
+
+ protected Integer doInBackground(Void... params) {
+ int count = -1;
+ try {
+ if (stat != STAT_VIEW_COUNT && stat != STAT_SUB_COUNT) {
+ throw new LbryioRequestException("Invalid stat count specified.");
+ }
+
+ JSONArray results = (JSONArray)
+ Lbryio.parseResponse(Lbryio.call(
+ stat == STAT_VIEW_COUNT ? "file" : "subscription",
+ stat == STAT_VIEW_COUNT ? "view_count" : "sub_count",
+ Lbryio.buildSingleParam("claim_id", claimId),
+ Helper.METHOD_GET, null));
+ if (results.length() > 0) {
+ count = results.getInt(0);
+ }
+ } catch (ClassCastException | LbryioRequestException | LbryioResponseException | JSONException ex) {
+ error = ex;
+ }
+
+ return count;
+ }
+
+ protected void onPostExecute(Integer count) {
+ Helper.setViewVisibility(progressView, View.GONE);
+ if (handler != null) {
+ if (count > -1) {
+ handler.onSuccess(count);
+ } else {
+ handler.onError(error);
+ }
+ }
+ }
+
+ public interface FetchStatCountHandler {
+ void onSuccess(int count);
+ void onError(Exception error);
+ }
+}
diff --git a/app/src/main/java/io/lbry/browser/tasks/lbryinc/LogFileViewTask.java b/app/src/main/java/io/lbry/browser/tasks/lbryinc/LogFileViewTask.java
new file mode 100644
index 00000000..c0055a7c
--- /dev/null
+++ b/app/src/main/java/io/lbry/browser/tasks/lbryinc/LogFileViewTask.java
@@ -0,0 +1,55 @@
+package io.lbry.browser.tasks.lbryinc;
+
+import android.os.AsyncTask;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+import io.lbry.browser.exceptions.LbryioRequestException;
+import io.lbry.browser.exceptions.LbryioResponseException;
+import io.lbry.browser.model.Claim;
+import io.lbry.browser.tasks.GenericTaskHandler;
+import io.lbry.browser.utils.Lbryio;
+import okhttp3.Response;
+
+public class LogFileViewTask extends AsyncTask {
+ private String uri;
+ private Claim claim;
+ private Exception error;
+ private GenericTaskHandler handler;
+ private long timeToStart;
+
+ public LogFileViewTask(String uri, Claim claim, long timeToStart, GenericTaskHandler handler) {
+ this.uri = uri;
+ this.claim = claim;
+ this.timeToStart = timeToStart;
+ this.handler = handler;
+ }
+ protected Boolean doInBackground(Void... params) {
+ try {
+ Map options = new HashMap<>();
+ options.put("uri", uri);
+ options.put("claim_id", claim.getClaimId());
+ options.put("outpoint", String.format("%s:%d", claim.getTxid(), claim.getNout()));
+ if (timeToStart > 0) {
+ options.put("time_to_start", String.valueOf(timeToStart));
+ }
+ Lbryio.call("file", "view", options, null).close();
+ } catch (LbryioRequestException | LbryioResponseException ex) {
+ error = ex;
+ return false;
+ }
+ return true;
+ }
+ protected void onPostExecute(Boolean result) {
+ if (handler != null) {
+ if (result) {
+ handler.onSuccess();
+ } else {
+ handler.onError(error);
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/io/lbry/browser/tasks/content/LogPublishTask.java b/app/src/main/java/io/lbry/browser/tasks/lbryinc/LogPublishTask.java
similarity index 96%
rename from app/src/main/java/io/lbry/browser/tasks/content/LogPublishTask.java
rename to app/src/main/java/io/lbry/browser/tasks/lbryinc/LogPublishTask.java
index 31bc6915..f807f360 100644
--- a/app/src/main/java/io/lbry/browser/tasks/content/LogPublishTask.java
+++ b/app/src/main/java/io/lbry/browser/tasks/lbryinc/LogPublishTask.java
@@ -1,4 +1,4 @@
-package io.lbry.browser.tasks.content;
+package io.lbry.browser.tasks.lbryinc;
import android.os.AsyncTask;
diff --git a/app/src/main/java/io/lbry/browser/ui/allcontent/AllContentFragment.java b/app/src/main/java/io/lbry/browser/ui/allcontent/AllContentFragment.java
index d30c4b9c..64b9fd5b 100644
--- a/app/src/main/java/io/lbry/browser/ui/allcontent/AllContentFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/allcontent/AllContentFragment.java
@@ -38,6 +38,7 @@ import io.lbry.browser.tasks.FollowUnfollowTagTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
+import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.Predefined;
import lombok.Getter;
@@ -295,6 +296,10 @@ public class AllContentFragment extends BaseFragment implements SharedPreference
fetchClaimSearchContent(true);
}
+ Bundle bundle = new Bundle();
+ bundle.putString("tag", tag.getLowercaseName());
+ LbryAnalytics.logEvent(unfollowing ? LbryAnalytics.EVENT_TAG_UNFOLLOW : LbryAnalytics.EVENT_TAG_FOLLOW, bundle);
+
Context context = getContext();
if (context instanceof MainActivity) {
((MainActivity) context).saveSharedUserState();
@@ -359,6 +364,18 @@ public class AllContentFragment extends BaseFragment implements SharedPreference
public void onResume() {
super.onResume();
Helper.setWunderbarValue(null, getContext());
+ checkParams(false);
+
+ Context context = getContext();
+ if (context instanceof MainActivity) {
+ MainActivity activity = (MainActivity) context;
+ if (singleTagView) {
+ LbryAnalytics.setCurrentScreen(activity, "Tag", "Tag");
+ } else {
+ LbryAnalytics.setCurrentScreen(activity, "All Content", "AllContent");
+ }
+ }
+
PreferenceManager.getDefaultSharedPreferences(getContext()).registerOnSharedPreferenceChangeListener(this);
updateContentFromLinkText();
updateContentScopeLinkText();
@@ -424,7 +441,8 @@ public class AllContentFragment extends BaseFragment implements SharedPreference
@Override
public void onClaimClicked(Claim claim) {
String claimId = claim.getClaimId();
- String url = claim.getPermanentUrl();
+ String url = !Helper.isNullOrEmpty(claim.getShortUrl()) ? claim.getShortUrl() : claim.getPermanentUrl();
+
if (claim.getName().startsWith("@")) {
// channel claim
Context context = getContext();
diff --git a/app/src/main/java/io/lbry/browser/ui/channel/ChannelContentFragment.java b/app/src/main/java/io/lbry/browser/ui/channel/ChannelContentFragment.java
index 6f7a3ae0..542ee2e6 100644
--- a/app/src/main/java/io/lbry/browser/ui/channel/ChannelContentFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/channel/ChannelContentFragment.java
@@ -251,7 +251,7 @@ public class ChannelContentFragment extends Fragment implements SharedPreference
@Override
public void onClaimClicked(Claim claim) {
String claimId = claim.getClaimId();
- String url = claim.getPermanentUrl();
+ String url = !Helper.isNullOrEmpty(claim.getShortUrl()) ? claim.getShortUrl() : claim.getPermanentUrl();
if (claim.getName().startsWith("@")) {
// channel claim
Context context = getContext();
diff --git a/app/src/main/java/io/lbry/browser/ui/channel/ChannelFormFragment.java b/app/src/main/java/io/lbry/browser/ui/channel/ChannelFormFragment.java
index 6999fdc0..d546a1ec 100644
--- a/app/src/main/java/io/lbry/browser/ui/channel/ChannelFormFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/channel/ChannelFormFragment.java
@@ -42,15 +42,15 @@ import io.lbry.browser.model.Claim;
import io.lbry.browser.model.NavMenuItem;
import io.lbry.browser.model.Tag;
import io.lbry.browser.model.WalletBalance;
-import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.tasks.UpdateSuggestedTagsTask;
import io.lbry.browser.tasks.UploadImageTask;
-import io.lbry.browser.tasks.content.ChannelCreateUpdateTask;
-import io.lbry.browser.tasks.content.ClaimResultHandler;
-import io.lbry.browser.tasks.content.LogPublishTask;
+import io.lbry.browser.tasks.ChannelCreateUpdateTask;
+import io.lbry.browser.tasks.ClaimResultHandler;
+import io.lbry.browser.tasks.lbryinc.LogPublishTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
+import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.LbryUri;
import lombok.Getter;
@@ -508,6 +508,7 @@ public class ChannelFormFragment extends BaseFragment implements WalletBalanceLi
Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
+ LbryAnalytics.setCurrentScreen(activity, "Channel Form", "ChannelForm");
if (editMode) {
ActionBar actionBar = activity.getSupportActionBar();
if (actionBar != null) {
diff --git a/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java b/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java
index 7c8e4023..73f17a57 100644
--- a/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java
@@ -25,6 +25,7 @@ import com.google.android.material.tabs.TabLayoutMediator;
import java.math.BigDecimal;
import java.text.DecimalFormat;
+import java.text.NumberFormat;
import java.util.List;
import java.util.Map;
@@ -38,11 +39,13 @@ import io.lbry.browser.model.lbryinc.Subscription;
import io.lbry.browser.tasks.lbryinc.ChannelSubscribeTask;
import io.lbry.browser.tasks.ClaimListResultHandler;
import io.lbry.browser.tasks.ResolveTask;
+import io.lbry.browser.tasks.lbryinc.FetchStatCountTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.ui.controls.SolidIconView;
import io.lbry.browser.ui.following.FollowingFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
+import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.LbryUri;
import io.lbry.browser.utils.Lbryio;
import lombok.SneakyThrows;
@@ -68,12 +71,18 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen
private View buttonShare;
private View buttonTip;
private View buttonFollowUnfollow;
+ private int subCount;
private SolidIconView iconFollowUnfollow;
+ private View layoutNothingAtLocation;
+ private View layoutLoadingState;
+
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_channel, container, false);
+ layoutLoadingState = root.findViewById(R.id.channel_view_loading_state);
+ layoutNothingAtLocation = root.findViewById(R.id.container_nothing_at_location);
layoutDisplayArea = root.findViewById(R.id.channel_view_claim_display_area);
layoutResolving = root.findViewById(R.id.channel_view_loading_container);
@@ -244,12 +253,13 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen
public void onResume() {
super.onResume();
Context context = getContext();
-
Map params = getParams();
String url = params != null && params.containsKey("url") ? (String) params.get("url") : null;
Helper.setWunderbarValue(url, context);
if (context instanceof MainActivity) {
- ((MainActivity) context).addFetchChannelsListener(this);
+ MainActivity activity = (MainActivity) context;
+ activity.addFetchChannelsListener(this);
+ LbryAnalytics.setCurrentScreen(activity, "Channel", "Channel");
}
checkParams();
@@ -284,6 +294,7 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen
}
}
if (updateRequired) {
+ resetSubCount();
if (!Helper.isNullOrEmpty(url)) {
resolveUrl();
} else if (claim == null) {
@@ -302,7 +313,7 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen
ResolveTask task = new ResolveTask(url, Lbry.LBRY_TV_CONNECTION_STRING, layoutResolving, new ClaimListResultHandler() {
@Override
public void onSuccess(List claims) {
- if (claims.size() > 0) {
+ if (claims.size() > 0 && !Helper.isNullOrEmpty(claims.get(0).getClaimId())) {
claim = claims.get(0);
renderClaim();
checkOwnChannel();
@@ -320,7 +331,9 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen
}
private void renderNothingAtLocation() {
-
+ layoutLoadingState.setVisibility(View.VISIBLE);
+ layoutNothingAtLocation.setVisibility(View.VISIBLE);
+ layoutDisplayArea.setVisibility(View.INVISIBLE);
}
public void setParams(Map params) {
@@ -336,7 +349,9 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen
return;
}
+ loadSubCount();
checkIsFollowing();
+ layoutLoadingState.setVisibility(View.GONE);
layoutDisplayArea.setVisibility(View.VISIBLE);
String thumbnailUrl = claim.getThumbnailUrl();
@@ -376,6 +391,36 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen
}).attach();
}
+ private void resetSubCount() {
+ subCount = -1;
+ Helper.setViewText(textFollowerCount, null);
+ Helper.setViewVisibility(textFollowerCount, View.INVISIBLE);
+ }
+
+ private void loadSubCount() {
+ if (claim != null) {
+ FetchStatCountTask task = new FetchStatCountTask(
+ FetchStatCountTask.STAT_SUB_COUNT, claim.getClaimId(), null, new FetchStatCountTask.FetchStatCountHandler() {
+ @Override
+ public void onSuccess(int count) {
+ try {
+ String displayText = getResources().getQuantityString(R.plurals.follower_count, count, NumberFormat.getInstance().format(count));
+ Helper.setViewText(textFollowerCount, displayText);
+ Helper.setViewVisibility(textFollowerCount, View.VISIBLE);
+ } catch (IllegalStateException ex) {
+ // pass
+ }
+ }
+
+ @Override
+ public void onError(Exception error) {
+ // pass
+ }
+ });
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+ }
+
private static class ChannelPagerAdapter extends FragmentStateAdapter {
private Claim channelClaim;
public ChannelPagerAdapter(Claim channelClaim, FragmentActivity activity) {
diff --git a/app/src/main/java/io/lbry/browser/ui/channel/ChannelManagerFragment.java b/app/src/main/java/io/lbry/browser/ui/channel/ChannelManagerFragment.java
index fb4e173f..0d0207eb 100644
--- a/app/src/main/java/io/lbry/browser/ui/channel/ChannelManagerFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/channel/ChannelManagerFragment.java
@@ -40,6 +40,7 @@ import io.lbry.browser.tasks.ClaimListTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
+import io.lbry.browser.utils.LbryAnalytics;
public class ChannelManagerFragment extends BaseFragment implements ActionMode.Callback, SelectionModeListener, SdkStatusListener {
@@ -109,7 +110,9 @@ public class ChannelManagerFragment extends BaseFragment implements ActionMode.C
super.onResume();
Context context = getContext();
if (context instanceof MainActivity) {
- ((MainActivity) context).setWunderbarValue(null);
+ MainActivity activity = (MainActivity) context;
+ activity.setWunderbarValue(null);
+ LbryAnalytics.setCurrentScreen(activity, "Channel Manager", "ChannelManager");
}
if (!Lbry.SDK_READY) {
diff --git a/app/src/main/java/io/lbry/browser/ui/editorschoice/EditorsChoiceFragment.java b/app/src/main/java/io/lbry/browser/ui/editorschoice/EditorsChoiceFragment.java
index ca9b15d4..8cfa9b35 100644
--- a/app/src/main/java/io/lbry/browser/ui/editorschoice/EditorsChoiceFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/editorschoice/EditorsChoiceFragment.java
@@ -34,6 +34,7 @@ import io.lbry.browser.tasks.ClaimSearchTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
+import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.Predefined;
public class EditorsChoiceFragment extends BaseFragment {
@@ -86,7 +87,13 @@ public class EditorsChoiceFragment extends BaseFragment {
public void onResume() {
super.onResume();
- Helper.setWunderbarValue(null, getContext());
+ Context context = getContext();
+ Helper.setWunderbarValue(null, context);
+ if (context instanceof MainActivity) {
+ MainActivity activity = (MainActivity) context;
+ LbryAnalytics.setCurrentScreen(activity, "Editor's Choice", "EditorsChoice");
+ }
+
if (contentListAdapter == null || contentListAdapter.getItemCount() == 0) {
fetchClaimSearchContent();
} else {
diff --git a/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java b/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java
index 98e262f3..8a9b8fd3 100644
--- a/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java
@@ -46,6 +46,7 @@ import io.lbry.browser.listener.ChannelItemSelectionListener;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
+import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.LbryUri;
import io.lbry.browser.utils.Lbryio;
import io.lbry.browser.utils.Predefined;
@@ -327,8 +328,13 @@ public class FollowingFragment extends BaseFragment implements
public void onResume() {
super.onResume();
- Helper.setWunderbarValue(null, getContext());
- PreferenceManager.getDefaultSharedPreferences(getContext()).registerOnSharedPreferenceChangeListener(this);
+ Context context = getContext();
+ Helper.setWunderbarValue(null, context);
+ PreferenceManager.getDefaultSharedPreferences(context).registerOnSharedPreferenceChangeListener(this);
+ if (context instanceof MainActivity) {
+ MainActivity activity = (MainActivity) context;
+ LbryAnalytics.setCurrentScreen(activity, "Subscriptions", "Subscriptions");
+ }
// check if subscriptions exist
if (suggestedChannelAdapter != null) {
@@ -562,7 +568,7 @@ public class FollowingFragment extends BaseFragment implements
@Override
public void onClaimClicked(Claim claim) {
String claimId = claim.getClaimId();
- String url = claim.getPermanentUrl();
+ String url = !Helper.isNullOrEmpty(claim.getShortUrl()) ? claim.getShortUrl() : claim.getPermanentUrl();
if (claim.getName().startsWith("@")) {
// channel claim
diff --git a/app/src/main/java/io/lbry/browser/ui/search/SearchFragment.java b/app/src/main/java/io/lbry/browser/ui/search/SearchFragment.java
index e51172d1..208e8b9c 100644
--- a/app/src/main/java/io/lbry/browser/ui/search/SearchFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/search/SearchFragment.java
@@ -1,5 +1,6 @@
package io.lbry.browser.ui.search;
+import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
@@ -28,6 +29,7 @@ import io.lbry.browser.tasks.ResolveTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
+import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.LbryUri;
import lombok.Setter;
@@ -87,9 +89,15 @@ public class SearchFragment extends BaseFragment implements
public void onResume() {
super.onResume();
- Helper.setWunderbarValue(currentQuery, getContext());
- PreferenceManager.getDefaultSharedPreferences(getContext()).registerOnSharedPreferenceChangeListener(this);
+ Context context = getContext();
+ Helper.setWunderbarValue(currentQuery, context);
+ PreferenceManager.getDefaultSharedPreferences(context).registerOnSharedPreferenceChangeListener(this);
+ if (context instanceof MainActivity) {
+ MainActivity activity = (MainActivity) context;
+ LbryAnalytics.setCurrentScreen(activity, "Search", "Search");
+ }
if (!Helper.isNullOrEmpty(currentQuery)) {
+ logSearch(currentQuery);
search(currentQuery, currentFrom);
} else {
noQueryView.setVisibility(View.VISIBLE);
@@ -170,17 +178,28 @@ public class SearchFragment extends BaseFragment implements
unresolved.setValue(resolved.getValue());
unresolved.setSigningChannel(resolved.getSigningChannel());
unresolved.setUnresolved(false);
+ unresolved.setConfirmations(resolved.getConfirmations());
resultListAdapter.notifyDataSetChanged();
}
}
+ private void logSearch(String query) {
+ Bundle bundle = new Bundle();
+ bundle.putString("query", query);
+ LbryAnalytics.logEvent(LbryAnalytics.EVENT_SEARCH, bundle);
+ }
+
public void search(String query, int from) {
boolean queryChanged = checkQuery(query);
if (!queryChanged && from > 0) {
currentFrom = from;
}
+ if (queryChanged) {
+ logSearch(query);
+ }
+
searchLoading = true;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
boolean canShowMatureContent = sp.getBoolean(MainActivity.PREFERENCE_KEY_SHOW_MATURE_CONTENT, false);
diff --git a/app/src/main/java/io/lbry/browser/ui/settings/SettingsFragment.java b/app/src/main/java/io/lbry/browser/ui/settings/SettingsFragment.java
index 73104e0a..65a7377c 100644
--- a/app/src/main/java/io/lbry/browser/ui/settings/SettingsFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/settings/SettingsFragment.java
@@ -11,6 +11,7 @@ import androidx.preference.PreferenceManager;
import io.lbry.browser.MainActivity;
import io.lbry.browser.R;
+import io.lbry.browser.utils.LbryAnalytics;
public class SettingsFragment extends PreferenceFragmentCompat implements SharedPreferences.OnSharedPreferenceChangeListener {
@Override
@@ -38,7 +39,12 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared
@Override
public void onResume() {
super.onResume();
- PreferenceManager.getDefaultSharedPreferences(getContext()).registerOnSharedPreferenceChangeListener(this);
+ Context context = getContext();
+ PreferenceManager.getDefaultSharedPreferences(context).registerOnSharedPreferenceChangeListener(this);
+ if (context instanceof MainActivity) {
+ MainActivity activity = (MainActivity) context;
+ LbryAnalytics.setCurrentScreen(activity, "Settings", "Settings");
+ }
}
@Override
public void onPause() {
diff --git a/app/src/main/java/io/lbry/browser/ui/wallet/InvitesFragment.java b/app/src/main/java/io/lbry/browser/ui/wallet/InvitesFragment.java
index 6746964f..0d1a906b 100644
--- a/app/src/main/java/io/lbry/browser/ui/wallet/InvitesFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/wallet/InvitesFragment.java
@@ -41,15 +41,16 @@ import io.lbry.browser.model.lbryinc.Invitee;
import io.lbry.browser.tasks.ClaimListResultHandler;
import io.lbry.browser.tasks.ClaimListTask;
import io.lbry.browser.tasks.GenericTaskHandler;
-import io.lbry.browser.tasks.content.ChannelCreateUpdateTask;
-import io.lbry.browser.tasks.content.ClaimResultHandler;
-import io.lbry.browser.tasks.content.LogPublishTask;
+import io.lbry.browser.tasks.ChannelCreateUpdateTask;
+import io.lbry.browser.tasks.ClaimResultHandler;
+import io.lbry.browser.tasks.lbryinc.LogPublishTask;
import io.lbry.browser.tasks.lbryinc.FetchInviteStatusTask;
import io.lbry.browser.tasks.lbryinc.FetchReferralCodeTask;
import io.lbry.browser.tasks.lbryinc.InviteByEmailTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
+import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.LbryUri;
import io.lbry.browser.utils.Lbryio;
@@ -287,9 +288,14 @@ public class InvitesFragment extends BaseFragment implements SdkStatusListener,
super.onResume();
layoutAccountDriver.setVisibility(Lbryio.isSignedIn() ? View.GONE : View.VISIBLE);
+ Context context = getContext();
+ if (context instanceof MainActivity) {
+ MainActivity activity = (MainActivity) context;
+ LbryAnalytics.setCurrentScreen(activity, "Invites", "Invites");
+ }
+
fetchInviteStatus();
if (!Lbry.SDK_READY) {
- Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
activity.addSdkStatusListener(this);
diff --git a/app/src/main/java/io/lbry/browser/ui/wallet/RewardsFragment.java b/app/src/main/java/io/lbry/browser/ui/wallet/RewardsFragment.java
index b3aa0ec5..3851969e 100644
--- a/app/src/main/java/io/lbry/browser/ui/wallet/RewardsFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/wallet/RewardsFragment.java
@@ -1,6 +1,7 @@
package io.lbry.browser.ui.wallet;
import android.content.Context;
+import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.Typeface;
import android.os.AsyncTask;
@@ -13,6 +14,7 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
+import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -32,6 +34,7 @@ import io.lbry.browser.tasks.lbryinc.FetchRewardsTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
+import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.Lbryio;
public class RewardsFragment extends BaseFragment implements RewardListAdapter.RewardClickListener, SdkStatusListener {
@@ -87,8 +90,13 @@ public class RewardsFragment extends BaseFragment implements RewardListAdapter.R
checkRewardsStatus();
fetchRewards();
+ Context context = getContext();
+ if (context instanceof MainActivity) {
+ MainActivity activity = (MainActivity) context;
+ LbryAnalytics.setCurrentScreen(activity, "Rewards", "Rewards");
+ }
+
if (!Lbry.SDK_READY) {
- Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
activity.addSdkStatusListener(this);
@@ -161,9 +169,17 @@ public class RewardsFragment extends BaseFragment implements RewardListAdapter.R
linkNotInterested.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
+
+
Context context = getContext();
+
if (context instanceof MainActivity) {
- ((MainActivity) context).onBackPressed();
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
+ sp.edit().putBoolean(MainActivity.PREFERENCE_KEY_INTERNAL_REWARDS_NOT_INTERESTED, true).apply();
+
+ MainActivity activity = (MainActivity) context;
+ activity.hideFloatingRewardsValue();
+ activity.onBackPressed();
}
}
});
@@ -210,13 +226,17 @@ public class RewardsFragment extends BaseFragment implements RewardListAdapter.R
}
public void updateUnclaimedRewardsValue() {
- String accountDriverTitle = getResources().getQuantityString(
- R.plurals.available_credits,
- Lbryio.totalUnclaimedRewardAmount == 1 ? 1 : 2,
- Helper.shortCurrencyFormat(Lbryio.totalUnclaimedRewardAmount));
- double unclaimedRewardAmountUsd = Lbryio.totalUnclaimedRewardAmount * Lbryio.LBCUSDRate;
- Helper.setViewText(textAccountDriverTitle, accountDriverTitle);
- Helper.setViewText(textFreeCreditsWorth, getString(R.string.free_credits_worth, Helper.USD_CURRENCY_FORMAT.format(unclaimedRewardAmountUsd)));
+ try {
+ String accountDriverTitle = getResources().getQuantityString(
+ R.plurals.available_credits,
+ Lbryio.totalUnclaimedRewardAmount == 1 ? 1 : 2,
+ Helper.shortCurrencyFormat(Lbryio.totalUnclaimedRewardAmount));
+ double unclaimedRewardAmountUsd = Lbryio.totalUnclaimedRewardAmount * Lbryio.LBCUSDRate;
+ Helper.setViewText(textAccountDriverTitle, accountDriverTitle);
+ Helper.setViewText(textFreeCreditsWorth, getString(R.string.free_credits_worth, Helper.USD_CURRENCY_FORMAT.format(unclaimedRewardAmountUsd)));
+ } catch (IllegalStateException ex) {
+ // pass
+ }
}
@Override
diff --git a/app/src/main/java/io/lbry/browser/ui/wallet/TransactionHistoryFragment.java b/app/src/main/java/io/lbry/browser/ui/wallet/TransactionHistoryFragment.java
index 86ee9982..4076ddbb 100644
--- a/app/src/main/java/io/lbry/browser/ui/wallet/TransactionHistoryFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/wallet/TransactionHistoryFragment.java
@@ -23,6 +23,7 @@ import io.lbry.browser.model.Transaction;
import io.lbry.browser.tasks.wallet.TransactionListTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
+import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.LbryUri;
public class TransactionHistoryFragment extends BaseFragment implements TransactionListAdapter.TransactionClickListener {
@@ -77,6 +78,12 @@ public class TransactionHistoryFragment extends BaseFragment implements Transact
@Override
public void onResume() {
super.onResume();
+ Context context = getContext();
+ if (context instanceof MainActivity) {
+ MainActivity activity = (MainActivity) context;
+ LbryAnalytics.setCurrentScreen(activity, "Transaction History", "TransactionHistory");
+ }
+
if (adapter != null && adapter.getItemCount() > 0 && transactionList != null) {
transactionList.setAdapter(adapter);
}
diff --git a/app/src/main/java/io/lbry/browser/ui/wallet/WalletFragment.java b/app/src/main/java/io/lbry/browser/ui/wallet/WalletFragment.java
index 79e00c30..3475378b 100644
--- a/app/src/main/java/io/lbry/browser/ui/wallet/WalletFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/wallet/WalletFragment.java
@@ -45,6 +45,7 @@ import io.lbry.browser.tasks.wallet.WalletSendTask;
import io.lbry.browser.ui.BaseFragment;
import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.Lbry;
+import io.lbry.browser.utils.LbryAnalytics;
import io.lbry.browser.utils.LbryUri;
import io.lbry.browser.utils.Lbryio;
@@ -393,9 +394,14 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W
public void onResume() {
super.onResume();
- Helper.setWunderbarValue(null, getContext());
+ Context context = getContext();
+ Helper.setWunderbarValue(null, context);
+ if (context instanceof MainActivity) {
+ MainActivity activity = (MainActivity) context;
+ LbryAnalytics.setCurrentScreen(activity, "Wallet", "Wallet");
+ }
+
if (!Lbry.SDK_READY) {
- Context context = getContext();
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
activity.addSdkStatusListener(this);
diff --git a/app/src/main/java/io/lbry/browser/utils/LbryAnalytics.java b/app/src/main/java/io/lbry/browser/utils/LbryAnalytics.java
new file mode 100644
index 00000000..ce20980c
--- /dev/null
+++ b/app/src/main/java/io/lbry/browser/utils/LbryAnalytics.java
@@ -0,0 +1,53 @@
+package io.lbry.browser.utils;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+
+import com.google.firebase.analytics.FirebaseAnalytics;
+
+public class LbryAnalytics {
+
+ public static final String EVENT_APP_EXCEPTION = "app_exception";
+ public static final String EVENT_APP_LAUNCH = "app_launch";
+ public static final String EVENT_EMAIL_ADDED = "email_added";
+ public static final String EVENT_EMAIL_VERIFIED = "email_verified";
+ public static final String EVENT_FIRST_RUN_COMPLETED = "first_run_completed";
+ public static final String EVENT_FIRST_USER_AUTH = "first_user_auth";
+ public static final String EVENT_LBRY_NOTIFICATION_OPEN = "lbry_notification_open";
+ public static final String EVENT_LBRY_NOTIFICATION_RECEIVE = "lbry_notification_receive";
+ public static final String EVENT_OPEN_FILE_PAGE = "open_file_page";
+ public static final String EVENT_PLAY = "play";
+ public static final String EVENT_PURCHASE_URI = "purchase_uri";
+ public static final String EVENT_REWARD_ELIGIBILITY_COMPLETED = "reward_eligibility_completed";
+ public static final String EVENT_TAG_FOLLOW = "tag_follow";
+ public static final String EVENT_TAG_UNFOLLOW = "tag_unfollow";
+ public static final String EVENT_PUBLISH = "publish";
+ public static final String EVENT_CHANNEL_CREATE = "channel_create";
+ public static final String EVENT_SEARCH = "search";
+
+ private static FirebaseAnalytics analytics;
+
+ public static void init(Context context) {
+ analytics = FirebaseAnalytics.getInstance(context);
+ }
+
+ public static void setCurrentScreen(Activity activity, String name, String className) {
+ analytics.setCurrentScreen(activity, name, className);
+ }
+
+ public static void logEvent(String name) {
+ logEvent(name, null);
+ }
+
+ public static void logEvent(String name, Bundle bundle) {
+ analytics.logEvent(name, bundle);
+ }
+
+ public static void logException(String message, String exceptionName) {
+ Bundle bundle = new Bundle();
+ bundle.putString("message", message);
+ bundle.putString("name", exceptionName);
+ logEvent("app_exception", bundle);
+ }
+}
diff --git a/app/src/main/res/drawable-anydpi/ic_fullscreen.xml b/app/src/main/res/drawable-anydpi/ic_fullscreen.xml
new file mode 100644
index 00000000..b8f99968
--- /dev/null
+++ b/app/src/main/res/drawable-anydpi/ic_fullscreen.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable-anydpi/ic_fullscreen_exit.xml b/app/src/main/res/drawable-anydpi/ic_fullscreen_exit.xml
new file mode 100644
index 00000000..f8116a2e
--- /dev/null
+++ b/app/src/main/res/drawable-anydpi/ic_fullscreen_exit.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable-hdpi/ic_fullscreen.png b/app/src/main/res/drawable-hdpi/ic_fullscreen.png
new file mode 100644
index 00000000..10decc15
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_fullscreen.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_fullscreen_exit.png b/app/src/main/res/drawable-hdpi/ic_fullscreen_exit.png
new file mode 100644
index 00000000..a43ff782
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_fullscreen_exit.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_fullscreen.png b/app/src/main/res/drawable-mdpi/ic_fullscreen.png
new file mode 100644
index 00000000..baed2aa2
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_fullscreen.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_fullscreen_exit.png b/app/src/main/res/drawable-mdpi/ic_fullscreen_exit.png
new file mode 100644
index 00000000..b4a402c2
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_fullscreen_exit.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_fullscreen.png b/app/src/main/res/drawable-xhdpi/ic_fullscreen.png
new file mode 100644
index 00000000..7f3b8676
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_fullscreen.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_fullscreen_exit.png b/app/src/main/res/drawable-xhdpi/ic_fullscreen_exit.png
new file mode 100644
index 00000000..9c052625
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_fullscreen_exit.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_fullscreen.png b/app/src/main/res/drawable-xxhdpi/ic_fullscreen.png
new file mode 100644
index 00000000..ff166dd0
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_fullscreen.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_fullscreen_exit.png b/app/src/main/res/drawable-xxhdpi/ic_fullscreen_exit.png
new file mode 100644
index 00000000..60c521bb
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_fullscreen_exit.png differ
diff --git a/app/src/main/res/layout/activity_file_view.xml b/app/src/main/res/layout/activity_file_view.xml
index f2f7109c..93619cd0 100644
--- a/app/src/main/res/layout/activity_file_view.xml
+++ b/app/src/main/res/layout/activity_file_view.xml
@@ -4,9 +4,9 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/pageBackground"
- android:fitsSystemWindows="true">
+ android:background="@color/pageBackground">
+ android:visibility="invisible">
-
+
+
+
+
+
+
+
-
+ android:layout_height="match_parent"
+ app:controller_layout_id="@layout/exo_playback_control_view"/>
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/exo_playback_control_view.xml b/app/src/main/res/layout/exo_playback_control_view.xml
new file mode 100644
index 00000000..c3adccfb
--- /dev/null
+++ b/app/src/main/res/layout/exo_playback_control_view.xml
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_channel.xml b/app/src/main/res/layout/fragment_channel.xml
index 36979755..3fd3504d 100644
--- a/app/src/main/res/layout/fragment_channel.xml
+++ b/app/src/main/res/layout/fragment_channel.xml
@@ -30,6 +30,8 @@
android:textSize="16sp"
android:textFontWeight="300" />
+
+
#CC000000
#F4E866
+ #33000000
+ @color/nextLbryGreen
+ @color/nextLbryGreen
+ @color/nextLbryGreenSemiTransparent
+
#EEEEEE
#555555
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 71ea513c..d47f47c1 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -14,6 +14,11 @@
#CC000000
#F4E866
+ #33000000
+ @color/nextLbryGreen
+ @color/nextLbryGreen
+ @color/nextLbryGreenSemiTransparent
+
#222222
#AAAAAA
#333333
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f0406d18..ec5bf9a8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -59,15 +59,28 @@
Loading decentralized data...
Related Content
Share LBRY content
-
+ View
+ Play
+
+ - %1$s view
+ - %1$s views
+
Unsupported Content
Sorry, we are unable to display this content in the app. You can find the file named %1$s in your downloads folder.
+ There\'s nothing at this location.
+ Publish something here
+ This content cannot be accessed at this time. Please try again later.
+ 00:00
There\'s nothing here yet.\nPlease check back later.
Content
Website
reposted
+
+ - %1$s follower
+ - %1$s followers
+
Content & User interface