Channel follow/unfollow fixes. Display stream cost.

This commit is contained in:
Akinwale Ariwodola 2020-05-05 01:25:30 +01:00
parent c78f669fb1
commit f45c517048
17 changed files with 363 additions and 44 deletions

View file

@ -610,13 +610,17 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
urlSuggestionListAdapter.setListener(new UrlSuggestionListAdapter.UrlSuggestionClickListener() { urlSuggestionListAdapter.setListener(new UrlSuggestionListAdapter.UrlSuggestionClickListener() {
@Override @Override
public void onUrlSuggestionClicked(UrlSuggestion urlSuggestion) { public void onUrlSuggestionClicked(UrlSuggestion urlSuggestion) {
Context context = MainActivity.this;
switch (urlSuggestion.getType()) { switch (urlSuggestion.getType()) {
case UrlSuggestion.TYPE_CHANNEL: case UrlSuggestion.TYPE_CHANNEL:
// open channel page // open channel page
openChannelUrl(urlSuggestion.getUri().toString()); if (urlSuggestion.getClaim() != null) {
openChannelClaim(urlSuggestion.getClaim());
} else {
openChannelUrl(urlSuggestion.getUri().toString());
}
break; break;
case UrlSuggestion.TYPE_FILE: case UrlSuggestion.TYPE_FILE:
Context context = MainActivity.this;
if (urlSuggestion.getClaim() != null) { if (urlSuggestion.getClaim() != null) {
openFileClaim(urlSuggestion.getClaim(), context); openFileClaim(urlSuggestion.getClaim(), context);
} else { } 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); UrlSuggestion suggestion = new UrlSuggestion(UrlSuggestion.TYPE_TAG, text);
suggestions.add(suggestion); suggestions.add(suggestion);
} }

View file

@ -26,6 +26,7 @@ public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilter
private Context context; private Context context;
private List<Claim> items; private List<Claim> items;
@Getter @Getter
@Setter
private Claim selectedItem; private Claim selectedItem;
@Setter @Setter
private ChannelItemSelectionListener listener; private ChannelItemSelectionListener listener;
@ -66,6 +67,11 @@ public class ChannelFilterListAdapter extends RecyclerView.Adapter<ChannelFilter
return claim.equals(selectedItem); return claim.equals(selectedItem);
} }
public void clearClaims() {
items = new ArrayList<>(items.subList(0, 1));
notifyDataSetChanged();
}
public void addClaims(List<Claim> claims) { public void addClaims(List<Claim> claims) {
for (Claim claim : claims) { for (Claim claim : claims) {
if (!items.contains(claim)) { if (!items.contains(claim)) {

View file

@ -13,6 +13,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions; import com.bumptech.glide.request.RequestOptions;
import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -79,6 +80,8 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
} }
public static class ViewHolder extends RecyclerView.ViewHolder { public static class ViewHolder extends RecyclerView.ViewHolder {
protected View feeContainer;
protected TextView feeView;
protected ImageView thumbnailView; protected ImageView thumbnailView;
protected View noThumbnailView; protected View noThumbnailView;
protected TextView alphaView; protected TextView alphaView;
@ -91,6 +94,8 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
protected TextView repostChannelView; protected TextView repostChannelView;
public ViewHolder(View v) { public ViewHolder(View v) {
super(v); super(v);
feeContainer = v.findViewById(R.id.claim_fee_container);
feeView = v.findViewById(R.id.claim_fee);
alphaView = v.findViewById(R.id.claim_thumbnail_alpha); alphaView = v.findViewById(R.id.claim_thumbnail_alpha);
noThumbnailView = v.findViewById(R.id.claim_no_thumbnail); noThumbnailView = v.findViewById(R.id.claim_no_thumbnail);
thumbnailView = v.findViewById(R.id.claim_thumbnail); thumbnailView = v.findViewById(R.id.claim_thumbnail);
@ -191,6 +196,7 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
vh.vanityUrlView.setText(vanityUrl.toString()); vh.vanityUrlView.setText(vanityUrl.toString());
} }
vh.feeContainer.setVisibility(item.isUnresolved() || !Claim.TYPE_STREAM.equalsIgnoreCase(item.getValueType()) ? View.GONE : View.VISIBLE);
vh.noThumbnailView.setVisibility(Helper.isNullOrEmpty(thumbnailUrl) ? View.VISIBLE : View.GONE); vh.noThumbnailView.setVisibility(Helper.isNullOrEmpty(thumbnailUrl) ? View.VISIBLE : View.GONE);
Helper.setIconViewBackgroundColor(vh.noThumbnailView, bgColor, false, context); Helper.setIconViewBackgroundColor(vh.noThumbnailView, bgColor, false, context);
@ -209,6 +215,9 @@ public class ClaimListAdapter extends RecyclerView.Adapter<ClaimListAdapter.View
into(vh.thumbnailView); into(vh.thumbnailView);
} }
BigDecimal cost = streamMetadata != null && streamMetadata.getFee() != null ? new BigDecimal(streamMetadata.getFee().getAmount()) : new BigDecimal(0);
vh.feeContainer.setVisibility(cost.doubleValue() > 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.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.publisherView.setText(signingChannel != null ? signingChannel.getName() : context.getString(R.string.anonymous));
vh.publishTimeView.setText(DateUtils.getRelativeTimeSpanString( vh.publishTimeView.setText(DateUtils.getRelativeTimeSpanString(

View file

@ -13,6 +13,7 @@ import java.util.List;
import io.lbry.browser.exceptions.LbryUriException; import io.lbry.browser.exceptions.LbryUriException;
import io.lbry.browser.model.Tag; import io.lbry.browser.model.Tag;
import io.lbry.browser.model.UrlSuggestion; import io.lbry.browser.model.UrlSuggestion;
import io.lbry.browser.model.ViewHistory;
import io.lbry.browser.model.lbryinc.Subscription; import io.lbry.browser.model.lbryinc.Subscription;
import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryUri; import io.lbry.browser.utils.LbryUri;
@ -25,27 +26,49 @@ public class DatabaseHelper extends SQLiteOpenHelper {
// local subscription store // local subscription store
"CREATE TABLE subscriptions (url TEXT PRIMARY KEY NOT NULL, channel_name TEXT NOT NULL)", "CREATE TABLE subscriptions (url TEXT PRIMARY KEY NOT NULL, channel_name TEXT NOT NULL)",
// url entry / suggestion history // 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) // tags (known and followed)
"CREATE TABLE tags (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, is_followed INTEGER NOT NULL)" "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)? // 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 = { private static final String[] SQL_CREATE_INDEXES = {
"CREATE UNIQUE INDEX idx_subscription_url ON subscriptions (url)", "CREATE UNIQUE INDEX idx_subscription_url ON subscriptions (url)",
"CREATE UNIQUE INDEX idx_history_value ON history (value)", "CREATE UNIQUE INDEX idx_url_history_value ON url_history (value)",
"CREATE UNIQUE INDEX idx_history_url ON history (url)", "CREATE UNIQUE INDEX idx_url_history_url ON url_history (url)",
"CREATE UNIQUE INDEX idx_tag_name ON tags (name)" "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_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_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_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_INSERT_URL_HISTORY = "REPLACE INTO url_history (value, url, type, timestamp) VALUES (?, ?, ?)";
private static final String SQL_CLEAR_HISTORY = "DELETE FROM history"; private static final String SQL_CLEAR_URL_HISTORY = "DELETE FROM url_history";
private static final String SQL_CLEAR_HISTORY_BEFORE_TIME = "DELETE FROM history WHERE timestamp < ?"; private static final String SQL_CLEAR_URL_HISTORY_BEFORE_TIME = "DELETE FROM url_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_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_INSERT_TAG = "REPLACE INTO tags (name, is_followed) VALUES (?, ?)";
private static final String SQL_GET_KNOWN_TAGS = "SELECT name, is_followed FROM tags"; 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) { public static void createOrUpdateUrlHistoryItem(String text, String url, int type, SQLiteDatabase db) {
db.execSQL(SQL_INSERT_HISTORY, new Object[] { db.execSQL(SQL_INSERT_URL_HISTORY, new Object[] {
text, url, type, new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(new Date()) text, url, type, new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(new Date())
}); });
} }
public static void clearHistory(SQLiteDatabase db) { public static void clearUrlHistory(SQLiteDatabase db) {
db.execSQL(SQL_CLEAR_HISTORY); db.execSQL(SQL_CLEAR_URL_HISTORY);
} }
public static void clearHistoryBefore(Date date, SQLiteDatabase db) { public static void clearUrlHistoryBefore(Date date, SQLiteDatabase db) {
db.execSQL(SQL_CLEAR_HISTORY_BEFORE_TIME, new Object[] { new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(new Date()) }); 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 // History items are essentially url suggestions
public static List<UrlSuggestion> getRecentHistory(SQLiteDatabase db) { public static List<UrlSuggestion> getRecentHistory(SQLiteDatabase db) {
List<UrlSuggestion> suggestions = new ArrayList<>(); List<UrlSuggestion> suggestions = new ArrayList<>();
Cursor cursor = null; Cursor cursor = null;
try { try {
cursor = db.rawQuery(SQL_GET_RECENT_HISTORY, null); cursor = db.rawQuery(SQL_GET_RECENT_URL_HISTORY, null);
while (cursor.moveToNext()) { while (cursor.moveToNext()) {
UrlSuggestion suggestion = new UrlSuggestion(); UrlSuggestion suggestion = new UrlSuggestion();
suggestion.setText(cursor.getString(0)); suggestion.setText(cursor.getString(0));
@ -105,6 +128,24 @@ public class DatabaseHelper extends SQLiteOpenHelper {
return suggestions; 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) { public static void createOrUpdateTag(Tag tag, SQLiteDatabase db) {
db.execSQL(SQL_INSERT_TAG, new Object[] { tag.getLowercaseName(), tag.isFollowed() ? 1 : 0 }); db.execSQL(SQL_INSERT_TAG, new Object[] { tag.getLowercaseName(), tag.isFollowed() ? 1 : 0 });
} }

View file

@ -14,6 +14,7 @@ import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.stream.Stream;
import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Helper;
import io.lbry.browser.utils.LbryUri; import io.lbry.browser.utils.LbryUri;
@ -160,6 +161,45 @@ public class Claim {
return 0; 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) { public static Claim fromJSONObject(JSONObject claimObject) {
Claim claim = null; Claim claim = null;
String claimJson = claimObject.toString(); String claimJson = claimObject.toString();

View file

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

View file

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

View file

@ -160,7 +160,7 @@ public class ChannelFragment extends BaseFragment {
public void onSuccess() { public void onSuccess() {
if (isFollowing) { if (isFollowing) {
Lbryio.removeSubscription(subscription); Lbryio.removeSubscription(subscription);
Lbryio.addCachedResolvedSubscription(claim); Lbryio.removeCachedResolvedSubscription(claim);
} else { } else {
Lbryio.addSubscription(subscription); Lbryio.addSubscription(subscription);
Lbryio.addCachedResolvedSubscription(claim); Lbryio.addCachedResolvedSubscription(claim);

View file

@ -239,6 +239,7 @@ public class FollowingFragment extends BaseFragment implements
discoverLink.setOnClickListener(new View.OnClickListener() { discoverLink.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
buildChannelIdsAndUrls();
discoverDialog = DiscoverDialogFragment.newInstance(); discoverDialog = DiscoverDialogFragment.newInstance();
excludeChannelIdsForDiscover = channelIds != null ? new ArrayList<>(channelIds) : null; excludeChannelIdsForDiscover = channelIds != null ? new ArrayList<>(channelIds) : null;
discoverDialog.setAdapter(suggestedChannelAdapter); discoverDialog.setAdapter(suggestedChannelAdapter);
@ -351,7 +352,7 @@ public class FollowingFragment extends BaseFragment implements
subscriptionsList = new ArrayList<>(Lbryio.subscriptions); subscriptionsList = new ArrayList<>(Lbryio.subscriptions);
buildChannelIdsAndUrls(); buildChannelIdsAndUrls();
if (Lbryio.cacheResolvedSubscriptions.size() > 0) { if (Lbryio.cacheResolvedSubscriptions.size() > 0) {
updateChannelFilterListAdapter(Lbryio.cacheResolvedSubscriptions); updateChannelFilterListAdapter(Lbryio.cacheResolvedSubscriptions, resetClaimSearchContent);
} else { } else {
fetchAndResolveChannelList(); 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() { ResolveTask resolveSubscribedTask = new ResolveTask(channelUrls, Lbry.LBRY_TV_CONNECTION_STRING, channelListLoading, new ResolveTask.ResolveResultHandler() {
@Override @Override
public void onSuccess(List<Claim> claims) { public void onSuccess(List<Claim> claims) {
updateChannelFilterListAdapter(claims); updateChannelFilterListAdapter(claims, true);
Lbryio.cacheResolvedSubscriptions = claims; Lbryio.cacheResolvedSubscriptions = claims;
} }
@ -488,7 +489,7 @@ public class FollowingFragment extends BaseFragment implements
return (contentListAdapter == null || contentListAdapter.getItemCount() == 0) ? bigContentLoading : contentLoading; return (contentListAdapter == null || contentListAdapter.getItemCount() == 0) ? bigContentLoading : contentLoading;
} }
private void updateChannelFilterListAdapter(List<Claim> resolvedSubs) { private void updateChannelFilterListAdapter(List<Claim> resolvedSubs, boolean reset) {
if (channelFilterListAdapter == null) { if (channelFilterListAdapter == null) {
channelFilterListAdapter = new ChannelFilterListAdapter(getContext()); channelFilterListAdapter = new ChannelFilterListAdapter(getContext());
channelFilterListAdapter.setListener(new ChannelItemSelectionListener() { channelFilterListAdapter.setListener(new ChannelItemSelectionListener() {
@ -528,6 +529,10 @@ public class FollowingFragment extends BaseFragment implements
if (horizontalChannelList != null && horizontalChannelList.getAdapter() == null) { if (horizontalChannelList != null && horizontalChannelList.getAdapter() == null) {
horizontalChannelList.setAdapter(channelFilterListAdapter); horizontalChannelList.setAdapter(channelFilterListAdapter);
} }
if (reset) {
channelFilterListAdapter.clearClaims();
channelFilterListAdapter.setSelectedItem(null);
}
channelFilterListAdapter.addClaims(resolvedSubs); channelFilterListAdapter.addClaims(resolvedSubs);
} }
@ -622,7 +627,7 @@ public class FollowingFragment extends BaseFragment implements
suggestedHasReachedEnd = hasReachedEnd; suggestedHasReachedEnd = hasReachedEnd;
suggestedClaimSearchLoading = false; suggestedClaimSearchLoading = false;
if (discoverDialog != null) { if (discoverDialog != null) {
discoverDialog.setLoading(true); discoverDialog.setLoading(false);
} }
if (suggestedChannelAdapter == null) { if (suggestedChannelAdapter == null) {
@ -684,46 +689,45 @@ public class FollowingFragment extends BaseFragment implements
public void onChannelItemSelected(Claim claim) { public void onChannelItemSelected(Claim claim) {
// subscribe // subscribe
Subscription subscription = new Subscription(); Subscription subscription = Subscription.fromClaim(claim);
subscription.setChannelName(claim.getName());
subscription.setUrl(claim.getPermanentUrl());
String channelClaimId = claim.getClaimId(); String channelClaimId = claim.getClaimId();
ChannelSubscribeTask task = new ChannelSubscribeTask(getContext(), channelClaimId, subscription, false, new ChannelSubscribeTask.ChannelSubscribeHandler() { ChannelSubscribeTask task = new ChannelSubscribeTask(getContext(), channelClaimId, subscription, false, new ChannelSubscribeTask.ChannelSubscribeHandler() {
@Override @Override
public void onSuccess() { public void onSuccess() {
if (discoverDialog != null) { if (discoverDialog != null) {
fetchSubscriptions(); Lbryio.addSubscription(subscription);
Lbryio.addCachedResolvedSubscription(claim);
resetClaimSearchContent = true;
fetchLoadedSubscriptions();
} }
saveSharedUserState(); saveSharedUserState();
} }
@Override @Override
public void onError(Exception exception) { public void onError(Exception error) { }
}
}); });
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
updateSuggestedDoneButtonText(); updateSuggestedDoneButtonText();
} }
public void onChannelItemDeselected(Claim claim) { public void onChannelItemDeselected(Claim claim) {
// unsubscribe // unsubscribe
Subscription subscription = new Subscription(); Subscription subscription = Subscription.fromClaim(claim);
subscription.setChannelName(claim.getName());
subscription.setUrl(claim.getPermanentUrl());
String channelClaimId = claim.getClaimId(); String channelClaimId = claim.getClaimId();
ChannelSubscribeTask task = new ChannelSubscribeTask(getContext(), channelClaimId, subscription, true, new ChannelSubscribeTask.ChannelSubscribeHandler() { ChannelSubscribeTask task = new ChannelSubscribeTask(getContext(), channelClaimId, subscription, true, new ChannelSubscribeTask.ChannelSubscribeHandler() {
@Override @Override
public void onSuccess() { public void onSuccess() {
if (discoverDialog != null) { if (discoverDialog != null) {
fetchSubscriptions(); Lbryio.removeSubscription(subscription);
Lbryio.removeCachedResolvedSubscription(claim);
resetClaimSearchContent = true;
fetchLoadedSubscriptions();
} }
saveSharedUserState(); saveSharedUserState();
} }
@Override @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) { private void checkNoContent(boolean suggested) {
RecyclerView.Adapter adpater = suggested ? suggestedChannelAdapter : contentListAdapter; RecyclerView.Adapter adapter = suggested ? suggestedChannelAdapter : contentListAdapter;
boolean noContent = adpater == null || adpater.getItemCount() == 0; boolean noContent = adapter == null || adapter.getItemCount() == 0;
Helper.setViewVisibility(noContentView, noContent ? View.VISIBLE : View.GONE); Helper.setViewVisibility(noContentView, noContent ? View.VISIBLE : View.GONE);
} }

View file

@ -9,6 +9,7 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.GradientDrawable;
import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.ShapeDrawable;
import android.os.Build;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
@ -37,6 +38,7 @@ import io.lbry.browser.model.Tag;
import okhttp3.MediaType; import okhttp3.MediaType;
public final class Helper { public final class Helper {
public static final String UNKNOWN = "Unknown";
public static final String METHOD_GET = "GET"; public static final String METHOD_GET = "GET";
public static final String METHOD_POST = "POST"; public static final String METHOD_POST = "POST";
public static final String ISO_DATE_FORMAT_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS"; 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); ((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);
}
} }

View file

@ -43,6 +43,13 @@ public class LbryUri {
return (!Helper.isNullOrEmpty(channelName) && Helper.isNullOrEmpty(streamName)) || (!Helper.isNullOrEmpty(claimName) && claimName.startsWith("@")); 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 { public static LbryUri parse(String url) throws LbryUriException {
return parse(url, false); return parse(url, false);
} }
@ -93,7 +100,7 @@ public class LbryUri {
throw new LbryUriException("URL does not include name."); 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) { if (component.indexOf(' ') > -1) {
throw new LbryUriException("URL cannot include a space."); throw new LbryUriException("URL cannot include a space.");
} }
@ -132,7 +139,7 @@ public class LbryUri {
LbryUri uri = new LbryUri(); LbryUri uri = new LbryUri();
uri.setChannel(isChannel); 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.setStreamName(streamName);
uri.setStreamClaimId(streamClaimId); uri.setStreamClaimId(streamClaimId);
uri.setChannelName(channelName); uri.setChannelName(channelName);

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/costBackground" />
<corners android:radius="16dp" />
</shape>

View file

@ -46,7 +46,7 @@
android:textColor="@color/lightForeground" android:textColor="@color/lightForeground"
android:textFontWeight="300" android:textFontWeight="300"
android:textSize="12sp" /> android:textSize="12sp" />
</LinearLayout>w </LinearLayout>
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
@ -76,6 +76,36 @@
android:textColor="@color/white" android:textColor="@color/white"
android:textFontWeight="300" /> android:textFontWeight="300" />
</RelativeLayout> </RelativeLayout>
<LinearLayout
android:id="@+id/claim_fee_container"
android:background="@color/nextLbryGreen"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentRight="true"
android:layout_marginTop="4dp"
android:layout_marginRight="4dp"
android:paddingTop="1dp"
android:paddingBottom="1dp"
android:paddingLeft="2dp"
android:paddingRight="2dp"
android:visibility="gone">
<io.lbry.browser.ui.controls.SolidIconView
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_gravity="center_vertical"
android:textSize="12dp"
android:text="@string/fa_coins" />
<TextView
android:id="@+id/claim_fee"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="2dp"
android:fontFamily="@font/inter"
android:textSize="14sp"
android:textFontWeight="300" />
</LinearLayout>
</RelativeLayout> </RelativeLayout>
<LinearLayout <LinearLayout

View file

@ -87,6 +87,36 @@
android:textFontWeight="300" android:textFontWeight="300"
android:padding="2dp" android:padding="2dp"
android:visibility="gone" /> android:visibility="gone" />
<LinearLayout
android:id="@+id/claim_fee_container"
android:background="@drawable/bg_stream_cost"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentRight="true"
android:layout_marginTop="4dp"
android:layout_marginRight="4dp"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:paddingLeft="6dp"
android:paddingRight="7dp"
android:visibility="gone">
<io.lbry.browser.ui.controls.SolidIconView
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_gravity="center_vertical"
android:textSize="8dp"
android:text="@string/fa_coins" />
<TextView
android:id="@+id/claim_fee"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="1dp"
android:fontFamily="@font/inter"
android:textSize="14sp"
android:textFontWeight="300" />
</LinearLayout>
</RelativeLayout> </RelativeLayout>
<LinearLayout <LinearLayout

View file

@ -91,6 +91,36 @@
android:textFontWeight="300" android:textFontWeight="300"
android:padding="2dp" android:padding="2dp"
android:visibility="gone" /> android:visibility="gone" />
<LinearLayout
android:id="@+id/claim_fee_container"
android:background="@drawable/bg_stream_cost"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_alignParentRight="true"
android:layout_marginTop="4dp"
android:layout_marginRight="4dp"
android:paddingTop="2dp"
android:paddingBottom="2dp"
android:paddingLeft="6dp"
android:paddingRight="7dp"
android:visibility="gone">
<io.lbry.browser.ui.controls.SolidIconView
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_gravity="center_vertical"
android:textSize="8dp"
android:text="@string/fa_coins" />
<TextView
android:id="@+id/claim_fee"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="1dp"
android:fontFamily="@font/inter"
android:textSize="14sp"
android:textFontWeight="300" />
</LinearLayout>
</RelativeLayout> </RelativeLayout>
<LinearLayout <LinearLayout

View file

@ -12,6 +12,7 @@
<color name="menuItemForeground">#AAAAAA</color> <color name="menuItemForeground">#AAAAAA</color>
<color name="selectedNavItem">#0E0E0E</color> <color name="selectedNavItem">#0E0E0E</color>
<color name="channelCoverBackground">#CC000000</color> <color name="channelCoverBackground">#CC000000</color>
<color name="costBackground">#F4E866</color>
<!-- At some point, these colours have to be renamed --> <!-- At some point, these colours have to be renamed -->
<color name="darkForeground">#EEEEEE</color> <color name="darkForeground">#EEEEEE</color>

View file

@ -12,6 +12,7 @@
<color name="menuItemForeground">#444444</color> <color name="menuItemForeground">#444444</color>
<color name="selectedNavItem">#F1F1F1</color> <color name="selectedNavItem">#F1F1F1</color>
<color name="channelCoverBackground">#CC000000</color> <color name="channelCoverBackground">#CC000000</color>
<color name="costBackground">#F4E866</color>
<color name="darkForeground">#222222</color> <color name="darkForeground">#222222</color>
<color name="lightForeground">#AAAAAA</color> <color name="lightForeground">#AAAAAA</color>