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 @@ + + + + + + + + + + + + + + + +