videoStreamsList = new ArrayList<>(ListHelper.getSortedStreamVideosList(context, info.getVideoStreams(), null, false));
+ int index = ListHelper.getDefaultResolutionIndex(context, videoStreamsList);
+
+ if (index == -1) {
+ Toast.makeText(context, R.string.video_streams_empty, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ VideoStream videoStream = videoStreamsList.get(index);
+ playOnExternalPlayer(context, info.getName(), info.getUploaderName(), videoStream);
+ }
+
+ public static void playOnExternalPlayer(Context context, String name, String artist, Stream stream) {
+ Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_VIEW);
+ intent.setDataAndType(Uri.parse(stream.getUrl()), stream.getFormat().getMimeType());
+ intent.putExtra(Intent.EXTRA_TITLE, name);
+ intent.putExtra("title", name);
+ intent.putExtra("artist", artist);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ resolveActivityOrAskToInstall(context, intent);
+ }
+
+ public static void resolveActivityOrAskToInstall(Context context, Intent intent) {
+ if (intent.resolveActivity(context.getPackageManager()) != null) {
+ context.startActivity(intent);
+ } else {
+ if (context instanceof Activity) {
+ new AlertDialog.Builder(context)
+ .setMessage(R.string.no_player_found)
+ .setPositiveButton(R.string.install, (dialog, which) -> {
+ Intent i = new Intent();
+ i.setAction(Intent.ACTION_VIEW);
+ i.setData(Uri.parse(context.getString(R.string.fdroid_vlc_url)));
+ context.startActivity(i);
+ })
+ .setNegativeButton(R.string.cancel, (dialog, which) -> Log.i("NavigationHelper", "You unlocked a secret unicorn."))
+ .show();
+ //Log.e("NavigationHelper", "Either no Streaming player for audio was installed, or something important crashed:");
+ } else {
+ Toast.makeText(context, R.string.no_player_found_toast, Toast.LENGTH_LONG).show();
+ }
+ }
+ }
+
/*//////////////////////////////////////////////////////////////////////////
// Through FragmentManager
//////////////////////////////////////////////////////////////////////////*/
@@ -287,19 +395,6 @@ public class NavigationHelper {
// Link handling
//////////////////////////////////////////////////////////////////////////*/
- public static boolean openByLink(Context context, String url) {
- Intent intentByLink;
- try {
- intentByLink = getIntentByLink(context, url);
- } catch (ExtractionException e) {
- return false;
- }
- intentByLink.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intentByLink.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- context.startActivity(intentByLink);
- return true;
- }
-
private static Intent getOpenIntent(Context context, String url, int serviceId, StreamingService.LinkType type) {
Intent mIntent = new Intent(context, MainActivity.class);
mIntent.putExtra(Constants.KEY_SERVICE_ID, serviceId);
@@ -317,15 +412,14 @@ public class NavigationHelper {
throw new ExtractionException("Service not supported at the moment");
}
- int serviceId = service.getServiceId();
StreamingService.LinkType linkType = service.getLinkTypeByUrl(url);
if (linkType == StreamingService.LinkType.NONE) {
- throw new ExtractionException("Url not known to service. service=" + serviceId + " url=" + url);
+ throw new ExtractionException("Url not known to service. service=" + service + " url=" + url);
}
url = getCleanUrl(service, url, linkType);
- Intent rIntent = getOpenIntent(context, url, serviceId, linkType);
+ Intent rIntent = getOpenIntent(context, url, service.getServiceId(), linkType);
switch (linkType) {
case STREAM:
@@ -337,7 +431,7 @@ public class NavigationHelper {
return rIntent;
}
- private static String getCleanUrl(StreamingService service, String dirtyUrl, StreamingService.LinkType linkType) throws ExtractionException {
+ public static String getCleanUrl(StreamingService service, String dirtyUrl, StreamingService.LinkType linkType) throws ExtractionException {
switch (linkType) {
case STREAM:
return service.getStreamUrlIdHandler().cleanUrl(dirtyUrl);
@@ -351,7 +445,6 @@ public class NavigationHelper {
return null;
}
-
private static Uri openMarketUrl(String packageName) {
return Uri.parse("market://details")
.buildUpon()
diff --git a/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java b/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java
index 7cf804401..a33348934 100644
--- a/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/PermissionHelper.java
@@ -20,7 +20,6 @@ import org.schabi.newpipe.R;
public class PermissionHelper {
public static final int PERMISSION_WRITE_STORAGE = 778;
public static final int PERMISSION_READ_STORAGE = 777;
- public static final int PERMISSION_SYSTEM_ALERT_WINDOW = 779;
public static boolean checkStoragePermissions(Activity activity) {
@@ -80,27 +79,25 @@ public class PermissionHelper {
* In order to be able to draw over other apps, the permission android.permission.SYSTEM_ALERT_WINDOW have to be granted.
*
* On < API 23 (MarshMallow) the permission was granted when the user installed the application (via AndroidManifest),
- * on > 23, however, it have to start a activity asking the user if he agree.
+ * on > 23, however, it have to start a activity asking the user if he agrees.
*
- * This method just return if canDraw over other apps, if it doesn't, try to get the permission,
- * it does not get the result of the startActivityForResult, if the user accept, the next time that he tries to open
- * it will return true.
+ * This method just return if the app has permission to draw over other apps, and if it doesn't, it will try to get the permission.
*
- * @param activity context to startActivityForResult
* @return returns {@link Settings#canDrawOverlays(Context)}
**/
@RequiresApi(api = Build.VERSION_CODES.M)
- public static boolean checkSystemAlertWindowPermission(Activity activity) {
- if (!Settings.canDrawOverlays(activity)) {
- Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + activity.getPackageName()));
- activity.startActivityForResult(i, PERMISSION_SYSTEM_ALERT_WINDOW);
+ public static boolean checkSystemAlertWindowPermission(Context context) {
+ if (!Settings.canDrawOverlays(context)) {
+ Intent i = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context.getPackageName()));
+ i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ context.startActivity(i);
return false;
}else return true;
}
- public static boolean isPopupEnabled(Activity activity) {
+ public static boolean isPopupEnabled(Context context) {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
- PermissionHelper.checkSystemAlertWindowPermission(activity);
+ PermissionHelper.checkSystemAlertWindowPermission(context);
}
public static void showPopupEnablementToast(Context context) {
diff --git a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java
index 6fdf035f4..b078ac0c8 100644
--- a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java
+++ b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java
@@ -1,7 +1,10 @@
package org.schabi.newpipe.util;
import android.content.Context;
+import android.content.res.TypedArray;
import android.preference.PreferenceManager;
+import android.support.annotation.AttrRes;
+import android.support.annotation.StyleRes;
import org.schabi.newpipe.R;
@@ -13,17 +16,7 @@ public class ThemeHelper {
* @param context context that the theme will be applied
*/
public static void setTheme(Context context) {
- String lightTheme = context.getResources().getString(R.string.light_theme_key);
- String darkTheme = context.getResources().getString(R.string.dark_theme_key);
- String blackTheme = context.getResources().getString(R.string.black_theme_key);
-
- String selectedTheme = getSelectedTheme(context);
-
- if (selectedTheme.equals(lightTheme)) context.setTheme(R.style.LightTheme);
- else if (selectedTheme.equals(blackTheme)) context.setTheme(R.style.BlackTheme);
- else if (selectedTheme.equals(darkTheme)) context.setTheme(R.style.DarkTheme);
- // Fallback
- else context.setTheme(R.style.DarkTheme);
+ context.setTheme(getSelectedThemeStyle(context));
}
/**
@@ -35,9 +28,34 @@ public class ThemeHelper {
return getSelectedTheme(context).equals(context.getResources().getString(R.string.light_theme_key));
}
+ @StyleRes
+ public static int getSelectedThemeStyle(Context context) {
+ String lightTheme = context.getResources().getString(R.string.light_theme_key);
+ String darkTheme = context.getResources().getString(R.string.dark_theme_key);
+ String blackTheme = context.getResources().getString(R.string.black_theme_key);
+
+ String selectedTheme = getSelectedTheme(context);
+
+ if (selectedTheme.equals(lightTheme)) return R.style.LightTheme;
+ else if (selectedTheme.equals(blackTheme)) return R.style.BlackTheme;
+ else if (selectedTheme.equals(darkTheme)) return R.style.DarkTheme;
+ // Fallback
+ else return R.style.DarkTheme;
+ }
+
public static String getSelectedTheme(Context context) {
String themeKey = context.getString(R.string.theme_key);
String defaultTheme = context.getResources().getString(R.string.default_theme_value);
return PreferenceManager.getDefaultSharedPreferences(context).getString(themeKey, defaultTheme);
}
+
+ /**
+ * Get a resource id from a resource styled according to the the context's theme.
+ */
+ public static int resolveResourceIdFromAttr(Context context, @AttrRes int attr) {
+ TypedArray a = context.getTheme().obtainStyledAttributes(new int[]{attr});
+ int attributeResourceId = a.getResourceId(0, 0);
+ a.recycle();
+ return attributeResourceId;
+ }
}
diff --git a/app/src/main/res/drawable-hdpi/ic_play_arrow_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_play_arrow_black_24dp.png
new file mode 100644
index 000000000..e9c288c99
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_play_arrow_black_24dp.png differ
diff --git a/app/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png
new file mode 100644
index 000000000..57c9fa546
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_play_arrow_white_24dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_play_arrow_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_play_arrow_black_24dp.png
new file mode 100644
index 000000000..d78c57bad
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_play_arrow_black_24dp.png differ
diff --git a/app/src/main/res/drawable-mdpi/ic_play_arrow_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_play_arrow_white_24dp.png
new file mode 100644
index 000000000..c61e948bb
Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_play_arrow_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_play_arrow_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_play_arrow_black_24dp.png
new file mode 100644
index 000000000..f208795fc
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_play_arrow_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png
new file mode 100644
index 000000000..a3c80e73d
Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_play_arrow_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_play_arrow_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_play_arrow_black_24dp.png
new file mode 100644
index 000000000..5345ee3c4
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_play_arrow_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png
new file mode 100644
index 000000000..547ef30aa
Binary files /dev/null and b/app/src/main/res/drawable-xxhdpi/ic_play_arrow_white_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_play_arrow_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_play_arrow_black_24dp.png
new file mode 100644
index 000000000..d12d49562
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_play_arrow_black_24dp.png differ
diff --git a/app/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_24dp.png
new file mode 100644
index 000000000..be5c062b5
Binary files /dev/null and b/app/src/main/res/drawable-xxxhdpi/ic_play_arrow_white_24dp.png differ
diff --git a/app/src/main/res/drawable/dark_checked_selector.xml b/app/src/main/res/drawable/dark_checked_selector.xml
new file mode 100644
index 000000000..59019470f
--- /dev/null
+++ b/app/src/main/res/drawable/dark_checked_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/light_checked_selector.xml b/app/src/main/res/drawable/light_checked_selector.xml
new file mode 100644
index 000000000..b782a3688
--- /dev/null
+++ b/app/src/main/res/drawable/light_checked_selector.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/list_radio_icon_item.xml b/app/src/main/res/layout/list_radio_icon_item.xml
new file mode 100644
index 000000000..20b966995
--- /dev/null
+++ b/app/src/main/res/layout/list_radio_icon_item.xml
@@ -0,0 +1,19 @@
+
+
diff --git a/app/src/main/res/layout/preferred_player_dialog_view.xml b/app/src/main/res/layout/preferred_player_dialog_view.xml
new file mode 100644
index 000000000..83e1031a5
--- /dev/null
+++ b/app/src/main/res/layout/preferred_player_dialog_view.xml
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
index 86b9644ae..e14d9cb80 100644
--- a/app/src/main/res/values/attrs.xml
+++ b/app/src/main/res/values/attrs.xml
@@ -22,10 +22,12 @@
+
+
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index b77a2d229..694e4900f 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -8,6 +8,7 @@
#000000
#32000000
#48868686
+ #2a868686
#1fa6a6a6
#5a000000
#ffffff
@@ -21,6 +22,7 @@
#FFFFFF
#0affffff
#48ffffff
+ #2affffff
#1f717171
#82000000
#424242
diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml
index f0c496aa2..7a34d296b 100644
--- a/app/src/main/res/values/settings_keys.xml
+++ b/app/src/main/res/values/settings_keys.xml
@@ -149,6 +149,29 @@
@string/charset_most_special_characters_value
+
+ preferred_player_key
+ @string/always_ask_player_key
+ preferred_player_last_selected
+
+ video_player
+ background_player
+ popup_player
+ always_ask_player
+
+
+ - @string/video_player
+ - @string/background_player
+ - @string/popup_player
+ - @string/always_ask_player
+
+
+ - @string/video_player_key
+ - @string/background_player_key
+ - @string/popup_player_key
+ - @string/always_ask_player_key
+
+
- af
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 6a6014a29..6d5e48d2d 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -5,6 +5,7 @@
%1$s views
Published on %1$s
No stream player found. Do you want to install VLC?
+ No stream player found (you can install VLC to play it)
Install
Cancel
https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc
@@ -119,6 +120,8 @@
Best resolution
Undo
Play All
+ Always
+ Just Once
newpipe
NewPipe Notification
@@ -148,6 +151,10 @@
Failed to play this stream
Unrecoverable player error occurred
Recovering from player error
+ External players don\'t support these types of links
+ Invalid URL
+ No video streams found
+ No audio streams found
Sorry, that should not have happened.
@@ -336,4 +343,17 @@
Close Drawer
YouTube
SoundCloud
+
+
+ @string/preferred_player_settings_title
+ Open with preferred player
+ Preferred player
+
+ Video player
+ Background player
+ Popup player
+ Always ask
+
+ Getting info…
+ "The requested content is loading"
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index c0c16e30f..b9c1d9f9c 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -29,9 +29,11 @@
- @drawable/ic_fiber_manual_record_black_24dp
- @drawable/ic_arrow_top_left_black_24dp
- @drawable/ic_more_vert_black_24dp
+ - @drawable/ic_play_arrow_black_24dp
- @color/light_separator_color
- @color/light_contrast_background_color
+ - @drawable/light_checked_selector
- @color/light_queue_background_color
- @drawable/toolbar_shadow_light
- @drawable/light_selector
@@ -69,9 +71,11 @@
- @drawable/ic_fiber_manual_record_white_24dp
- @drawable/ic_arrow_top_left_white_24dp
- @drawable/ic_more_vert_white_24dp
+ - @drawable/ic_play_arrow_white_24dp
- @color/dark_separator_color
- @color/dark_contrast_background_color
+ - @drawable/dark_checked_selector
- @color/dark_queue_background_color
- @drawable/toolbar_shadow_dark
- @drawable/dark_selector
@@ -164,12 +168,27 @@
- @color/dark_youtube_primary_color
-
+
+
diff --git a/app/src/main/res/xml/video_audio_settings.xml b/app/src/main/res/xml/video_audio_settings.xml
index 6685f1a25..ceacfb142 100644
--- a/app/src/main/res/xml/video_audio_settings.xml
+++ b/app/src/main/res/xml/video_audio_settings.xml
@@ -1,7 +1,6 @@
+
+