# Conflicts:
#	app/src/main/java/io/lbry/browser/MainActivity.java
This commit is contained in:
Javi Rueda 2020-09-21 13:35:51 +02:00
commit f5c1068052
17 changed files with 966 additions and 642 deletions

View file

@ -14,14 +14,15 @@ android {
applicationId "io.lbry.browser"
minSdkVersion 21
targetSdkVersion 29
versionCode 1602
versionName "0.16.2"
versionCode 1604
versionName "0.16.4"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'lib/x86_64/darwin/libscrypt.dylib'
}
productFlavors {

View file

@ -65,6 +65,7 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
@ -113,6 +114,8 @@ import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.ssl.SSLParameters;
import io.lbry.browser.adapter.NavigationMenuAdapter;
import io.lbry.browser.adapter.NotificationListAdapter;
import io.lbry.browser.adapter.UrlSuggestionListAdapter;
@ -171,9 +174,10 @@ import io.lbry.browser.ui.other.AboutFragment;
import io.lbry.browser.ui.publish.PublishFormFragment;
import io.lbry.browser.ui.publish.PublishFragment;
import io.lbry.browser.ui.publish.PublishesFragment;
import io.lbry.browser.ui.findcontent.SearchFragment;
import io.lbry.browser.ui.other.SettingsFragment;
import io.lbry.browser.ui.findcontent.AllContentFragment;
import io.lbry.browser.ui.findcontent.SearchFragment;
import io.lbry.browser.ui.findcontent.ShuffleFragment;
import io.lbry.browser.ui.other.SettingsFragment;
import io.lbry.browser.ui.wallet.InvitesFragment;
import io.lbry.browser.ui.wallet.RewardsFragment;
import io.lbry.browser.ui.wallet.WalletFragment;
@ -191,11 +195,14 @@ import lombok.Setter;
import lombok.SneakyThrows;
import okhttp3.OkHttpClient;
public class MainActivity extends AppCompatActivity implements SdkStatusListener {
public class MainActivity extends AppCompatActivity implements SdkStatusListener, SharedPreferences.OnSharedPreferenceChangeListener {
private static final String CHANNEL_ID_PLAYBACK = "io.lbry.browser.LBRY_PLAYBACK_CHANNEL";
private static final int PLAYBACK_NOTIFICATION_ID = 3;
private static final String SPECIAL_URL_PREFIX = "lbry://?";
private static final int REMOTE_NOTIFICATION_REFRESH_TTL = 300000; // 5 minutes
public static final int SOURCE_NOW_PLAYING_FILE = 1;
public static final int SOURCE_NOW_PLAYING_SHUFFLE = 2;
public static MainActivity instance;
private boolean shuttingDown;
@ -214,6 +221,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public static boolean playerReassigned;
public CastContext castContext;
public static CastPlayer castPlayer;
public static int nowPlayingSource;
public static Claim nowPlayingClaim;
public static String nowPlayingClaimUrl;
public static boolean startingFilePickerActivity = false;
@ -242,6 +250,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
fragmentClassNavIdMap.put(FollowingFragment.class, NavMenuItem.ID_ITEM_FOLLOWING);
fragmentClassNavIdMap.put(EditorsChoiceFragment.class, NavMenuItem.ID_ITEM_EDITORS_CHOICE);
fragmentClassNavIdMap.put(AllContentFragment.class, NavMenuItem.ID_ITEM_ALL_CONTENT);
fragmentClassNavIdMap.put(ShuffleFragment.class, NavMenuItem.ID_ITEM_SHUFFLE);
fragmentClassNavIdMap.put(PublishFragment.class, NavMenuItem.ID_ITEM_NEW_PUBLISH);
fragmentClassNavIdMap.put(ChannelManagerFragment.class, NavMenuItem.ID_ITEM_CHANNELS);
@ -292,6 +301,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public static final String PREFERENCE_KEY_DARK_MODE = "io.lbry.browser.preference.userinterface.DarkMode";
public static final String PREFERENCE_KEY_SHOW_MATURE_CONTENT = "io.lbry.browser.preference.userinterface.ShowMatureContent";
public static final String PREFERENCE_KEY_SHOW_URL_SUGGESTIONS = "io.lbry.browser.preference.userinterface.UrlSuggestions";
public static final String PREFERENCE_KEY_MINI_PLAYER_BOTTOM_MARGIN = "io.lbry.browser.preference.userinterface.MiniPlayerBottomMargin";
public static final String PREFERENCE_KEY_NOTIFICATION_COMMENTS = "io.lbry.browser.preference.notifications.Comments";
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";
@ -372,6 +382,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
private static final int STARTUP_STAGE_NEW_INSTALL_DONE = 5;
private static final int STARTUP_STAGE_SUBSCRIPTIONS_LOADED = 6;
private static final int STARTUP_STAGE_SUBSCRIPTIONS_RESOLVED = 7;
private static final int DEFAULT_MINI_PLAYER_MARGIN = 4;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -401,6 +412,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
updateMiniPlayerMargins();
playerNotificationManager = new PlayerNotificationManager(
this, LbrynetService.NOTIFICATION_CHANNEL_ID, PLAYBACK_NOTIFICATION_ID, new PlayerNotificationDescriptionAdapter());
@ -522,7 +535,11 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
public void onClick(View view) {
if (nowPlayingClaim != null && !Helper.isNullOrEmpty(nowPlayingClaimUrl)) {
hideNotifications();
openFileUrl(nowPlayingClaimUrl);
if (nowPlayingSource == SOURCE_NOW_PLAYING_SHUFFLE) {
openFragment(ShuffleFragment.class, true, NavMenuItem.ID_ITEM_SHUFFLE);
} else {
openFileUrl(nowPlayingClaimUrl);
}
}
}
});
@ -559,6 +576,17 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
});
}
private void updateMiniPlayerMargins() {
// mini-player bottom margin setting
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
int miniPlayerBottomMargin = Helper.parseInt(
sp.getString(PREFERENCE_KEY_MINI_PLAYER_BOTTOM_MARGIN, String.valueOf(DEFAULT_MINI_PLAYER_MARGIN)), DEFAULT_MINI_PLAYER_MARGIN);
ConstraintLayout.LayoutParams lp = (ConstraintLayout.LayoutParams) findViewById(R.id.global_now_playing_card).getLayoutParams();
int scaledMiniPlayerMargin = getScaledValue(DEFAULT_MINI_PLAYER_MARGIN);
int scaledMiniPlayerBottomMargin = getScaledValue(miniPlayerBottomMargin);
lp.setMargins(scaledMiniPlayerMargin, 0, scaledMiniPlayerMargin, scaledMiniPlayerBottomMargin);
}
public boolean isDarkMode() {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this);
return sp.getBoolean(PREFERENCE_KEY_DARK_MODE, false);
@ -589,6 +617,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
specialRouteFragmentClassMap.put("settings", SettingsFragment.class);
specialRouteFragmentClassMap.put("subscription", FollowingFragment.class);
specialRouteFragmentClassMap.put("subscriptions", FollowingFragment.class);
specialRouteFragmentClassMap.put("surf", ShuffleFragment.class);
specialRouteFragmentClassMap.put("wallet", WalletFragment.class);
specialRouteFragmentClassMap.put("discover", FollowingFragment.class);
}
@ -744,6 +773,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
case NavMenuItem.ID_ITEM_ALL_CONTENT:
openFragment(AllContentFragment.class, true, NavMenuItem.ID_ITEM_ALL_CONTENT);
break;
case NavMenuItem.ID_ITEM_SHUFFLE:
openFragment(ShuffleFragment.class, true, NavMenuItem.ID_ITEM_SHUFFLE);
break;
case NavMenuItem.ID_ITEM_NEW_PUBLISH:
openFragment(PublishFragment.class, true, NavMenuItem.ID_ITEM_NEW_PUBLISH);
@ -958,7 +990,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
fragment instanceof LibraryFragment ||
fragment instanceof SearchFragment;
findViewById(R.id.floating_balance_main_container).setVisibility(!canShowFloatingBalance || inFullscreenMode ? View.INVISIBLE : View.VISIBLE);
if (!(fragment instanceof FileViewFragment) && !inFullscreenMode) {
if (!(fragment instanceof FileViewFragment) && !(fragment instanceof ShuffleFragment) && !inFullscreenMode) {
findViewById(R.id.global_now_playing_card).setVisibility(View.VISIBLE);
}
/*if (!Lbry.SDK_READY && !inFullscreenMode) {
@ -1075,6 +1107,13 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
@Override
public void onError(Exception ex) { }
protected void onSetSSLParameters(SSLParameters sslParameters) {
// don't call setEndpointIdentificationAlgorithm for API level < 24
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
sslParameters.setEndpointIdentificationAlgorithm("HTTPS");
}
}
};
webSocketClient.connect();
}
@ -1083,7 +1122,10 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
@Override
protected void onResume() {
super.onResume();
PreferenceManager.getDefaultSharedPreferences(this).registerOnSharedPreferenceChangeListener(this);
checkWebSocketClient();
updateMiniPlayerMargins();
enteringPIPMode = false;
applyNavbarSigninPadding();
@ -1133,6 +1175,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
@Override
protected void onPause() {
PreferenceManager.getDefaultSharedPreferences(this).unregisterOnSharedPreferenceChangeListener(this);
if (!enteringPIPMode && !inPictureInPictureMode && appPlayer != null && !isBackgroundPlaybackEnabled()) {
appPlayer.setPlayWhenReady(false);
}
@ -1745,6 +1788,13 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
}
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
if (PREFERENCE_KEY_MINI_PLAYER_BOTTOM_MARGIN.equalsIgnoreCase(key)) {
updateMiniPlayerMargins();
}
}
private class PlayerNotificationDescriptionAdapter implements PlayerNotificationManager.MediaDescriptionAdapter {
@Override
@ -2907,7 +2957,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
findContentGroup.setItems(Arrays.asList(
new NavMenuItem(NavMenuItem.ID_ITEM_FOLLOWING, R.string.fa_heart, R.string.following, "Following", context),
new NavMenuItem(NavMenuItem.ID_ITEM_EDITORS_CHOICE, R.string.fa_star, R.string.editors_choice, "EditorsChoice", context),
new NavMenuItem(NavMenuItem.ID_ITEM_ALL_CONTENT, R.string.fa_globe_americas, R.string.all_content, "AllContent", context)
new NavMenuItem(NavMenuItem.ID_ITEM_ALL_CONTENT, R.string.fa_globe_americas, R.string.all_content, "AllContent", context),
new NavMenuItem(NavMenuItem.ID_ITEM_SHUFFLE, R.string.fa_random, R.string.shuffle, "Shuffle",context)
));
yourContentGroup.setItems(Arrays.asList(

View file

@ -20,6 +20,7 @@ public class NavMenuItem {
public static final int ID_ITEM_FOLLOWING = 101;
public static final int ID_ITEM_EDITORS_CHOICE = 102;
public static final int ID_ITEM_ALL_CONTENT = 103;
public static final int ID_ITEM_SHUFFLE = 104;
// Your Content
public static final int ID_ITEM_CHANNELS = 201;

View file

@ -51,8 +51,8 @@ public class CommentListTask extends AsyncTask<Void, Void, List<Comment>> {
options.put("skip_validation", true);
options.put("visible", true);
JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_COMMENT_LIST, options);
android.util.Log.d("LbryMain", result.toString(2));
JSONArray items = result.getJSONArray("items");
List<Comment> children = new ArrayList<>();
@ -78,6 +78,7 @@ public class CommentListTask extends AsyncTask<Void, Void, List<Comment>> {
}
} catch (Exception ex) {
error = ex;
android.util.Log.d("LbryMain", ex.toString(), ex);
}
return comments;
}

View file

@ -227,6 +227,8 @@ public class ChannelContentFragment extends Fragment implements DownloadActionLi
null,
getContentSortOrder(),
contentReleaseTime,
0,
0,
currentClaimSearchPage == 0 ? 1 : currentClaimSearchPage,
Helper.CONTENT_PAGE_SIZE);
}

View file

@ -414,6 +414,8 @@ public class AllContentFragment extends BaseFragment implements DownloadActionLi
null,
getContentSortOrder(),
contentReleaseTime,
0,
0,
currentClaimSearchPage == 0 ? 1 : currentClaimSearchPage,
Helper.CONTENT_PAGE_SIZE);
}

View file

@ -9,7 +9,6 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.graphics.Color;
import android.graphics.Outline;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
@ -37,7 +36,6 @@ import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.AppCompatSpinner;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import androidx.core.widget.NestedScrollView;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager;
@ -167,7 +165,7 @@ public class FileViewFragment extends BaseFragment implements
WalletBalanceListener {
private static final int RELATED_CONTENT_SIZE = 16;
private static final String DEFAULT_PLAYBACK_SPEED = "1x";
private static final String CDN_PREFIX = "https://cdn.lbryplayer.xyz";
public static final String CDN_PREFIX = "https://cdn.lbryplayer.xyz";
private PlayerControlView castControlView;
private Player currentPlayer;
@ -609,7 +607,7 @@ public class FileViewFragment extends BaseFragment implements
}
}
if (!Helper.isNullOrEmpty(lbryFile.getStreamingUrl()) && !Lbryio.isSignedIn()) {
if (!Helper.isNullOrEmpty(lbryFile.getStreamingUrl()) && (!claim.isFree() || !Lbryio.isSignedIn())) {
return lbryFile.getStreamingUrl();
}
}
@ -741,6 +739,13 @@ public class FileViewFragment extends BaseFragment implements
}
}
public void onPause() {
if (MainActivity.appPlayer != null) {
MainActivity.nowPlayingSource = MainActivity.SOURCE_NOW_PLAYING_FILE;
}
super.onPause();
}
public void onStop() {
super.onStop();
Context context = getContext();
@ -1874,7 +1879,7 @@ public class FileViewFragment extends BaseFragment implements
}
private void handleMainActionForClaim() {
if (claim.isPlayable() && Lbryio.isSignedIn()) {
if (claim.isPlayable() && claim.isFree() && Lbryio.isSignedIn()) {
// always use lbry.tv streaming when signed in and playabble
startTimeMillis = System.currentTimeMillis();
showExoplayerView();
@ -2781,7 +2786,7 @@ public class FileViewFragment extends BaseFragment implements
}
}
private static class StreamLoadErrorPolicy extends DefaultLoadErrorHandlingPolicy {
public static class StreamLoadErrorPolicy extends DefaultLoadErrorHandlingPolicy {
@Override
public long getRetryDelayMsFor(int dataType, long loadDurationMs, IOException exception, int errorCount) {
return exception instanceof ParserException

View file

@ -434,6 +434,8 @@ public class FollowingFragment extends BaseFragment implements
null,
getContentSortOrder(),
contentReleaseTime,
0,
0,
currentClaimSearchPage == 0 ? 1 : currentClaimSearchPage,
Helper.CONTENT_PAGE_SIZE);
}

View file

@ -0,0 +1,748 @@
package io.lbry.browser.ui.findcontent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceManager;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory;
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.Util;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import io.lbry.browser.MainActivity;
import io.lbry.browser.R;
import io.lbry.browser.exceptions.LbryUriException;
import io.lbry.browser.model.Claim;
import io.lbry.browser.model.lbryinc.Reward;
import io.lbry.browser.tasks.BufferEventTask;
import io.lbry.browser.tasks.GenericTaskHandler;
import io.lbry.browser.tasks.claim.ClaimSearchResultHandler;
import io.lbry.browser.tasks.claim.ClaimSearchTask;
import io.lbry.browser.tasks.lbryinc.ClaimRewardTask;
import io.lbry.browser.tasks.lbryinc.LogFileViewTask;
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;
public class ShuffleFragment extends BaseFragment {
private static final int PAGE_SIZE = 50;
private int currentClaimSearchPage;
private int playlistIndex;
private Claim current;
private List<Claim> playlist;
private long sessionStart;
private ProgressBar surfModeLoading;
private TextView textTitle;
private TextView textPublisher;
private Player player;
private long elapsedDuration = 0;
private long totalDuration = 0;
private boolean elapsedPlaybackScheduled;
private ScheduledExecutorService elapsedPlaybackScheduler;
private boolean playbackStarted;
private long startTimeMillis;
private boolean isPlaying;
private boolean newPlayerCreated;
private String currentUrl;
private Player.EventListener playerListener;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_shuffle, container, false);
surfModeLoading = root.findViewById(R.id.shuffle_loading);
textTitle = root.findViewById(R.id.shuffle_content_title);
textPublisher = root.findViewById(R.id.shuffle_content_publisher);
playerListener = new Player.EventListener() {
@Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (playbackState == Player.STATE_READY) {
elapsedDuration = MainActivity.appPlayer.getCurrentPosition();
totalDuration = MainActivity.appPlayer.getDuration() < 0 ? 0 : MainActivity.appPlayer.getDuration();
if (!playbackStarted) {
logPlay(currentUrl, startTimeMillis);
playbackStarted = true;
isPlaying = true;
}
renderTotalDuration();
scheduleElapsedPlayback();
hideBuffering();
} else if (playbackState == Player.STATE_BUFFERING) {
Context ctx = getContext();
boolean sendBufferingEvents = true;
if (ctx != null) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(ctx);
sendBufferingEvents = sp.getBoolean(MainActivity.PREFERENCE_KEY_SEND_BUFFERING_EVENTS, true);
}
if (MainActivity.appPlayer != null && MainActivity.appPlayer.getCurrentPosition() > 0 && sendBufferingEvents) {
// we only want to log a buffer event after the media has already started playing
String mediaSourceUrl = getStreamingUrl();
long duration = MainActivity.appPlayer.getDuration();
long position = MainActivity.appPlayer.getCurrentPosition();
// TODO: Determine a hash for the userId
String userIdHash = Helper.SHA256(Lbryio.currentUser != null ? String.valueOf(Lbryio.currentUser.getId()) : "0");
if (mediaSourceUrl.startsWith(FileViewFragment.CDN_PREFIX)) {
BufferEventTask bufferEvent = new BufferEventTask(current.getPermanentUrl(), duration, position, 1, userIdHash);
bufferEvent.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR);
}
}
showBuffering();
} else if (playbackState == Player.STATE_ENDED) {
playNextClaim();
} else {
hideBuffering();
}
}
};
Context context = getContext();
PlayerView playerView = root.findViewById(R.id.shuffle_exoplayer_view);
playerView.setOnTouchListener(new SwipeListener(playerView, context) {
@Override
public void onSwipeLeft() { playNextClaim(); }
@Override
public void onSwipeRight() { playPreviousClaim(); }
});
root.findViewById(R.id.shuffle_share_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (current != null) {
try {
String shareUrl = LbryUri.parse(
!Helper.isNullOrEmpty(current.getCanonicalUrl()) ? current.getCanonicalUrl() :
(!Helper.isNullOrEmpty(current.getShortUrl()) ? current.getShortUrl() : current.getPermanentUrl())).toTvString();
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setType("text/plain");
shareIntent.putExtra(Intent.EXTRA_TEXT, shareUrl);
MainActivity.startingShareActivity = true;
Intent shareUrlIntent = Intent.createChooser(shareIntent, getString(R.string.share_lbry_content));
shareUrlIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(shareUrlIntent);
} catch (LbryUriException ex) {
// pass
}
}
}
});
root.setOnTouchListener(new SwipeListener(root, context) {
@Override
public void onSwipeLeft() { playNextClaim(); }
@Override
public void onSwipeRight() { playPreviousClaim(); }
});
return root;
}
private String getStreamingUrl() {
return current != null ? String.format("https://cdn.lbryplayer.xyz/content/claims/%s/%s/stream", current.getName(), current.getClaimId()) : "";
}
private Map<String, Object> buildContentOptions() {
Context context = getContext();
boolean canShowMatureContent = false;
if (context != null) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
canShowMatureContent = sp.getBoolean(MainActivity.PREFERENCE_KEY_SHOW_MATURE_CONTENT, false);
}
return Lbry.buildClaimSearchOptions(
Claim.TYPE_STREAM,
canShowMatureContent ? null : new ArrayList<>(Predefined.MATURE_TAGS),
null/*contentChannelIds*/,
Arrays.asList(Claim.ORDER_BY_TRENDING_GROUP),
121, // 2 minutes or less
1,
currentClaimSearchPage == 0 ? 1 : currentClaimSearchPage,
PAGE_SIZE);
}
public void onStart() {
super.onStart();
MainActivity activity = (MainActivity) getContext();
if (activity != null) {
activity.hideFloatingWalletBalance();
}
}
public void onResume() {
super.onResume();
sessionStart = System.currentTimeMillis();
MainActivity activity = (MainActivity) getContext();
if (activity != null) {
LbryAnalytics.setCurrentScreen(activity, "Shuffle", "Shuffle");
}
if (MainActivity.appPlayer != null && MainActivity.nowPlayingSource != MainActivity.SOURCE_NOW_PLAYING_SHUFFLE) {
MainActivity.appPlayer.setPlayWhenReady(false);
}
if (playlist == null) {
loadContent();
} else {
if (current != null) {
playbackCurrentClaim();
} else {
startPlaylist();
}
}
}
public void onPause() {
if (MainActivity.appPlayer != null && MainActivity.appPlayer.isPlaying()) {
MainActivity.nowPlayingSource = MainActivity.SOURCE_NOW_PLAYING_SHUFFLE;
}
super.onPause();
}
public void onStop() {
long sessionDuration = System.currentTimeMillis() - sessionStart;
if (sessionStart > 0 && sessionDuration > 0) {
Bundle bundle = new Bundle();
bundle.putLong("duration_ms", sessionDuration);
bundle.putInt("duration", Double.valueOf(Math.ceil(sessionDuration / 1000.0)).intValue());
LbryAnalytics.logEvent(LbryAnalytics.EVENT_SHUFFLE_SESSION, bundle);
}
sessionStart = 0;
MainActivity activity = (MainActivity) getContext();
if (activity != null) {
activity.hideFloatingWalletBalance();
}
super.onStop();
}
private void loadContent() {
if (playlist == null || playlist.size() == 0) {
Helper.setViewVisibility(surfModeLoading, View.VISIBLE);
}
Map<String, Object> claimSearchOptions = buildContentOptions();
ClaimSearchTask task = new ClaimSearchTask(claimSearchOptions, Lbry.LBRY_TV_CONNECTION_STRING, null, new ClaimSearchResultHandler() {
@Override
public void onSuccess(List<Claim> claims, boolean hasReachedEnd) {
if (playlist == null) {
playlist = new ArrayList<>(claims);
startPlaylist();
} else {
for (Claim claim : claims) {
if (!playlist.contains(claim)) {
playlist.add(claim);
}
}
}
Helper.setViewVisibility(surfModeLoading, View.GONE);
}
@Override
public void onError(Exception error) {
Helper.setViewVisibility(surfModeLoading, View.GONE);
}
});
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void startPlaylist() {
if (playlist == null || playlist.size() == 0) {
return;
}
playlistIndex = 0;
current = playlist.get(playlistIndex);
checkCurrentClaimIsVideo(false);
playbackCurrentClaim();
}
private void checkCurrentClaimIsVideo(boolean previous) {
while (current == null || current.getMediaType() == null || !current.getMediaType().startsWith("video")) {
// only play videos
if (previous) {
playlistIndex--;
} else {
playlistIndex++;
}
current = playlist.get(playlistIndex);
}
}
private void playPreviousClaim() {
if (playlist == null || playlist.size() == 0) {
return;
}
if (playlistIndex > 0) {
playlistIndex--;
}
current = playlist.get(playlistIndex);
checkCurrentClaimIsVideo(true);
playbackCurrentClaim();
}
private void playNextClaim() {
if (playlist == null || playlist.size() == 0) {
return;
}
if (playlistIndex < playlist.size() - 1) {
playlistIndex++;
}
if (playlist.size() - playlistIndex < 10) {
currentClaimSearchPage++;
loadContent();
}
current = playlist.get(playlistIndex);
checkCurrentClaimIsVideo(false);
playbackCurrentClaim();
}
private void playbackCurrentClaim() {
resetPlayer();
String publisherText = !Helper.isNullOrEmpty(current.getPublisherTitle()) ?
String.format("%s (%s)", current.getPublisherTitle(), current.getPublisherName()) :
!Helper.isNullOrEmpty(current.getPublisherName()) ? current.getPublisherName() : getString(R.string.anonymous);
textTitle.setText(current.getTitle());
textPublisher.setText(publisherText);
Context context = getContext();
if (MainActivity.appPlayer == null && context != null) {
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setUsage(C.USAGE_MEDIA)
.setContentType(C.CONTENT_TYPE_MOVIE)
.build();
MainActivity.appPlayer = new SimpleExoPlayer.Builder(context).build();
MainActivity.appPlayer.setAudioAttributes(audioAttributes, true);
MainActivity.playerCache =
new SimpleCache(context.getCacheDir(),
new LeastRecentlyUsedCacheEvictor(1024 * 1024 * 256), new ExoDatabaseProvider(context));
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
activity.initMediaSession();
activity.initPlaybackNotification();
}
if (playerListener != null) {
MainActivity.appPlayer.addListener(playerListener);
}
newPlayerCreated = true;
}
if (context instanceof MainActivity) {
MainActivity activity = (MainActivity) context;
activity.initPlaybackNotification();
}
View root = getView();
if (root != null) {
PlayerView view = root.findViewById(R.id.shuffle_exoplayer_view);
view.setShutterBackgroundColor(Color.TRANSPARENT);
view.setPlayer(MainActivity.appPlayer);
view.setUseController(true);
if (context instanceof MainActivity) {
((MainActivity) context).getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
if (MainActivity.nowPlayingClaim != null &&
MainActivity.nowPlayingClaim.getClaimId().equalsIgnoreCase(current.getClaimId()) &&
!newPlayerCreated) {
// if the claim is already playing, we don't need to reload the media source
return;
}
if (MainActivity.appPlayer != null) {
showBuffering();
if (context instanceof MainActivity) {
((MainActivity) context).setNowPlayingClaim(current, current.getPermanentUrl());
}
MainActivity.appPlayer.setPlayWhenReady(true);
String userAgent = Util.getUserAgent(context, getString(R.string.app_name));
String mediaSourceUrl = getStreamingUrl();
MediaSource mediaSource = new ProgressiveMediaSource.Factory(
new CacheDataSourceFactory(MainActivity.playerCache, new DefaultDataSourceFactory(context, userAgent)),
new DefaultExtractorsFactory()
).setLoadErrorHandlingPolicy(new FileViewFragment.StreamLoadErrorPolicy()).createMediaSource(Uri.parse(mediaSourceUrl));
MainActivity.appPlayer.prepare(mediaSource, true, true);
}
}
}
private void resetPlayer() {
elapsedDuration = 0;
totalDuration = 0;
renderElapsedDuration();
renderTotalDuration();
elapsedPlaybackScheduled = false;
if (elapsedPlaybackScheduler != null) {
elapsedPlaybackScheduler.shutdownNow();
elapsedPlaybackScheduler = null;
}
playbackStarted = false;
startTimeMillis = 0;
/*
if (MainActivity.appPlayer != null) {
MainActivity.appPlayer.stop(true);
MainActivity.appPlayer.removeListener(fileViewPlayerListener);
PlaybackParameters params = new PlaybackParameters(1.0f);
MainActivity.appPlayer.setPlaybackParameters(params);
}*/
}
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(current.getPermanentUrl(), timeToStartMillis);
}
private void logFileView(String url, long timeToStart) {
if (current != null) {
LogFileViewTask task = new LogFileViewTask(url, current, 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 showBuffering() {
View root = getView();
if (root != null) {
root.findViewById(R.id.player_buffering_progress).setVisibility(View.VISIBLE);
PlayerView playerView = root.findViewById(R.id.shuffle_exoplayer_view);
playerView.findViewById(R.id.player_skip_back_10).setVisibility(View.INVISIBLE);
playerView.findViewById(R.id.player_skip_forward_10).setVisibility(View.INVISIBLE);
}
}
private void hideBuffering() {
View root = getView();
if (root != null) {
root.findViewById(R.id.player_buffering_progress).setVisibility(View.INVISIBLE);
PlayerView playerView = root.findViewById(R.id.shuffle_exoplayer_view);
playerView.findViewById(R.id.player_skip_back_10).setVisibility(View.VISIBLE);
playerView.findViewById(R.id.player_skip_forward_10).setVisibility(View.VISIBLE);
}
}
private void renderElapsedDuration() {
View view = getView();
if (view != null) {
Helper.setViewText(view.findViewById(R.id.player_duration_elapsed), Helper.formatDuration(Double.valueOf(elapsedDuration / 1000.0).longValue()));
}
}
private void renderTotalDuration() {
View view = getView();
if (view != null) {
Helper.setViewText(view.findViewById(R.id.player_duration_total), Helper.formatDuration(Double.valueOf(totalDuration / 1000.0).longValue()));
}
}
private void loadAndScheduleDurations() {
if (MainActivity.appPlayer != null && playbackStarted) {
elapsedDuration = MainActivity.appPlayer.getCurrentPosition() < 0 ? 0 : MainActivity.appPlayer.getCurrentPosition();
totalDuration = MainActivity.appPlayer.getDuration() < 0 ? 0 : MainActivity.appPlayer.getDuration();
renderElapsedDuration();
renderTotalDuration();
scheduleElapsedPlayback();
}
}
private void scheduleElapsedPlayback() {
if (!elapsedPlaybackScheduled) {
elapsedPlaybackScheduler = Executors.newSingleThreadScheduledExecutor();
elapsedPlaybackScheduler.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Context context = getContext();
if (context instanceof MainActivity) {
((MainActivity) context).runOnUiThread(new Runnable() {
@Override
public void run() {
if (MainActivity.appPlayer != null) {
elapsedDuration = MainActivity.appPlayer.getCurrentPosition();
int elapsedSeconds = Double.valueOf(elapsedDuration / 1000.0).intValue();
renderElapsedDuration();
}
}
});
}
}
}, 0, 500, TimeUnit.MILLISECONDS);
elapsedPlaybackScheduled = true;
}
}
// TODO: Move this call to MainActivity?
private void claimEligibleRewards() {
// attempt to claim eligible rewards after viewing or playing a file (fail silently)
Context context = getContext();
ClaimRewardTask firstStreamTask = new ClaimRewardTask(Reward.TYPE_FIRST_STREAM, null, null, context, eligibleRewardHandler);
ClaimRewardTask dailyViewTask = new ClaimRewardTask(Reward.TYPE_DAILY_VIEW, null, null, context, 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));
}
Context context = getContext();
if (context instanceof MainActivity) {
((MainActivity) context).showMessage(message);
}
}
@Override
public void onError(Exception error) {
// pass
}
};
private static class SwipeListener implements View.OnTouchListener {
private final GestureDetector gestureDetector;
private final View control;
public SwipeListener(View control, Context context) {
this.control = control;
gestureDetector = new GestureDetector(context, new SwipeGestureListener());
}
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
return gestureDetector.onTouchEvent(motionEvent);
}
public void onSwipeLeft() { }
public void onSwipeRight() { }
public void onSwipeTop() { }
public void onSwipeBottom() { }
private final class SwipeGestureListener extends GestureDetector.SimpleOnGestureListener {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
@Override
public boolean onDown(MotionEvent e) {
if (control instanceof PlayerView) {
return false;
}
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
onSwipeRight();
} else {
onSwipeLeft();
}
result = true;
}
}
else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
onSwipeBottom();
} else {
onSwipeTop();
}
result = true;
}
} catch (Exception ex) {
// pass
}
return result;
}
}
}
@Override
public boolean shouldHideGlobalPlayer() {
return true;
}
private static final List<String> contentChannelIds = Arrays.asList(
"3fec094c5937e9eb4e8f5e71e4ca430e8a993d03",
"6184648aab0431c4c95c649072d1f9ff08b9bb7c",
"b5d31cde873073718c033076656a27471e392afc",
"7317cdf6f62be93b22295062e191f6ba59a5db26",
"1cdb5d0bdcb484907d0a2fea4efdfe0153838642",
"b516294f541a18ce00b71a60b2c82ad2f87ff78d",
"91e42cc450075f2c4c245bac7617bf903f16b4ce",
"b6e207c5f8c58e7c8362cd05a1501bf2f5b694f2",
"25f384bd95e218f6ac37fcaca99ed40f36760d8c",
"f33657a2fcbab2dc3ce555d5d6728f8758af7bc7",
"294f5c164da5ac9735658b2d58d8fee6745dfc45",
"119a2e8c0b50f78d3861636d37c3b44ba8e689b5",
"7b23cca3f49059f005e812be03931c81272eaac4",
"fb0efeaa3788d1292bb49a94d77622503fe08129",
"797a528c49b6535560f7fd8222b121b0223287c8",
"bc490776f367b8afccf0ea7349d657431ba1ded6",
"48c7ea8bc2c4adba09bf21a29689e3b8c2967522",
"bf7490f905904e79de5c90e472bb9e6f26e634a0",
"df961194a798cc76306b9290701130c592530fb6",
"cf0be9078d76951e2e228df68b5b0bbf71313aaa",
"d746ac8d782f94d12d176c7a591f5bf8365bef3d",
"1f30267438257020f08abf452746a48e53a71ad5",
"4ad942982e43326c7700b1b6443049b3cfd82161",
"1cdb5d0bdcb484907d0a2fea4efdfe0153838642",
"6616707e1109aaa1c11b9f399f914d0cfb4f5303",
"4ee7cfaf1fc50a6df858ed0b99c278d633bccca9",
"b7d02b4a0036114732c072269adb891dc5e34ca4",
"9c51c1a119137cd17ed5ae09daa80c1cab6ac01d",
"5f2a5c14b971a6f5eed0a67dc7af3a3fe5c0b6a4",
"0e2b5b4cf59e859860000ff123dc12a317ad416b",
"3fe68ad3da93065e35c37b14fbeef88b4b7785ed",
"fd7ffcbafb74412a8812df4720feaf11fe70fe12",
"b4c30fe36b79870a79c55e1e909adb5ad23f323f",
"92c0f2f3239f1f61496997bd2cdc197ec51bd423",
"29193e9240a71a735639c66ee954e68414f11236",
"25f384bd95e218f6ac37fcaca99ed40f36760d8c",
"87b13b074936b1f42a7c6758c7c2995f58c602e7",
"8d935c6c30510e1dfc10f803a9646fa8aa128b07",
"8f4fecfc836ea33798ee3e5cef56926fa54e2cf9",
"9a5dfcb1a4b29c3a1598392d039744b9938b5a26",
"c5724e280283cd985186af9a62494aae377daabd",
"b39833be3032bbe1005f4f719f379a4621faeb13",
"589276465a23c589801d874f484cc39f307d7ec7",
"fb364ef587872515f545a5b4b3182b58073f230f",
"6c0bf1fed2705d675da950a94e4af004ec975a06",
"b924ac36b7499591f7929d9c4903de79b07b1cb9",
"113515e893b8186595595e594ecc410bae50c026",
"72f9815b087b6d346745e3de71a6ce5fe73a8677",
"b0198a465290f065378f3535666bee0653d6a9bb",
"020ebeb40642bfb4bc3d9f6d28c098afc0a47481",
"5c15e604c4207f52c8cf58fe21e63164c230e257",
"273a2fa759f1a9f56b078633ea2f08fc2406002a",
"930fc43ca7bae20d4706543e97175d1872b0671f",
"0cb2ec46f06ba85520a1c1a56706acf35d5176dd",
"057053dfb657aaa98553e2c544b06e1a2371557e",
"64e091964a611a48424d254a3de2b952d0d6565a",
"50ebba2b06908f93d7963b1c6826cc0fd6104477",
"374ff82251a384601da73f30485c3ac8d7f4176b",
"1487afc813124abbeb0629d2172be0f01ccec3bf",
"6a4fa1a68b92336e64006a4310cb160b07854329",
"15f986a262fc6eff5774050c94d174c0533d505d",
"6184648aab0431c4c95c649072d1f9ff08b9bb7c",
"1efa9b640ad980b2ec53834d60e9cff9554979cd",
"064d4999ea15e433e06f16f391922390acab01cb",
"4884e30b93b3c4c123a83154516196095f9e831e",
"2827bfc459c12d7c6d280cbacee750811291d4ba",
"9626816275585ac3443e7cddd1272c8652c23f1d",
"a2e1bb1fed32c6a6290b679785dd31ca5c59cb5f",
"d9535951222dd7a1ff7f763872cb0df44f7962bf",
"243b6f18093ff97c861d0568c7d3379606201a4b",
"1ce5ac7bab7f2e82af02305ced3c095e320b52e5",
"3e63119a8503a6f666b0a736c8fdeb9e79d11eb4",
"e33372c0d8b2cdd3e12252962ee1671d66143075",
"7364ba2ac9090e468855ce9074bb50c306196f4c",
"d6350f9158825662b99e4b5e0442bcc94d39bc11",
"2a294ea41312c6da8de5ebd0f18dbfb2963bb1a4",
"44c49bbab8a3e9999f3ba9dee0186288b1d960a7",
"2305db36455aa0d18571015b9e9bd0950262aa0f",
"82f1d8c257d3e76b711a5cecd1e49bd3fa6a9de9",
"faed2b028a9b5a712d5180eaa6fd2aa619f941bc",
"39ac239b5687f7d1c2ba74cd020b3547545dfdaf",
"5737eb22f6119f27c9afccfe73ba710afd885371",
"5f22b6daf7204d73cf79d3ff0b46fc4fe237c7f7",
"3583f5a570af6870504eea5a5f7afad6e1508508",
"b0e489f986c345aef23c4a48d91cbcf5a6fdb9ac",
"ba79c80788a9e1751e49ad401f5692d86f73a2db",
"c54323436f50c633c870298bb374ac8e7560e6cd",
"83725c7ee23bd4a8ca28a4fab0e313409def1dc7",
"61c4e8636704f2f38bbe88b1f30ef0d74d6c0f49",
"87ef9ba36019f7f3bf217cf47511645893b13f2e",
"1bd0adfcf1c75bafc1ba3fc9b65a1a0470df6a91",
"1be15348c51955179b7bf9aa90230a9425927ef6",
"1f45ab3495df2c3be7d9c882bca9966305115cbb",
"7317777e3751efa66218f6da5ef0d01dda69af48",
"3346a4ff80b70ee7eea8a79fc79f19c43bb4464a",
"452916a904030d2ce4ea2440fad2d0774e7296d9",
"2675ef3adf52ebf8a44ff5da4306c293dfa6f901",
"e2a76643735f8611a561794509c6bb2aac70eb04",
"dc577db3caf5ff83a3b573ba92f2d447f067eee1",
"89c4cf244099918b1d3ed413df27d4216e97b499",
"4b2b5822c8af3074c6ef9b789a8142d0ef623402",
"3c5794f775975669745c412b0c30f48991d9e455",
"1df464dbb302ced815c61431a5548a273e6de8e1"
);
}

