diff --git a/app/src/main/java/io/lbry/browser/FileViewActivity.java b/app/src/main/java/io/lbry/browser/FileViewActivity.java index 8e316805..9537722c 100644 --- a/app/src/main/java/io/lbry/browser/FileViewActivity.java +++ b/app/src/main/java/io/lbry/browser/FileViewActivity.java @@ -11,12 +11,14 @@ import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; +import android.os.Handler; import android.text.format.DateUtils; import android.view.View; import android.widget.ImageView; import android.widget.ProgressBar; import android.widget.TextView; +import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.widget.NestedScrollView; import androidx.preference.PreferenceManager; @@ -39,6 +41,7 @@ import java.util.List; import io.lbry.browser.adapter.ClaimListAdapter; import io.lbry.browser.adapter.TagListAdapter; +import io.lbry.browser.exceptions.LbryUriException; import io.lbry.browser.model.Claim; import io.lbry.browser.model.ClaimCacheKey; import io.lbry.browser.model.File; @@ -49,11 +52,14 @@ import io.lbry.browser.tasks.LighthouseSearchTask; import io.lbry.browser.tasks.ResolveTask; import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Lbry; +import io.lbry.browser.utils.LbryUri; public class FileViewActivity extends AppCompatActivity { public static FileViewActivity instance = null; private static final int RELATED_CONTENT_SIZE = 16; + private static final int SHARE_REQUEST_CODE = 3001; + private static boolean startingShareActivity; private SimpleExoPlayer player; private boolean loadFilePending; @@ -64,6 +70,14 @@ public class FileViewActivity extends AppCompatActivity { private BroadcastReceiver sdkReadyReceiver; private Player.EventListener fileViewPlayerListener; + private View buttonShareAction; + private View buttonTipAction; + private View buttonRepostAction; + private View buttonDownloadAction; + private View buttonEditAction; + private View buttonDeleteAction; + private View buttonReportAction; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -233,6 +247,14 @@ public class FileViewActivity extends AppCompatActivity { public void onSuccess(List claims) { if (claims.size() > 0) { claim = claims.get(0); + if (Claim.TYPE_REPOST.equalsIgnoreCase(claim.getValueType())) { + claim = claim.getRepostedClaim(); + + // cache the reposted claim too for subsequent loads + ClaimCacheKey key = ClaimCacheKey.fromClaim(claim); + Lbry.claimCache.put(key, claim); + } + checkAndResetNowPlayingClaim(); loadFile(); renderClaim(); @@ -263,6 +285,29 @@ public class FileViewActivity extends AppCompatActivity { } }); + findViewById(R.id.file_view_action_share).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (claim != null) { + try { + String shareUrl = LbryUri.parse( + !Helper.isNullOrEmpty(claim.getShortUrl()) ? claim.getShortUrl() : claim.getPermanentUrl()).toTvString(); + Intent shareIntent = new Intent(); + shareIntent.setAction(Intent.ACTION_SEND); + shareIntent.setType("text/plain"); + shareIntent.putExtra(Intent.EXTRA_TEXT, shareUrl); + + 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 + } + } + } + }); + RecyclerView relatedContentList = findViewById(R.id.file_view_related_content_list); relatedContentList.setNestedScrollingEnabled(false); LinearLayoutManager llm = new LinearLayoutManager(this); @@ -375,6 +420,10 @@ public class FileViewActivity extends AppCompatActivity { MainActivity.appPlayer.prepare(mediaSource, true, true); } + private void loadViewCount() { + + } + private void loadRelatedContent() { // reset the list view ((RecyclerView) findViewById(R.id.file_view_related_content_list)).setAdapter(null); @@ -431,6 +480,16 @@ public class FileViewActivity extends AppCompatActivity { } protected void onUserLeaveHint() { + if (startingShareActivity) { + // share activity triggered this, so reset the flag at this point + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + startingShareActivity = false; + } + }, 1000); + return; + } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !MainActivity.mainActive) { PictureInPictureParams params = new PictureInPictureParams.Builder().build(); enterPictureInPictureMode(params); diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index 50129f1f..066ee069 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -175,6 +175,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener private NavigationMenuAdapter navMenuAdapter; private UrlSuggestionListAdapter urlSuggestionListAdapter; private List recentHistory; + private boolean hasLoadedFirstBalance; // broadcast receivers private BroadcastReceiver serviceActionsReceiver; @@ -500,6 +501,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener } } Lbry.walletBalance = walletBalance; + updateFloatingWalletBalance(); } @Override @@ -855,6 +857,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener } else { scheduleWalletBalanceUpdate(); scheduleWalletSyncTask(); + initFloatingWalletBalance(); } } @@ -863,9 +866,37 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener checkSyncedWallet(); } - //overrideRemoteWallet(); scheduleWalletBalanceUpdate(); scheduleWalletSyncTask(); + initFloatingWalletBalance(); + } + + public void showFloatingWalletBalance() { + findViewById(R.id.floating_balance_main_container).setVisibility(View.VISIBLE); + } + public void hideFloatingWalletBalance() { + findViewById(R.id.floating_balance_main_container).setVisibility(View.GONE); + } + + private void initFloatingWalletBalance() { + + findViewById(R.id.floating_balance_container).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + openFragment(WalletFragment.class, true, NavMenuItem.ID_ITEM_WALLET); + } + }); + } + + private void updateFloatingWalletBalance() { + if (!hasLoadedFirstBalance) { + findViewById(R.id.floating_balance_loading).setVisibility(View.GONE); + findViewById(R.id.floating_balance_value).setVisibility(View.VISIBLE); + hasLoadedFirstBalance = true; + } + + ((TextView) findViewById(R.id.floating_balance_value)).setText(Helper.shortCurrencyFormat( + Lbry.walletBalance == null ? 0 : Lbry.walletBalance.getAvailable().doubleValue())); } private void scheduleWalletBalanceUpdate() { diff --git a/app/src/main/java/io/lbry/browser/adapter/TransactionListAdapter.java b/app/src/main/java/io/lbry/browser/adapter/TransactionListAdapter.java index ff4bd478..98de0618 100644 --- a/app/src/main/java/io/lbry/browser/adapter/TransactionListAdapter.java +++ b/app/src/main/java/io/lbry/browser/adapter/TransactionListAdapter.java @@ -6,7 +6,6 @@ import android.net.Uri; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ImageView; import android.widget.TextView; import androidx.recyclerview.widget.RecyclerView; @@ -14,13 +13,10 @@ import androidx.recyclerview.widget.RecyclerView; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Date; import java.util.List; import io.lbry.browser.R; -import io.lbry.browser.model.Claim; import io.lbry.browser.model.Transaction; -import io.lbry.browser.model.UrlSuggestion; import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.LbryUri; import lombok.Setter; @@ -76,12 +72,22 @@ public class TransactionListAdapter extends RecyclerView.Adapter 0 ? View.VISIBLE : View.GONE); + vh.claimView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + LbryUri claimUrl = item.getClaimUrl(); + if (claimUrl != null && listener != null) { + listener.onClaimUrlClicked(claimUrl); + } + } + }); + vh.txidLinkView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -122,5 +128,6 @@ public class TransactionListAdapter extends RecyclerView.Adapter 0) { + info = TransactionInfo.fromJSONObject(array.getJSONObject(0)); + descStringId = R.string.abandon; + transaction.setAbandonInfo(info); + } + } + if (info == null && jsonObject.has("claim_info")) { + JSONArray array = jsonObject.getJSONArray("claim_info"); + if (array.length() > 0) { + info = TransactionInfo.fromJSONObject(array.getJSONObject(0)); + descStringId = info.getClaimName().startsWith("@") ? R.string.channel : R.string.publish; + transaction.setClaimInfo(info); + } + } + if (info == null && jsonObject.has("support_info")) { + JSONArray array = jsonObject.getJSONArray("support_info"); + if (array.length() > 0) { + info = TransactionInfo.fromJSONObject(array.getJSONObject(0)); + descStringId = info.isTip() ? R.string.tip : R.string.support; + transaction.setSupportInfo(info); + } } - if (info != null) { transaction.setClaim(info.getClaimName()); + transaction.setClaimId(info.getClaimId()); } } catch (JSONException ex) { // pass } + if (transaction.getValue().doubleValue() == 0 && info != null && info.getBalanceDelta().doubleValue() != 0) { + transaction.setValue(info.getBalanceDelta()); + } + if (descStringId == -1) { descStringId = transaction.getValue().signum() == -1 || transaction.getFee().signum() == -1 ? R.string.spend : R.string.receive; } @@ -71,6 +101,7 @@ public class Transaction { public static class TransactionInfo { private String address; private BigDecimal amount; + private BigDecimal balanceDelta; private String claimId; private String claimName; private boolean isTip; @@ -81,6 +112,7 @@ public class Transaction { info.setAddress(Helper.getJSONString("address", null, jsonObject)); info.setAmount(new BigDecimal(Helper.getJSONString("amount", "0", jsonObject))); + info.setBalanceDelta(new BigDecimal(Helper.getJSONString("balance_delta", "0", jsonObject))); info.setClaimId(Helper.getJSONString("claim_id", null, jsonObject)); info.setClaimName(Helper.getJSONString("claim_name", null, jsonObject)); info.setTip(Helper.getJSONBoolean("is_tip", false, jsonObject)); diff --git a/app/src/main/java/io/lbry/browser/tasks/wallet/SyncGetTask.java b/app/src/main/java/io/lbry/browser/tasks/wallet/SyncGetTask.java index 89d230bc..c6c85b0f 100644 --- a/app/src/main/java/io/lbry/browser/tasks/wallet/SyncGetTask.java +++ b/app/src/main/java/io/lbry/browser/tasks/wallet/SyncGetTask.java @@ -64,7 +64,7 @@ public class SyncGetTask extends AsyncTask { //Lbry.sync_apply({ password, data: response.data, blocking: true }); try { Map options = new HashMap<>(); - options.put("hash", walletSync.getHash()); + options.put("password", Helper.isNullOrEmpty(password) ? "" : password); options.put("data", walletSync.getData()); options.put("blocking", true); diff --git a/app/src/main/java/io/lbry/browser/ui/search/SearchFragment.java b/app/src/main/java/io/lbry/browser/ui/search/SearchFragment.java index a68eb816..052ec913 100644 --- a/app/src/main/java/io/lbry/browser/ui/search/SearchFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/search/SearchFragment.java @@ -10,7 +10,6 @@ import android.widget.ProgressBar; import android.widget.TextView; import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; diff --git a/app/src/main/java/io/lbry/browser/ui/settings/SettingsFragment.java b/app/src/main/java/io/lbry/browser/ui/settings/SettingsFragment.java index 039eee06..73104e0a 100644 --- a/app/src/main/java/io/lbry/browser/ui/settings/SettingsFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/settings/SettingsFragment.java @@ -3,9 +3,6 @@ package io.lbry.browser.ui.settings; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatDelegate; @@ -21,14 +18,6 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared setPreferencesFromResource(R.xml.settings, rootKey); } - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = super.onCreateView(inflater, container, savedInstanceState); - view.setBackgroundColor(getResources().getColor(R.color.pageBackground)); - - return view; - } - @Override public void onStart() { super.onStart(); @@ -37,6 +26,7 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared activity.hideSearchBar(); activity.showNavigationBackIcon(); activity.lockDrawer(); + activity.hideFloatingWalletBalance(); ActionBar actionBar = activity.getSupportActionBar(); if (actionBar != null) { @@ -59,7 +49,9 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared public void onStop() { Context context = getContext(); if (context instanceof MainActivity) { - ((MainActivity) context).restoreToggle(); + MainActivity activity = (MainActivity) getContext(); + activity.restoreToggle(); + activity.showFloatingWalletBalance(); } super.onStop(); } @@ -68,6 +60,13 @@ public class SettingsFragment extends PreferenceFragmentCompat implements Shared if (key.equalsIgnoreCase(MainActivity.PREFERENCE_KEY_DARK_MODE)) { boolean darkMode = sp.getBoolean(MainActivity.PREFERENCE_KEY_DARK_MODE, false); AppCompatDelegate.setDefaultNightMode(darkMode ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO); + + Context context = getContext(); + if (context instanceof MainActivity) { + MainActivity activity = (MainActivity) context; + activity.getDelegate().applyDayNight(); + activity.recreate(); + } } } } diff --git a/app/src/main/java/io/lbry/browser/ui/wallet/TransactionHistoryFragment.java b/app/src/main/java/io/lbry/browser/ui/wallet/TransactionHistoryFragment.java new file mode 100644 index 00000000..dd44bd12 --- /dev/null +++ b/app/src/main/java/io/lbry/browser/ui/wallet/TransactionHistoryFragment.java @@ -0,0 +1,158 @@ +package io.lbry.browser.ui.wallet; + +import android.content.Context; +import android.os.AsyncTask; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ProgressBar; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.ActionBar; +import androidx.recyclerview.widget.DividerItemDecoration; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.List; + +import io.lbry.browser.MainActivity; +import io.lbry.browser.R; +import io.lbry.browser.adapter.TransactionListAdapter; +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.LbryUri; + +public class TransactionHistoryFragment extends BaseFragment implements TransactionListAdapter.TransactionClickListener { + + private static final int TRANSACTION_PAGE_LIMIT = 50; + private boolean transactionsHaveReachedEnd; + private boolean transactionsLoading; + private ProgressBar loading; + private RecyclerView transactionList; + private TransactionListAdapter adapter; + private View noTransactionsView; + private int currentTransactionPage; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View root = inflater.inflate(R.layout.fragment_transaction_history, container, false); + + loading = root.findViewById(R.id.transaction_history_loading); + transactionList = root.findViewById(R.id.transaction_history_list); + noTransactionsView = root.findViewById(R.id.transaction_history_no_transactions); + + Context context = getContext(); + LinearLayoutManager llm = new LinearLayoutManager(context); + transactionList.setLayoutManager(llm); + transactionList.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL)); + + transactionList.addOnScrollListener(new RecyclerView.OnScrollListener() { + @Override + public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { + if (transactionsLoading) { + return; + } + LinearLayoutManager lm = (LinearLayoutManager) recyclerView.getLayoutManager(); + if (lm != null) { + int visibleItemCount = lm.getChildCount(); + int totalItemCount = lm.getItemCount(); + int pastVisibleItems = lm.findFirstVisibleItemPosition(); + if (pastVisibleItems + visibleItemCount >= totalItemCount) { + if (!transactionsHaveReachedEnd) { + // load more + currentTransactionPage++; + loadTransactions(); + } + } + } + } + }); + + return root; + } + + @Override + public void onResume() { + super.onResume(); + if (adapter != null && adapter.getItemCount() > 0 && transactionList != null) { + transactionList.setAdapter(adapter); + } + loadTransactions(); + } + + private void checkNoTransactions() { + Helper.setViewVisibility(noTransactionsView, adapter == null || adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE); + } + + private void loadTransactions() { + currentTransactionPage = currentTransactionPage == 0 ? 1 : currentTransactionPage; + transactionsLoading = true; + TransactionListTask task = new TransactionListTask(currentTransactionPage, TRANSACTION_PAGE_LIMIT, loading, new TransactionListTask.TransactionListHandler() { + @Override + public void onSuccess(List transactions, boolean hasReachedEnd) { + transactionsLoading = false; + transactionsHaveReachedEnd = hasReachedEnd; + if (adapter == null) { + adapter = new TransactionListAdapter(transactions, getContext()); + adapter.setListener(TransactionHistoryFragment.this); + if (transactionList != null) { + transactionList.setAdapter(adapter); + } + } else { + adapter.addTransactions(transactions); + } + checkNoTransactions(); + } + + @Override + public void onError(Exception error) { + transactionsLoading = false; + checkNoTransactions(); + } + }); + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + @Override + public void onStart() { + super.onStart(); + MainActivity activity = (MainActivity) getContext(); + if (activity != null) { + activity.hideSearchBar(); + activity.showNavigationBackIcon(); + activity.lockDrawer(); + + ActionBar actionBar = activity.getSupportActionBar(); + if (actionBar != null) { + actionBar.setTitle(R.string.transaction_history); + } + } + } + + @Override + public void onStop() { + Context context = getContext(); + if (context instanceof MainActivity) { + ((MainActivity) context).restoreToggle(); + } + super.onStop(); + } + + public void onTransactionClicked(Transaction transaction) { + // Don't do anything? Or open the transaction in a browser? + } + public void onClaimUrlClicked(LbryUri uri) { + Context context = getContext(); + if (context instanceof MainActivity) { + MainActivity activity = (MainActivity) context; + if (uri.isChannel()) { + activity.openChannelUrl(uri.toString()); + } else { + MainActivity.openFileUrl(uri.toString(), context); + } + } + } +} diff --git a/app/src/main/java/io/lbry/browser/ui/wallet/WalletFragment.java b/app/src/main/java/io/lbry/browser/ui/wallet/WalletFragment.java index 1ee169eb..5b169fb5 100644 --- a/app/src/main/java/io/lbry/browser/ui/wallet/WalletFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/wallet/WalletFragment.java @@ -4,7 +4,6 @@ import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.content.SharedPreferences; -import android.gesture.Gesture; import android.os.AsyncTask; import android.os.Bundle; import android.text.method.LinkMovementMethod; @@ -19,7 +18,6 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.core.text.HtmlCompat; -import androidx.fragment.app.Fragment; import androidx.preference.PreferenceManager; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; @@ -38,6 +36,7 @@ import io.lbry.browser.R; import io.lbry.browser.adapter.TransactionListAdapter; import io.lbry.browser.listener.SdkStatusListener; import io.lbry.browser.listener.WalletBalanceListener; +import io.lbry.browser.model.NavMenuItem; import io.lbry.browser.model.Transaction; import io.lbry.browser.model.WalletBalance; import io.lbry.browser.tasks.wallet.TransactionListTask; @@ -219,7 +218,6 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W recentTransactionsList.setLayoutManager(llm); recentTransactionsList.addItemDecoration(new DividerItemDecoration(context, DividerItemDecoration.VERTICAL)); - buttonGetNewAddress.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -272,6 +270,16 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W } }); + linkViewAll.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Context context = getContext(); + if (context instanceof MainActivity) { + ((MainActivity) context).openFragment(TransactionHistoryFragment.class, true, NavMenuItem.ID_ITEM_WALLET); + } + } + }); + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); final boolean walletSyncEnabled = sp.getBoolean(MainActivity.PREFERENCE_KEY_INTERNAL_WALLET_SYNC_ENABLED, false); switchSyncStatus.setChecked(walletSyncEnabled); @@ -398,12 +406,21 @@ public class WalletFragment extends BaseFragment implements SdkStatusListener, W hasFetchedRecentTransactions = false; super.onPause(); } + public void onStart() { + super.onStart(); + Context context = getContext(); + if (context instanceof MainActivity) { + MainActivity activity = (MainActivity) context; + activity.hideFloatingWalletBalance(); + } + } public void onStop() { Context context = getContext(); if (context instanceof MainActivity) { MainActivity activity = (MainActivity) context; activity.removeWalletBalanceListener(this); + activity.showFloatingWalletBalance(); } super.onStop(); } diff --git a/app/src/main/java/io/lbry/browser/utils/LbryUri.java b/app/src/main/java/io/lbry/browser/utils/LbryUri.java index aa7517e9..56672a98 100644 --- a/app/src/main/java/io/lbry/browser/utils/LbryUri.java +++ b/app/src/main/java/io/lbry/browser/utils/LbryUri.java @@ -10,6 +10,7 @@ import lombok.Data; @Data public class LbryUri { + public static final String LBRY_TV_BASE_URL = "https://lbry.tv"; public static final String PROTO_DEFAULT = "lbry://"; public static final String REGEX_INVALID_URI = "[ =&#:$@%?;/\\\\\"<>%\\{\\}|^~\\[\\]`\u0000-\u0008\u000b-\u000c\u000e-\u001F\uD800-\uDFFF\uFFFE-\uFFFF]"; public static final String REGEX_ADDRESS = "^(b|r)(?=[^0OIl]{32,33})[0-9A-Za-z]{32,33}$"; @@ -38,6 +39,10 @@ public class LbryUri { private String contentName; private String queryString; + private boolean isChannelUrl() { + return (!Helper.isNullOrEmpty(channelName) && Helper.isNullOrEmpty(streamName)) || (!Helper.isNullOrEmpty(claimName) && claimName.startsWith("@")); + } + public static LbryUri parse(String url) throws LbryUriException { return parse(url, false); } @@ -209,6 +214,59 @@ public class LbryUri { return sb.toString(); } + public String toTvString() { + String formattedChannelName = null; + if (channelName != null) { + formattedChannelName = channelName.startsWith("@") ? channelName : String.format("@%s", channelName); + } + String primaryClaimName = claimName; + if (Helper.isNullOrEmpty(primaryClaimName)) { + primaryClaimName = contentName; + } + if (Helper.isNullOrEmpty(primaryClaimName)) { + primaryClaimName = formattedChannelName; + } + if (Helper.isNullOrEmpty(primaryClaimName)) { + primaryClaimName = streamName; + } + + String primaryClaimId = claimId; + if (Helper.isNullOrEmpty(primaryClaimId)) { + primaryClaimId = !Helper.isNullOrEmpty(formattedChannelName) ? channelClaimId : streamClaimId; + } + + StringBuilder sb = new StringBuilder(); + sb.append(LBRY_TV_BASE_URL).append('/'); + sb.append(primaryClaimName); + + String secondaryClaimName = null; + if (Helper.isNullOrEmpty(claimName) && !Helper.isNullOrEmpty(contentName)) { + secondaryClaimName = contentName; + } + if (Helper.isNullOrEmpty(secondaryClaimName)) { + secondaryClaimName = !Helper.isNullOrEmpty(formattedChannelName) ? streamName : null; + } + String secondaryClaimId = !Helper.isNullOrEmpty(secondaryClaimName) ? streamClaimId : null; + + if (!Helper.isNullOrEmpty(primaryClaimId)) { + sb.append('#').append(primaryClaimId); + } + if (primaryClaimSequence > 0) { + sb.append(':').append(primaryClaimSequence); + } + if (!Helper.isNullOrEmpty(secondaryClaimName)) { + sb.append('/').append(secondaryClaimName); + } + if (!Helper.isNullOrEmpty(secondaryClaimId)) { + sb.append('#').append(secondaryClaimId); + } + if (secondaryClaimSequence > 0) { + sb.append(':').append(secondaryClaimSequence); + } + + return sb.toString(); + } + public static String normalize(String url) throws LbryUriException { return parse(url).toString(); } diff --git a/app/src/main/java/io/lbry/browser/utils/Lighthouse.java b/app/src/main/java/io/lbry/browser/utils/Lighthouse.java index be277d8d..cd8d4da2 100644 --- a/app/src/main/java/io/lbry/browser/utils/Lighthouse.java +++ b/app/src/main/java/io/lbry/browser/utils/Lighthouse.java @@ -22,6 +22,19 @@ import okhttp3.Response; public class Lighthouse { public static final String CONNECTION_STRING = "https://lighthouse.lbry.com"; public static Map> autocompleteCache = new HashMap<>(); + public static Map, List> searchCache = new HashMap<>(); + + private static Map buildSearchOptionsKey(String rawQuery, int size, int from, boolean nsfw, String relatedTo) { + Map options = new HashMap<>(); + options.put("s", rawQuery); + options.put("size", size); + options.put("from", from); + options.put("nsfw", nsfw); + if (!Helper.isNullOrEmpty(relatedTo)) { + options.put("related_to", relatedTo); + } + return options; + } public static List search(String rawQuery, int size, int from, boolean nsfw, String relatedTo) throws LbryRequestException, LbryResponseException { Uri.Builder uriBuilder = Uri.parse(String.format("%s/search", CONNECTION_STRING)).buildUpon(). @@ -34,6 +47,11 @@ public class Lighthouse { uriBuilder.appendQueryParameter("related_to", relatedTo); } + Map cacheKey = buildSearchOptionsKey(rawQuery, size, from, nsfw, relatedTo); + if (searchCache.containsKey(cacheKey)) { + return searchCache.get(cacheKey); + } + List results = new ArrayList<>(); Request request = new Request.Builder().url(uriBuilder.toString()).build(); OkHttpClient client = new OkHttpClient(); @@ -45,6 +63,7 @@ public class Lighthouse { Claim claim = Claim.fromSearchJSONObject(array.getJSONObject(i)); results.add(claim); } + searchCache.put(cacheKey, results); } else { throw new LbryResponseException(response.message()); } diff --git a/app/src/main/res/drawable-anydpi/ic_arrow_left.xml b/app/src/main/res/drawable-anydpi/ic_arrow_left.xml new file mode 100644 index 00000000..b94a76b7 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_arrow_left.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable-anydpi/ic_arrow_right.xml b/app/src/main/res/drawable-anydpi/ic_arrow_right.xml new file mode 100644 index 00000000..ac8898d5 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_arrow_right.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable-anydpi/ic_delete.xml b/app/src/main/res/drawable-anydpi/ic_delete.xml new file mode 100644 index 00000000..24678bc6 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_delete.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable-anydpi/ic_edit.xml b/app/src/main/res/drawable-anydpi/ic_edit.xml new file mode 100644 index 00000000..f13ba712 --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_edit.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable-hdpi/ic_arrow_left.png b/app/src/main/res/drawable-hdpi/ic_arrow_left.png new file mode 100644 index 00000000..11d1f4b6 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_arrow_left.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_arrow_right.png b/app/src/main/res/drawable-hdpi/ic_arrow_right.png new file mode 100644 index 00000000..76c1c906 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_arrow_right.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_delete.png b/app/src/main/res/drawable-hdpi/ic_delete.png new file mode 100644 index 00000000..e366b650 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_delete.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_edit.png b/app/src/main/res/drawable-hdpi/ic_edit.png new file mode 100644 index 00000000..a3226fb9 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_edit.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_arrow_left.png b/app/src/main/res/drawable-mdpi/ic_arrow_left.png new file mode 100644 index 00000000..ceaf25a6 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_arrow_left.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_arrow_right.png b/app/src/main/res/drawable-mdpi/ic_arrow_right.png new file mode 100644 index 00000000..3aec31d3 Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_arrow_right.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_delete.png b/app/src/main/res/drawable-mdpi/ic_delete.png new file mode 100644 index 00000000..554abc4c Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_delete.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_edit.png b/app/src/main/res/drawable-mdpi/ic_edit.png new file mode 100644 index 00000000..f0c1fafa Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_edit.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_arrow_left.png b/app/src/main/res/drawable-xhdpi/ic_arrow_left.png new file mode 100644 index 00000000..7217af6e Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_arrow_left.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_arrow_right.png b/app/src/main/res/drawable-xhdpi/ic_arrow_right.png new file mode 100644 index 00000000..714857e2 Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_arrow_right.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_delete.png b/app/src/main/res/drawable-xhdpi/ic_delete.png new file mode 100644 index 00000000..5eede98d Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_delete.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_edit.png b/app/src/main/res/drawable-xhdpi/ic_edit.png new file mode 100644 index 00000000..b508285a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_edit.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_arrow_left.png b/app/src/main/res/drawable-xxhdpi/ic_arrow_left.png new file mode 100644 index 00000000..6220d1ea Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_arrow_left.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_arrow_right.png b/app/src/main/res/drawable-xxhdpi/ic_arrow_right.png new file mode 100644 index 00000000..b6b817dd Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_arrow_right.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_delete.png b/app/src/main/res/drawable-xxhdpi/ic_delete.png new file mode 100644 index 00000000..df20cf5d Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_delete.png differ diff --git a/app/src/main/res/drawable-xxhdpi/ic_edit.png b/app/src/main/res/drawable-xxhdpi/ic_edit.png new file mode 100644 index 00000000..40ef06e3 Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_edit.png differ diff --git a/app/src/main/res/drawable/bg_floating_balance.xml b/app/src/main/res/drawable/bg_floating_balance.xml new file mode 100644 index 00000000..56b4ed14 --- /dev/null +++ b/app/src/main/res/drawable/bg_floating_balance.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/bg_floating_reward.xml b/app/src/main/res/drawable/bg_floating_reward.xml new file mode 100644 index 00000000..524e0a45 --- /dev/null +++ b/app/src/main/res/drawable/bg_floating_reward.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_file_view.xml b/app/src/main/res/layout/activity_file_view.xml index 7cc3884a..307a25b1 100644 --- a/app/src/main/res/layout/activity_file_view.xml +++ b/app/src/main/res/layout/activity_file_view.xml @@ -39,13 +39,20 @@ android:layout_weight="10" android:layout_width="match_parent" android:layout_height="match_parent" - android:visibility="invisible"> + android:visibility="visible"> + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/card_wallet_recent_transactions.xml b/app/src/main/res/layout/card_wallet_recent_transactions.xml index 916bf3c8..0bee6c1a 100644 --- a/app/src/main/res/layout/card_wallet_recent_transactions.xml +++ b/app/src/main/res/layout/card_wallet_recent_transactions.xml @@ -29,6 +29,7 @@ android:layout_height="wrap_content" android:layout_alignParentEnd="true" android:layout_centerVertical="true" + android:background="?attr/selectableItemBackground" android:clickable="true" android:fontFamily="@font/inter" android:text="@string/view_all" diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index 81f12902..a9d18a88 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -28,17 +28,18 @@ android:layout_height="match_parent" /> + - - - \ No newline at end of file diff --git a/app/src/main/res/layout/floating_wallet_balance.xml b/app/src/main/res/layout/floating_wallet_balance.xml new file mode 100644 index 00000000..3cc6bb29 --- /dev/null +++ b/app/src/main/res/layout/floating_wallet_balance.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_transaction_history.xml b/app/src/main/res/layout/fragment_transaction_history.xml new file mode 100644 index 00000000..2762311d --- /dev/null +++ b/app/src/main/res/layout/fragment_transaction_history.xml @@ -0,0 +1,31 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 48107090..b5b9d2aa 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -58,6 +58,7 @@ Report Loading decentralized data... Related Content + Share LBRY content Unsupported Content Sorry, we are unable to display this content in the app. You can find the file named %1$s in your downloads folder. @@ -156,7 +157,9 @@ Your credits could not be sent at this time. Please try again later. Loading transactions... There are no recent transactions to display. + There are no transactions to display at this time. fee %1$s + Transaction History You sent %1$s credit