diff --git a/app/build.gradle b/app/build.gradle
index 62cd8dc7b..dc301755c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,8 +8,8 @@ android {
applicationId "org.schabi.newpipe"
minSdkVersion 15
targetSdkVersion 25
- versionCode 24
- versionName "0.8.10"
+ versionCode 25
+ versionName "0.8.11"
}
buildTypes {
release {
@@ -32,10 +32,10 @@ android {
dependencies {
testCompile 'junit:junit:4.12'
- compile 'com.android.support:appcompat-v7:25.1.1'
- compile 'com.android.support:support-v4:25.1.1'
- compile 'com.android.support:design:25.1.1'
- compile 'com.android.support:recyclerview-v7:25.1.1'
+ compile 'com.android.support:appcompat-v7:25.2.0'
+ compile 'com.android.support:support-v4:25.2.0'
+ compile 'com.android.support:design:25.2.0'
+ compile 'com.android.support:recyclerview-v7:25.2.0'
compile 'org.jsoup:jsoup:1.8.3'
compile 'org.mozilla:rhino:1.7.7'
compile 'info.guardianproject.netcipher:netcipher:1.2'
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index e070a62d2..bc050f2ce 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -16,7 +16,6 @@
android:logo="@mipmap/ic_launcher"
android:theme="@style/AppTheme"
tools:ignore="AllowBackup">
-
@@ -34,53 +33,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:launchMode="singleTop"
+ android:theme="@style/FilePickerTheme"/>
-
+ android:launchMode="singleTask" />
@@ -170,8 +117,64 @@
android:grantUriPermissions="true">
+ android:resource="@xml/provider_paths" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/org/schabi/newpipe/ChannelActivity.java b/app/src/main/java/org/schabi/newpipe/ChannelActivity.java
index c8e0ad4a8..37ef28a13 100644
--- a/app/src/main/java/org/schabi/newpipe/ChannelActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/ChannelActivity.java
@@ -1,31 +1,24 @@
package org.schabi.newpipe;
-import android.annotation.TargetApi;
-import android.content.Context;
import android.content.Intent;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
-import android.preference.PreferenceManager;
-import android.support.design.widget.CollapsingToolbarLayout;
-import android.support.design.widget.FloatingActionButton;
-import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.Toolbar;
import android.util.Log;
+import android.view.Menu;
+import android.view.MenuItem;
import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
+import android.widget.Button;
import android.widget.ImageView;
import android.widget.ProgressBar;
+import android.widget.TextView;
import android.widget.Toast;
import com.nostra13.universalimageloader.core.ImageLoader;
-import org.schabi.newpipe.detail.VideoItemDetailActivity;
import org.schabi.newpipe.detail.VideoItemDetailFragment;
import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.StreamingService;
@@ -36,13 +29,12 @@ import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.info_list.InfoItemBuilder;
import org.schabi.newpipe.info_list.InfoListAdapter;
import org.schabi.newpipe.report.ErrorActivity;
+import org.schabi.newpipe.settings.SettingsActivity;
import org.schabi.newpipe.util.NavStack;
-
import java.io.IOException;
-import java.util.Objects;
-
-import static android.os.Build.VERSION.SDK;
import static android.os.Build.VERSION.SDK_INT;
+import org.schabi.newpipe.util.ThemeHelper;
+
/**
* Copyright (C) Christian Schabesberger 2016
@@ -75,38 +67,36 @@ public class ChannelActivity extends AppCompatActivity {
private ImageLoader imageLoader = ImageLoader.getInstance();
private InfoListAdapter infoListAdapter = null;
+ private String subS = "";
+
+ ProgressBar progressBar = null;
+ ImageView channelBanner = null;
+ ImageView avatarView = null;
+ TextView titleView = null;
+ TextView subscirberView = null;
+ Button subscriberButton = null;
+ View subscriberLayout = null;
+
+ View header = null;
+
@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());
-
+ ThemeHelper.setTheme(this, true);
setContentView(R.layout.activity_channel);
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- rootView = findViewById(R.id.rootView);
- setSupportActionBar(toolbar);
- if(savedInstanceState == null) {
- Intent i = getIntent();
- channelUrl = i.getStringExtra(NavStack.URL);
- serviceId = i.getIntExtra(NavStack.SERVICE_ID, -1);
- } else {
- channelUrl = savedInstanceState.getString(NavStack.URL);
- serviceId = savedInstanceState.getInt(NavStack.SERVICE_ID);
- NavStack.getInstance()
- .restoreSavedInstanceState(savedInstanceState);
- }
+ rootView = findViewById(android.R.id.content);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setDisplayShowTitleEnabled(true);
infoListAdapter = new InfoListAdapter(this, rootView);
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.channel_streams_view);
final LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
+ header = getLayoutInflater().inflate(R.layout.channel_header, recyclerView, false);
+ infoListAdapter.setHeader(header);
+ infoListAdapter.setFooter(
+ getLayoutInflater().inflate(R.layout.pignate_footer, recyclerView, false));
recyclerView.setAdapter(infoListAdapter);
infoListAdapter.setOnStreamInfoItemSelectedListener(
new InfoItemBuilder.OnInfoItemSelectedListener() {
@@ -140,6 +130,36 @@ public class ChannelActivity extends AppCompatActivity {
}
});
+ subS = getString(R.string.subscriber);
+
+ progressBar = (ProgressBar) findViewById(R.id.progressBar);
+ channelBanner = (ImageView) header.findViewById(R.id.channel_banner_image);
+ avatarView = (ImageView) header.findViewById(R.id.channel_avatar_view);
+ titleView = (TextView) header.findViewById(R.id.channel_title_view);
+ subscirberView = (TextView) header.findViewById(R.id.channel_subscriber_view);
+ subscriberButton = (Button) header.findViewById(R.id.channel_subscribe_button);
+ subscriberLayout = header.findViewById(R.id.channel_subscriber_layout);
+
+ if(savedInstanceState == null) {
+ handleIntent(getIntent());
+ } else {
+ channelUrl = savedInstanceState.getString(NavStack.URL);
+ serviceId = savedInstanceState.getInt(NavStack.SERVICE_ID);
+ NavStack.getInstance()
+ .restoreSavedInstanceState(savedInstanceState);
+ }
+
+ }
+
+ @Override
+ public void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+ handleIntent(intent);
+ }
+
+ private void handleIntent(Intent i) {
+ channelUrl = i.getStringExtra(NavStack.URL);
+ serviceId = i.getIntExtra(NavStack.SERVICE_ID, -1);
requestData(false);
}
@@ -153,33 +173,36 @@ 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);
-
+ findViewById(R.id.channel_header_layout).setVisibility(View.VISIBLE);
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()) {
avatarView.setVisibility(View.VISIBLE);
- haloView.setVisibility(View.VISIBLE);
imageLoader.displayImage(info.avatar_url, avatarView,
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)) {
+ subscriberLayout.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 +211,9 @@ public class ChannelActivity extends AppCompatActivity {
}
});
} else {
- feedButton.setVisibility(View.GONE);
+ subscriberButton.setVisibility(View.INVISIBLE);
}
+
}
private void addVideos(final ChannelInfo info) {
@@ -209,6 +233,22 @@ public class ChannelActivity extends AppCompatActivity {
private void requestData(final boolean onlyVideos) {
// start processing
isLoading = true;
+
+ if(!onlyVideos) {
+ //delete already displayed content
+ progressBar.setVisibility(View.VISIBLE);
+ infoListAdapter.clearSteamItemList();
+ pageNumber = 0;
+ subscriberLayout.setVisibility(View.GONE);
+ titleView.setText("");
+ getSupportActionBar().setTitle("");
+ if (SDK_INT >= 21) {
+ channelBanner.setImageDrawable(getDrawable(R.drawable.channel_banner));
+ avatarView.setImageDrawable(getDrawable(R.drawable.buddy));
+ }
+ infoListAdapter.showFooter(false);
+ }
+
Thread channelExtractorThread = new Thread(new Runnable() {
Handler h = new Handler();
@@ -229,8 +269,12 @@ public class ChannelActivity extends AppCompatActivity {
isLoading = false;
if(!onlyVideos) {
updateUi(info);
+ infoListAdapter.showFooter(true);
}
hasNextPage = info.hasNextPage;
+ if(!hasNextPage) {
+ infoListAdapter.showFooter(false);
+ }
addVideos(info);
}
});
@@ -297,30 +341,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 +351,54 @@ public class ChannelActivity extends AppCompatActivity {
}
}
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ getMenuInflater().inflate(R.menu.menu_channel, menu);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ super.onOptionsItemSelected(item);
+ switch(item.getItemId()) {
+ case R.id.action_settings: {
+ Intent intent = new Intent(this, SettingsActivity.class);
+ startActivity(intent);
+ return true;
+ }
+ case R.id.menu_item_openInBrowser: {
+ Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(channelUrl));
+
+ startActivity(Intent.createChooser(intent, getString(R.string.choose_browser)));
+ }
+ case R.id.menu_item_share:
+ Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_SEND);
+ intent.putExtra(Intent.EXTRA_TEXT, channelUrl);
+ intent.setType("text/plain");
+ startActivity(Intent.createChooser(intent, getString(R.string.share_dialog_title)));
+ case android.R.id.home:
+ NavStack.getInstance().openMainActivity(this);
+ default:
+ return super.onOptionsItemSelected(item);
+ }
+ }
+
+ 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/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java
index b7375fd16..eb9fd313c 100644
--- a/app/src/main/java/org/schabi/newpipe/MainActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java
@@ -2,19 +2,17 @@ package org.schabi.newpipe;
import android.content.Intent;
import android.media.AudioManager;
+import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.NavUtils;
-import android.os.Bundle;
-import android.util.Log;
+import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
-import android.view.View;
-import android.widget.AdapterView;
-
import org.schabi.newpipe.download.DownloadActivity;
import org.schabi.newpipe.settings.SettingsActivity;
import org.schabi.newpipe.util.PermissionHelper;
+import org.schabi.newpipe.util.ThemeHelper;
/**
* Created by Christian Schabesberger on 02.08.16.
@@ -36,13 +34,15 @@ import org.schabi.newpipe.util.PermissionHelper;
* along with NewPipe. If not, see .
*/
-public class MainActivity extends ThemableActivity {
+
+public class MainActivity extends AppCompatActivity {
private Fragment mainFragment = null;
private static final String TAG = MainActivity.class.toString();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ ThemeHelper.setTheme(this, true);
setContentView(R.layout.activity_main);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
mainFragment = getSupportFragmentManager()
@@ -53,7 +53,6 @@ public class MainActivity extends ThemableActivity {
public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(menu);
MenuInflater inflater = getMenuInflater();
-
inflater.inflate(R.menu.main_menu, menu);
return true;
}
diff --git a/app/src/main/java/org/schabi/newpipe/RouterActivity.java b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
new file mode 100644
index 000000000..b87d97683
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/RouterActivity.java
@@ -0,0 +1,158 @@
+package org.schabi.newpipe;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.preference.PreferenceManager;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.util.Log;
+import android.widget.Toast;
+
+import org.schabi.newpipe.detail.VideoItemDetailActivity;
+import org.schabi.newpipe.detail.VideoItemDetailFragment;
+import org.schabi.newpipe.extractor.NewPipe;
+import org.schabi.newpipe.extractor.StreamingService;
+import org.schabi.newpipe.util.NavStack;
+
+import java.util.Collection;
+import java.util.HashSet;
+
+/**
+ * Copyright (C) Christian Schabesberger 2017
+ * RouterActivity .java is part of NewPipe.
+ *
+ * OpenHitboxStreams 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.
+ *
+ * OpenHitboxStreams 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 OpenHitboxStreams. If not, see .
+ */
+
+/**
+ * This Acitivty is designed to route share/open intents to the specified service, and
+ * to the part of the service which can handle the url.
+ */
+public class RouterActivity extends Activity {
+ private static final String TAG = RouterActivity.class.toString();
+
+ /**
+ * Removes invisible separators (\p{Z}) and punctuation characters including
+ * brackets (\p{P}). See http://www.regular-expressions.info/unicode.html for
+ * more details.
+ */
+ private final static String REGEX_REMOVE_FROM_URL = "[\\p{Z}\\p{P}]";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ handleIntent(getIntent());
+ finish();
+ }
+
+
+ private static String removeHeadingGibberish(final String input) {
+ int start = 0;
+ for (int i = input.indexOf("://") - 1; i >= 0; i--) {
+ if (!input.substring(i, i + 1).matches("\\p{L}")) {
+ start = i + 1;
+ break;
+ }
+ }
+ return input.substring(start, input.length());
+ }
+
+ private static String trim(final String input) {
+ if (input == null || input.length() < 1) {
+ return input;
+ } else {
+ String output = input;
+ while (output.length() > 0 && output.substring(0, 1).matches(REGEX_REMOVE_FROM_URL)) {
+ output = output.substring(1);
+ }
+ while (output.length() > 0
+ && output.substring(output.length() - 1, output.length()).matches(REGEX_REMOVE_FROM_URL)) {
+ output = output.substring(0, output.length() - 1);
+ }
+ return output;
+ }
+ }
+
+ /**
+ * Retrieves all Strings which look remotely like URLs from a text.
+ * Used if NewPipe was called through share menu.
+ *
+ * @param sharedText text to scan for URLs.
+ * @return potential URLs
+ */
+ private String[] getUris(final String sharedText) {
+ final Collection result = new HashSet<>();
+ if (sharedText != null) {
+ final String[] array = sharedText.split("\\p{Space}");
+ for (String s : array) {
+ s = trim(s);
+ if (s.length() != 0) {
+ if (s.matches(".+://.+")) {
+ result.add(removeHeadingGibberish(s));
+ } else if (s.matches(".+\\..+")) {
+ result.add("http://" + s);
+ }
+ }
+ }
+ }
+ return result.toArray(new String[result.size()]);
+ }
+
+ private void handleIntent(Intent intent) {
+ String videoUrl = "";
+ StreamingService service = null;
+
+ // first gather data and find service
+ if (intent.getData() != null) {
+ // this means the video was called though another app
+ videoUrl = intent.getData().toString();
+ } else if(intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
+ //this means that vidoe was called through share menu
+ String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
+ videoUrl = getUris(extraText)[0];
+ }
+
+ service = NewPipe.getServiceByUrl(videoUrl);
+ if(service == null) {
+ Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG)
+ .show();
+ return;
+ } else {
+ Intent callIntent = new Intent();
+ switch(service.getLinkTypeByUrl(videoUrl)) {
+ case CHANNEL:
+ callIntent.setClass(this, ChannelActivity.class);
+ break;
+ case STREAM:
+ callIntent.setClass(this, VideoItemDetailActivity.class);
+ callIntent.putExtra(VideoItemDetailFragment.AUTO_PLAY,
+ PreferenceManager.getDefaultSharedPreferences(this)
+ .getBoolean(
+ getString(R.string.autoplay_through_intent_key), false));
+ break;
+ case PLAYLIST:
+ Log.e(TAG, "NOT YET DEFINED");
+ break;
+ default:
+ Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG)
+ .show();
+ return;
+ }
+
+ callIntent.putExtra(NavStack.URL, videoUrl);
+ callIntent.putExtra(NavStack.SERVICE_ID, service.getServiceId());
+ startActivity(callIntent);
+ }
+ }
+}
diff --git a/app/src/main/java/org/schabi/newpipe/detail/VideoItemDetailActivity.java b/app/src/main/java/org/schabi/newpipe/detail/VideoItemDetailActivity.java
index 261e219cf..97935edf4 100644
--- a/app/src/main/java/org/schabi/newpipe/detail/VideoItemDetailActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/detail/VideoItemDetailActivity.java
@@ -1,29 +1,17 @@
package org.schabi.newpipe.detail;
-import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.support.v4.app.NavUtils;
+import android.support.v7.app.AppCompatActivity;
import android.util.Log;
-import android.view.Menu;
import android.view.MenuItem;
-import android.widget.Toast;
import org.schabi.newpipe.App;
-import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
-import org.schabi.newpipe.ThemableActivity;
-import org.schabi.newpipe.extractor.NewPipe;
-import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.util.NavStack;
-
-import java.util.Collection;
-import java.util.HashSet;
-
-import static android.os.Build.VERSION.SDK_INT;
+import org.schabi.newpipe.util.ThemeHelper;
/**
@@ -44,15 +32,7 @@ import static android.os.Build.VERSION.SDK_INT;
* along with NewPipe. If not, see .
*/
-public class VideoItemDetailActivity extends ThemableActivity {
-
- /**
- * Removes invisible separators (\p{Z}) and punctuation characters including
- * brackets (\p{P}). See http://www.regular-expressions.info/unicode.html for
- * more details.
- */
- private final static String REGEX_REMOVE_FROM_URL = "[\\p{Z}\\p{P}]";
-
+public class VideoItemDetailActivity extends AppCompatActivity {
private static final String TAG = VideoItemDetailActivity.class.toString();
private VideoItemDetailFragment fragment;
@@ -62,6 +42,7 @@ public class VideoItemDetailActivity extends ThemableActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ ThemeHelper.setTheme(this, true);
setContentView(R.layout.activity_videoitem_detail);
setVolumeControlStream(AudioManager.STREAM_MUSIC);
// Show the Up button in the action bar.
@@ -104,27 +85,13 @@ public class VideoItemDetailActivity extends ThemableActivity {
private void handleIntent(Intent intent) {
Bundle arguments = new Bundle();
boolean autoplay = false;
- if (intent.getData() != null) {
- // this means the video was called though another app
- videoUrl = intent.getData().toString();
- currentStreamingService = getServiceIdByUrl(videoUrl);
- if(currentStreamingService == -1) {
- Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG)
- .show();
- }
- autoplay = PreferenceManager.getDefaultSharedPreferences(this)
- .getBoolean(getString(R.string.autoplay_through_intent_key), false);
- } else if(intent.getStringExtra(Intent.EXTRA_TEXT) != null) {
- //this means that vidoe was called through share menu
- String extraText = intent.getStringExtra(Intent.EXTRA_TEXT);
- videoUrl = getUris(extraText)[0];
- currentStreamingService = getServiceIdByUrl(videoUrl);
- } else {
- //this is if the video was called through another NewPipe activity
- videoUrl = intent.getStringExtra(NavStack.URL);
- currentStreamingService = intent.getIntExtra(NavStack.SERVICE_ID, -1);
+
+ videoUrl = intent.getStringExtra(NavStack.URL);
+ currentStreamingService = intent.getIntExtra(NavStack.SERVICE_ID, -1);
+ if(intent.hasExtra(VideoItemDetailFragment.AUTO_PLAY)) {
+ arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY,
+ intent.getBooleanExtra(VideoItemDetailFragment.AUTO_PLAY, false));
}
- arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY, autoplay);
arguments.putString(NavStack.URL, videoUrl);
arguments.putInt(NavStack.SERVICE_ID, currentStreamingService);
addFragment(arguments);
@@ -185,69 +152,4 @@ public class VideoItemDetailActivity extends ThemableActivity {
ErrorActivity.reportUiError(this, e);
}
}
-
- /**
- * Retrieves all Strings which look remotely like URLs from a text.
- * Used if NewPipe was called through share menu.
- *
- * @param sharedText text to scan for URLs.
- * @return potential URLs
- */
- private String[] getUris(final String sharedText) {
- final Collection result = new HashSet<>();
- if (sharedText != null) {
- final String[] array = sharedText.split("\\p{Space}");
- for (String s : array) {
- s = trim(s);
- if (s.length() != 0) {
- if (s.matches(".+://.+")) {
- result.add(removeHeadingGibberish(s));
- } else if (s.matches(".+\\..+")) {
- result.add("http://" + s);
- }
- }
- }
- }
- return result.toArray(new String[result.size()]);
- }
-
- private static String removeHeadingGibberish(final String input) {
- int start = 0;
- for (int i = input.indexOf("://") - 1; i >= 0; i--) {
- if (!input.substring(i, i + 1).matches("\\p{L}")) {
- start = i + 1;
- break;
- }
- }
- return input.substring(start, input.length());
- }
-
- private static String trim(final String input) {
- if (input == null || input.length() < 1) {
- return input;
- } else {
- String output = input;
- while (output.length() > 0 && output.substring(0, 1).matches(REGEX_REMOVE_FROM_URL)) {
- output = output.substring(1);
- }
- while (output.length() > 0
- && output.substring(output.length() - 1, output.length()).matches(REGEX_REMOVE_FROM_URL)) {
- output = output.substring(0, output.length() - 1);
- }
- return output;
- }
- }
-
- private int getServiceIdByUrl(String url) {
- StreamingService[] serviceList = NewPipe.getServices();
- int service = -1;
- for (int i = 0; i < serviceList.length; i++) {
- if (serviceList[i].getStreamUrlIdHandlerInstance().acceptUrl(videoUrl)) {
- service = i;
- //videoExtractor = ServiceList.getService(i).getExtractorInstance();
- break;
- }
- }
- return service;
- }
}
diff --git a/app/src/main/java/org/schabi/newpipe/detail/VideoItemDetailFragment.java b/app/src/main/java/org/schabi/newpipe/detail/VideoItemDetailFragment.java
index bf9a32ae2..8dc403f11 100644
--- a/app/src/main/java/org/schabi/newpipe/detail/VideoItemDetailFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/detail/VideoItemDetailFragment.java
@@ -33,6 +33,7 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
+
import com.google.android.exoplayer.util.Util;
import com.nostra13.universalimageloader.core.DisplayImageOptions;
import com.nostra13.universalimageloader.core.ImageLoader;
@@ -797,8 +798,11 @@ public class VideoItemDetailFragment extends Fragment {
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- super.onOptionsItemSelected(item);
- return actionBarHandler.onItemSelected(item);
+ if(!actionBarHandler.onItemSelected(item)) {
+ return super.onOptionsItemSelected(item);
+ } else {
+ return true;
+ }
}
public void setOnInvokeCreateOptionsMenuListener(OnInvokeCreateOptionsMenuListener listener) {
diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java b/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java
index 3c80e3be0..61e0a12b7 100644
--- a/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/download/DownloadActivity.java
@@ -3,18 +3,15 @@ package org.schabi.newpipe.download;
import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.app.FragmentTransaction;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.os.Bundle;
-import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.v4.app.NavUtils;
import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -28,32 +25,28 @@ import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
-import org.schabi.newpipe.ThemableActivity;
-import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.R;
+import org.schabi.newpipe.report.ErrorActivity;
import org.schabi.newpipe.settings.NewPipeSettings;
import org.schabi.newpipe.settings.SettingsActivity;
+import org.schabi.newpipe.util.ThemeHelper;
import java.io.File;
import java.util.Vector;
-import us.shandian.giga.get.DownloadManager;
import us.shandian.giga.service.DownloadManagerService;
import us.shandian.giga.ui.fragment.AllMissionsFragment;
import us.shandian.giga.ui.fragment.MissionsFragment;
import us.shandian.giga.util.CrashHandler;
import us.shandian.giga.util.Utility;
-public class DownloadActivity extends ThemableActivity implements AdapterView.OnItemClickListener{
+public class DownloadActivity extends AppCompatActivity implements AdapterView.OnItemClickListener {
public static final String INTENT_DOWNLOAD = "us.shandian.giga.intent.DOWNLOAD";
public static final String INTENT_LIST = "us.shandian.giga.intent.LIST";
-
- private static final String TAG = DownloadActivity.class.toString();
public static final String THREADS = "threads";
-
-
+ private static final String TAG = DownloadActivity.class.toString();
private MissionsFragment mFragment;
@@ -72,9 +65,9 @@ public class DownloadActivity extends ThemableActivity implements AdapterView.On
startService(i);
super.onCreate(savedInstanceState);
+ ThemeHelper.setTheme(this, true);
setContentView(R.layout.activity_downloader);
-
//noinspection ConstantConditions
// its ok if this fails, we will catch that error later, and send it as report
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..0b8fda717 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
@@ -55,6 +55,7 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
private static String avatarUrl = "";
private static String bannerUrl = "";
private static String feedUrl = "";
+ private static long subscriberCount = -1;
// the fist page is html all other pages are ajax. Every new page can be requested by sending
// this request url.
private static String nextPageUrl = "";
@@ -153,7 +154,7 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
@Override
public StreamInfoItemCollector getStreams() throws ParsingException {
StreamInfoItemCollector collector = getStreamPreviewInfoCollector();
- Element ul = null;
+ Element ul;
if(isAjaxPage) {
ul = doc.select("body").first();
} else {
@@ -168,6 +169,15 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
return AbstractStreamInfo.StreamType.VIDEO_STREAM;
}
+ @Override
+ public boolean isAd() throws ParsingException {
+ if(!li.select("span[class*=\"icon-not-available\"]").isEmpty()) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
@Override
public String getWebPageUrl() throws ParsingException {
try {
@@ -213,9 +223,14 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
@Override
public String getUploadDate() throws ParsingException {
try {
- return li.select("div[class=\"yt-lockup-meta\"]").first()
- .select("li").first()
- .text();
+ Element meta = li.select("div[class=\"yt-lockup-meta\"]").first();
+ Element li = meta.select("li").first();
+ if (li == null && meta != null) {
+ //this means we have a youtube red video
+ return "";
+ }else {
+ return li.text();
+ }
} catch(Exception e) {
throw new ParsingException("Could not get uplaod date", e);
}
@@ -230,13 +245,7 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
.select("li").get(1)
.text();
} catch (IndexOutOfBoundsException e) {
- if(isLiveStream(li)) {
- // -1 for no view count
- return -1;
- } else {
- throw new ParsingException(
- "Could not parse yt-lockup-meta although available: " + getTitle(), e);
- }
+ return -1;
}
output = Parser.matchGroup1("([0-9,\\. ]*)", input)
@@ -294,6 +303,18 @@ public class YoutubeChannelExtractor extends ChannelExtractor {
return collector;
}
+ @Override
+ public long getSubscriberCount() throws ParsingException {
+ Element el = doc.select("span[class*=\"yt-subscription-button-subscriber-count\"]")
+ .first();
+ if(el != null) {
+ subscriberCount = Long.parseLong(el.text().replaceAll("\\D+",""));
+ } else if(el == null && subscriberCount == -1) {
+ throw new ParsingException("Could not get subscriber count");
+ }
+ return subscriberCount;
+ }
+
@Override
public String getFeedUrl() throws ParsingException {
try {
diff --git a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamExtractor.java b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamExtractor.java
index 30846fedc..52a42f645 100644
--- a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamExtractor.java
+++ b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamExtractor.java
@@ -10,6 +10,7 @@ import org.mozilla.javascript.Function;
import org.mozilla.javascript.ScriptableObject;
import org.schabi.newpipe.extractor.AbstractStreamInfo;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
+import org.schabi.newpipe.extractor.exceptions.FoundAdException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.stream_info.AudioStream;
@@ -420,9 +421,15 @@ public class YoutubeStreamExtractor extends StreamExtractor {
@Override
public String getDashMpdUrl() throws ParsingException {
- /*
try {
- String dashManifestUrl = videoInfoPage.get("dashmpd");
+ String dashManifestUrl = "";
+ if(videoInfoPage != null && videoInfoPage.containsKey("dashmpd")) {
+ dashManifestUrl = videoInfoPage.get("dashmpd");
+ } else if (playerArgs.has("dashmpd")) {
+ dashManifestUrl = playerArgs.getString("dashmpd");
+ } else {
+ return "";
+ }
if(!dashManifestUrl.contains("/signature/")) {
String encryptedSig = Parser.matchGroup1("/s/([a-fA-F0-9\\.]+)", dashManifestUrl);
String decryptedSig;
@@ -435,8 +442,6 @@ public class YoutubeStreamExtractor extends StreamExtractor {
throw new ParsingException(
"Could not get \"dashmpd\" maybe VideoInfoPage is broken.", e);
}
- */
- return "";
}
@@ -447,9 +452,17 @@ public class YoutubeStreamExtractor extends StreamExtractor {
String encodedUrlMap;
// playerArgs could be null if the video is age restricted
if (playerArgs == null) {
- encodedUrlMap = videoInfoPage.get("adaptive_fmts");
+ if(videoInfoPage.containsKey("adaptive_fmts")) {
+ encodedUrlMap = videoInfoPage.get("adaptive_fmts");
+ } else {
+ return null;
+ }
} else {
- encodedUrlMap = playerArgs.getString("adaptive_fmts");
+ if(playerArgs.has("adaptive_fmts")) {
+ encodedUrlMap = playerArgs.getString("adaptive_fmts");
+ } else {
+ return null;
+ }
}
for(String url_data_str : encodedUrlMap.split(",")) {
// This loop iterates through multiple streams, therefor tags
@@ -713,7 +726,16 @@ public class YoutubeStreamExtractor extends StreamExtractor {
return new StreamInfoItemExtractor() {
@Override
public AbstractStreamInfo.StreamType getStreamType() throws ParsingException {
- return null;
+ return AbstractStreamInfo.StreamType.VIDEO_STREAM;
+ }
+
+ @Override
+ public boolean isAd() throws ParsingException {
+ if(!li.select("span[class*=\"icon-not-available\"]").isEmpty()) {
+ return true;
+ } else {
+ return false;
+ }
}
@Override
diff --git a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamInfoItemExtractor.java b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamInfoItemExtractor.java
index 1afb8f57d..44d606e2d 100644
--- a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamInfoItemExtractor.java
+++ b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamInfoItemExtractor.java
@@ -3,6 +3,7 @@ package org.schabi.newpipe.extractor.services.youtube;
import org.jsoup.nodes.Element;
import org.schabi.newpipe.extractor.AbstractStreamInfo;
import org.schabi.newpipe.extractor.Parser;
+import org.schabi.newpipe.extractor.exceptions.FoundAdException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.stream_info.StreamInfoItemExtractor;
@@ -28,7 +29,7 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
private final Element item;
- public YoutubeStreamInfoItemExtractor(Element item) {
+ public YoutubeStreamInfoItemExtractor(Element item) throws FoundAdException {
this.item = item;
}
@@ -161,6 +162,15 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
}
}
+ @Override
+ public boolean isAd() throws ParsingException {
+ if(!item.select("span[class*=\"icon-not-available\"]").isEmpty()) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
private boolean isLiveStream(Element item) {
Element bla = item.select("span[class*=\"yt-badge-live\"]").first();
diff --git a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamUrlIdHandler.java b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamUrlIdHandler.java
index 355da0402..055cd5970 100644
--- a/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamUrlIdHandler.java
+++ b/app/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamUrlIdHandler.java
@@ -15,7 +15,6 @@ import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
-import java.util.regex.Matcher;
/**
* Created by Christian Schabesberger on 02.02.16.
@@ -149,9 +148,9 @@ public class YoutubeStreamUrlIdHandler implements UrlIdHandler {
@Override
public boolean acceptUrl(String videoUrl) {
- videoUrl = videoUrl.toLowerCase();
- if(videoUrl.contains("youtube") ||
- videoUrl.contains("youtu.be")) {
+ String lowercaseUrl = videoUrl.toLowerCase();
+ if(lowercaseUrl.contains("youtube") ||
+ lowercaseUrl.contains("youtu.be")) {
// bad programming I know
try {
getId(videoUrl);
diff --git a/app/src/main/java/org/schabi/newpipe/extractor/stream_info/StreamInfoItemCollector.java b/app/src/main/java/org/schabi/newpipe/extractor/stream_info/StreamInfoItemCollector.java
index 5c2a8e74d..03ff7bd83 100644
--- a/app/src/main/java/org/schabi/newpipe/extractor/stream_info/StreamInfoItemCollector.java
+++ b/app/src/main/java/org/schabi/newpipe/extractor/stream_info/StreamInfoItemCollector.java
@@ -43,6 +43,9 @@ public class StreamInfoItemCollector extends InfoItemCollector {
}
public StreamInfoItem extract(StreamInfoItemExtractor extractor) throws Exception {
+ if(extractor.isAd()) {
+ throw new FoundAdException("Found ad");
+ }
StreamInfoItem resultItem = new StreamInfoItem();
// importand information
@@ -91,7 +94,7 @@ public class StreamInfoItemCollector extends InfoItemCollector {
try {
addItem(extract(extractor));
} catch(FoundAdException ae) {
- System.out.println("AD_WARNING: " + ae.getMessage());
+ //System.out.println("AD_WARNING: " + ae.getMessage());
} catch (Exception e) {
addError(e);
}
diff --git a/app/src/main/java/org/schabi/newpipe/extractor/stream_info/StreamInfoItemExtractor.java b/app/src/main/java/org/schabi/newpipe/extractor/stream_info/StreamInfoItemExtractor.java
index 4a4080a88..b5432b42d 100644
--- a/app/src/main/java/org/schabi/newpipe/extractor/stream_info/StreamInfoItemExtractor.java
+++ b/app/src/main/java/org/schabi/newpipe/extractor/stream_info/StreamInfoItemExtractor.java
@@ -32,4 +32,5 @@ public interface StreamInfoItemExtractor {
String getUploadDate() throws ParsingException;
long getViewCount() throws ParsingException;
String getThumbnailUrl() throws ParsingException;
+ boolean isAd() throws ParsingException;
}
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..d6f173350 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,27 @@ 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 boolean showFooter = false;
+ private View header = null;
+ private View footer = null;
+
+ public class HFHolder extends RecyclerView.ViewHolder {
+ public HFHolder(View v) {
+ super(v);
+ view = v;
+ }
+ public View view;
+ }
+
+ public void showFooter(boolean show) {
+ showFooter = show;
+ notifyDataSetChanged();
+ }
public InfoListAdapter(Activity a, View rootView) {
infoItemBuilder = new InfoItemBuilder(a, rootView);
@@ -54,9 +70,9 @@ public class InfoListAdapter extends RecyclerView.Adapter {
infoItemBuilder.setOnChannelInfoItemSelectedListener(listener);
}
- public void addInfoItemList(List videos) {
- if(videos!= null) {
- infoItemList.addAll(videos);
+ public void addInfoItemList(List data) {
+ if(data != null) {
+ infoItemList.addAll(data);
notifyDataSetChanged();
}
}
@@ -66,21 +82,42 @@ public class InfoListAdapter extends RecyclerView.Adapter {
notifyDataSetChanged();
}
+ public void setHeader(View header) {
+ this.header = header;
+ notifyDataSetChanged();
+ }
+
+ public void setFooter(View view) {
+ this.footer = view;
+ notifyDataSetChanged();
+ }
+
@Override
public int getItemCount() {
- return infoItemList.size();
+ int cound = infoItemList.size();
+ if(header != null) cound++;
+ if(footer != null && showFooter) cound++;
+ return cound;
}
// 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--;
+ }
+ if(footer != null && position == infoItemList.size() && showFooter) {
+ return 1;
+ }
switch(infoItemList.get(position).infoType()) {
case STREAM:
- return 0;
- case CHANNEL:
- return 1;
- case PLAYLIST:
return 2;
+ case CHANNEL:
+ return 3;
+ case PLAYLIST:
+ return 4;
default:
Log.e(TAG, "Trollolo");
return -1;
@@ -88,15 +125,19 @@ 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 HFHolder(header);
+ case 1:
+ return new HFHolder(footer);
+ case 2:
return new StreamInfoItemHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.stream_item, parent, false));
- case 1:
+ case 3:
return new ChannelInfoItemHolder(LayoutInflater.from(parent.getContext())
.inflate(R.layout.channel_item, parent, false));
- case 2:
+ case 4:
Log.e(TAG, "Playlist is not yet implemented");
return null;
default:
@@ -106,7 +147,17 @@ 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 HFHolder && i == 0 && header != null) {
+ ((HFHolder) holder).view = header;
+ } else if(holder instanceof HFHolder && i == infoItemList.size() && footer != null && showFooter) {
+ ((HFHolder) holder).view = footer;
+ }
}
}
diff --git a/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java
index e95a5e710..c15042de8 100644
--- a/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/report/ErrorActivity.java
@@ -1,5 +1,3 @@
-
-
package org.schabi.newpipe.report;
import android.app.Activity;
@@ -8,14 +6,14 @@ import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
import android.os.Parcel;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.support.design.widget.Snackbar;
import android.support.v4.app.NavUtils;
import android.support.v7.app.ActionBar;
-import android.os.Bundle;
-import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.Menu;
@@ -35,8 +33,8 @@ import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.Downloader;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
-import org.schabi.newpipe.ThemableActivity;
import org.schabi.newpipe.extractor.Parser;
+import org.schabi.newpipe.util.ThemeHelper;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -66,65 +64,12 @@ import java.util.Vector;
* along with NewPipe. If not, see .
*/
-public class ErrorActivity extends ThemableActivity {
- public static class ErrorInfo implements Parcelable {
- public int userAction;
- public String request;
- public String serviceName;
- public int message;
-
- public static ErrorInfo make(int userAction, String serviceName, String request, int message) {
- ErrorInfo info = new ErrorInfo();
- info.userAction = userAction;
- info.serviceName = serviceName;
- info.request = request;
- info.message = message;
- return info;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(this.userAction);
- dest.writeString(this.request);
- dest.writeString(this.serviceName);
- dest.writeInt(this.message);
- }
-
- public ErrorInfo() {
- }
-
- protected ErrorInfo(Parcel in) {
- this.userAction = in.readInt();
- this.request = in.readString();
- this.serviceName = in.readString();
- this.message = in.readInt();
- }
-
- public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
- @Override
- public ErrorInfo createFromParcel(Parcel source) {
- return new ErrorInfo(source);
- }
-
- @Override
- public ErrorInfo[] newArray(int size) {
- return new ErrorInfo[size];
- }
- };
- }
-
+public class ErrorActivity extends AppCompatActivity {
// LOG TAGS
public static final String TAG = ErrorActivity.class.toString();
-
// BUNDLE TAGS
public static final String ERROR_INFO = "error_info";
public static final String ERROR_LIST = "error_list";
-
// MESSAGE ID
public static final int SEARCHED = 0;
public static final int REQUESTED_STREAM = 1;
@@ -134,7 +79,6 @@ public class ErrorActivity extends ThemableActivity {
public static final int LOAD_IMAGE = 5;
public static final int UI_ERROR = 6;
public static final int REQUESTED_CHANNEL = 7;
-
// MESSAGE STRING
public static final String SEARCHED_STRING = "searched";
public static final String REQUESTED_STREAM_STRING = "requested stream";
@@ -144,17 +88,14 @@ public class ErrorActivity extends ThemableActivity {
public static final String LOAD_IMAGE_STRING = "load image";
public static final String UI_ERROR_STRING = "ui error";
public static final String REQUESTED_CHANNEL_STRING = "requested channel";
-
public static final String ERROR_EMAIL_ADDRESS = "crashreport@newpipe.schabi.org";
public static final String ERROR_EMAIL_SUBJECT = "Exception in NewPipe " + BuildConfig.VERSION_NAME;
-
+ Thread globIpRangeThread;
private String[] errorList;
private ErrorInfo errorInfo;
private Class returnActivity;
private String currentTimeStamp;
private String globIpRange;
- Thread globIpRangeThread;
-
// views
private TextView errorView;
private EditText userCommentBox;
@@ -243,9 +184,26 @@ public class ErrorActivity extends ThemableActivity {
context.startActivity(intent);
}
+ private static String getStackTrace(final Throwable throwable) {
+ final StringWriter sw = new StringWriter();
+ final PrintWriter pw = new PrintWriter(sw, true);
+ throwable.printStackTrace(pw);
+ return sw.getBuffer().toString();
+ }
+
+ // errorList to StringList
+ private static String[] elToSl(List stackTraces) {
+ String[] out = new String[stackTraces.size()];
+ for (int i = 0; i < stackTraces.size(); i++) {
+ out[i] = getStackTrace(stackTraces.get(i));
+ }
+ return out;
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ ThemeHelper.setTheme(this, true);
setContentView(R.layout.activity_error);
Intent intent = getIntent();
@@ -335,13 +293,6 @@ public class ErrorActivity extends ThemableActivity {
return false;
}
- private static String getStackTrace(final Throwable throwable) {
- final StringWriter sw = new StringWriter();
- final PrintWriter pw = new PrintWriter(sw, true);
- throwable.printStackTrace(pw);
- return sw.getBuffer().toString();
- }
-
private String formErrorText(String[] el) {
String text = "";
if(el != null) {
@@ -478,6 +429,56 @@ public class ErrorActivity extends ThemableActivity {
return df.format(new Date());
}
+ public static class ErrorInfo implements Parcelable {
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ @Override
+ public ErrorInfo createFromParcel(Parcel source) {
+ return new ErrorInfo(source);
+ }
+
+ @Override
+ public ErrorInfo[] newArray(int size) {
+ return new ErrorInfo[size];
+ }
+ };
+ public int userAction;
+ public String request;
+ public String serviceName;
+ public int message;
+
+ public ErrorInfo() {
+ }
+
+ protected ErrorInfo(Parcel in) {
+ this.userAction = in.readInt();
+ this.request = in.readString();
+ this.serviceName = in.readString();
+ this.message = in.readInt();
+ }
+
+ public static ErrorInfo make(int userAction, String serviceName, String request, int message) {
+ ErrorInfo info = new ErrorInfo();
+ info.userAction = userAction;
+ info.serviceName = serviceName;
+ info.request = request;
+ info.message = message;
+ return info;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(this.userAction);
+ dest.writeString(this.request);
+ dest.writeString(this.serviceName);
+ dest.writeInt(this.message);
+ }
+ }
+
private class IpRagneRequester implements Runnable {
Handler h = new Handler();
public void run() {
@@ -497,8 +498,6 @@ public class ErrorActivity extends ThemableActivity {
}
}
-
-
private class IpRageReturnRunnable implements Runnable {
String ipRange;
public IpRageReturnRunnable(String ipRange) {
@@ -514,13 +513,4 @@ public class ErrorActivity extends ThemableActivity {
}
}
}
-
- // errorList to StringList
- private static String[] elToSl(List stackTraces) {
- String[] out = new String[stackTraces.size()];
- for(int i = 0; i < stackTraces.size(); i++) {
- out[i] = getStackTrace(stackTraces.get(i));
- }
- return out;
- }
}
diff --git a/app/src/main/java/org/schabi/newpipe/search_fragment/SearchInfoItemFragment.java b/app/src/main/java/org/schabi/newpipe/search_fragment/SearchInfoItemFragment.java
index b710a7977..6bf261e14 100644
--- a/app/src/main/java/org/schabi/newpipe/search_fragment/SearchInfoItemFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/search_fragment/SearchInfoItemFragment.java
@@ -205,7 +205,6 @@ public class SearchInfoItemFragment extends Fragment {
RECAPTCHA_REQUEST);
}
});
-
}
@Override
@@ -221,6 +220,8 @@ public class SearchInfoItemFragment extends Fragment {
infoListAdapter = new InfoListAdapter(getActivity(),
getActivity().findViewById(android.R.id.content));
+ infoListAdapter.setFooter(inflater.inflate(R.layout.pignate_footer, recyclerView, false));
+ infoListAdapter.showFooter(false);
infoListAdapter.setOnStreamInfoItemSelectedListener(
new InfoItemBuilder.OnInfoItemSelectedListener() {
@Override
@@ -324,6 +325,7 @@ public class SearchInfoItemFragment extends Fragment {
private void search(String query) {
infoListAdapter.clearSteamItemList();
+ infoListAdapter.showFooter(false);
pageNumber = 0;
searchQuery = query;
search(query, pageNumber);
@@ -344,6 +346,7 @@ public class SearchInfoItemFragment extends Fragment {
private void setDoneLoading() {
this.isLoading = false;
loadingIndicator.setVisibility(View.GONE);
+ infoListAdapter.showFooter(true);
}
/**
diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java
index 7765f9653..1ad2747a7 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/SettingsActivity.java
@@ -5,7 +5,6 @@ import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceActivity;
-import android.preference.PreferenceManager;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.v7.app.ActionBar;
@@ -16,8 +15,7 @@ import android.view.View;
import android.view.ViewGroup;
import org.schabi.newpipe.R;
-
-import java.util.Objects;
+import org.schabi.newpipe.util.ThemeHelper;
/**
@@ -41,16 +39,16 @@ import java.util.Objects;
*/
public class SettingsActivity extends PreferenceActivity {
- private AppCompatDelegate mDelegate = null;
SettingsFragment f = new SettingsFragment();
+ private AppCompatDelegate mDelegate = null;
+
+ public static void initSettings(Context context) {
+ NewPipeSettings.initSettings(context);
+ }
@Override
protected void onCreate(Bundle savedInstanceBundle) {
- 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);
- }
+ ThemeHelper.setTheme(this, true);
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceBundle);
super.onCreate(savedInstanceBundle);
@@ -156,8 +154,4 @@ public class SettingsActivity extends PreferenceActivity {
}
return true;
}
-
- public static void initSettings(Context context) {
- NewPipeSettings.initSettings(context);
- }
}
diff --git a/app/src/main/java/org/schabi/newpipe/settings/SettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/SettingsFragment.java
index a6466daf9..d6af888fb 100644
--- a/app/src/main/java/org/schabi/newpipe/settings/SettingsFragment.java
+++ b/app/src/main/java/org/schabi/newpipe/settings/SettingsFragment.java
@@ -1,27 +1,27 @@
package org.schabi.newpipe.settings;
import android.app.Activity;
-import android.app.ListActivity;
import android.content.ClipData;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
-import android.preference.CheckBoxPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
+import android.support.v7.app.AlertDialog;
import com.nononsenseapps.filepicker.FilePickerActivity;
import org.schabi.newpipe.App;
+import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import java.util.ArrayList;
-import java.util.Objects;
import info.guardianproject.netcipher.proxy.OrbotHelper;
@@ -48,8 +48,8 @@ import info.guardianproject.netcipher.proxy.OrbotHelper;
public class SettingsFragment extends PreferenceFragment
implements SharedPreferences.OnSharedPreferenceChangeListener
{
+ public static final int REQUEST_INSTALL_ORBOT = 0x1234;
SharedPreferences.OnSharedPreferenceChangeListener prefListener;
-
// get keys
String DEFAULT_RESOLUTION_PREFERENCE;
String DEFAULT_AUDIO_FORMAT_PREFERENCE;
@@ -58,9 +58,6 @@ public class SettingsFragment extends PreferenceFragment
String DOWNLOAD_PATH_AUDIO_PREFERENCE;
String USE_TOR_KEY;
String THEME;
-
- public static final int REQUEST_INSTALL_ORBOT = 0x1234;
-
private ListPreference defaultResolutionPreference;
private ListPreference defaultAudioFormatPreference;
private ListPreference searchLanguagePreference;
@@ -98,6 +95,8 @@ public class SettingsFragment extends PreferenceFragment
downloadPathAudioPreference = findPreference(DOWNLOAD_PATH_AUDIO_PREFERENCE);
themePreference = findPreference(THEME);
+ final String currentTheme = defaultPreferences.getString(THEME, "Light");
+
prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
@@ -139,8 +138,27 @@ public class SettingsFragment extends PreferenceFragment
}
else if (key == THEME)
{
- String theme = sharedPreferences.getString(THEME, "Light");
- themePreference.setSummary(theme);
+ String selectedTheme = sharedPreferences.getString(THEME, "Light");
+ themePreference.setSummary(selectedTheme);
+
+ if(!selectedTheme.equals(currentTheme)) { // If it's not the current theme
+ new AlertDialog.Builder(activity)
+ .setTitle(R.string.restart_title)
+ .setMessage(R.string.msg_restart)
+ .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ Intent intentToMain = new Intent(activity, MainActivity.class);
+ intentToMain.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ activity.startActivity(intentToMain);
+
+ activity.finish();
+ Runtime.getRuntime().exit(0);
+ }
+ })
+ .setNegativeButton(R.string.later, null)
+ .create().show();
+ }
}
updateSummary();
}
diff --git a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java
new file mode 100644
index 000000000..a4fdb72f7
--- /dev/null
+++ b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java
@@ -0,0 +1,31 @@
+package org.schabi.newpipe.util;
+
+import android.content.Context;
+import android.preference.PreferenceManager;
+
+import org.schabi.newpipe.R;
+
+public class ThemeHelper {
+
+ public static void setTheme(Context context, boolean mode) {
+ // mode is true for normal theme, false for no action bar theme.
+
+ String themeKey = context.getString(R.string.theme_key);
+ //String lightTheme = context.getResources().getString(R.string.light_theme_title);
+ String darkTheme = context.getResources().getString(R.string.dark_theme_title);
+ String blackTheme = context.getResources().getString(R.string.black_theme_title);
+
+ String sp = PreferenceManager.getDefaultSharedPreferences(context)
+ .getString(themeKey, context.getResources().getString(R.string.light_theme_title));
+
+ if (mode) {
+ if (sp.equals(darkTheme)) context.setTheme(R.style.DarkTheme);
+ else if (sp.equals(blackTheme)) context.setTheme(R.style.BlackTheme);
+ else context.setTheme(R.style.AppTheme);
+ } else {
+ if (sp.equals(darkTheme)) context.setTheme(R.style.DarkTheme_NoActionBar);
+ else if (sp.equals(blackTheme)) context.setTheme(R.style.BlackTheme_NoActionBar);
+ else context.setTheme(R.style.AppTheme_NoActionBar);
+ }
+ }
+}
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/drawable-v21/splash_screen.xml b/app/src/main/res/drawable-v21/splash_screen.xml
new file mode 100644
index 000000000..34a890727
--- /dev/null
+++ b/app/src/main/res/drawable-v21/splash_screen.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+ -
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/splash_screen.xml b/app/src/main/res/drawable/splash_screen.xml
index e049c2941..af9458579 100644
--- a/app/src/main/res/drawable/splash_screen.xml
+++ b/app/src/main/res/drawable/splash_screen.xml
@@ -1,9 +1,6 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
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..87a05c13c
--- /dev/null
+++ b/app/src/main/res/layout/channel_header.xml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/pignate_footer.xml b/app/src/main/res/layout/pignate_footer.xml
new file mode 100644
index 000000000..ea4592179
--- /dev/null
+++ b/app/src/main/res/layout/pignate_footer.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_channel.xml b/app/src/main/res/menu/menu_channel.xml
index e296e17ad..58f0f7750 100644
--- a/app/src/main/res/menu/menu_channel.xml
+++ b/app/src/main/res/menu/menu_channel.xml
@@ -2,6 +2,16 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="org.schabi.newpipe.ChannelActivity">
+
+
+
+
+
-
- @string/light_theme_title
- @string/dark_theme_title
+ - @string/black_theme_title
- @string/light_theme_title
- @string/dark_theme_title
+ - @string/black_theme_title
default_audio_format
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 11e9e97b2..71c11fd50 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -86,6 +86,8 @@
Error report
All
Channel
+ Yes
+ Later
Error
@@ -151,10 +153,12 @@
Experimental
videos
subscriber
+ Subscribe
views
- T
+ K
M
B
+ Restart
Start
@@ -183,6 +187,7 @@
Please wait…
Copied to clipboard.
Please select an available download directory.
+ You have to restart the application to apply the theme.\n\nDo you want to restart now?
MD5
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index a6a25f2d3..606da4eb0 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -49,6 +49,10 @@
- @drawable/ic_rss_feed_black_24dp
+
+
+
+
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/app/src/test/java/org/schabi/newpipe/extractor/services/youtube/youtube/YoutubeStreamUrlIdHandlerTest.java b/app/src/test/java/org/schabi/newpipe/extractor/services/youtube/youtube/YoutubeStreamUrlIdHandlerTest.java
index 79bb5d88e..67746ade3 100644
--- a/app/src/test/java/org/schabi/newpipe/extractor/services/youtube/youtube/YoutubeStreamUrlIdHandlerTest.java
+++ b/app/src/test/java/org/schabi/newpipe/extractor/services/youtube/youtube/YoutubeStreamUrlIdHandlerTest.java
@@ -111,9 +111,9 @@ public class YoutubeStreamUrlIdHandlerTest {
assertTrue(urlIdHandler.acceptUrl("vnd.youtube:jZViOEv90dI"));
- String sharedId = "7JIArTByb3E";
+ String sharedId = "8A940MXKFmQ";
assertTrue(urlIdHandler.acceptUrl("vnd.youtube://www.youtube.com/shared?ci=" + sharedId + "&feature=twitter-deep-link"));
assertTrue(urlIdHandler.acceptUrl("vnd.youtube://www.youtube.com/shared?ci=" + sharedId ));
- assertTrue(urlIdHandler.acceptUrl("https://www.youtube.com/shared?ci=7JIArTByb3E"));
+ assertTrue(urlIdHandler.acceptUrl("https://www.youtube.com/shared?ci=" + sharedId));
}
}
\ No newline at end of file
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 @@
+
+
+
+