View file

@ -4,9 +4,13 @@ import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.InputType;
import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.EditTextPreference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
@ -23,6 +27,15 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.settings, rootKey);
PreferenceManager manager = getPreferenceManager();
EditTextPreference miniPlayerBottomMarginPreference = manager.findPreference(MainActivity.PREFERENCE_KEY_MINI_PLAYER_BOTTOM_MARGIN);
miniPlayerBottomMarginPreference.setOnBindEditTextListener(new EditTextPreference.OnBindEditTextListener() {
@Override
public void onBindEditText(@NonNull EditText editText) {
editText.setInputType(InputType.TYPE_CLASS_NUMBER);
}
});
}
@Override

View file

@ -375,6 +375,23 @@ public final class Lbry {
"any_tags", "channel_ids", "order_by", "not_tags", "not_channel_ids", "urls"
};
// build claim search for surf mode
public static Map<String, Object> buildClaimSearchOptions(
String claimType, List<String> notTags, List<String> channelIds, List<String> orderBy, long maxDuration, int limitClaimsPerChannel, int page, int pageSize) {
return buildClaimSearchOptions(
Collections.singletonList(claimType),
null,
notTags,
channelIds,
null,
orderBy,
null,
maxDuration,
limitClaimsPerChannel,
page,
pageSize);
}
public static Map<String, Object> buildClaimSearchOptions(
String claimType,
List<String> anyTags,
@ -393,6 +410,8 @@ public final class Lbry {
notChannelIds,
orderBy,
releaseTime,
0,
0,
page,
pageSize);
}
@ -405,6 +424,8 @@ public final class Lbry {
List<String> notChannelIds,
List<String> orderBy,
String releaseTime,
long maxDuration,
int limitClaimsPerChannel,
int page,
int pageSize) {
Map<String, Object> options = new HashMap<>();
@ -417,6 +438,12 @@ public final class Lbry {
if (!Helper.isNullOrEmpty(releaseTime)) {
options.put("release_time", releaseTime);
}
if (maxDuration > 0) {
options.put("duration", String.format("<%d", maxDuration));
}
if (limitClaimsPerChannel > 0) {
options.put("limit_claims_per_channel", limitClaimsPerChannel);
}
addClaimSearchListOption("any_tags", anyTags, options);
addClaimSearchListOption("not_tags", notTags, options);

View file

@ -26,6 +26,7 @@ public class LbryAnalytics {
public static final String EVENT_PUBLISH_UPDATE = "publish_update";
public static final String EVENT_CHANNEL_CREATE = "channel_create";
public static final String EVENT_SEARCH = "search";
public static final String EVENT_SHUFFLE_SESSION = "shuffle_session";
public static void init(Context context) {

View file

@ -0,0 +1,87 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:background="@android:color/black"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="@+id/shuffle_exoplayer_container"
android:background="@android:color/black"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_above="@id/shuffle_content_details">
<com.google.android.exoplayer2.ui.PlayerView
android:id="@+id/shuffle_exoplayer_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:controller_layout_id="@layout/exo_playback_control_view"/>
<ProgressBar
android:id="@+id/player_buffering_progress"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_centerInParent="true"
android:visibility="gone" />
</RelativeLayout>
<LinearLayout
android:id="@+id/shuffle_content_details"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="8dp"
android:layout_alignParentBottom="true">
<TextView
android:id="@+id/shuffle_content_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/inter"
android:textColor="@color/white"
android:textFontWeight="300"
android:minLines="1"
android:maxLines="3"
android:textSize="20sp"
/>
<TextView
android:id="@+id/shuffle_content_publisher"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/inter"
android:textColor="@color/white"
android:textFontWeight="300"
android:minLines="1"
android:maxLines="1"
android:textSize="14sp" />
</LinearLayout>
<ProgressBar
android:id="@+id/shuffle_loading"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_centerInParent="true"
android:visibility="gone" />
<RelativeLayout
android:id="@+id/shuffle_share_button"
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:clickable="true"
android:background="?attr/selectableItemBackground">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_centerInParent="true"
android:tint="@color/white"
android:src="@drawable/ic_share" />
</RelativeLayout>
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ui.slideshow.SlideshowFragment">
<TextView
android:id="@+id/text_slideshow"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,605 +0,0 @@
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_name">LBRY</string>
<string name="navigation_drawer_open">Avaa navigointilaatikko</string>
<string name="navigation_drawer_close">Sulje navigointilaatikko</string>
<!-- Nav menu -->
<string name="find_content">Etsi sisältöä</string>
<string name="your_content">Sinun sisältö</string>
<string name="wallet">Lompakko</string>
<string name="following">Seuraamassa</string>
<string name="editors_choice">Toimittajan valinta</string>
<string name="your_tags">Sinun Tunnisteet</string>
<string name="all_content">Kaikki sisältö</string>
<string name="channels">Kanavat</string>
<string name="library">Kirjasto</string>
<string name="publishes">Julkaisut</string>
<string name="new_publish">Uusi julkaisu</string>
<string name="rewards">Palkinnot</string>
<string name="invites">Kutsut</string>
<string name="settings">Asetukset</string>
<string name="about">Noin</string>
<string name="sign_in">Kirjaudu sisään</string>
<string name="startup_failed">Sovelluksen käynnistys epäonnistui. Tarkista datayhteys ja yritä uudelleen. Jos tämä ongelma jatkuu, lähetä sähköpostia osoitteeseen hello@lbry.com</string>
<string name="no_claim_search_content">Ei näytettävää sisältöä tällä hetkellä. Tarkenna valintaasi tai tarkista myöhemmin uudelleen.</string>
<!-- Welcome Page -->
<string name="welcome_to_lbry">Tervetuloa LBRY:lle</string>
<string name="welcome_paragraph">LBRY on yhteisön ohjaama sisältöalusta, josta voit löytää ja julkaista videoita, musiikkia, kirjoja ja paljon muuta.</string>
<string name="welcome_tos">Jatkamalla, hyväksyn &lt;a href=\"https://lbry.com/termsofservice\"&gt;Terms of Service&lt;/a&gt; ja vahvistan että olen yli 13vuotias.</string>
<string name="welcome_please_wait">Odota, kunnes saamme asiat valmiiksi ...</string>
<string name="use_lbry">Käytä LBRY »</string>
<!-- URI bar -->
<string name="uri_placeholder">Etsi videoita, musiikkia ja muuta</string>
<!-- Following page -->
<string name="find_channels_to_follow">Etsi seurattavat kanavat</string>
<string name="channels_you_follow">Kanavat joita seuraat</string>
<string name="discover">Tutustu</string>
<string name="lbry_works_better">LBRY toimii paremmin, jos seuraat vähintään 5 haluamaasi tekijää. Kirjaudu sisään näyttääksesi seuraamasi tekijät, jos sinulla on jo tili.</string>
<string name="select_five_subscriptions">Valitse enintään 5 tekijää jatkaaksesi.</string>
<string name="n_remaining">%1$djäljellä...</string>
<string name="done">Tehty</string>
<string name="all">Kaikki</string>
<string name="discover_channels">Löydä uusia kanavia</string>
<!-- Claim lists -->
<string name="anonymous">Anonyymi</string>
<!-- File view -->
<string name="tags">Tunnisteet</string>
<string name="share">Jaa</string>
<string name="repost">Repost</string>
<string name="tip">Tippi</string>
<string name="edit">Muokkaa</string>
<string name="delete">Poista</string>
<string name="download">Lataa</string>
<string name="open">Avoin</string>
<string name="report">Ilmianna</string>
<string name="loading_decentralized_data">Ladataan hajautettua tietoa ...</string>
<string name="related_content">Samankaltaista sisältöä</string>
<string name="comments">Kommentit</string>
<string name="no_comments">Ei kommentteja näytettäväksi tällä hetkellä.</string>
<string name="sdk_initializing_comments">Kommentit tulevat näkyviin, kun taustapalvelu on alustettu.</string>
<string name="comment_error">Kommenttiasi ei voitu lähettää tällä hetkellä. Yritä uudelleen myöhemmin.</string>
<string name="share_lbry_content">Jaa LBRY-sisältö</string>
<string name="view">Näytä</string>
<string name="play">Toista</string>
<string name="unsupported_content">Ei tuettu sisältö</string>
<string name="unsupported_content_desc">Valitettavasti emme pysty näyttämään tätä sisältöä sovelluksessa. Löydät tiedoston %1$s latauskansiostasi.</string>
<string name="nothing_at_this_location">Tässä paikassa ei ole mitään.</string>
<string name="publish_something_here">Julkaise jotain täällä</string>
<string name="cannot_view_claim">Tätä sisältöä ei voida käyttää tällä hetkellä. Yritä uudelleen myöhemmin.</string>
<string name="zero_duration">0:00</string>
<string name="claim_file_not_found">Tiedostoa kohteessa \"%1$s\" ei ole.</string>
<string name="confirm_purchase">Vahvista ostos</string>
<string name="delete_file">Poista tiedosto</string>
<string name="confirm_delete_file_message">Haluatko varmasti poistaa tämän tiedoston laitteestasi?</string>
<string name="unable_to_view_url">Lataus epäonnistui %1$s.Yritä uudelleen myöhemmin.</string>
<string name="no_cast_session_available">Tällä hetkellä ei ole saatavana suoratoistoistuntoa.</string>
<string name="delete_content">Poistetaanko sisältö?</string>
<string name="confirm_delete_content_message">Haluatko varmasti poistaa tämän sisällön julkaisun? Laitteistasi ei poisteta tiedostoja.</string>
<string name="content_deleted">Sisältö poistettiin onnistuneesti lohkoketjusta.</string>
<string name="content_failed_delete">Sisältöä ei voitu poistaa tällä hetkellä. Yritä uudelleen myöhemmin.</string>
<string name="comment">Kommentti</string>
<string name="comment_as">Kommentoi nimellä</string>
<string name="please_enter_comment">Kirjoita kommentti lähettääksesi viestin.</string>
<string name="please_select_channel">Valitse kanava, johon haluat lähettää kommenttisi.</string>
<string name="comment_posted">Kommenttisi lähetetty onnistuneesti.</string>
<string name="please_select_repost_channel">Valitse kanava, johon haluat lähettää uudelleen.</string>
<string name="reply">Vastaa</string>
<string name="replying_to">Vastaa käyttäjille %1$s</string>
<plurals name="post_and_tip">
<item quantity="one">Posti- ja tip-l%1$s uottotiedot?</item>
<item quantity="other">Posti- ja tippi %1$s krediitit?</item>
</plurals>
<plurals name="post_for_credits">
<item quantity="one">Lähetä %1$s krediitillä</item>
<item quantity="other">Post for %1$scredits</item>
</plurals>
<plurals name="confirm_post_comment">
<item quantity="one">Tämä lähettää kommenttisi %1$s hyvityksellä %2$s</item>
<item quantity="other">Tämä lähettää kommenttisi %1$s hyvityksellä %2$s</item>
</plurals>
<plurals name="view_count">
<item quantity="one">%1$s Näyttökertaa</item>
<item quantity="other">%1$s Näyttökertaa</item>
</plurals>
<plurals name="confirm_purchase_message">
<item quantity="one">Tämä ostos \"%1$s\" maksaa %2$s Crediittiä</item>
<item quantity="other">Tämä ostos \"%1$s\" maksaa %2$s Crediittiä</item>
</plurals>
<!-- Channel view -->
<string name="no_channel_info">Täällä ei ole vielä mitään.\nTarkista myöhemmin uudelleen.</string>
<string name="content">Sisältö</string>
<string name="website">Nettisivu</string>
<string name="reposted">uudelleen julkaistu</string>
<plurals name="follower_count">
<item quantity="one">%1$s Seuraaja</item>
<item quantity="other">%1$s Seuraajaa</item>
</plurals>
<!-- Publish -->
<string name="no_publishes_created">Näyttää siltä, että et ole vielä julkaissut sisältöä LBRY: lle.</string>
<string name="record">Tallentaa</string>
<string name="take_photo">Ota kuva</string>
<string name="upload_file">Lähetä tiedosto</string>
<string name="no_videos_found">Laitteestasi ei löytynyt videoita. Ota valokuva tai nauhoita video aloittaaksesi.</string>
<string name="loading_videos">Odota, kun lataamme videoitasi ...</string>
<string name="storage_permission_rationale_videos">LBRY vaatii pääsyn voidaksesi näyttää ja julkaista videoitasi, kuvia ja muita tiedostoja laitteeltasi.</string>
<string name="camera_permission_rationale_record">LBRY vaatii pääsyn kameraan videoiden tallentamiseksi.</string>
<string name="camera_permission_rationale_photo">LBRY vaatii pääsyn kameraan valokuvien ottamista varten.</string>
<string name="edit_content">Muokkaa sisältöä</string>
<string name="mature_tags">Kypsät tunnisteet</string>
<string name="price">Hinta</string>
<string name="free_publish">Sisältösi on ilmaista. Aseta hinta painamalla kytkintä.</string>
<string name="content_address">Sisältöosoite</string>
<string name="randomize">Satunnainen</string>
<string name="address">Osoite</string>
<string name="content_address_desc">Osoite, josta ihmiset voivat löytää sisältösi (esim. Lbry://myvideo)</string>
<string name="license">Lisenssi</string>
<string name="license_desc">Kuvaus</string>
<string name="additional_options">Lisävaihtoehtoja</string>
<string name="show_extra_fields">Näytä ylimääräiset kentät</string>
<string name="hide_extra_fields">Piilota ylimääräiset kentät</string>
<string name="no_file_found">Tiedostoa ei löytynyt julkaistavaksi.</string>
<string name="publish_invalid_claim_type">Muokkaamiseen määritetty virheellinen vaatimus.</string>
<string name="video_optimization">Videon optimointi</string>
<string name="thumbnail_creation_failed">Pikkukuvaa ei voitu luoda automaattisesti sisältötiedostostasi.</string>
<string name="video_being_optimized">Videosi on optimoitu paremman tuen tarjoamiseksi monille laitteille. Voit täyttää jäljellä olevat kentät alla, kun tämä on käynnissä.</string>
<string name="video_optimized">Videosi optimoitiin onnistuneesti parempaan toistoon mahdollisimman monissa laitteissa. Jatka julkaisemasi sisältöä.</string>
<string name="video_optimize_failed">Videota ei voitu optimoida. Tiedosto ladataan ilman muutoksia.</string>
<string name="completed_video_duration">Valmistunut videon kesto: %1$s</string>
<string name="sdk_initializing_publish">Et voi julkaista sisältöä tällä hetkellä, koska taustapalvelu on edelleen alustamassa.</string>
<string name="publish_successful">Sisällön julkaiseminen onnistui. Voi kestää hetken, että näyttöön pääsyketju.</string>
<string name="transcode_in_progress">Videon optimointi on käynnissä. Jos haluat peruuttaa, paina Peruuta sivun alaosassa.</string>
<string name="optimization_in_progress">Videon optimointi on käynnissä.</string>
<string name="cannot_capture_video">Tällä laitteella ei ole käytettävissä kamerasovellusta videoiden nauhoittamiseen.</string>
<string name="cannot_take_photo">Tällä laitteella ei ole käytettävissä kamerasovellusta valokuvien ottamiseen.</string>
<string name="please_provide_title">Anna otsikko.</string>
<string name="please_specify_address">Määritä osoite, josta ihmiset voivat löytää sisältösi.</string>
<string name="address_invalid_characters">Sisältöosoitteesi sisältää virheellisiä merkkejä.</string>
<string name="address_already_used">Olet jo julkaissut määritettyyn sisältöosoitteeseen. Anna uusi osoite.</string>
<string name="no_file_selected">Ei tiedostoa valittuna. Valitse video tai ota valokuva tai valitse tiedosto ennen julkaisemista.</string>
<string name="price_amount_not_set">Anna hinta tai kytke kytkin pois päältä, jotta sisältösi on ilmaista.</string>
<string name="publish_no_thumbnail">Valitse ladattava pikkukuva ennen julkaisua.</string>
<string name="publish_thumbnail_in_progress">Odota, että pikkukuva latautuu loppuun ennen julkaisua.</string>
<string name="language">Kieli</string>
<string name="english">Englanti</string>
<string name="chinese">Kiina</string>
<string name="french">Ranska</string>
<string name="german">Saksa</string>
<string name="japanese">Japani</string>
<string name="russian">Venäjä</string>
<string name="spanish">Espanja</string>
<string name="indonesian">Indoneesia</string>
<string name="italian">Italia</string>
<string name="dutch">Hollanti</string>
<string name="turkish">Turkki</string>
<string name="polish">Puola</string>
<string name="malay">Malaiji</string>
<string name="portuguese">Portugali</string>
<string name="vietnamese">Vietnami</string>
<string name="thai">Thaimaa</string>
<string name="arabic">Arabi</string>
<string name="czech">Tshekki</string>
<string name="croatian">Kroatia</string>
<string name="cambodian">Kambodžan</string>
<string name="korean">Korea</string>
<string name="norwegian">Norja</string>
<string name="romanian">Romaania</string>
<string name="hindi">Hindi</string>
<string name="greek">Kreikka</string>
<string name="catalan">Katalaani</string>
<string name="none">Ei mitään</string>
<string name="public_domain">Julkinen</string>
<string name="copyrighted">Tekijänoikeudella suojattuja ...</string>
<string name="cca_4_0_international">Creative Commons Attribution 4.0 International</string>
<string name="cca_sa_4_0_international">Creative Commons Attribution-ShareAlike 4.0 International</string>
<string name="cca_nd_4_0_international">Creative Commons Attribution-NoDerivatives 4.0 International</string>
<string name="cca_nc_4_0_international">Creative Commons Attribution-NonCommercial 4.0 International</string>
<string name="cca_nc_sa_4_0_international">Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International</string>
<string name="cca_nc_nd_4_0_international">Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International</string>
<string-array name="publish_currencies">
<item>LBC</item>
<item>USD</item>
</string-array>
<!-- Publishes -->
<string name="one_or_more_publishes_failed_abandon">Yhtä tai useampaa sisältökohdetta ei voitu poistaa tällä hetkellä. Yritä uudelleen myöhemmin.</string>
<plurals name="confirm_delete_publishes">
<item quantity="one">Haluatko varmasti poistaa valitut sisältökohteet?</item>
<item quantity="other">Haluatko varmasti poistaa valitut sisältökohteet?</item>
</plurals>
<plurals name="publishes_deleted">
<item quantity="one">Sisältökohteet poistettiin onnistuneesti.</item>
<item quantity="other">Sisältökohteet poistettiin onnistuneesti.</item>
</plurals>
<!-- Splash -->
<string name="oops_something_went_wrong">Oho! Jotain meni pieleen.</string>
<string name="installation_id_loaded">Ladattu asennustunnus.</string>
<string name="known_tags_loaded">Ladattu paikalliset tunnetut ja seuratut tunnisteet.</string>
<string name="exchange_rate_loaded">Ladattu LBC / USD-vaihtokurssi.</string>
<string name="user_authenticated">Käyttäjän todennettu.</string>
<string name="installation_registered">Asennus rekisteröity.</string>
<string name="subscriptions_loaded">Ladatut tilaukset.</string>
<string name="subscriptions_resolved">Ratkaistut tilaukset.</string>
<!-- Settings -->
<string name="user_interface">Content &amp; Käyttäjä näkymä</string>
<string name="other">Muu</string>
<string name="enable_background_playback">Ota taustamedian toisto käyttöön</string>
<string name="enable_dark_mode">Ota tumma teema käyttöön</string>
<string name="show_mature_content">Näytä kypsä sisältö</string>
<string name="show_url_suggestions">Näytä URL-ehdotukset</string>
<string name="notifications">Ilmoitukset</string>
<string name="subscriptions">Tilaukset</string>
<string name="content_interests">Sisältö kiinnostaa</string>
<string name="keep_sdk_in_background">Pidä LBRY-palvelu käynnissä taustalla parantaaksesi lompakkoa ja verkon suorituskykyä</string>
<string name="participate_in_data_network">Osallistu tietoverkkoon (vaatii sovelluksen ja taustapalvelun uudelleenkäynnistyksen)</string>
<!-- URL suggestions -->
<string name="search_url_title">%1$s - Etsi</string>
<string name="tag_url_title">%1$s - Tunniste</string>
<string name="search_url_desc">Etsi \'%1$s\'</string>
<string name="explore_tag_url_desc">Tutustu \'%1$s\' Tunnisteeseen</string>
<string name="view_file_url_desc">Näytä sisältöä %1$s</string>
<string name="view_channel_url_desc">Näytä %1$s kanava</string>
<!-- Search -->
<string name="search_no_results">Ei tuloksia, joita näyttää \'%1$s\'. Kokeile toista hakutermiä.</string>
<string name="search_no_query">Voit etsiä mitä tahansa, mukaan lukien elokuvat, musiikki, e-kirjat, ohjelmistot ja paljon muuta.</string>
<string name="no_related_content">Ei liittyvää sisältöä näytettäväksi tällä hetkellä.</string>
<!-- Wallet -->
<string name="balance">Saldo</string>
<string name="you_currently_have">Sinulla on tällä hetkellä</string>
<string name="convert_credits">Voit muuntaa luotosi USD: iin ja nostaa muunnetun summan vaihdon avulla. &lt;a href=\"https://lbry.com/faq/exchanges\"&gt;Learn more&lt;/a&gt;.</string>
<string name="convert_credits_bittrex">&lt;a href=\"https://bittrex.com/Account/Register?referralCode=4M1-P30-BON\"&gt;Convert Muunna hyvitykset USD: ksi Bittrexillä&lt;/a&gt;</string>
<string name="you_also_have">Sinulla on myös</string>
<string name="you_staked">Olet panostanut</string>
<string name="in_tips">Lahjoituksissa</string>
<string name="in_your_publishes">julkaisuissasi</string>
<string name="in_your_supports">tuillasi</string>
<string name="earn_more_tips">Ansaitse lisää vinkkejä lähettämällä hienoja videoita</string>
<string name="sdk_initializing">Taustapalvelu alustetaan ...</string>
<string name="sdk_still_initializing">Taustapalvelu on edelleen alustamassa. Voit tutkia ja katsella sisältöä sillä välin.</string>
<string name="sdk_initializing_functionality">Et voi tehdä tätä nyt, koska taustapalvelu on edelleen käynnistymässä.</string>
<string name="backup_synced">Varmuuskopio lompakostasi synkronoidaan lbry.tv-tiedoston kanssa</string>
<string name="backup_notsynced">Lompakkoasi ei ole tällä hetkellä synkronoitu lbry.tv: n kanssa. Olet vastuussa lompakkosi varmuuskopiosta.</string>
<string name="synced_what_does_this_mean">&lt;a href=\"https://lbry.com/faq/account-sync\"&gt;What Mitä se tarkoittaa?&lt;/a&gt;</string>
<string name="backup_what_does_this_mean">&lt;a href=\"https://lbry.com/faq/how-to-backup-wallet#android\"&gt;What Mitä se tarkoittaa?&lt;/a&gt;</string>
<string name="receive_credits">Saa krediittejä</string>
<string name="use_this_address_hint">Käytä tätä lompakko-osoitetta saadaksesi toisen käyttäjän (tai itsesi) lähettämiä krediittejä.</string>
<string name="get_new_address">Saa uusi osoite</string>
<string name="generate_address_hint">Voit luoda uuden osoitteen milloin tahansa, ja kaikki aiemmat osoitteet toimivat edelleen. Useiden osoitteiden käyttäminen voi olla hyödyllistä seurata useista lähteistä tulevia maksuja.</string>
<string name="send_credits">Lähetä krediittejä</string>
<string name="recipient_address">Vastaanottajan osoite</string>
<string name="recipient_address_placeholder">bbFxRyXXXXXXXXXXXZD8nE7XTLUxYnddTs</string>
<string name="amount">Määrä</string>
<string name="send">Lähetä</string>
<string name="recent_transactions">Viimeaikaiset tapahtumat</string>
<string name="view_all">Näytä kaikki</string>
<string name="receive">Vastaanota</string>
<string name="spend">Tuhlaa</string>
<string name="publish">Julkaise</string>
<string name="support">Tue</string>
<string name="abandon">Hylätä</string>
<string name="channel">Kanava</string>
<string name="channel_update">Kanavan päivitys</string>
<string name="publish_update">Julkaise päivitys</string>
<string name="wallet_sync">Synkronoi lompakko</string>
<string name="sync_status">Synkronoinnin tila</string>
<string name="on">Päällä</string>
<string name="off">Kiinni</string>
<string name="email">Sähköposti</string>
<string name="no_connected_email">Ei yhdistettyjä sähköposteja</string>
<string name="manual_backup">&lt;a href=\"https://lbry.com/faq/how-to-backup-wallet#android\"&gt;Manual Manuaalinen palautus&lt;/a&gt;</string>
<string name="sync_faq">&lt;a href=\"https://lbry.com/faq/how-to-backup-wallet#sync\"&gt;Sync FAQ&lt;/a&gt;</string>
<string name="zero">0</string>
<string name="lbc">LBC</string>
<string name="account_recommended">Suositellut tilit</string>
<string name="wallet_account_desc">Lbry.tv-tilin avulla voit ansaita palkintoja, varmuuskopioida lompakkosi ja pitää kaiken synkronoituna.</string>
<string name="wallet_without_account">Ilman tiliäsi olet vastuussa lompakon ja LBRY-tietojen suojaamisesta.</string>
<string name="skip_account">Ohita tili</string>
<string name="sign_up">Rekisteröidy</string>
<string name="address_copied">Osoite kopioitu</string>
<string name="invalid_recipient_address">Anna kelvollinen osoite, johon haluat lähettää hyvityksiä</string>
<string name="insufficient_balance">Riittämätön tasapaino</string>
<string name="invalid_amount">Anna oikea summa</string>
<string name="send_credit_error">Hyvityksiäsi ei voitu lähettää tällä hetkellä. Yritä uudelleen myöhemmin.</string>
<string name="loading_transactions">Ladataan tapahtumia ...</string>
<string name="no_recent_transactions">Viimeisimmät näytettävät tapahtumat eivät ole.</string>
<string name="no_transactions">Tällä hetkellä ei ole näkyviä tapahtumia.</string>
<string name="tx_list_fee">maksu %1$s</string>
<string name="transaction_history">Tapahtumahistoria</string>
<string name="unlock">Avata</string>
<string name="unlock_tips">Avaako tippejä?</string>
<string name="confirm_unlock_tips">Haluatko varmasti avata kaikki tippisi?</string>
<string name="min_spend_required">Anna summa, joka on enemmän kuin 0,0001 krediittiä.</string>
<string name="buy_lbc">Osta LBC</string>
<string name="hash_not_supported">Laitteesi ei tue vähimmäisvaatimuksia ostopyynnön turvaamiseksi.</string>
<string name="receive_address_not_set">Sinulla ei ole lompakon osoitetta määritetty. Luo uusi osoite ja yritä uudelleen.</string>
<plurals name="you_sent_credits">
<item quantity="one">Sinä lähetät %1$s krediittiä</item>
<item quantity="other">Sinä lähetät %1$s krediittiä</item>
</plurals>
<!-- Dialogs -->
<string name="customize_your_tags">Muokkaa sinun tunnisteita</string>
<string name="sort_content_by">Lajittele sisältö</string>
<string name="content_from">Sisältö</string>
<string name="trending_content">Trendikäs sisältö</string>
<string name="new_content">Uusi sisältö</string>
<string name="top_content">Suosituin sisältö</string>
<string name="trending">Nousussa</string>
<string name="top">Paras</string>
<string name="new_text">Uusi</string>
<string name="past_24_hours">Viimeisen 24 tunnin aikana</string>
<string name="past_week">Mennyt viikko</string>
<string name="past_month">Viime kuukausi</string>
<string name="past_year">Viime vuosi</string>
<string name="all_time">Koko aikana</string>
<string name="from">tullut</string>
<string name="for_text">varten</string>
<string name="filter_for">Suodata</string>
<string name="everyone">Jokaiselle</string>
<string name="tags_you_follow">Tunnisteet mitä sinä seuraat</string>
<string name="customize">Muokkaa</string>
<string name="not_yet_implemented">Valittu näkymä ei ole vielä käytettävissä.</string>
<string name="customize_tags_hint">Näyttää siltä, että et ole vielä seurannut yhtään tunnistetta.</string>
<string name="search_for_more_tags">Etsi lisää tunnisteita</string>
<string name="no_followed_tags">Et ole vielä seurannut yhtään tunnistetta. Aloita lisäämällä kiinnostavia tunnisteita!</string>
<string name="no_tag_results">Emme löytäneet uusia tunnisteita, joita et seuraa.</string>
<string name="tag_already_added">\'%1$s\' tunniste on jo lisätty.</string>
<string name="tag_limit_reached">Et voi lisätä enempää kuin 5 tunnistetta.</string>
<string name="send_a_tip">Lähetä tippi</string>
<string name="send_a_tip_to">Lähetä tippiä %1$s</string>
<string name="support_this_content">Tue tätä sisältöä</string>
<string name="support_info">Tämä nostaa tämän sisällön kokonaishintamäärää, mikä parantaa sen kykyä löytää edelleen aktiivisena. &lt;a href=\"https://lbry.com/faq/tipping\"&gt;Learn more&lt;/a&gt;.</string>
<string name="channel_to_show_support_as">Kanava tuen näyttämiseksi nimellä</string>
<string name="make_this_a_tip">Tee tästä Tippi</string>
<string name="send_revocable_support">Lähetä peruutettava tuki</string>
<string name="send_lbc_tip">Lähetä %1$s LBC tippi</string>
<string name="send_tip_info_content">Tämä näyttää tipille %1$s, mikä parantaa sen kykyä löytää edelleen aktiivisena. &lt;a href=\"https://lbry.com/faq/tipping\"&gt;Learn more&lt;/a&gt;.</string>
<string name="send_tip_info_channel">Tämä näyttää tipille %1$s, mikä parantaa sen kykyä löytää edelleen aktiivisena. &lt;a href=\"https://lbry.com/faq/tipping\"&gt;Learn more&lt;/a&gt;.</string>
<string name="cancel">Peruuta</string>
<string name="repost_title">Repost %1$s</string>
<string name="repost_your_favorite">Lähetä suosikkisisältösi uudelleen, jotta useammat ihmiset löytävät ne!</string>
<string name="channel_to_post_on">Kanava, johon lähettää viesti</string>
<string name="show_advanced">Näytä edistyneet</string>
<string name="hide_advanced">Piilota edistynyt</string>
<string name="name">Nimi</string>
<string name="min_deposit">0.001</string>
<string name="content_successfully_reposted">Sisältö postitettiin onnistuneesti!</string>
<string name="repost_name_invalid_characters">Jälleenlähetys nimi sisältää virheellisiä merkkejä.</string>
<plurals name="you_sent_a_tip">
<item quantity="one">Sinä lähetit %1$s LBC tippinä, Mahtavaa!</item>
<item quantity="other">Sinä lähetit %1$s LBC tippinä, Mahtavaa!</item>
</plurals>
<plurals name="you_sent_a_support">
<item quantity="one">Panosit %1$s hyvityksiä tueksi. Voit peruuttaa tuen milloin tahansa. </item>
<item quantity="other">Panosit %1$s hyvityksiä tueksi. Voit peruuttaa tuen milloin tahansa. </item>
</plurals>
<!-- Verification -->
<string name="provide_email_address">Anna sähköpostiosoite.</string>
<string name="email_placeholder">you@example.com</string>
<string name="email_sent_to">Sähköposti on lähetetty osoitteeseen</string>
<string name="please_click_link">Napsauta viestin linkkiä suorittaaksesi kirjautumisen loppuun.</string>
<string name="resend">Uudelleen lähetä</string>
<string name="continue_text">Jatka</string>
<string name="provide_valid_email">Ole hyvä ja syötä toimiva sähköpostiosoite</string>
<string name="please_follow_instructions">Noudata osoitteeseesi lähetetyn sähköpostin ohjeita jatkaaksesi.</string>
<string name="sign_in_successful">Olet onnistuneesti kirjautunut sisään lbry.tv-sivustoon</string>
<string name="retrieving_account_information">Haetaan tilitietoja ...</string>
<string name="apply_wallet_data">Sovelletaan lompakotietoja ...</string>
<string name="please_enter_your_password">Anna salasana, jolla turvasit lompakon.</string>
<string name="please_enter_a_password">Anna salasana suojataksesi lompakon.</string>
<string name="wallet_security_purposes">Huomaa: LBRY ei pysty uudelleen asettaa salasanaa lompakon suojausta varten.</string>
<string name="password">Salasana</string>
<string name="enable_sync">Ota synkronointi käyttöön</string>
<string name="wallet_sync_op_failed">Lompakon synkronointia ei voitu suorittaa tällä hetkellä. Yritä uudelleen myöhemmin. Jos ongelma jatkuu, lähetä sähköpostia osoitteeseen hello@lbry.com</string>
<string name="phone_number">Puhelinnumero</string>
<string name="enter_phone_number">Ole hyvä ja anna puhelinnumerosi.</string>
<string name="not_interested">Ei kiinnostunut</string>
<string name="manual_reward_verification">Manuaalinen palkkion todentaminen</string>
<string name="account_undergo_review">Tämä tili on tarkistettava ennen kuin voit osallistua palkitsemisohjelmaan. Tämä voi viedä useita minuutteja useisiin päiviin.</string>
<string name="enjoy_free_content">Nauti ilmaisesta sisällöstä sillä välin!</string>
<string name="verify_phone_number">Vahvista puhelinnumero</string>
<string name="enter_phone_verify_code">Anna vahvistuskoodi, joka lähetettiin osoitteeseen %1$s</string>
<string name="code_placeholder">0000</string>
<string name="verify">Vahvista</string>
<string name="please_enter_valid_phone">Ole hyvä ja näppäile voimassaoleva puhelinnumero.</string>
<string name="please_enter_verification_code">Anna puhelinnumeroosi lähetetty vahvistuskoodi.</string>
<string name="fetch_current_user_error">Käyttäjätiliä ei voitu noutaa tällä hetkellä. Yritä uudelleen myöhemmin.</string>
<!-- Forms -->
<string name="no_added_tags">Et ole vielä lisännyt tageja. Lisää tunnisteita etsinnän parantamiseksi.</string>
<string name="form_no_tag_results">Emme löytäneet uusia tunnisteita, joita ei ole vielä lisätty.</string>
<!-- Channels -->
<string name="no_channel_created">Et ole luonut kanavaa.
Aloita nyt luomalla uusi kanava!</string>
<string name="create_a_channel">Tee kanava</string>
<string name="create_a_channel_item">Tee kanava...</string>
<string name="edit_channel">Muokkaa kanavaa</string>
<string name="delete_selection">Poistetaanko valinta?</string>
<string name="delete_channel">Poistetaanko kanava?</string>
<string name="confirm_delete_channel">Haluatko varmasti poistaa tämän kanavan?</string>
<string name="channel_deleted">Kanava poistettiin onnistuneesti.</string>
<string name="channel_failed_delete">Kanavaa ei voitu poistaa tällä hetkellä. Yritä uudelleen myöhemmin.</string>
<string name="description">Kuvaus</string>
<string name="yes">Kyllä</string>
<string name="no">Ei</string>
<string name="show_optional_fields">Näytä valinnaiset kentät</string>
<string name="hide_optional_fields">Näytä valinnaiset kentät</string>
<string name="save">Tallenna</string>
<string name="channel_name">Kanavan nimi</string>
<string name="title">Otsikko</string>
<string name="at">\@</string>
<string name="deposit">Tallettaa</string>
<string name="deposit_remains_yours">Tämä LBC on sinun. Nimen varaaminen on talletus, ja sen voi peruuttaa milloin tahansa.</string>
<string name="storage_permission_rationale_download">LBRY vaatii pääsyn sisällön lataamiseen laitteellesi.</string>
<string name="storage_permission_rationale_images">LBRY vaatii pääsyn kuvien lataamiseen laitteen varastosta.</string>
<string name="select_thumbnail">Valitse pikkukuva</string>
<string name="select_cover">Valitse kannen kuva</string>
<string name="undetermined_image_filepath">Tiedostopolkua ei voitu määrittää valitulle kuvalle. Valitse kuva eri sijainnista.</string>
<string name="wait_for_upload">Odota, että nykyinen lataus on valmis.</string>
<string name="image_upload_failed">Kuvan lähetyspyyntö epäonnistui. Yritä uudelleen.</string>
<string name="uploading">Lataaminen ...</string>
<string name="please_enter_channel_name">Anna kanavan nimi.</string>
<string name="channel_name_invalid_characters">Kanavasi nimi sisältää virheellisiä merkkejä.</string>
<string name="channel_name_already_created">Olet jo luonut kanavan samalla nimellä.</string>
<string name="please_enter_valid_deposit">Anna oikea talletussumma.</string>
<string name="deposit_more_than_balance">Talletus ei voi olla suurempi kuin saldosi.</string>
<string name="channel_save_failed">Kanavan tallennuspyyntö epäonnistui. Yritä uudelleen.</string>
<string name="channel_save_successful">Kanava tallennettiin onnistuneesti.</string>
<string name="item_pending_blockchain">Vaatimus odottaa julkaisua lohkoketjussa. Voit käyttää vaatimusta tai muokata sitä hetkessä.</string>
<string name="pending">vireillä</string>
<string name="create">Luo</string>
<string name="one_or_more_channels_failed_abandon">Yhtä tai useampaa sisältökohdetta ei voitu poistaa tällä hetkellä. Yritä uudelleen myöhemmin.</string>
<plurals name="min_deposit_required">
<item quantity="one">Vaaditaan vähintään %1$s luottojen talletus.</item>
<item quantity="other">Vaaditaan vähintään %1$s luottojen talletus.</item>
</plurals>
<plurals name="confirm_delete_channels">
<item quantity="one">Haluatko varmasti poistaa valitut kanava?</item>
<item quantity="other">Haluatko varmasti poistaa valitut kanavat?</item>
</plurals>
<plurals name="channels_deleted">
<item quantity="one">Kanava poistettiin onnistuneesti.</item>
<item quantity="other">Kanava poistettiin onnistuneesti.</item>
</plurals>
<!-- Rewards -->
<string name="lbry_credits_allow">LBRY-crediitit antavat sinun julkaista tai ostaa sisältöä.</string>
<string name="free_credits_worth">Voit saada ilmaisia hyvityksiä, joiden arvo on %1$s, kun olet antanut sähköpostiosoitteen.</string>
<string name="rewards_learn_more">&lt;a href=\"https://lbry.com/faq/earn-credits\"&gt;Learn more&lt;/a&gt;.</string>
<string name="get_started">Pääse alkuun</string>
<string name="reward_code_placeholder">abc123</string>
<string name="claim">vaatimus</string>
<string name="please_enter_claim_code">Anna mukautettu palkituskoodi vaatiaksesi.</string>
<string name="unclaimed">Lunastamattomat</string>
<string name="custom_reward_title">Kustomoitu koodi</string>
<string name="up_to">aikeissa</string>
<string name="custom_reward_description">Oletko supermalli tai rockstar, joka sai mukautetun palkinnon? Vaadi sitä täältä.</string>
<plurals name="claim_reward_message">
<item quantity="one">Olet vaatinut %1$s hyvitystä palkkiona.</item>
<item quantity="other">Olet vaatinut %1$shyvitystä palkkiona.</item>
</plurals>
<plurals name="available_credits">
<item quantity="one">%1$s käytettävissä olevia krediittejä</item>
<item quantity="other">%1$s käytettävissä olevia krediittejä</item>
</plurals>
<!-- Reward drivers -->
<string name="publishing_requires_credits">Julkaiseminen vaatii krediittejä.</string>
<string name="channel_creation_requires_credits">Kanavien luominen vaatii krediittejä.</string>
<string name="earn_rewards_for_inviting">Ansaitse palkkioita ystävien kutsumisesta.</string>
<string name="earn_some_credits_to_access">Ansaitse joitakin hyvityksiä tämän sisällön käyttämiseksi.</string>
<string name="tap_here_to_get_some">Napauta tätä saadaksesi ilmaiseksi.</string>
<string name="free_credits_available">Ilmaisia hyvityksiä palkkioina.</string>
<plurals name="wallet_signed_in_free_credits">
<item quantity="one"> %1$s Ilmaisia hyvityksiä palkkioina.</item>
<item quantity="other">%1$s Ilmaisia hyvityksiä palkkioina.</item>
</plurals>
<plurals name="wallet_get_free_credits">
<item quantity="one">Hanki %1$s ilmaisia krediittejä tilin luomisen jälkeen.</item>
<item quantity="other">Hanki %1$s ilmaisia krediittejä tilin luomisen jälkeen.</item>
</plurals>
<!-- Invites -->
<string name="lbry_invite_program">LBRY-kutsuohjelma</string>
<string name="earn_extra_credits_invites">Voit ansaita ylimääräisiä krediittejä jokaisesta henkilöstä, jonka kutsut käyttämään LBRY: tä.</string>
<string name="invites_learn_more">&lt;a href=\"https://lbry.com/faq/invites\"&gt;Learn more&lt;/a&gt;.</string>
<string name="invite_link">Kutsu linkki</string>
<string name="share_this_link">Jaa tämä linkki ystävien (tai vihollisten) kanssa ja hanki krediittejä liittyessään lbry.tv.</string>
<string name="your_invite_link">Kutsu-linkkisi</string>
<string name="customize_invite_link">Mukauta kutsulinkki</string>
<string name="invite_by_email">Kutsu sähköpostitse</string>
<string name="invite_someone">Kutsu tuntemaasi henkilö sähköpostilla ja ansaitse krediittejä liittyessään lbry.tv.</string>
<string name="invite_email_placeholder">imaginary@friend.com</string>
<string name="invite">Kutsu</string>
<string name="invite_history">Kutsu historia</string>
<string name="earn_credits_for_inviting">Ansaitse pisteitä ystävän, vihollisen, frenemian tai eneystävän kutsumiseen. Jokainen tarvitsee sisältövapauden.</string>
<string name="reward">Palkinto</string>
<string name="claimed">noutaa</string>
<string name="claimable">lunastettavana</string>
<string name="unclaimable">Ei vaadittavissa</string>
<string name="invite_link_copied">Kutsu linkki kopioitu.</string>
<string name="invite_sent_to">Kutsu lähetetty %1$s</string>
<!-- Library -->
<string name="downloads">Lataukset</string>
<string name="purchases">ostos</string>
<string name="history">Historia</string>
<string name="library_no_downloads">Sinulla ei ole yhtään ladattua sisältöä tälle laitteelle.</string>
<string name="library_no_history">Et ole katsellut mitään sisältöä tällä laitteella.</string>
<string name="library_no_purchases">Et ole ostanut sisältöä tililtäsi.</string>
<string name="hide">Piilota</string>
<string name="stats">Tilastot</string>
<string name="video">Video</string>
<string name="audio">Ääni</string>
<string name="images">Kuvat</string>
<string name="mb">MB</string>
<string name="kb">KB</string>
<string name="gb">GB</string>
<string name="zero_mb">0MB</string>
<plurals name="confirm_delete_files">
<item quantity="one">Haluatko varmasti poistaa valitut tiedostot laitteestasi?</item>
<item quantity="other">Haluatko varmasti poistaa valitut tiedostot laitteestasi?</item>
</plurals>
<plurals name="files_deleted">
<item quantity="one">Tiedostot poistettiin onnistuneesti.</item>
<item quantity="other">Tiedostot poistettiin onnistuneesti.</item>
</plurals>
<!-- About -->
<string name="about_lbry">Tietoa LBRY</string>
<string name="content_freedom">Sisällönvapaus</string>
<string name="about_paragraph">LBRY on ilmainen, avoin ja yhteisömäinen digitaalinen markkinapaikka. Se on hajautettu vertaisverkkosisällön jakelualusta, jonka avulla tekijät voivat ladata ja jakaa sisältöä sekä ansaita LBRY-krediittejä työstään. Käyttäjät voivat löytää laajan valikoiman videoita, musiikkia, e-kirjoja ja muuta kiinnostavaa digitaalista sisältöä.</string>
<string name="get_social">Hanki sosiaalinen</string>
<string name="social_paragraph">Voit olla tekemisissä LBRY-tiimin ja yhteisön jäsenten kanssa Discordissa, Facebookissa, Instagramissa, Twitterissä tai Redditissä.</string>
<string name="app_info">Sovellustiedot</string>
<string name="loading">Latautuu...</string>
<string name="about_link_what_is_lbry">&lt;a href=\"https://lbry.com/faq/what-is-lbry\"&gt;What is LBRY?&lt;/a&gt;</string>
<string name="about_link_android_basics">&lt;a href=\"https://lbry.com/faq/android-basics\"&gt;Android Basics&lt;/a&gt;</string>
<string name="about_link_faq">&lt;a href=\"https://lbry.com/faq\"&gt;FAQ&lt;/a&gt;</string>
<string name="about_link_discord">&lt;a href=\"https://discordapp.com/invite/Z3bERWA\"&gt;Discord&lt;/a&gt;</string>
<string name="about_link_facebook">&lt;a href=\"https://www.facebook.com/LBRYio\"&gt;Facebook&lt;/a&gt;</string>
<string name="about_link_instagram">&lt;a href=\"https://www.instagram.com/LBRYio\"&gt;Instagram&lt;/a&gt;</string>
<string name="about_link_reddit">&lt;a href=\"https://reddit.com/r/lbry\"&gt;Reddit&lt;/a&gt;</string>
<string name="about_link_telegram">&lt;a href=\"https://t.me/lbryofficial\"&gt;Telegram&lt;/a&gt;</string>
<string name="about_link_twitter">&lt;a href=\"https://twitter.com/LBRYio\"&gt;Twitter&lt;/a&gt;</string>
<string name="update_mailing_preferences">Päivitä postitusasetukset</string>
<string name="app_version">Sovellus versio</string>
<string name="lbry_sdk">LBRY SDK</string>
<string name="platform">Alusta</string>
<string name="installation_id">Asennustunnus</string>
<string name="firebase_token">Firebase-tunnus</string>
<string name="logs">Lokit</string>
<string name="send_log">Lähetä loki</string>
<string name="connected_email">Yhdistetty sähköposti</string>
<string name="unknown">Tuntematon</string>
<string name="cannot_find_lbrynet_log">Lbrynet.log-tiedostoa ei löytynyt.</string>
<string name="cannot_share_lbrynet_log">Lbrynet.log-tiedostoa ei voi jakaa luparajoitusten takia.</string>
</resources>

View file

@ -20,6 +20,7 @@
<string name="settings">Settings</string>
<string name="about">About</string>
<string name="sign_in">Sign In</string>
<string name="shuffle">Shuffle</string>
<string name="startup_failed">App startup failed. Please check your data connection and try again. If this problem persists, please email hello@lbry.com</string>
<string name="no_claim_search_content">No content to display at this time. Please refine your selection or check back later.</string>
@ -242,6 +243,7 @@
<string name="notifications">Notifications</string>
<string name="subscriptions">Subscriptions</string>
<string name="content_interests">Content Interests</string>
<string name="mini_player_bottom_spacing">Mini-player bottom spacing</string>
<string name="keep_sdk_in_background">Keep the LBRY service running in the background for improved wallet and network performance</string>
<string name="participate_in_data_network">Participate in the data network (requires app and background service restart)</string>
@ -637,4 +639,6 @@
<string name="fa_asterisk" translatable="false">&#xf069;</string>
<string name="fa_comment_alt" translatable="false">&#xf27a;</string>
<string name="fa_broadcast_tower" translatable="false">&#xf519;</string>
<string name="fa_random" translatable="false">&#xf074;</string>
</resources>

View file

@ -23,6 +23,12 @@
app:title="@string/show_url_suggestions"
app:defaultValue="true"
app:iconSpaceReserved="false" />
<EditTextPreference
android:inputType="numberDecimal|numberSigned"
app:key="io.lbry.browser.preference.userinterface.MiniPlayerBottomMargin"
app:title="@string/mini_player_bottom_spacing"
app:defaultValue="4"
app:iconSpaceReserved="false" />
</PreferenceCategory>
<PreferenceCategory