setup core for search channel support
This commit is contained in:
parent
f29bd0a6e7
commit
91434dd2ac
26 changed files with 930 additions and 80 deletions
|
@ -92,7 +92,8 @@ public class ChannelActivity extends AppCompatActivity {
|
|||
final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
|
||||
recyclerView.setLayoutManager(layoutManager);
|
||||
recyclerView.setAdapter(infoListAdapter);
|
||||
infoListAdapter.setOnItemSelectedListener(new InfoItemBuilder.OnItemSelectedListener() {
|
||||
infoListAdapter.setOnStreamItemSelectedListener(
|
||||
new InfoItemBuilder.OnInfoItemSelectedListener() {
|
||||
@Override
|
||||
public void selected(String url) {
|
||||
Intent detailIntent = new Intent(ChannelActivity.this, VideoItemDetailActivity.class);
|
||||
|
@ -172,7 +173,7 @@ public class ChannelActivity extends AppCompatActivity {
|
|||
}
|
||||
|
||||
private void addVideos(final ChannelInfo info) {
|
||||
infoListAdapter.addStreamItemList(info.related_streams);
|
||||
infoListAdapter.addInfoItemList(info.related_streams);
|
||||
}
|
||||
|
||||
private void postNewErrorToast(Handler h, final int stringResource) {
|
||||
|
|
|
@ -28,11 +28,9 @@ import java.util.Vector;
|
|||
public class InfoItemCollector {
|
||||
private List<InfoItem> itemList = new Vector<>();
|
||||
private List<Throwable> errors = new Vector<>();
|
||||
private UrlIdHandler urlIdHandler;
|
||||
private int serviceId = -1;
|
||||
|
||||
public InfoItemCollector(UrlIdHandler handler, int serviceId) {
|
||||
urlIdHandler = handler;
|
||||
public InfoItemCollector(int serviceId) {
|
||||
this.serviceId = serviceId;
|
||||
}
|
||||
|
||||
|
@ -60,7 +58,4 @@ public class InfoItemCollector {
|
|||
protected int getServiceId() {
|
||||
return serviceId;
|
||||
}
|
||||
protected UrlIdHandler getUrlIdHandler() {
|
||||
return urlIdHandler;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,14 +24,18 @@ import org.schabi.newpipe.extractor.InfoItem;
|
|||
|
||||
public class ChannelInfoItem implements InfoItem {
|
||||
|
||||
public int serviceId = -1;
|
||||
public String channelName = "";
|
||||
public String webPageUrl = "";
|
||||
public int subscriberCount = -1;
|
||||
public int videoAmount = -1;
|
||||
|
||||
public InfoType infoType() {
|
||||
return InfoType.CHANNEL;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getLink() {
|
||||
return "";
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package org.schabi.newpipe.extractor.channel;
|
||||
|
||||
import org.schabi.newpipe.extractor.InfoItemCollector;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.exceptions.FoundAdException;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.stream_info.StreamInfoItem;
|
||||
import org.schabi.newpipe.extractor.stream_info.StreamInfoItemExtractor;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 12.02.17.
|
||||
*
|
||||
* Copyright (C) Christian Schabesberger 2017 <chris.schabesberger@mailbox.org>
|
||||
* ChannelInfoItemCollector.java is part of NewPipe.
|
||||
*
|
||||
* NewPipe is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NewPipe is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class ChannelInfoItemCollector extends InfoItemCollector {
|
||||
public ChannelInfoItemCollector(int serviceId) {
|
||||
super(serviceId);
|
||||
}
|
||||
|
||||
public void commit(ChannelInfoItemExtractor extractor) throws ParsingException {
|
||||
try {
|
||||
ChannelInfoItem resultItem = new ChannelInfoItem();
|
||||
// importand information
|
||||
resultItem.channelName = extractor.getChannelName();
|
||||
|
||||
resultItem.serviceId = getServiceId();
|
||||
resultItem.webPageUrl = extractor.getWebPageUrl();
|
||||
|
||||
// optional information
|
||||
try {
|
||||
resultItem.subscriberCount = extractor.getSubscriberCount();
|
||||
} catch (Exception e) {
|
||||
addError(e);
|
||||
}
|
||||
try {
|
||||
resultItem.videoAmount = extractor.getVideoAmount();
|
||||
} catch (Exception e) {
|
||||
addError(e);
|
||||
}
|
||||
|
||||
addItem(resultItem);
|
||||
} catch (Exception e) {
|
||||
addError(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package org.schabi.newpipe.extractor.channel;
|
||||
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 12.02.17.
|
||||
*
|
||||
* Copyright (C) Christian Schabesberger 2017 <chris.schabesberger@mailbox.org>
|
||||
* ChannelInfoItemExtractor.java is part of NewPipe.
|
||||
*
|
||||
* NewPipe is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NewPipe is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public interface ChannelInfoItemExtractor {
|
||||
String getChannelName() throws ParsingException;
|
||||
String getWebPageUrl() throws ParsingException;
|
||||
int getSubscriberCount() throws ParsingException;
|
||||
int getVideoAmount() throws ParsingException;
|
||||
}
|
|
@ -2,6 +2,8 @@ package org.schabi.newpipe.extractor.search;
|
|||
|
||||
import org.schabi.newpipe.extractor.InfoItemCollector;
|
||||
import org.schabi.newpipe.extractor.UrlIdHandler;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItemCollector;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.stream_info.StreamInfoItemCollector;
|
||||
|
@ -30,10 +32,12 @@ import org.schabi.newpipe.extractor.stream_info.StreamInfoItemExtractor;
|
|||
public class InfoItemSearchCollector extends InfoItemCollector {
|
||||
private String suggestion = "";
|
||||
private StreamInfoItemCollector streamCollector;
|
||||
private ChannelInfoItemCollector channelCollector;
|
||||
|
||||
InfoItemSearchCollector(UrlIdHandler handler, int serviceId) {
|
||||
super(handler, serviceId);
|
||||
super(serviceId);
|
||||
streamCollector = new StreamInfoItemCollector(handler, serviceId);
|
||||
channelCollector = new ChannelInfoItemCollector(serviceId);
|
||||
}
|
||||
|
||||
public void setSuggestion(String suggestion) {
|
||||
|
@ -43,6 +47,7 @@ public class InfoItemSearchCollector extends InfoItemCollector {
|
|||
public SearchResult getSearchResult() throws ExtractionException {
|
||||
SearchResult result = new SearchResult();
|
||||
|
||||
addFromCollector(channelCollector);
|
||||
addFromCollector(streamCollector);
|
||||
|
||||
result.suggestion = suggestion;
|
||||
|
@ -54,4 +59,8 @@ public class InfoItemSearchCollector extends InfoItemCollector {
|
|||
public void commit(StreamInfoItemExtractor extractor) throws ParsingException {
|
||||
streamCollector.commit(extractor);
|
||||
}
|
||||
|
||||
public void commit(ChannelInfoItemExtractor extractor) throws ParsingException {
|
||||
channelCollector.commit(extractor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
|||
import org.schabi.newpipe.extractor.stream_info.StreamInfoItemCollector;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 10.08.15.
|
||||
|
@ -27,6 +28,10 @@ import java.io.IOException;
|
|||
*/
|
||||
|
||||
public abstract class SearchEngine {
|
||||
public enum Filter {
|
||||
VIDEO, CHANNEL, PLAY_LIST
|
||||
}
|
||||
|
||||
public static class NothingFoundException extends ExtractionException {
|
||||
public NothingFoundException(String message) {
|
||||
super(message);
|
||||
|
@ -43,6 +48,6 @@ public abstract class SearchEngine {
|
|||
}
|
||||
//Result search(String query, int page);
|
||||
public abstract InfoItemSearchCollector search(
|
||||
String query, int page, String contentCountry)
|
||||
String query, int page, String contentCountry, EnumSet<Filter> filter)
|
||||
throws ExtractionException, IOException;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
|||
import org.schabi.newpipe.extractor.stream_info.StreamInfoItem;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
|
@ -30,10 +31,12 @@ import java.util.Vector;
|
|||
|
||||
public class SearchResult {
|
||||
public static SearchResult getSearchResult(SearchEngine engine, String query,
|
||||
int page, String languageCode)
|
||||
int page, String languageCode, EnumSet<SearchEngine.Filter> filter)
|
||||
throws ExtractionException, IOException {
|
||||
|
||||
SearchResult result = engine.search(query, page, languageCode).getSearchResult();
|
||||
SearchResult result = engine
|
||||
.search(query, page, languageCode, filter)
|
||||
.getSearchResult();
|
||||
if(result.resultList.isEmpty()) {
|
||||
if(result.suggestion.isEmpty()) {
|
||||
throw new ExtractionException("Empty result despite no error");
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package org.schabi.newpipe.extractor.services.youtube;
|
||||
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.jsoup.nodes.Element;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 12.02.17.
|
||||
*
|
||||
* Copyright (C) Christian Schabesberger 2017 <chris.schabesberger@mailbox.org>
|
||||
* YoutubeChannelInfoItemExtractor.java is part of NewPipe.
|
||||
*
|
||||
* NewPipe is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NewPipe is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class YoutubeChannelInfoItemExtractor implements ChannelInfoItemExtractor {
|
||||
private Element el;
|
||||
|
||||
public YoutubeChannelInfoItemExtractor(Element el) {
|
||||
this.el = el;
|
||||
}
|
||||
|
||||
public String getChannelName() throws ParsingException {
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getWebPageUrl() throws ParsingException {
|
||||
return "";
|
||||
}
|
||||
|
||||
public int getSubscriberCount() throws ParsingException {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getVideoAmount() throws ParsingException {
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -9,11 +9,10 @@ import org.schabi.newpipe.extractor.UrlIdHandler;
|
|||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.search.InfoItemSearchCollector;
|
||||
import org.schabi.newpipe.extractor.search.SearchEngine;
|
||||
import org.schabi.newpipe.extractor.stream_info.StreamInfoItemCollector;
|
||||
import org.schabi.newpipe.extractor.stream_info.StreamInfoItemExtractor;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -46,7 +45,10 @@ public class YoutubeSearchEngine extends SearchEngine {
|
|||
}
|
||||
|
||||
@Override
|
||||
public InfoItemSearchCollector search(String query, int page, String languageCode)
|
||||
public InfoItemSearchCollector search(String query,
|
||||
int page,
|
||||
String languageCode,
|
||||
EnumSet<Filter> filter)
|
||||
throws IOException, ExtractionException {
|
||||
InfoItemSearchCollector collector = getInfoItemSearchCollector();
|
||||
|
||||
|
@ -54,9 +56,13 @@ public class YoutubeSearchEngine extends SearchEngine {
|
|||
Downloader downloader = NewPipe.getDownloader();
|
||||
|
||||
String url = "https://www.youtube.com/results"
|
||||
+ "?search_query=" + URLEncoder.encode(query, CHARSET_UTF_8)
|
||||
+ "&page=" + Integer.toString(page + 1)
|
||||
+ "&filters=" + "video";
|
||||
+ "?q=" + URLEncoder.encode(query, CHARSET_UTF_8)
|
||||
+ "&page=" + Integer.toString(page + 1);
|
||||
if(filter.contains(Filter.VIDEO) && !filter.contains(Filter.CHANNEL)) {
|
||||
url += "&sp=EgIQAQ%253D%253D";
|
||||
} else if(!filter.contains(Filter.VIDEO) && filter.contains(Filter.CHANNEL)) {
|
||||
url += "&sp=EgIQAg%253D%253D";
|
||||
}
|
||||
|
||||
String site;
|
||||
//String url = builder.build().toString();
|
||||
|
@ -94,12 +100,13 @@ public class YoutubeSearchEngine extends SearchEngine {
|
|||
}
|
||||
// search message item
|
||||
} else if ((el = item.select("div[class*=\"search-message\"]").first()) != null) {
|
||||
//result.errorMessage = el.text();
|
||||
throw new NothingFoundException(el.text());
|
||||
|
||||
// video item type
|
||||
} else if ((el = item.select("div[class*=\"yt-lockup-video\"").first()) != null) {
|
||||
} else if ((el = item.select("div[class*=\"yt-lockup-video\"]").first()) != null) {
|
||||
collector.commit(new YoutubeStreamInfoItemExtractor(el));
|
||||
} else if((el = item.select("div[class*=\"yt-lockup-channel\"]").first()) != null) {
|
||||
collector.commit(new YoutubeChannelInfoItemExtractor(el));
|
||||
} else {
|
||||
//noinspection ConstantConditions
|
||||
throw new ExtractionException("unexpected element found:\"" + el + "\"");
|
||||
|
|
|
@ -31,8 +31,15 @@ import java.util.Vector;
|
|||
|
||||
public class StreamInfoItemCollector extends InfoItemCollector {
|
||||
|
||||
private UrlIdHandler urlIdHandler;
|
||||
|
||||
public StreamInfoItemCollector(UrlIdHandler handler, int serviceId) {
|
||||
super(handler, serviceId);
|
||||
super(serviceId);
|
||||
urlIdHandler = handler;
|
||||
}
|
||||
|
||||
private UrlIdHandler getUrlIdHandler() {
|
||||
return urlIdHandler;
|
||||
}
|
||||
|
||||
public void commit(StreamInfoItemExtractor extractor) throws ParsingException {
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package org.schabi.newpipe.info_list;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
|
||||
import de.hdodenhof.circleimageview.CircleImageView;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 12.02.17.
|
||||
*
|
||||
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
||||
* ChannelInfoItemHolder .java is part of NewPipe.
|
||||
*
|
||||
* NewPipe is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NewPipe is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class ChannelInfoItemHolder extends InfoItemHolder {
|
||||
public final CircleImageView itemThumbnailView;
|
||||
public final TextView itemChannelTitleView;
|
||||
public final Button itemButton;
|
||||
|
||||
ChannelInfoItemHolder(View v) {
|
||||
super(v);
|
||||
itemThumbnailView = (CircleImageView) v.findViewById(R.id.itemThumbnailView);
|
||||
itemChannelTitleView = (TextView) v.findViewById(R.id.itemChannelTitleView);
|
||||
itemButton = (Button) v.findViewById(R.id.item_button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InfoItem.InfoType infoType() {
|
||||
return InfoItem.InfoType.CHANNEL;
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import android.util.Log;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
|
||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
|
@ -13,6 +14,7 @@ import org.schabi.newpipe.ImageErrorLoadingListener;
|
|||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.AbstractStreamInfo;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||
import org.schabi.newpipe.extractor.stream_info.StreamInfoItem;
|
||||
|
||||
/**
|
||||
|
@ -37,7 +39,8 @@ import org.schabi.newpipe.extractor.stream_info.StreamInfoItem;
|
|||
|
||||
public class InfoItemBuilder {
|
||||
|
||||
public interface OnItemSelectedListener {
|
||||
private static final String TAG = InfoItemBuilder.class.toString();
|
||||
public interface OnInfoItemSelectedListener {
|
||||
void selected(String url);
|
||||
}
|
||||
|
||||
|
@ -46,19 +49,64 @@ public class InfoItemBuilder {
|
|||
private ImageLoader imageLoader = ImageLoader.getInstance();
|
||||
private DisplayImageOptions displayImageOptions =
|
||||
new DisplayImageOptions.Builder().cacheInMemory(true).build();
|
||||
private OnItemSelectedListener onItemSelectedListener;
|
||||
private OnInfoItemSelectedListener onStreamInfoItemSelectedListener;
|
||||
private OnInfoItemSelectedListener onChannelInfoItemSelectedListener;
|
||||
|
||||
public InfoItemBuilder(Activity a, View rootView) {
|
||||
activity = a;
|
||||
this.rootView = rootView;
|
||||
}
|
||||
|
||||
public void setOnItemSelectedListener(OnItemSelectedListener onItemSelectedListener) {
|
||||
this.onItemSelectedListener = onItemSelectedListener;
|
||||
public void setOnStreamInfoItemSelectedListener(
|
||||
OnInfoItemSelectedListener listener) {
|
||||
this.onStreamInfoItemSelectedListener = listener;
|
||||
}
|
||||
|
||||
public void setOnChannelInfoItemSelectedListener(
|
||||
OnInfoItemSelectedListener listener) {
|
||||
this.onChannelInfoItemSelectedListener = listener;
|
||||
}
|
||||
|
||||
public void buildByHolder(InfoItemHolder holder, final InfoItem i) {
|
||||
final StreamInfoItem info = (StreamInfoItem) i;
|
||||
switch(i.infoType()) {
|
||||
case STREAM:
|
||||
buildStreamInfoItem((StreamInfoItemHolder) holder, (StreamInfoItem) i);
|
||||
break;
|
||||
case CHANNEL:
|
||||
buildChannelInfoItem((ChannelInfoItemHolder) holder, (ChannelInfoItem) i);
|
||||
break;
|
||||
case PLAYLIST:
|
||||
Log.e(TAG, "Not yet implemented");
|
||||
break;
|
||||
default:
|
||||
Log.e(TAG, "Trollolo");
|
||||
}
|
||||
}
|
||||
|
||||
public View buildView(ViewGroup parent, final InfoItem info) {
|
||||
View itemView = null;
|
||||
InfoItemHolder holder = null;
|
||||
switch(info.infoType()) {
|
||||
case STREAM:
|
||||
itemView = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.stream_item, parent, false);
|
||||
holder = new StreamInfoItemHolder(itemView);
|
||||
break;
|
||||
case CHANNEL:
|
||||
itemView = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.channel_item, parent, false);
|
||||
holder = new ChannelInfoItemHolder(itemView);
|
||||
break;
|
||||
case PLAYLIST:
|
||||
Log.e(TAG, "Not yet implemented");
|
||||
default:
|
||||
Log.e(TAG, "Trollolo");
|
||||
}
|
||||
buildByHolder(holder, info);
|
||||
return itemView;
|
||||
}
|
||||
|
||||
private void buildStreamInfoItem(StreamInfoItemHolder holder, final StreamInfoItem info) {
|
||||
if(info.infoType() != InfoItem.InfoType.STREAM) {
|
||||
Log.e("InfoItemBuilder", "Info type not yet supported");
|
||||
}
|
||||
|
@ -98,18 +146,21 @@ public class InfoItemBuilder {
|
|||
holder.itemButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
onItemSelectedListener.selected(info.webpage_url);
|
||||
onStreamInfoItemSelectedListener.selected(info.webpage_url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public View buildView(ViewGroup parent, final InfoItem info) {
|
||||
View streamPreviewView = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.video_item, parent, false);
|
||||
InfoItemHolder holder = new InfoItemHolder(streamPreviewView);
|
||||
buildByHolder(holder, info);
|
||||
return streamPreviewView;
|
||||
private void buildChannelInfoItem(ChannelInfoItemHolder holder, final ChannelInfoItem info) {
|
||||
holder.itemChannelTitleView.setText(info.getTitle());
|
||||
holder.itemButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
onChannelInfoItemSelectedListener.selected(info.getLink());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static String shortViewCount(Long viewCount){
|
||||
|
|
|
@ -2,14 +2,11 @@ package org.schabi.newpipe.info_list;
|
|||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 01.08.16.
|
||||
* Created by Christian Schabesberger on 12.02.17.
|
||||
*
|
||||
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
||||
* InfoItemHolder.java is part of NewPipe.
|
||||
|
@ -28,25 +25,9 @@ import org.schabi.newpipe.R;
|
|||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class InfoItemHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public final ImageView itemThumbnailView;
|
||||
public final TextView itemVideoTitleView,
|
||||
itemUploaderView,
|
||||
itemDurationView,
|
||||
itemUploadDateView,
|
||||
itemViewCountView;
|
||||
public final Button itemButton;
|
||||
|
||||
public abstract class InfoItemHolder extends RecyclerView.ViewHolder {
|
||||
public InfoItemHolder(View v) {
|
||||
super(v);
|
||||
itemThumbnailView = (ImageView) v.findViewById(R.id.itemThumbnailView);
|
||||
itemVideoTitleView = (TextView) v.findViewById(R.id.itemVideoTitleView);
|
||||
itemUploaderView = (TextView) v.findViewById(R.id.itemUploaderView);
|
||||
itemDurationView = (TextView) v.findViewById(R.id.itemDurationView);
|
||||
itemUploadDateView = (TextView) v.findViewById(R.id.itemUploadDateView);
|
||||
itemViewCountView = (TextView) v.findViewById(R.id.itemViewCountView);
|
||||
itemButton = (Button) v.findViewById(R.id.item_button);
|
||||
}
|
||||
|
||||
public abstract InfoItem.InfoType infoType();
|
||||
}
|
||||
|
|
|
@ -2,13 +2,13 @@ package org.schabi.newpipe.info_list;
|
|||
|
||||
import android.app.Activity;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.stream_info.StreamInfoItem;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
@ -34,47 +34,58 @@ import java.util.Vector;
|
|||
*/
|
||||
|
||||
public class InfoListAdapter extends RecyclerView.Adapter<InfoItemHolder> {
|
||||
private static final String TAG = InfoListAdapter.class.toString();
|
||||
|
||||
private final InfoItemBuilder infoItemBuilder;
|
||||
private final List<InfoItem> streamList;
|
||||
private final List<InfoItem> infoItemList;
|
||||
|
||||
public InfoListAdapter(Activity a, View rootView) {
|
||||
infoItemBuilder = new InfoItemBuilder(a, rootView);
|
||||
streamList = new Vector<>();
|
||||
infoItemList = new Vector<>();
|
||||
}
|
||||
|
||||
public void setOnItemSelectedListener
|
||||
(InfoItemBuilder.OnItemSelectedListener onItemSelectedListener) {
|
||||
infoItemBuilder.setOnItemSelectedListener(onItemSelectedListener);
|
||||
public void setOnStreamItemSelectedListener
|
||||
(InfoItemBuilder.OnInfoItemSelectedListener onItemSelectedListener) {
|
||||
infoItemBuilder.setOnStreamInfoItemSelectedListener(onItemSelectedListener);
|
||||
}
|
||||
|
||||
public void addStreamItemList(List<InfoItem> videos) {
|
||||
public void addInfoItemList(List<InfoItem> videos) {
|
||||
if(videos!= null) {
|
||||
streamList.addAll(videos);
|
||||
infoItemList.addAll(videos);
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public void clearSteamItemList() {
|
||||
streamList.clear();
|
||||
infoItemList.clear();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return streamList.size();
|
||||
return infoItemList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InfoItemHolder onCreateViewHolder(ViewGroup parent, int i) {
|
||||
View itemView = LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.video_item, parent, false);
|
||||
|
||||
return new InfoItemHolder(itemView);
|
||||
switch(infoItemList.get(i).infoType()) {
|
||||
case STREAM:
|
||||
return new StreamInfoItemHolder(LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.stream_item, parent, false));
|
||||
case CHANNEL:
|
||||
return new ChannelInfoItemHolder(LayoutInflater.from(parent.getContext())
|
||||
.inflate(R.layout.channel_item, parent, false));
|
||||
case PLAYLIST:
|
||||
Log.e(TAG, "Playlist is not yet implemented");
|
||||
return null;
|
||||
default:
|
||||
Log.e(TAG, "Trollolo");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(InfoItemHolder holder, int i) {
|
||||
infoItemBuilder.buildByHolder(holder, streamList.get(i));
|
||||
infoItemBuilder.buildByHolder(holder, infoItemList.get(i));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package org.schabi.newpipe.info_list;
|
||||
|
||||
import android.icu.text.IDNA;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 01.08.16.
|
||||
*
|
||||
* Copyright (C) Christian Schabesberger 2016 <chris.schabesberger@mailbox.org>
|
||||
* StreamInfoItemHolder.java is part of NewPipe.
|
||||
*
|
||||
* NewPipe is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* NewPipe is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with NewPipe. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
public class StreamInfoItemHolder extends InfoItemHolder {
|
||||
|
||||
public final ImageView itemThumbnailView;
|
||||
public final TextView itemVideoTitleView,
|
||||
itemUploaderView,
|
||||
itemDurationView,
|
||||
itemUploadDateView,
|
||||
itemViewCountView;
|
||||
public final Button itemButton;
|
||||
|
||||
public StreamInfoItemHolder(View v) {
|
||||
super(v);
|
||||
itemThumbnailView = (ImageView) v.findViewById(R.id.itemThumbnailView);
|
||||
itemVideoTitleView = (TextView) v.findViewById(R.id.itemVideoTitleView);
|
||||
itemUploaderView = (TextView) v.findViewById(R.id.itemUploaderView);
|
||||
itemDurationView = (TextView) v.findViewById(R.id.itemDurationView);
|
||||
itemUploadDateView = (TextView) v.findViewById(R.id.itemUploadDateView);
|
||||
itemViewCountView = (TextView) v.findViewById(R.id.itemViewCountView);
|
||||
itemButton = (Button) v.findViewById(R.id.item_button);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InfoItem.InfoType infoType() {
|
||||
return InfoItem.InfoType.STREAM;
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ import android.widget.Toast;
|
|||
|
||||
import org.schabi.newpipe.ReCaptchaActivity;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.search.SearchEngine;
|
||||
import org.schabi.newpipe.extractor.search.SearchResult;
|
||||
import org.schabi.newpipe.info_list.InfoItemBuilder;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
|
@ -29,6 +30,8 @@ import org.schabi.newpipe.detail.VideoItemDetailActivity;
|
|||
import org.schabi.newpipe.detail.VideoItemDetailFragment;
|
||||
import org.schabi.newpipe.info_list.InfoListAdapter;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
import static org.schabi.newpipe.ReCaptchaActivity.RECAPTCHA_REQUEST;
|
||||
|
||||
|
@ -166,7 +169,7 @@ public class SearchInfoItemFragment extends Fragment {
|
|||
sw.setSearchWorkerResultListener(new SearchWorker.SearchWorkerResultListener() {
|
||||
@Override
|
||||
public void onResult(SearchResult result) {
|
||||
infoListAdapter.addStreamItemList(result.resultList);
|
||||
infoListAdapter.addInfoItemList(result.resultList);
|
||||
setDoneLoading();
|
||||
}
|
||||
|
||||
|
@ -213,7 +216,8 @@ public class SearchInfoItemFragment extends Fragment {
|
|||
|
||||
infoListAdapter = new InfoListAdapter(getActivity(),
|
||||
getActivity().findViewById(android.R.id.content));
|
||||
infoListAdapter.setOnItemSelectedListener(new InfoItemBuilder.OnItemSelectedListener() {
|
||||
infoListAdapter.setOnStreamItemSelectedListener(
|
||||
new InfoItemBuilder.OnInfoItemSelectedListener() {
|
||||
@Override
|
||||
public void selected(String url) {
|
||||
startDetailActivity(url);
|
||||
|
@ -298,7 +302,11 @@ public class SearchInfoItemFragment extends Fragment {
|
|||
private void search(String query, int page) {
|
||||
isLoading = true;
|
||||
SearchWorker sw = SearchWorker.getInstance();
|
||||
sw.search(streamingServiceId, query, page, getActivity());
|
||||
sw.search(streamingServiceId,
|
||||
query,
|
||||
page,
|
||||
getActivity(),
|
||||
EnumSet.of(SearchEngine.Filter.CHANNEL));
|
||||
}
|
||||
|
||||
private void setDoneLoading() {
|
||||
|
|
|
@ -16,6 +16,7 @@ import org.schabi.newpipe.R;
|
|||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.EnumSet;
|
||||
|
||||
/**
|
||||
* Created by Christian Schabesberger on 02.08.16.
|
||||
|
@ -67,14 +68,21 @@ public class SearchWorker {
|
|||
public static final String YOUTUBE = "Youtube";
|
||||
private final String query;
|
||||
private final int page;
|
||||
private final EnumSet<SearchEngine.Filter> filter;
|
||||
final Handler h = new Handler();
|
||||
private volatile boolean runs = true;
|
||||
private Activity a = null;
|
||||
private int serviceId = -1;
|
||||
public SearchRunnable(int serviceId, String query, int page, Activity activity, int requestId) {
|
||||
public SearchRunnable(int serviceId,
|
||||
String query,
|
||||
int page,
|
||||
EnumSet<SearchEngine.Filter> filter,
|
||||
Activity activity,
|
||||
int requestId) {
|
||||
this.serviceId = serviceId;
|
||||
this.query = query;
|
||||
this.page = page;
|
||||
this.filter = filter;
|
||||
this.a = activity;
|
||||
}
|
||||
void terminate() {
|
||||
|
@ -102,7 +110,7 @@ public class SearchWorker {
|
|||
String searchLanguage = sp.getString(searchLanguageKey,
|
||||
a.getString(R.string.default_language_value));
|
||||
result = SearchResult
|
||||
.getSearchResult(engine, query, page, searchLanguage);
|
||||
.getSearchResult(engine, query, page, searchLanguage, filter);
|
||||
if(runs) {
|
||||
h.post(new ResultRunnable(result, requestId));
|
||||
}
|
||||
|
@ -180,11 +188,15 @@ public class SearchWorker {
|
|||
|
||||
}
|
||||
|
||||
public void search(int serviceId, String query, int page, Activity a) {
|
||||
public void search(int serviceId,
|
||||
String query,
|
||||
int page,
|
||||
Activity a,
|
||||
EnumSet<SearchEngine.Filter> filter) {
|
||||
if(runnable != null) {
|
||||
terminate();
|
||||
}
|
||||
runnable = new SearchRunnable(serviceId, query, page, a, requestId);
|
||||
runnable = new SearchRunnable(serviceId, query, page, filter, a, requestId);
|
||||
Thread thread = new Thread(runnable);
|
||||
thread.start();
|
||||
}
|
||||
|
|
BIN
app/src/main/res/drawable-nodpi/buddy_channel_item.png
Normal file
BIN
app/src/main/res/drawable-nodpi/buddy_channel_item.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
BIN
app/src/main/res/drawable-nodpi/dummi_thumbnail_playlist.png
Normal file
BIN
app/src/main/res/drawable-nodpi/dummi_thumbnail_playlist.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
69
app/src/main/res/layout/channel_item.xml
Normal file
69
app/src/main/res/layout/channel_item.xml
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/item_main_layout"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="12dp">
|
||||
|
||||
<RelativeLayout android:id="@+id/itemThumbnailViewContainer"
|
||||
android:layout_marginRight="@dimen/video_item_search_image_right_margin"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:ignore="RtlHardcoded">
|
||||
|
||||
<de.hdodenhof.circleimageview.CircleImageView android:id="@+id/itemThumbnailView"
|
||||
android:contentDescription="@string/list_thumbnail_view_description"
|
||||
android:layout_width="@dimen/video_item_search_thumbnail_image_width"
|
||||
android:layout_height="@dimen/video_item_search_thumbnail_image_height"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:src="@drawable/buddy_channel_item"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="@dimen/video_item_search_thumbnail_image_height"
|
||||
android:layout_toRightOf="@id/itemThumbnailViewContainer"
|
||||
tools:ignore="RtlHardcoded">
|
||||
|
||||
<TextView android:id="@+id/itemChannelTitleView"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="0dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textSize="@dimen/video_item_search_title_text_size"/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/item_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/selectableItemBackground"/>
|
||||
</FrameLayout>
|
71
app/src/main/res/layout/play_list_item.xml
Normal file
71
app/src/main/res/layout/play_list_item.xml
Normal file
|
@ -0,0 +1,71 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/item_main_layout"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="12dp">
|
||||
|
||||
<RelativeLayout android:id="@+id/itemThumbnailViewContainer"
|
||||
android:layout_marginRight="@dimen/video_item_search_image_right_margin"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:ignore="RtlHardcoded">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/itemThumbnailView"
|
||||
android:contentDescription="@string/list_thumbnail_view_description"
|
||||
android:layout_width="@dimen/video_item_search_thumbnail_image_width"
|
||||
android:layout_height="@dimen/video_item_search_thumbnail_image_height"
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:src="@drawable/dummi_thumbnail_playlist"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="@dimen/video_item_search_thumbnail_image_height"
|
||||
android:layout_toRightOf="@id/itemThumbnailViewContainer"
|
||||
tools:ignore="RtlHardcoded">
|
||||
|
||||
<TextView android:id="@+id/itemTitleView"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="0dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textSize="@dimen/video_item_search_title_text_size"/>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/item_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/selectableItemBackground"/>
|
||||
</FrameLayout>
|
108
app/src/main/res/layout/stream_item.xml
Normal file
108
app/src/main/res/layout/stream_item.xml
Normal file
|
@ -0,0 +1,108 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/item_main_layout"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="12dp">
|
||||
|
||||
<RelativeLayout android:id="@+id/itemThumbnailViewContainer"
|
||||
android:layout_marginRight="@dimen/video_item_search_image_right_margin"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:ignore="RtlHardcoded">
|
||||
|
||||
<ImageView android:id="@+id/itemThumbnailView"
|
||||
android:contentDescription="@string/list_thumbnail_view_description"
|
||||
android:layout_width="@dimen/video_item_search_thumbnail_image_width"
|
||||
android:layout_height="@dimen/video_item_search_thumbnail_image_height"
|
||||
android:scaleType="centerCrop"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:src="@drawable/dummy_thumbnail"/>
|
||||
|
||||
<TextView android:id="@+id/itemDurationView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@id/itemThumbnailView"
|
||||
android:layout_alignRight="@id/itemThumbnailView"
|
||||
android:layout_alignEnd="@id/itemThumbnailView"
|
||||
android:layout_marginRight="@dimen/video_item_search_duration_margin"
|
||||
android:layout_marginEnd="@dimen/video_item_search_duration_margin"
|
||||
android:layout_marginBottom="@dimen/video_item_search_duration_margin"
|
||||
android:paddingTop="@dimen/video_item_search_duration_vertical_padding"
|
||||
android:paddingBottom="@dimen/video_item_search_duration_vertical_padding"
|
||||
android:paddingRight="@dimen/video_item_search_duration_horizontal_padding"
|
||||
android:paddingLeft="@dimen/video_item_search_duration_horizontal_padding"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textSize="@dimen/video_item_search_duration_text_size"
|
||||
android:background="@color/duration_background_color"
|
||||
android:textColor="@color/duration_text_color"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="@dimen/video_item_search_thumbnail_image_height"
|
||||
android:layout_toRightOf="@id/itemThumbnailViewContainer"
|
||||
tools:ignore="RtlHardcoded">
|
||||
|
||||
<TextView android:id="@+id/itemVideoTitleView"
|
||||
android:layout_weight="1"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="0dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:textSize="@dimen/video_item_search_title_text_size"/>
|
||||
|
||||
<TextView android:id="@+id/itemUploaderView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textSize="@dimen/video_item_search_uploader_text_size"/>
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:id="@+id/itemUploadDateView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textSize="@dimen/video_item_search_upload_date_text_size"/>
|
||||
|
||||
<TextView android:id="@+id/itemViewCountView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||
android:textSize="@dimen/video_item_search_upload_date_text_size"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/item_button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/selectableItemBackground"/>
|
||||
</FrameLayout>
|
85
assets/buddy_channel_item.svg
Normal file
85
assets/buddy_channel_item.svg
Normal file
|
@ -0,0 +1,85 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="200"
|
||||
height="200"
|
||||
viewBox="0 0 187.5 187.5"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.0 r"
|
||||
sodipodi:docname="buddy_channel_item.svg"
|
||||
inkscape:export-filename="/home/the-scrabi/Projects/NewPipe/app/src/main/res/drawable-nodpi/buddy_channel_item.png"
|
||||
inkscape:export-xdpi="96"
|
||||
inkscape:export-ydpi="96">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.6269531"
|
||||
inkscape:cx="-8.1138818"
|
||||
inkscape:cy="101.30232"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1012"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="32"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-864.86216)">
|
||||
<rect
|
||||
style="opacity:0.997;fill:#999999;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.6875;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4136"
|
||||
width="187.5"
|
||||
height="187.5"
|
||||
x="0"
|
||||
y="864.86218" />
|
||||
<g
|
||||
id="g4487"
|
||||
transform="matrix(0.5625,0,0,0.5625,37.5,418.22093)">
|
||||
<ellipse
|
||||
ry="75"
|
||||
rx="100"
|
||||
cy="1052.3622"
|
||||
cx="100"
|
||||
id="path4152"
|
||||
style="opacity:0.997;fill:#6c6c6c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<circle
|
||||
r="60"
|
||||
cy="942.36218"
|
||||
cx="100"
|
||||
id="path4154"
|
||||
style="opacity:0.997;fill:#6c6c6c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
105
assets/dummi_thumbnail_playlist.svg
Normal file
105
assets/dummi_thumbnail_playlist.svg
Normal file
|
@ -0,0 +1,105 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="454.39999"
|
||||
height="256"
|
||||
viewBox="0 0 426.00001 240"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.0 r"
|
||||
sodipodi:docname="dummi_thumbnail_playlist.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.6106014"
|
||||
inkscape:cx="305.7725"
|
||||
inkscape:cy="81.056384"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1012"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="32"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-812.36212)">
|
||||
<rect
|
||||
style="opacity:0.997;fill:#999999;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4136"
|
||||
width="426"
|
||||
height="240"
|
||||
x="0"
|
||||
y="812.36212" />
|
||||
<g
|
||||
id="g850"
|
||||
transform="matrix(0.99796952,0,0,1,32.067586,0)">
|
||||
<path
|
||||
inkscape:transform-center-y="-0.54163706"
|
||||
transform="matrix(0.65046494,0.01393934,-0.01048956,0.86438861,173.20818,83.099197)"
|
||||
inkscape:transform-center-x="-13.894569"
|
||||
d="M 122.12368,980.33878 65.844916,1014.7522 2.6244521,1052.3621 0.9609674,986.41661 -1.2793975e-6,912.86109 57.942247,944.39324 Z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:arg2="0.93534698"
|
||||
sodipodi:arg1="-0.018810925"
|
||||
sodipodi:r2="40.877174"
|
||||
sodipodi:r1="80.555222"
|
||||
sodipodi:cy="981.854"
|
||||
sodipodi:cx="41.58271"
|
||||
sodipodi:sides="3"
|
||||
id="path4164"
|
||||
style="opacity:0.997;fill:#6c6c6c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
sodipodi:type="star" />
|
||||
<path
|
||||
inkscape:transform-center-y="-0.54163706"
|
||||
transform="matrix(0.65046494,0.01393934,-0.01048956,0.86438861,129.96106,83.099439)"
|
||||
inkscape:transform-center-x="-13.894569"
|
||||
d="M 122.12368,980.33878 65.844916,1014.7522 2.6244521,1052.3621 0.9609674,986.41661 -1.2793975e-6,912.86109 57.942247,944.39324 Z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:arg2="0.93534698"
|
||||
sodipodi:arg1="-0.018810925"
|
||||
sodipodi:r2="40.877174"
|
||||
sodipodi:r1="80.555222"
|
||||
sodipodi:cy="981.854"
|
||||
sodipodi:cx="41.58271"
|
||||
sodipodi:sides="3"
|
||||
id="path4164-3"
|
||||
style="opacity:0.997;fill:#6c6c6c;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
sodipodi:type="star" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.7 KiB |
72
assets/dummi_thumbnail_playlist_background.svg
Normal file
72
assets/dummi_thumbnail_playlist_background.svg
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="534.39996"
|
||||
height="336"
|
||||
viewBox="0 0 500.99998 315"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.0 r"
|
||||
sodipodi:docname="dummi_thumbnail_playlist_background.svg">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.3101865"
|
||||
inkscape:cx="235.67736"
|
||||
inkscape:cy="200.81947"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1012"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="32"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Ebene 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-737.36212)">
|
||||
<rect
|
||||
style="opacity:0.997;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4136-6-5"
|
||||
width="426.00003"
|
||||
height="240"
|
||||
x="18.75"
|
||||
y="756.11212" />
|
||||
<rect
|
||||
style="opacity:0.997;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:2.81250004;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect4136-6"
|
||||
width="426"
|
||||
height="240"
|
||||
x="28.125"
|
||||
y="765.48712" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.2 KiB |
Loading…
Reference in a new issue