private Disposable monitorSubscribeButton(final Button subscribeButton, final Function<Object, Object> action) { final Consumer<Object> onNext = (@NonNull Object o) -> { if (DEBUG) Log.d(TAG, "Changed subscription status to this channel!"); }; final Consumer<Throwable> onError = (@NonNull Throwable throwable) -> onUnrecoverableError(throwable, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(currentInfo.getServiceId()), "Subscription Change", R.string.subscription_change_failed); /* Emit clicks from main thread unto io thread */ return RxView.clicks(subscribeButton) .subscribeOn(AndroidSchedulers.mainThread()) .observeOn(Schedulers.io()) .debounce(BUTTON_DEBOUNCE_INTERVAL, TimeUnit.MILLISECONDS) // Ignore rapid clicks .map(action) .subscribe(onNext, onError); }
private PlayQueue getPlayQueue(final int index) { final List<StreamInfoItem> streamItems = new ArrayList<>(); for(InfoItem i : infoListAdapter.getItemsList()) { if(i instanceof StreamInfoItem) { streamItems.add((StreamInfoItem) i); } } return new ChannelPlayQueue( currentInfo.getServiceId(), currentInfo.getUrl(), currentInfo.getNextPageUrl(), streamItems, index ); }
public ChannelPlayQueue(final int serviceId, final String url, final String nextPageUrl, final List<StreamInfoItem> streams, final int index) { super(serviceId, url, nextPageUrl, streams, index); }
private void updateSubscription(final ChannelInfo info) { if (DEBUG) Log.d(TAG, "updateSubscription() called with: info = [" + info + "]"); final Action onComplete = () -> { if (DEBUG) Log.d(TAG, "Updated subscription: " + info.getUrl()); }; final Consumer<Throwable> onError = (@NonNull Throwable throwable) -> onUnrecoverableError(throwable, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(info.getServiceId()), "Updating Subscription for " + info.getUrl(), R.string.subscription_update_failed); disposables.add(subscriptionService.updateChannelInfo(info) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(onComplete, onError)); }
private void monitorSubscription(final ChannelInfo info) { final Consumer<Throwable> onError = (Throwable throwable) -> { animateView(headerSubscribeButton, false, 100); showSnackBarError(throwable, UserAction.SUBSCRIPTION, NewPipe.getNameOfService(currentInfo.getServiceId()), "Get subscription status", 0); }; final Observable<List<SubscriptionEntity>> observable = subscriptionService.subscriptionTable() .getSubscription(info.getServiceId(), info.getUrl()) .toObservable(); disposables.add(observable .observeOn(AndroidSchedulers.mainThread()) .subscribe(getSubscribeUpdateMonitor(info), onError)); disposables.add(observable // Some updates are very rapid (when calling the updateSubscription(info), for example) // so only update the UI for the latest emission ("sync" the subscribe button's state) .debounce(100, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe((List<SubscriptionEntity> subscriptionEntities) -> updateSubscribeButton(!subscriptionEntities.isEmpty()) , onError)); }
private boolean isSubscriptionUpToDate(final ChannelInfo info, final SubscriptionEntity entity) { return info.getUrl().equals(entity.getUrl()) && info.getServiceId() == entity.getServiceId() && info.getName().equals(entity.getName()) && info.getAvatarUrl().equals(entity.getAvatarUrl()) && info.getDescription().equals(entity.getDescription()) && info.getSubscriberCount() == entity.getSubscriberCount(); } }
private Consumer<List<SubscriptionEntity>> getSubscribeUpdateMonitor(final ChannelInfo info) { return (List<SubscriptionEntity> subscriptionEntities) -> { if (DEBUG) Log.d(TAG, "subscriptionService.subscriptionTable.doOnNext() called with: subscriptionEntities = [" + subscriptionEntities + "]"); if (subscribeButtonMonitor != null) subscribeButtonMonitor.dispose(); if (subscriptionEntities.isEmpty()) { if (DEBUG) Log.d(TAG, "No subscription to this channel!"); SubscriptionEntity channel = new SubscriptionEntity(); channel.setServiceId(info.getServiceId()); channel.setUrl(info.getUrl()); channel.setData(info.getName(), info.getAvatarUrl(), info.getDescription(), info.getSubscriberCount()); subscribeButtonMonitor = monitorSubscribeButton(headerSubscribeButton, mapOnSubscribe(channel)); } else { if (DEBUG) Log.d(TAG, "Found subscription to this channel!"); final SubscriptionEntity subscription = subscriptionEntities.get(0); subscribeButtonMonitor = monitorSubscribeButton(headerSubscribeButton, mapOnUnsubscribe(subscription)); } }; }
@Override public void handleResult(@NonNull ChannelInfo result) { super.handleResult(result); headerRootLayout.setVisibility(View.VISIBLE); imageLoader.displayImage(result.getBannerUrl(), headerChannelBanner, ImageDisplayConstants.DISPLAY_BANNER_OPTIONS); imageLoader.displayImage(result.getAvatarUrl(), headerAvatarView, ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); headerSubscribersTextView.setVisibility(View.VISIBLE); if (result.getSubscriberCount() >= 0) { headerSubscribersTextView.setText(Localization.localizeSubscribersCount(activity, result.getSubscriberCount())); } else { headerSubscribersTextView.setText(R.string.subscribers_count_not_available); } if (menuRssButton != null) menuRssButton.setVisible(!TextUtils.isEmpty(result.getFeedUrl())); playlistCtrl.setVisibility(View.VISIBLE); if (!result.getErrors().isEmpty()) { showSnackBarError(result.getErrors(), UserAction.REQUESTED_CHANNEL, NewPipe.getNameOfService(result.getServiceId()), result.getUrl(), 0); } if (disposables != null) disposables.clear(); if (subscribeButtonMonitor != null) subscribeButtonMonitor.dispose(); updateSubscription(result); monitorSubscription(result); headerPlayAllButton.setOnClickListener( view -> NavigationHelper.playOnMainPlayer(activity, getPlayQueue())); headerPopupButton.setOnClickListener( view -> NavigationHelper.playOnPopupPlayer(activity, getPlayQueue())); headerBackgroundButton.setOnClickListener( view -> NavigationHelper.playOnBackgroundPlayer(activity, getPlayQueue())); }
public Completable updateChannelInfo(final ChannelInfo info) { final Function<List<SubscriptionEntity>, CompletableSource> update = new Function<List<SubscriptionEntity>, CompletableSource>() { @Override public CompletableSource apply(@NonNull List<SubscriptionEntity> subscriptionEntities) { if (DEBUG) Log.d(TAG, "updateChannelInfo() called with: subscriptionEntities = [" + subscriptionEntities + "]"); if (subscriptionEntities.size() == 1) { SubscriptionEntity subscription = subscriptionEntities.get(0); // Subscriber count changes very often, making this check almost unnecessary. // Consider removing it later. if (!isSubscriptionUpToDate(info, subscription)) { subscription.setData(info.getName(), info.getAvatarUrl(), info.getDescription(), info.getSubscriberCount()); return Completable.fromRunnable(() -> subscriptionTable().update(subscription)); } } return Completable.complete(); } }; return subscriptionTable().getSubscription(info.getServiceId(), info.getUrl()) .firstOrError() .flatMapCompletable(update); }
@Ignore public static SubscriptionEntity from(@NonNull ChannelInfo info) { SubscriptionEntity result = new SubscriptionEntity(); result.setServiceId(info.getServiceId()); result.setUrl(info.getUrl()); result.setData(info.getName(), info.getAvatarUrl(), info.getDescription(), info.getSubscriberCount()); return result; } }