Native rewrite #878

Merged
akinwale merged 65 commits from native-rewrite into master 2020-05-23 08:49:00 +02:00
46 changed files with 1187 additions and 90 deletions
Showing only changes of commit 6ac4a25715 - Show all commits

View file

@ -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'

View file

@ -19,6 +19,19 @@
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_lbry" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/lbryGreen" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="@string/default_notification_channel_id"/>
<meta-data android:name="wakelock" android:value="0"/>
<activity
android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|screenLayout"
android:name=".MainActivity"
@ -58,6 +71,14 @@
android:parentActivityName=".MainActivity"
android:supportsPictureInPicture="true"
android:theme="@style/AppTheme.NoActionBarBlack" />
</application>
<service
android:name="io.lbry.browser.LbrynetMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
</manifest>

View file

@ -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
}
};
}

View file

@ -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();
}

View file

@ -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<String, String> 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<String> getEnabledTypes() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
List<String> enabledTypes = new ArrayList<String>();
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;
}
}

View file

@ -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<String, Fragment> openNavFragments;
private static final Map<Class, Integer> 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<InstanceIdResult>() {
@Override
public void onComplete(Task<InstanceIdResult> 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);
}

View file

@ -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;

View file

@ -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());

View file

@ -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;

View file

@ -1,4 +1,4 @@
package io.lbry.browser.tasks.content;
package io.lbry.browser.tasks;
import io.lbry.browser.model.Claim;

View file

@ -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<Void, Void, Integer> {
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);
}
}

View file

@ -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<Void, Void, Boolean> {
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<String, String> 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);
}
}
}
}

View file

@ -1,4 +1,4 @@
package io.lbry.browser.tasks.content;
package io.lbry.browser.tasks.lbryinc;
import android.os.AsyncTask;

View file

@ -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();

View file

@ -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();

View file

@ -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) {

View file

@ -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<String, Object> 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<Claim> 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<String, Object> 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) {

View file

@ -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) {

View file

@ -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 {

View file

@ -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

View file

@ -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);

View file

@ -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() {

View file

@ -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);

View file

@ -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

View file

@ -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);
}

View file

@ -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);

View file

@ -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);
}
}

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF"
android:alpha="0.8">
<path
android:fillColor="#FF000000"
android:pathData="M7,14L5,14v5h5v-2L7,17v-3zM5,10h2L7,7h3L10,5L5,5v5zM17,17h-3v2h5v-5h-2v3zM14,5v2h3v3h2L19,5h-5z"/>
</vector>

View file

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF"
android:alpha="0.8">
<path
android:fillColor="#FF000000"
android:pathData="M5,16h3v3h2v-5L5,14v2zM8,8L5,8v2h5L10,5L8,5v3zM14,19h2v-3h3v-2h-5v5zM16,8L16,5h-2v5h5L19,8h-3z"/>
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

View file

@ -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">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/file_view_global_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
@ -42,19 +42,60 @@
android:layout_weight="10"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible">
android:visibility="invisible">
<RelativeLayout
android:id="@+id/file_view_media_container"
android:background="@color/mediaContainerBackground"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3.25">
<!--RelativeLayout
<RelativeLayout
android:id="@+id/file_view_media_meta_container"
android:clickable="true"
android:foreground="?attr/selectableItemBackground"
android:layout_width="match_parent"
android:layout_height="match_parent">
</RelativeLayout-->
<ImageView
android:id="@+id/file_view_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/file_view_main_action_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/play" />
<LinearLayout
android:id="@+id/file_view_fee_container"
android:background="@drawable/bg_stream_cost"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentRight="true"
android:layout_marginTop="4dp"
android:layout_marginRight="4dp"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:paddingLeft="6dp"
android:paddingRight="7dp"
android:visibility="gone">
<io.lbry.browser.ui.controls.SolidIconView
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_gravity="center_vertical"
android:textSize="8dp"
android:text="@string/fa_coins" />
<TextView
android:id="@+id/file_view_fee"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="1dp"
android:fontFamily="@font/inter"
android:textSize="14sp"
android:textFontWeight="300" />
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:id="@+id/file_view_exoplayer_container"
@ -65,12 +106,8 @@
<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/file_view_exoplayer_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.exoplayer2.ui.PlayerControlView
android:id="@+id/file_view_exoplayer_control_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" />
android:layout_height="match_parent"
app:controller_layout_id="@layout/exo_playback_control_view"/>
</RelativeLayout>
<RelativeLayout
@ -155,7 +192,7 @@
android:id="@+id/file_view_view_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="24dp"
android:layout_marginRight="16dp"
android:fontFamily="@font/inter"
android:textSize="12sp"
android:textFontWeight="300"

View file

