diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index d29d4e2b..37cd325b 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -610,13 +610,17 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener urlSuggestionListAdapter.setListener(new UrlSuggestionListAdapter.UrlSuggestionClickListener() { @Override public void onUrlSuggestionClicked(UrlSuggestion urlSuggestion) { + Context context = MainActivity.this; switch (urlSuggestion.getType()) { case UrlSuggestion.TYPE_CHANNEL: // open channel page - openChannelUrl(urlSuggestion.getUri().toString()); + if (urlSuggestion.getClaim() != null) { + openChannelClaim(urlSuggestion.getClaim()); + } else { + openChannelUrl(urlSuggestion.getUri().toString()); + } break; case UrlSuggestion.TYPE_FILE: - Context context = MainActivity.this; if (urlSuggestion.getClaim() != null) { openFileClaim(urlSuggestion.getClaim(), context); } else { @@ -809,7 +813,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener } } - if (!isUrlWithScheme) { + if (!isUrlWithScheme && !isChannel) { UrlSuggestion suggestion = new UrlSuggestion(UrlSuggestion.TYPE_TAG, text); suggestions.add(suggestion); } diff --git a/app/src/main/java/io/lbry/browser/adapter/ChannelFilterListAdapter.java b/app/src/main/java/io/lbry/browser/adapter/ChannelFilterListAdapter.java index 490de509..f4bc6fdf 100644 --- a/app/src/main/java/io/lbry/browser/adapter/ChannelFilterListAdapter.java +++ b/app/src/main/java/io/lbry/browser/adapter/ChannelFilterListAdapter.java @@ -26,6 +26,7 @@ public class ChannelFilterListAdapter extends RecyclerView.Adapter items; @Getter + @Setter private Claim selectedItem; @Setter private ChannelItemSelectionListener listener; @@ -66,6 +67,11 @@ public class ChannelFilterListAdapter extends RecyclerView.Adapter(items.subList(0, 1)); + notifyDataSetChanged(); + } + public void addClaims(List claims) { for (Claim claim : claims) { if (!items.contains(claim)) { diff --git a/app/src/main/java/io/lbry/browser/adapter/ClaimListAdapter.java b/app/src/main/java/io/lbry/browser/adapter/ClaimListAdapter.java index 095d80fc..8a03e95d 100644 --- a/app/src/main/java/io/lbry/browser/adapter/ClaimListAdapter.java +++ b/app/src/main/java/io/lbry/browser/adapter/ClaimListAdapter.java @@ -13,6 +13,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; +import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; @@ -79,6 +80,8 @@ public class ClaimListAdapter extends RecyclerView.Adapter 0 ? View.VISIBLE : View.GONE); + vh.feeView.setText(cost.doubleValue() > 0 ? Helper.shortCurrencyFormat(cost.divide(new BigDecimal(100000000)).doubleValue()) : null); vh.alphaView.setText(item.getName().substring(0, Math.min(5, item.getName().length() - 1))); vh.publisherView.setText(signingChannel != null ? signingChannel.getName() : context.getString(R.string.anonymous)); vh.publishTimeView.setText(DateUtils.getRelativeTimeSpanString( diff --git a/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java b/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java index 043978da..3c45d549 100644 --- a/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java +++ b/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java @@ -13,6 +13,7 @@ import java.util.List; import io.lbry.browser.exceptions.LbryUriException; import io.lbry.browser.model.Tag; import io.lbry.browser.model.UrlSuggestion; +import io.lbry.browser.model.ViewHistory; import io.lbry.browser.model.lbryinc.Subscription; import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.LbryUri; @@ -25,27 +26,49 @@ public class DatabaseHelper extends SQLiteOpenHelper { // local subscription store "CREATE TABLE subscriptions (url TEXT PRIMARY KEY NOT NULL, channel_name TEXT NOT NULL)", // url entry / suggestion history - "CREATE TABLE history (id INTEGER PRIMARY KEY NOT NULL, value TEXT NOT NULL, url TEXT, type INTEGER NOT NULL, timestamp TEXT NOT NULL)", + "CREATE TABLE url_history (id INTEGER PRIMARY KEY NOT NULL, value TEXT NOT NULL, url TEXT, type INTEGER NOT NULL, timestamp TEXT NOT NULL)", // tags (known and followed) - "CREATE TABLE tags (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, is_followed INTEGER NOT NULL)" - // local claim cache store for quick load / refresh (or offline mode)? - + "CREATE TABLE tags (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, is_followed INTEGER NOT NULL)", + // view history (stores only stream claims that have resolved) + "CREATE TABLE view_history (" + + " id INTEGER PRIMARY KEY NOT NULL" + + ", url TEXT NOT NULL" + + ", claim_id TEXT" + + ", claim_name TEXT" + + ", cost REAL " + + ", title TEXT " + + ", publisher_claim_id TEXT" + + ", publisher_name TEXT" + + ", publisher_title TEXT" + + ", thumbnail_url TEXT" + + ", release_time INTEGER " + + ", device TEXT" + + ", timestamp TEXT NOT NULL)" }; private static final String[] SQL_CREATE_INDEXES = { "CREATE UNIQUE INDEX idx_subscription_url ON subscriptions (url)", - "CREATE UNIQUE INDEX idx_history_value ON history (value)", - "CREATE UNIQUE INDEX idx_history_url ON history (url)", - "CREATE UNIQUE INDEX idx_tag_name ON tags (name)" + "CREATE UNIQUE INDEX idx_url_history_value ON url_history (value)", + "CREATE UNIQUE INDEX idx_url_history_url ON url_history (url)", + "CREATE UNIQUE INDEX idx_tag_name ON tags (name)", + "CREATE UNIQUE INDEX idx_view_history_url_device ON view_history (url, device)", + "CREATE INDEX idx_view_history_device ON view_history (device)" }; private static final String SQL_INSERT_SUBSCRIPTION = "REPLACE INTO subscriptions (channel_name, url) VALUES (?, ?)"; private static final String SQL_DELETE_SUBSCRIPTION = "DELETE FROM subscriptions WHERE url = ?"; private static final String SQL_GET_SUBSCRIPTIONS = "SELECT channel_name, url FROM subscriptions"; - private static final String SQL_INSERT_HISTORY = "REPLACE INTO history (value, url, type, timestamp) VALUES (?, ?, ?)"; - private static final String SQL_CLEAR_HISTORY = "DELETE FROM history"; - private static final String SQL_CLEAR_HISTORY_BEFORE_TIME = "DELETE FROM history WHERE timestamp < ?"; - private static final String SQL_GET_RECENT_HISTORY = "SELECT value, url, type FROM history ORDER BY timestamp DESC LIMIT 10"; + private static final String SQL_INSERT_URL_HISTORY = "REPLACE INTO url_history (value, url, type, timestamp) VALUES (?, ?, ?)"; + private static final String SQL_CLEAR_URL_HISTORY = "DELETE FROM url_history"; + private static final String SQL_CLEAR_URL_HISTORY_BEFORE_TIME = "DELETE FROM url_history WHERE timestamp < ?"; + private static final String SQL_GET_RECENT_URL_HISTORY = "SELECT value, url, type FROM url_history ORDER BY timestamp DESC LIMIT 10"; + + private static final String SQL_INSERT_VIEW_HISTORY = + "REPLACE INTO view_history (url, claim_id, claim_name, cost, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + private static final String SQL_CLEAR_VIEW_HISTORY = "DELETE FROM view_history"; + private static final String SQL_CLEAR_VIEW_HISTORY_BY_DEVICE = "DELETE FROM view_history WHERE device = ?"; + private static final String SQL_CLEAR_VIEW_HISTORY_BEFORE_TIME = "DELETE FROM view_history WHERE timestamp < ?"; + private static final String SQL_CLEAR_VIEW_HISTORY_BY_DEVICE_BEFORE_TIME = "DELETE FROM view_history WHERE device = ? AND timestamp < ?"; private static final String SQL_INSERT_TAG = "REPLACE INTO tags (name, is_followed) VALUES (?, ?)"; private static final String SQL_GET_KNOWN_TAGS = "SELECT name, is_followed FROM tags"; @@ -70,23 +93,23 @@ public class DatabaseHelper extends SQLiteOpenHelper { } - public static void createOrUpdateHistoryItem(String text, String url, int type, SQLiteDatabase db) { - db.execSQL(SQL_INSERT_HISTORY, new Object[] { + public static void createOrUpdateUrlHistoryItem(String text, String url, int type, SQLiteDatabase db) { + db.execSQL(SQL_INSERT_URL_HISTORY, new Object[] { text, url, type, new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(new Date()) }); } - public static void clearHistory(SQLiteDatabase db) { - db.execSQL(SQL_CLEAR_HISTORY); + public static void clearUrlHistory(SQLiteDatabase db) { + db.execSQL(SQL_CLEAR_URL_HISTORY); } - public static void clearHistoryBefore(Date date, SQLiteDatabase db) { - db.execSQL(SQL_CLEAR_HISTORY_BEFORE_TIME, new Object[] { new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(new Date()) }); + public static void clearUrlHistoryBefore(Date date, SQLiteDatabase db) { + db.execSQL(SQL_CLEAR_URL_HISTORY_BEFORE_TIME, new Object[] { new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(new Date()) }); } // History items are essentially url suggestions public static List getRecentHistory(SQLiteDatabase db) { List suggestions = new ArrayList<>(); Cursor cursor = null; try { - cursor = db.rawQuery(SQL_GET_RECENT_HISTORY, null); + cursor = db.rawQuery(SQL_GET_RECENT_URL_HISTORY, null); while (cursor.moveToNext()) { UrlSuggestion suggestion = new UrlSuggestion(); suggestion.setText(cursor.getString(0)); @@ -105,6 +128,24 @@ public class DatabaseHelper extends SQLiteOpenHelper { return suggestions; } + // View history items are stream claims + public static void createOrUpdateViewHistoryItem(ViewHistory viewHistory, SQLiteDatabase db) { + db.execSQL(SQL_INSERT_VIEW_HISTORY, new Object[] { + viewHistory.getUri().toString(), + viewHistory.getClaimId(), + viewHistory.getClaimName(), + viewHistory.getCost() != null ? viewHistory.getCost().doubleValue() : 0, + viewHistory.getTitle(), + viewHistory.getPublisherClaimId(), + viewHistory.getPublisherName(), + viewHistory.getPublisherTitle(), + viewHistory.getThumbnailUrl(), + viewHistory.getDevice(), + viewHistory.getReleaseTime(), + new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(new Date()) + }); + } + public static void createOrUpdateTag(Tag tag, SQLiteDatabase db) { db.execSQL(SQL_INSERT_TAG, new Object[] { tag.getLowercaseName(), tag.isFollowed() ? 1 : 0 }); } diff --git a/app/src/main/java/io/lbry/browser/model/Claim.java b/app/src/main/java/io/lbry/browser/model/Claim.java index 88e988d5..a8f85379 100644 --- a/app/src/main/java/io/lbry/browser/model/Claim.java +++ b/app/src/main/java/io/lbry/browser/model/Claim.java @@ -14,6 +14,7 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.stream.Stream; import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.LbryUri; @@ -160,6 +161,45 @@ public class Claim { return 0; } + public static Claim fromViewHistory(ViewHistory viewHistory) { + // only for stream claims + Claim claim = new Claim(); + claim.setClaimId(viewHistory.getClaimId()); + claim.setName(viewHistory.getClaimName()); + claim.setValueType(TYPE_STREAM); + claim.setPermanentUrl(viewHistory.getUri().toString()); + + StreamMetadata value = new StreamMetadata(); + value.setTitle(viewHistory.getTitle()); + value.setReleaseTime(viewHistory.getReleaseTime()); + if (!Helper.isNullOrEmpty(viewHistory.getThumbnailUrl())) { + Resource thumbnail = new Resource(); + thumbnail.setUrl(viewHistory.getThumbnailUrl()); + value.setThumbnail(thumbnail); + } + if (viewHistory.getCost() != null && viewHistory.getCost().doubleValue() > 0) { + Fee fee = new Fee(); + fee.setAmount(String.valueOf(viewHistory.getCost().doubleValue())); + fee.setCurrency("LBC"); // always LBC + } + + claim.setValue(value); + + if (!Helper.isNullOrEmpty(viewHistory.getPublisherClaimId())) { + Claim signingChannel = new Claim(); + signingChannel.setClaimId(viewHistory.getPublisherClaimId()); + signingChannel.setName(viewHistory.getPublisherName()); + if (!Helper.isNullOrEmpty(viewHistory.getPublisherTitle())) { + GenericMetadata channelValue = new GenericMetadata(); + channelValue.setTitle(viewHistory.getPublisherTitle()); + signingChannel.setValue(channelValue); + } + claim.setSigningChannel(signingChannel); + } + + return claim; + } + public static Claim fromJSONObject(JSONObject claimObject) { Claim claim = null; String claimJson = claimObject.toString(); diff --git a/app/src/main/java/io/lbry/browser/model/ViewHistory.java b/app/src/main/java/io/lbry/browser/model/ViewHistory.java new file mode 100644 index 00000000..6bcb75dd --- /dev/null +++ b/app/src/main/java/io/lbry/browser/model/ViewHistory.java @@ -0,0 +1,57 @@ +package io.lbry.browser.model; + +import java.math.BigDecimal; +import java.util.Date; + +import io.lbry.browser.exceptions.LbryUriException; +import io.lbry.browser.utils.LbryUri; +import lombok.Data; + +@Data +public class ViewHistory { + private LbryUri uri; + private String claimId; + private String claimName; + private BigDecimal cost; + private String title; + private String publisherClaimId; + private String publisherName; + private String publisherTitle; + private String thumbnailUrl; + private String device; + private long releaseTime; + private Date timestamp; + + public static ViewHistory fromClaimWithUrlAndDeviceName(Claim claim, String url, String deviceName) { + ViewHistory history = new ViewHistory(); + LbryUri uri = LbryUri.tryParse(url); + if (uri == null) { + uri = LbryUri.tryParse(claim.getPermanentUrl()); + } + history.setUri(uri); + history.setClaimId(claim.getClaimId()); + history.setClaimName(claim.getName()); + history.setTitle(claim.getTitle()); + history.setThumbnailUrl(claim.getThumbnailUrl()); + + Claim.GenericMetadata metadata = claim.getValue(); + if (metadata instanceof Claim.StreamMetadata) { + Claim.StreamMetadata value = (Claim.StreamMetadata) metadata; + history.setReleaseTime(value.getReleaseTime()); + if (value.getFee() != null) { + history.setCost(new BigDecimal(value.getFee().getAmount())); + } + } + + Claim signingChannel = claim.getSigningChannel(); + if (signingChannel != null) { + history.setPublisherClaimId(signingChannel.getClaimId()); + history.setPublisherName(signingChannel.getName()); + history.setPublisherTitle(signingChannel.getTitle()); + } + + history.setDevice(deviceName); + + return history; + } +} diff --git a/app/src/main/java/io/lbry/browser/tasks/localdata/CreateUrlHistoryTask.java b/app/src/main/java/io/lbry/browser/tasks/localdata/CreateUrlHistoryTask.java new file mode 100644 index 00000000..f74683eb --- /dev/null +++ b/app/src/main/java/io/lbry/browser/tasks/localdata/CreateUrlHistoryTask.java @@ -0,0 +1,44 @@ +package io.lbry.browser.tasks.localdata; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.os.AsyncTask; + +import io.lbry.browser.MainActivity; +import io.lbry.browser.data.DatabaseHelper; +import io.lbry.browser.model.UrlSuggestion; +import io.lbry.browser.tasks.GenericTaskHandler; + +public class CreateUrlHistoryTask extends AsyncTask { + private Context context; + private UrlSuggestion suggestion; + private GenericTaskHandler handler; + private Exception error; + + public CreateUrlHistoryTask(UrlSuggestion suggestion, Context context, GenericTaskHandler handler) { + this.suggestion = suggestion; + this.context = context; + this.handler = handler; + + } + protected Boolean doInBackground(Void... params) { + try { + SQLiteDatabase db = ((MainActivity) context).getDbHelper().getWritableDatabase(); + DatabaseHelper.createOrUpdateUrlHistoryItem(suggestion.getText(), suggestion.getUri().toString(), suggestion.getType(), db); + } catch (Exception ex) { + error = ex; + return false; + } + + return true; + } + protected void onPostExecute(Boolean result) { + if (handler != null) { + if (result) { + handler.onSuccess(); + } else { + handler.onError(error); + } + } + } +} diff --git a/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java b/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java index 6f7a5a63..6c2881c2 100644 --- a/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java @@ -160,7 +160,7 @@ public class ChannelFragment extends BaseFragment { public void onSuccess() { if (isFollowing) { Lbryio.removeSubscription(subscription); - Lbryio.addCachedResolvedSubscription(claim); + Lbryio.removeCachedResolvedSubscription(claim); } else { Lbryio.addSubscription(subscription); Lbryio.addCachedResolvedSubscription(claim); diff --git a/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java b/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java index b4e8db4e..28a4d92b 100644 --- a/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/following/FollowingFragment.java @@ -239,6 +239,7 @@ public class FollowingFragment extends BaseFragment implements discoverLink.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { + buildChannelIdsAndUrls(); discoverDialog = DiscoverDialogFragment.newInstance(); excludeChannelIdsForDiscover = channelIds != null ? new ArrayList<>(channelIds) : null; discoverDialog.setAdapter(suggestedChannelAdapter); @@ -351,7 +352,7 @@ public class FollowingFragment extends BaseFragment implements subscriptionsList = new ArrayList<>(Lbryio.subscriptions); buildChannelIdsAndUrls(); if (Lbryio.cacheResolvedSubscriptions.size() > 0) { - updateChannelFilterListAdapter(Lbryio.cacheResolvedSubscriptions); + updateChannelFilterListAdapter(Lbryio.cacheResolvedSubscriptions, resetClaimSearchContent); } else { fetchAndResolveChannelList(); } @@ -469,7 +470,7 @@ public class FollowingFragment extends BaseFragment implements ResolveTask resolveSubscribedTask = new ResolveTask(channelUrls, Lbry.LBRY_TV_CONNECTION_STRING, channelListLoading, new ResolveTask.ResolveResultHandler() { @Override public void onSuccess(List claims) { - updateChannelFilterListAdapter(claims); + updateChannelFilterListAdapter(claims, true); Lbryio.cacheResolvedSubscriptions = claims; } @@ -488,7 +489,7 @@ public class FollowingFragment extends BaseFragment implements return (contentListAdapter == null || contentListAdapter.getItemCount() == 0) ? bigContentLoading : contentLoading; } - private void updateChannelFilterListAdapter(List resolvedSubs) { + private void updateChannelFilterListAdapter(List resolvedSubs, boolean reset) { if (channelFilterListAdapter == null) { channelFilterListAdapter = new ChannelFilterListAdapter(getContext()); channelFilterListAdapter.setListener(new ChannelItemSelectionListener() { @@ -528,6 +529,10 @@ public class FollowingFragment extends BaseFragment implements if (horizontalChannelList != null && horizontalChannelList.getAdapter() == null) { horizontalChannelList.setAdapter(channelFilterListAdapter); } + if (reset) { + channelFilterListAdapter.clearClaims(); + channelFilterListAdapter.setSelectedItem(null); + } channelFilterListAdapter.addClaims(resolvedSubs); } @@ -622,7 +627,7 @@ public class FollowingFragment extends BaseFragment implements suggestedHasReachedEnd = hasReachedEnd; suggestedClaimSearchLoading = false; if (discoverDialog != null) { - discoverDialog.setLoading(true); + discoverDialog.setLoading(false); } if (suggestedChannelAdapter == null) { @@ -684,46 +689,45 @@ public class FollowingFragment extends BaseFragment implements public void onChannelItemSelected(Claim claim) { // subscribe - Subscription subscription = new Subscription(); - subscription.setChannelName(claim.getName()); - subscription.setUrl(claim.getPermanentUrl()); + Subscription subscription = Subscription.fromClaim(claim); String channelClaimId = claim.getClaimId(); ChannelSubscribeTask task = new ChannelSubscribeTask(getContext(), channelClaimId, subscription, false, new ChannelSubscribeTask.ChannelSubscribeHandler() { @Override public void onSuccess() { if (discoverDialog != null) { - fetchSubscriptions(); + Lbryio.addSubscription(subscription); + Lbryio.addCachedResolvedSubscription(claim); + resetClaimSearchContent = true; + fetchLoadedSubscriptions(); } saveSharedUserState(); } @Override - public void onError(Exception exception) { - - } + public void onError(Exception error) { } }); task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); updateSuggestedDoneButtonText(); } public void onChannelItemDeselected(Claim claim) { // unsubscribe - Subscription subscription = new Subscription(); - subscription.setChannelName(claim.getName()); - subscription.setUrl(claim.getPermanentUrl()); + Subscription subscription = Subscription.fromClaim(claim); String channelClaimId = claim.getClaimId(); - ChannelSubscribeTask task = new ChannelSubscribeTask(getContext(), channelClaimId, subscription, true, new ChannelSubscribeTask.ChannelSubscribeHandler() { @Override public void onSuccess() { if (discoverDialog != null) { - fetchSubscriptions(); + Lbryio.removeSubscription(subscription); + Lbryio.removeCachedResolvedSubscription(claim); + resetClaimSearchContent = true; + fetchLoadedSubscriptions(); } saveSharedUserState(); } @Override - public void onError(Exception exception) { + public void onError(Exception error) { } }); @@ -735,8 +739,8 @@ public class FollowingFragment extends BaseFragment implements } private void checkNoContent(boolean suggested) { - RecyclerView.Adapter adpater = suggested ? suggestedChannelAdapter : contentListAdapter; - boolean noContent = adpater == null || adpater.getItemCount() == 0; + RecyclerView.Adapter adapter = suggested ? suggestedChannelAdapter : contentListAdapter; + boolean noContent = adapter == null || adapter.getItemCount() == 0; Helper.setViewVisibility(noContentView, noContent ? View.VISIBLE : View.GONE); } diff --git a/app/src/main/java/io/lbry/browser/utils/Helper.java b/app/src/main/java/io/lbry/browser/utils/Helper.java index 1f596273..53f46162 100644 --- a/app/src/main/java/io/lbry/browser/utils/Helper.java +++ b/app/src/main/java/io/lbry/browser/utils/Helper.java @@ -9,6 +9,7 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.ShapeDrawable; +import android.os.Build; import android.view.View; import android.widget.TextView; @@ -37,6 +38,7 @@ import io.lbry.browser.model.Tag; import okhttp3.MediaType; public final class Helper { + public static final String UNKNOWN = "Unknown"; public static final String METHOD_GET = "GET"; public static final String METHOD_POST = "POST"; public static final String ISO_DATE_FORMAT_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS"; @@ -331,4 +333,11 @@ public final class Helper { ((MainActivity) context).setWunderbarValue(value); } } + + public static String getDeviceName() { + if (Helper.isNullOrEmpty(Build.MANUFACTURER) || UNKNOWN.equalsIgnoreCase(Build.MANUFACTURER)) { + return Build.MODEL; + } + return String.format("%s %s", Build.MANUFACTURER, Build.MODEL); + } } 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 56672a98..cf8929bf 100644 --- a/app/src/main/java/io/lbry/browser/utils/LbryUri.java +++ b/app/src/main/java/io/lbry/browser/utils/LbryUri.java @@ -43,6 +43,13 @@ public class LbryUri { return (!Helper.isNullOrEmpty(channelName) && Helper.isNullOrEmpty(streamName)) || (!Helper.isNullOrEmpty(claimName) && claimName.startsWith("@")); } + public static LbryUri tryParse(String url) { + try { + return parse(url, false); + } catch (LbryUriException ex) { + return null; + } + } public static LbryUri parse(String url) throws LbryUriException { return parse(url, false); } @@ -93,7 +100,7 @@ public class LbryUri { throw new LbryUriException("URL does not include name."); } - for (String component : components.subList(1, components.size() - 1)) { + for (String component : components.subList(1, components.size())) { if (component.indexOf(' ') > -1) { throw new LbryUriException("URL cannot include a space."); } @@ -132,7 +139,7 @@ public class LbryUri { LbryUri uri = new LbryUri(); uri.setChannel(isChannel); - uri.setPath(Helper.join(components.subList(1, components.size() - 1), "")); + uri.setPath(Helper.join(components.subList(1, components.size()), "")); uri.setStreamName(streamName); uri.setStreamClaimId(streamClaimId); uri.setChannelName(channelName); diff --git a/app/src/main/res/drawable/bg_stream_cost.xml b/app/src/main/res/drawable/bg_stream_cost.xml new file mode 100644 index 00000000..2d0dfb26 --- /dev/null +++ b/app/src/main/res/drawable/bg_stream_cost.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/list_item_channel.xml b/app/src/main/res/layout/list_item_channel.xml index 8ec69719..9ebbb515 100644 --- a/app/src/main/res/layout/list_item_channel.xml +++ b/app/src/main/res/layout/list_item_channel.xml @@ -46,7 +46,7 @@ android:textColor="@color/lightForeground" android:textFontWeight="300" android:textSize="12sp" /> - w + @@ -76,6 +76,36 @@ android:textColor="@color/white" android:textFontWeight="300" /> + + + + + + + + + + + + #AAAAAA #0E0E0E #CC000000 + #F4E866 #EEEEEE diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 0411d94f..c05dbb9b 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -12,6 +12,7 @@ #444444 #F1F1F1 #CC000000 + #F4E866 #222222 #AAAAAA