diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e070a62d2..6be6f597b 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -156,8 +156,7 @@
+ android:launchMode="singleTask"/>
@@ -62,7 +48,7 @@ import static android.os.Build.VERSION.SDK_INT;
* along with NewPipe. If not, see .
*/
-public class ChannelActivity extends AppCompatActivity {
+public class ChannelActivity extends ThemableActivity {
private static final String TAG = ChannelActivity.class.toString();
private View rootView = null;
@@ -75,22 +61,17 @@ public class ChannelActivity extends AppCompatActivity {
private ImageLoader imageLoader = ImageLoader.getInstance();
private InfoListAdapter infoListAdapter = null;
+ private String subS = "";
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- //since we set themeing we have to set translucent statusBar by hand
- if (PreferenceManager.getDefaultSharedPreferences(this)
- .getString("theme", getResources().getString(R.string.light_theme_title)).
- equals(getResources().getString(R.string.dark_theme_title))) {
- setTheme(R.style.DarkTheme_NoActionBar);
- }
- setTranslucentStatusBar(getWindow());
-
setContentView(R.layout.activity_channel);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- rootView = findViewById(R.id.rootView);
- setSupportActionBar(toolbar);
+ rootView = findViewById(android.R.id.content);
+
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setDisplayShowTitleEnabled(true);
if(savedInstanceState == null) {
Intent i = getIntent();
channelUrl = i.getStringExtra(NavStack.URL);
@@ -107,6 +88,7 @@ public class ChannelActivity extends AppCompatActivity {
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.channel_streams_view);
final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
+ infoListAdapter.setHeader(getLayoutInflater().inflate(R.layout.channel_header, recyclerView, false));
recyclerView.setAdapter(infoListAdapter);
infoListAdapter.setOnStreamInfoItemSelectedListener(
new InfoItemBuilder.OnInfoItemSelectedListener() {
@@ -140,6 +122,8 @@ public class ChannelActivity extends AppCompatActivity {
}
});
+ subS = getString(R.string.subscriber);
+
requestData(false);
}
@@ -153,22 +137,24 @@ public class ChannelActivity extends AppCompatActivity {
}
private void updateUi(final ChannelInfo info) {
- CollapsingToolbarLayout ctl = (CollapsingToolbarLayout) findViewById(R.id.channel_toolbar_layout);
ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
ImageView channelBanner = (ImageView) findViewById(R.id.channel_banner_image);
- final FloatingActionButton feedButton = (FloatingActionButton) findViewById(R.id.channel_rss_fab);
ImageView avatarView = (ImageView) findViewById(R.id.channel_avatar_view);
ImageView haloView = (ImageView) findViewById(R.id.channel_avatar_halo);
+ TextView titleView = (TextView) findViewById(R.id.channel_title_view);
+ TextView subscirberView = (TextView) findViewById(R.id.channel_subscriber_view);
+ Button subscriberButton = (Button) findViewById(R.id.channel_subscribe_button);
progressBar.setVisibility(View.GONE);
if(info.channel_name != null && !info.channel_name.isEmpty()) {
- ctl.setTitle(info.channel_name);
+ getSupportActionBar().setTitle(info.channel_name);
+ titleView.setText(info.channel_name);
}
if(info.banner_url != null && !info.banner_url.isEmpty()) {
imageLoader.displayImage(info.banner_url, channelBanner,
- new ImageErrorLoadingListener(this, rootView ,info.service_id));
+ new ImageErrorLoadingListener(this, rootView ,info.service_id));
}
if(info.avatar_url != null && !info.avatar_url.isEmpty()) {
@@ -178,8 +164,17 @@ public class ChannelActivity extends AppCompatActivity {
new ImageErrorLoadingListener(this, rootView ,info.service_id));
}
+ if(info.subscriberCount != -1) {
+ subscirberView.setText(buildSubscriberString(info.subscriberCount));
+ }
+
+ if((info.feed_url != null && !info.feed_url.isEmpty()) ||
+ (info.subscriberCount != -1)) {
+ findViewById(R.id.channel_subscriber_layout).setVisibility(View.VISIBLE);
+ }
+
if(info.feed_url != null && !info.feed_url.isEmpty()) {
- feedButton.setOnClickListener(new View.OnClickListener() {
+ subscriberButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d(TAG, info.feed_url);
@@ -188,8 +183,9 @@ public class ChannelActivity extends AppCompatActivity {
}
});
} else {
- feedButton.setVisibility(View.GONE);
+ subscriberButton.setVisibility(View.GONE);
}
+
}
private void addVideos(final ChannelInfo info) {
@@ -297,30 +293,6 @@ public class ChannelActivity extends AppCompatActivity {
channelExtractorThread.start();
}
-
- // fix transparent statusbar fuckup (fuck google why can't they just leave something that worked
- // as it is, and everyone gets happy)
- public static void setTranslucentStatusBar(Window window) {
- if (window == null) return;
- int sdkInt = Build.VERSION.SDK_INT;
- if (sdkInt >= Build.VERSION_CODES.LOLLIPOP) {
- setTranslucentStatusBarLollipop(window);
- } else if (sdkInt >= Build.VERSION_CODES.KITKAT) {
- setTranslucentStatusBarKiKat(window);
- }
- }
-
- @TargetApi(Build.VERSION_CODES.LOLLIPOP)
- private static void setTranslucentStatusBarLollipop(Window window) {
- window.setStatusBarColor(
- ContextCompat.getColor(window.getContext(), android.R.color.transparent));
- }
-
- @TargetApi(Build.VERSION_CODES.KITKAT)
- private static void setTranslucentStatusBarKiKat(Window window) {
- window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
- }
-
@Override
public void onBackPressed() {
try {
@@ -331,4 +303,19 @@ public class ChannelActivity extends AppCompatActivity {
}
}
+
+ private String buildSubscriberString(long count) {
+ String out = "";
+ if(count >= 1000000000){
+ out += Long.toString((count/1000000000)%1000)+".";
+ }
+ if(count>=1000000){
+ out += Long.toString((count/1000000)%1000) + ".";
+ }
+ if(count>=1000){
+ out += Long.toString((count/1000)%1000)+".";
+ }
+ out += Long.toString(count%1000) + " " + subS;
+ return out;
+ }
}
diff --git a/app/src/main/java/org/schabi/newpipe/extractor/channel/ChannelExtractor.java b/app/src/main/java/org/schabi/newpipe/extractor/channel/ChannelExtractor.java
index 18bf67550..fe7b9f7eb 100644
--- a/app/src/main/java/org/schabi/newpipe/extractor/channel/ChannelExtractor.java
+++ b/app/src/main/java/org/schabi/newpipe/extractor/channel/ChannelExtractor.java
@@ -54,6 +54,7 @@ public abstract class ChannelExtractor {
public abstract String getBannerUrl() throws ParsingException;
public abstract String getFeedUrl() throws ParsingException;
public abstract StreamInfoItemCollector getStreams() throws ParsingException;
+ public abstract long getSubscriberCount() throws ParsingException;
public abstract boolean hasNextPage() throws ParsingException;
public int getServiceId() {
return serviceId;
diff --git a/app/src/main/java/org/schabi/newpipe/extractor/channel/ChannelInfo.java b/app/src/main/java/org/schabi/newpipe/extractor/channel/ChannelInfo.java
index 68862ec32..e1fd96ada 100644
--- a/app/src/main/java/org/schabi/newpipe/extractor/channel/ChannelInfo.java
+++ b/app/src/main/java/org/schabi/newpipe/extractor/channel/ChannelInfo.java
@@ -29,8 +29,6 @@ import java.util.Vector;
*/
public class ChannelInfo {
-
-
public void addException(Exception e) {
errors.add(e);
}
@@ -66,6 +64,11 @@ public class ChannelInfo {
} catch(Exception e) {
info.errors.add(e);
}
+ try {
+ info.subscriberCount = extractor.getSubscriberCount();
+ } catch (Exception e) {
+ info.errors.add(e);
+ }
return info;
}
@@ -76,6 +79,7 @@ public class ChannelInfo {
public String banner_url = "";
public String feed_url = "";
public List related_streams = null;
+ public long subscriberCount = -1;
public boolean hasNextPage = false;
public List errors = new Vector<>();
diff --git a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeChannelExtractor.java b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeChannelExtractor.java
index 413471eda..f4e872056 100644
--- a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeChannelExtractor.java
+++ b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeChannelExtractor.java
@@ -294,6 +294,13 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
return collector;
}
+ @Override
+ public long getSubscriberCount() throws ParsingException {
+ String countRaw = doc.select("span[class*=\"yt-subscription-button-subscriber-count\"]").first()
+ .text();
+ return Long.parseLong(countRaw.replaceAll("\\D+",""));
+ }
+
@Override
public String getFeedUrl() throws ParsingException {
try {
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java
index 67b19520a..4ec6123ad 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoItemBuilder.java
@@ -105,7 +105,7 @@ public class InfoItemBuilder {
switch(info.infoType()) {
case STREAM:
itemView = LayoutInflater.from(parent.getContext())
- .inflate(R.layout.stream_item, parent, false);
+ .inflate(R.layout.stream_item, parent, false);
holder = new StreamInfoItemHolder(itemView);
break;
case CHANNEL:
@@ -202,15 +202,15 @@ public class InfoItemBuilder {
}
}
- public String shortSubscriber(Long viewCount){
- if(viewCount >= 1000000000){
- return Long.toString(viewCount/1000000000)+ billion + " " + subsS;
- }else if(viewCount>=1000000){
- return Long.toString(viewCount/1000000)+ million + " " + subsS;
- }else if(viewCount>=1000){
- return Long.toString(viewCount/1000)+ thousand + " " + subsS;
+ public String shortSubscriber(Long count){
+ if(count >= 1000000000){
+ return Long.toString(count/1000000000)+ billion + " " + subsS;
+ }else if(count>=1000000){
+ return Long.toString(count/1000000)+ million + " " + subsS;
+ }else if(count>=1000){
+ return Long.toString(count/1000)+ thousand + " " + subsS;
}else {
- return Long.toString(viewCount)+ " " + subsS;
+ return Long.toString(count)+ " " + subsS;
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java
index adbdc22e7..81d28f753 100644
--- a/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java
+++ b/app/src/main/java/org/schabi/newpipe/info_list/InfoListAdapter.java
@@ -33,11 +33,20 @@ import java.util.Vector;
* along with NewPipe. If not, see .
*/
-public class InfoListAdapter extends RecyclerView.Adapter {
+public class InfoListAdapter extends RecyclerView.Adapter {
private static final String TAG = InfoListAdapter.class.toString();
private final InfoItemBuilder infoItemBuilder;
private final List infoItemList;
+ private View header = null;
+
+ public class HeaderHolder extends RecyclerView.ViewHolder {
+ public HeaderHolder(View v) {
+ super(v);
+ view = v;
+ }
+ public View view;
+ }
public InfoListAdapter(Activity a, View rootView) {
infoItemBuilder = new InfoItemBuilder(a, rootView);
@@ -66,21 +75,30 @@ public class InfoListAdapter extends RecyclerView.Adapter {
notifyDataSetChanged();
}
+ public void setHeader(View header) {
+ this.header = header;
+ }
+
@Override
public int getItemCount() {
- return infoItemList.size();
+ return (header == null) ? infoItemList.size() : (infoItemList.size() + 1);
}
// don't ask why we have to do that this way... it's android accept it -.-
@Override
public int getItemViewType(int position) {
+ if(header != null && position == 0) {
+ return 0;
+ } else if(header != null) {
+ position--;
+ }
switch(infoItemList.get(position).infoType()) {
case STREAM:
- return 0;
- case CHANNEL:
return 1;
- case PLAYLIST:
+ case CHANNEL:
return 2;
+ case PLAYLIST:
+ return 3;
default:
Log.e(TAG, "Trollolo");
return -1;
@@ -88,15 +106,17 @@ public class InfoListAdapter extends RecyclerView.Adapter {
}
@Override
- public InfoItemHolder onCreateViewHolder(ViewGroup parent, int type) {
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) {
switch(type) {
case 0:
+ return new HeaderHolder(header);
+ case 1:
return new StreamInfoItemHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.stream_item, parent, false));
- case 1:
+ case 2:
return new ChannelInfoItemHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.channel_item, parent, false));
- case 2:
+ case 3:
Log.e(TAG, "Playlist is not yet implemented");
return null;
default:
@@ -106,7 +126,15 @@ public class InfoListAdapter extends RecyclerView.Adapter {
}
@Override
- public void onBindViewHolder(InfoItemHolder holder, int i) {
- infoItemBuilder.buildByHolder(holder, infoItemList.get(i));
+ public void onBindViewHolder(RecyclerView.ViewHolder holder, int i) {
+ //god damen f*** ANDROID SH**
+ if(holder instanceof InfoItemHolder) {
+ if(header != null) {
+ i--;
+ }
+ infoItemBuilder.buildByHolder((InfoItemHolder) holder, infoItemList.get(i));
+ } else if(holder instanceof HeaderHolder && i == 0 && header != null) {
+ ((HeaderHolder) holder).view = header;
+ }
}
}
diff --git a/app/src/main/res/drawable-nodpi/channel_banner.png b/app/src/main/res/drawable-nodpi/channel_banner.png
new file mode 100644
index 000000000..94b25e98b
Binary files /dev/null and b/app/src/main/res/drawable-nodpi/channel_banner.png differ
diff --git a/app/src/main/res/layout/activity_channel.xml b/app/src/main/res/layout/activity_channel.xml
index cf67d55c4..5a3257a95 100644
--- a/app/src/main/res/layout/activity_channel.xml
+++ b/app/src/main/res/layout/activity_channel.xml
@@ -1,81 +1,17 @@
-
+ android:orientation="vertical"
+ android:title="Channel">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="match_parent"
+ android:background="?android:windowBackground"
+ android:scrollbars="vertical"/>
-
-
+
diff --git a/app/src/main/res/layout/channel_header.xml b/app/src/main/res/layout/channel_header.xml
new file mode 100644
index 000000000..de836fd33
--- /dev/null
+++ b/app/src/main/res/layout/channel_header.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index b0db9a2e1..d7b20ebb5 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -151,6 +151,7 @@
Experimental
videos
subscriber
+ Subscribe
views
K
M
diff --git a/app/src/test/java/org/schabi/newpipe/extractor/services/youtube/youtube/YoutubeChannelExtractorTest.java b/app/src/test/java/org/schabi/newpipe/extractor/services/youtube/youtube/YoutubeChannelExtractorTest.java
index c78f84170..474e9012e 100644
--- a/app/src/test/java/org/schabi/newpipe/extractor/services/youtube/youtube/YoutubeChannelExtractorTest.java
+++ b/app/src/test/java/org/schabi/newpipe/extractor/services/youtube/youtube/YoutubeChannelExtractorTest.java
@@ -87,6 +87,11 @@ public class YoutubeChannelExtractorTest {
assertTrue("no next page link found", extractor.hasNextPage());
}
+ @Test
+ public void testGetSubscriberCount() throws Exception {
+ assertTrue("wrong subscriber count", extractor.getSubscriberCount() >= 0);
+ }
+
@Test
public void testGetNextPage() throws Exception {
extractor = NewPipe.getService("Youtube")
diff --git a/assets/channel_banner_desktop.svg b/assets/channel_banner_desktop.svg
new file mode 100644
index 000000000..4d1b0d7ca
--- /dev/null
+++ b/assets/channel_banner_desktop.svg
@@ -0,0 +1,186 @@
+
+
+
+
diff --git a/assets/channel_banner_mobild.svg b/assets/channel_banner_mobild.svg
new file mode 100644
index 000000000..785becc0d
--- /dev/null
+++ b/assets/channel_banner_mobild.svg
@@ -0,0 +1,144 @@
+
+
+
+