@ -0,0 +1,41 @@
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container_nothing_at_location"
android:background="@color/pageBackground"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:padding="36dp">
<ImageView
android:layout_gravity="center_horizontal"
android:layout_width="160dp"
android:layout_height="300dp"
android:adjustViewBounds="true"
android:src="@drawable/gerbil_happy" />
<TextView
android:text="@string/nothing_at_this_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_gravity="center_horizontal"
android:fontFamily="@font/inter"
android:textSize="16sp"
android:textAlignment="center" />
<com.google.android.material.button.MaterialButton
android:id="@+id/nothing_at_location_publish_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="24dp"
android:fontFamily="@font/inter"
android:textSize="14sp"
android:text="@string/publish_something_here"
android:textFontWeight="300"
android:visibility="gone" />
</LinearLayout>
</RelativeLayout>

View file

@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/playerControlsBackground"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageButton
android:id="@id/exo_play"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_centerInParent="true"
style="@style/ExoMediaButton.Play" />
<ImageButton
android:id="@id/exo_pause"
android:layout_width="128dp"
android:layout_height="128dp"
android:layout_centerInParent="true"
style="@style/ExoMediaButton.Pause" />
<ProgressBar
android:id="@+id/player_buffering_progress"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_centerInParent="true"
android:visibility="gone" />
<RelativeLayout
android:id="@+id/player_toggle_full_screen"
android:clickable="true"
android:background="?attr/selectableItemBackground"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true">
<ImageView
android:id="@+id/player_image_full_screen_toggle"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_centerInParent="true"
android:src="@drawable/ic_fullscreen"
android:tint="@color/white" />
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_alignParentBottom="true"
android:layout_toLeftOf="@id/player_toggle_full_screen"
android:paddingLeft="16dp"
android:paddingRight="4dp">
<TextView
android:id="@+id/player_duration_elapsed"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:fontFamily="@font/inter"
android:text="@string/zero_duration"
android:textColor="@color/white"
android:textSize="14sp" />
<com.google.android.exoplayer2.ui.DefaultTimeBar
android:id="@id/exo_progress"
android:layout_toLeftOf="@id/player_duration_total"
android:layout_toRightOf="@id/player_duration_elapsed"
android:layout_width="match_parent"
android:layout_height="24dp"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:layout_centerVertical="true"
app:scrubber_color="@color/scrubberColor"
app:played_color="@color/playedColor"
app:buffered_color="@color/bufferedColor" />
<TextView
android:id="@+id/player_duration_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:fontFamily="@font/inter"
android:text="@string/zero_duration"
android:textColor="@color/white"
android:textSize="14sp" />
</RelativeLayout>
</RelativeLayout>

View file

@ -30,6 +30,8 @@
android:textSize="16sp"
android:textFontWeight="300" />
</LinearLayout>
<include layout="@layout/container_nothing_at_location" />
</RelativeLayout>
<LinearLayout
@ -73,7 +75,8 @@
android:visibility="invisible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginTop="2dp"
android:layout_marginBottom="2dp"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:paddingTop="2dp"

View file

@ -14,6 +14,11 @@
<color name="channelCoverBackground">#CC000000</color>
<color name="costBackground">#F4E866</color>
<color name="playerControlsBackground">#33000000</color>
<color name="scrubberColor">@color/nextLbryGreen</color>
<color name="playedColor">@color/nextLbryGreen</color>
<color name="bufferedColor">@color/nextLbryGreenSemiTransparent</color>
<!-- At some point, these colours have to be renamed -->
<color name="darkForeground">#EEEEEE</color>
<color name="lightForeground">#555555</color>

View file

@ -14,6 +14,11 @@
<color name="channelCoverBackground">#CC000000</color>
<color name="costBackground">#F4E866</color>
<color name="playerControlsBackground">#33000000</color>
<color name="scrubberColor">@color/nextLbryGreen</color>
<color name="playedColor">@color/nextLbryGreen</color>
<color name="bufferedColor">@color/nextLbryGreenSemiTransparent</color>
<color name="darkForeground">#222222</color>
<color name="lightForeground">#AAAAAA</color>
<color name="foreground">#333333</color>

View file

@ -59,15 +59,28 @@
<string name="loading_decentralized_data">Loading decentralized data...</string>
<string name="related_content">Related Content</string>
<string name="share_lbry_content">Share LBRY content</string>
<string name="view">View</string>
<string name="play">Play</string>
<plurals name="view_count">
<item quantity="one">%1$s view</item>
<item quantity="other">%1$s views</item>
</plurals>
<string name="unsupported_content">Unsupported Content</string>
<string name="unsupported_content_desc">Sorry, we are unable to display this content in the app. You can find the file named %1$s in your downloads folder.</string>
<string name="nothing_at_this_location">There\'s nothing at this location.</string>
<string name="publish_something_here">Publish something here</string>
<string name="cannot_view_claim">This content cannot be accessed at this time. Please try again later.</string>
<string name="zero_duration">00:00</string>
<!-- Channel view -->
<string name="no_channel_info">There\'s nothing here yet.\nPlease check back later.</string>
<string name="content">Content</string>
<string name="website">Website</string>
<string name="reposted">reposted</string>
<plurals name="follower_count">
<item quantity="one">%1$s follower</item>
<item quantity="other">%1$s followers</item>
</plurals>
<!-- Settings -->
<string name="user_interface">Content &amp; User interface</string>