From 40f00af1964b60ffa72e680078e84524a35c014c Mon Sep 17 00:00:00 2001 From: chschtsch Date: Tue, 29 Dec 2015 17:35:51 +0300 Subject: [PATCH 01/57] refactor localization --- .../java/org/schabi/newpipe/Localization.java | 79 +++++++++++++++++++ .../newpipe/VideoInfoItemViewCreator.java | 6 +- .../newpipe/VideoItemDetailFragment.java | 63 +++------------ .../org/schabi/newpipe/VideoListAdapter.java | 2 +- 4 files changed, 93 insertions(+), 57 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/Localization.java diff --git a/app/src/main/java/org/schabi/newpipe/Localization.java b/app/src/main/java/org/schabi/newpipe/Localization.java new file mode 100644 index 000000000..8b9689585 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/Localization.java @@ -0,0 +1,79 @@ +package org.schabi.newpipe; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.SharedPreferences; +import android.content.res.Resources; +import android.preference.PreferenceManager; + +import java.text.DateFormat; +import java.text.NumberFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; + +/** + * Created by chschtsch on 12/29/15. + */ + +public class Localization { + + public static Context contextOfApplication = null; + + public static Locale getPreferredLocale(Context context) { + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + + String languageCode = sp.getString(String.valueOf(R.string.searchLanguage), "en"); + + if(languageCode.length() == 2) { + return new Locale(languageCode); + } + else if(languageCode.contains("_")) { + String country = languageCode + .substring(languageCode.indexOf("_"), languageCode.length()); + return new Locale(languageCode.substring(0, 2), country); + } + return Locale.getDefault(); + } + + public static String localizeViewCount(long viewCount, Context context) { + Locale locale = getPreferredLocale(context); + + Resources res = context.getResources(); + String viewsString = res.getString(R.string.viewCountText); + + NumberFormat nf = NumberFormat.getInstance(locale); + String formattedViewCount = nf.format(viewCount); + return String.format(viewsString, formattedViewCount); + } + + public static String localizeNumber(long number, Context context) { + Locale locale = getPreferredLocale(context); + NumberFormat nf = NumberFormat.getInstance(locale); + return nf.format(number); + } + + private static String formatDate(String date, Context context) { + Locale locale = getPreferredLocale(context); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + Date datum = null; + try { + datum = formatter.parse(date); + } catch (ParseException e) { + e.printStackTrace(); + } + + DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); + + return df.format(datum); + } + + public static String localizeDate(String date, Context context) { + Resources res = context.getResources(); + String dateString = res.getString(R.string.uploadDateText); + + String formattedDate = formatDate(date, context); + return String.format(dateString, formattedDate); + } +} diff --git a/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java b/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java index b7eaa4285..c2bbb069e 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java +++ b/app/src/main/java/org/schabi/newpipe/VideoInfoItemViewCreator.java @@ -1,5 +1,6 @@ package org.schabi.newpipe; +import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -33,7 +34,7 @@ class VideoInfoItemViewCreator { this.inflater = inflater; } - public View getViewFromVideoInfoItem(View convertView, ViewGroup parent, VideoPreviewInfo info) { + public View getViewFromVideoInfoItem(View convertView, ViewGroup parent, VideoPreviewInfo info, Context context) { ViewHolder holder; if(convertView == null) { convertView = inflater.inflate(R.layout.video_item, parent, false); @@ -59,8 +60,7 @@ class VideoInfoItemViewCreator { if(!info.upload_date.isEmpty()) { holder.itemUploadDateView.setText(info.upload_date); } else { - //tweak if necessary: This is a hack to prevent having white space in the layout :P - holder.itemUploadDateView.setText(String.format("%d", info.view_count)); + holder.itemUploadDateView.setText(Localization.localizeViewCount(info.view_count, context)); } return convertView; diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java index 0173c07de..92c25e2aa 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java @@ -1,9 +1,7 @@ package org.schabi.newpipe; -import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; -import android.content.SharedPreferences; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -35,13 +33,7 @@ import android.view.MenuItem; import android.widget.Toast; import java.net.URL; -import java.text.DateFormat; -import java.text.NumberFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Date; -import java.util.Locale; import java.util.Vector; import org.schabi.newpipe.services.VideoExtractor; @@ -235,7 +227,7 @@ public class VideoItemDetailFragment extends Fragment { switch (info.errorCode) { case VideoInfo.NO_ERROR: { View nextVideoView = videoItemViewCreator - .getViewFromVideoInfoItem(null, nextVideoFrame, info.nextVideo); + .getViewFromVideoInfoItem(null, nextVideoFrame, info.nextVideo, getContext()); nextVideoFrame.addView(nextVideoView); @@ -253,31 +245,20 @@ public class VideoItemDetailFragment extends Fragment { uploaderView.setText(info.uploader); actionBarHandler.setChannelName(info.uploader); - Locale locale = getPreferredLocale(); - NumberFormat nf = NumberFormat.getInstance(locale); - String localisedViewCount = nf.format(info.view_count); - viewCountView.setText( - String.format( - res.getString(R.string.viewCountText), localisedViewCount)); + String localizedViewCount = Localization.localizeViewCount(info.view_count, getContext()); + viewCountView.setText(localizedViewCount); - thumbsUpView.setText(nf.format(info.like_count)); - thumbsDownView.setText(nf.format(info.dislike_count)); + String localizedLikeCount = Localization.localizeNumber(info.like_count, getContext()); + thumbsUpView.setText(localizedLikeCount); - @SuppressLint("SimpleDateFormat") - SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); - Date datum = null; - try { - datum = formatter.parse(info.upload_date); - } catch (ParseException e) { - e.printStackTrace(); - } + String localizedDislikeCount = Localization.localizeNumber(info.dislike_count, getContext()); + thumbsDownView.setText(localizedDislikeCount); - DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); + String localizedDate = Localization.localizeDate(info.upload_date, getContext()); + uploadDateView.setText(localizedDate); - String localisedDate = df.format(datum); - uploadDateView.setText( - String.format(res.getString(R.string.uploadDateText), localisedDate)); descriptionView.setText(Html.fromHtml(info.description)); + descriptionView.setMovementMethod(LinkMovementMethod.getInstance()); actionBarHandler.setServiceId(streamingServiceId); @@ -458,30 +439,6 @@ public class VideoItemDetailFragment extends Fragment { } } - - - /**Returns the java.util.Locale object which corresponds to the locale set in NewPipe's preferences. - * Currently not affected by the device's locale.*/ - private Locale getPreferredLocale() { - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); - String languageKey = getContext().getString(R.string.searchLanguage); - //i know the following line defaults languageCode to "en", but java is picky about uninitialised values - // Schabi: well lint tels me the value is redundant. I'll suppress it for now. - @SuppressWarnings("UnusedAssignment") - String languageCode = "en"; - languageCode = sp.getString(languageKey, "en"); - - if(languageCode.length() == 2) { - return new Locale(languageCode); - } - else if(languageCode.contains("_")) { - String country = languageCode - .substring(languageCode.indexOf("_"), languageCode.length()); - return new Locale(languageCode.substring(0, 2), country); - } - return Locale.getDefault(); - } - private boolean checkIfLandscape() { DisplayMetrics displayMetrics = new DisplayMetrics(); getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); diff --git a/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java b/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java index e85e74e22..70672d040 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java @@ -96,7 +96,7 @@ class VideoListAdapter extends BaseAdapter { @Override public View getView(int position, View convertView, ViewGroup parent) { - convertView = viewCreator.getViewFromVideoInfoItem(convertView, parent, videoList.get(position)); + convertView = viewCreator.getViewFromVideoInfoItem(convertView, parent, videoList.get(position), context); if(listView.isItemChecked(position)) { convertView.setBackgroundColor(ContextCompat.getColor(context,R.color.primaryColorYoutube)); From 48e299b2ac2586a07808fff8f4b28f645f34fd0c Mon Sep 17 00:00:00 2001 From: chschtsch Date: Tue, 29 Dec 2015 17:53:24 +0300 Subject: [PATCH 02/57] code cleanup --- app/src/main/java/org/schabi/newpipe/Localization.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/Localization.java b/app/src/main/java/org/schabi/newpipe/Localization.java index 8b9689585..b38c52a90 100644 --- a/app/src/main/java/org/schabi/newpipe/Localization.java +++ b/app/src/main/java/org/schabi/newpipe/Localization.java @@ -19,8 +19,6 @@ import java.util.Locale; public class Localization { - public static Context contextOfApplication = null; - public static Locale getPreferredLocale(Context context) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); From f61b915894ee0c701a1407e27fe07e2c4a47d6e5 Mon Sep 17 00:00:00 2001 From: Greg Date: Tue, 29 Dec 2015 21:44:06 +0100 Subject: [PATCH 03/57] Translated using Weblate (Russian) Currently translated at 100.0% (48 of 48 strings) --- app/src/main/res/values-ru/strings.xml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index a2dbdd50f..36368fe09 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -51,4 +51,7 @@ Миниатюра аватара пользователся Дислайки Лайки - +Использовать внешний проигрыватель для видео + Использовать внешний проигрыватель для аудио + Проигрывание в фоновом режиме + From 78df57970330a2537faa77365ffc2685e47406cc Mon Sep 17 00:00:00 2001 From: Greg Date: Tue, 29 Dec 2015 21:45:44 +0100 Subject: [PATCH 04/57] Translated using Weblate (Hebrew) Currently translated at 100% (0 of 0 strings) Created new translation. --- app/src/main/res/values-he/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 app/src/main/res/values-he/strings.xml diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml new file mode 100644 index 000000000..a6b3daec9 --- /dev/null +++ b/app/src/main/res/values-he/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From 43149fd832093a215842a06386d9b89f8dce2386 Mon Sep 17 00:00:00 2001 From: M2ck Date: Mon, 21 Dec 2015 14:20:08 +0100 Subject: [PATCH 05/57] Translated using Weblate (French) Currently translated at 100.0% (48 of 48 strings) --- app/src/main/res/values-fr/strings.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 4800a7493..e1cfeeff0 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -49,4 +49,5 @@ Avatar de l\'utilisateur Utiliser un lecteur vidéo externe Utiliser un lecteur audio externe + Lecture en arrière-plan From e91fc225e1c9757aa4c78fd753ed6ae7c7df76ae Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 31 Dec 2015 21:53:14 +0100 Subject: [PATCH 06/57] after receiving panic trigger, quit remove from history This makes the app fully exit, and removes it from the Recent Apps listing with the goal of hiding whatever the user was currently watching, and/or searching for. PanicKit provides a common framework for creating "panic button" apps that can trigger actions in "panic responder" apps. In this case, the response is to lock the app, if it has been configured to do so https://dev.guardianproject.info/projects/panic/wiki --- app/src/main/AndroidManifest.xml | 13 +++++++ .../java/org/schabi/newpipe/ExitActivity.java | 36 +++++++++++++++++++ .../newpipe/PanicResponderActivity.java | 32 +++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 app/src/main/java/org/schabi/newpipe/ExitActivity.java create mode 100644 app/src/main/java/org/schabi/newpipe/PanicResponderActivity.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 05eda83c5..ae3f5f056 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -84,5 +84,18 @@ android:name=".SettingsActivity" android:label="@string/title_activity_settings" > + + + + + + + diff --git a/app/src/main/java/org/schabi/newpipe/ExitActivity.java b/app/src/main/java/org/schabi/newpipe/ExitActivity.java new file mode 100644 index 000000000..c193ffbde --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/ExitActivity.java @@ -0,0 +1,36 @@ + +package org.schabi.newpipe; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; + +public class ExitActivity extends Activity { + + @SuppressLint("NewApi") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (Build.VERSION.SDK_INT >= 21) { + finishAndRemoveTask(); + } else { + finish(); + } + + System.exit(0); + } + + public static void exitAndRemoveFromRecentApps(Activity activity) { + Intent intent = new Intent(activity, ExitActivity.class); + + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK + | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS + | Intent.FLAG_ACTIVITY_CLEAR_TASK + | Intent.FLAG_ACTIVITY_NO_ANIMATION); + + activity.startActivity(intent); + } +} diff --git a/app/src/main/java/org/schabi/newpipe/PanicResponderActivity.java b/app/src/main/java/org/schabi/newpipe/PanicResponderActivity.java new file mode 100644 index 000000000..e9bf0e985 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/PanicResponderActivity.java @@ -0,0 +1,32 @@ + +package org.schabi.newpipe; + +import android.annotation.SuppressLint; +import android.app.Activity; +import android.content.Intent; +import android.os.Build; +import android.os.Bundle; + +public class PanicResponderActivity extends Activity { + + public static final String PANIC_TRIGGER_ACTION = "info.guardianproject.panic.action.TRIGGER"; + + @SuppressLint("NewApi") + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + if (intent != null && PANIC_TRIGGER_ACTION.equals(intent.getAction())) { + // TODO explicitly clear the search results once they are restored when the app restarts + // or if the app reloads the current video after being killed, that should be cleared also + ExitActivity.exitAndRemoveFromRecentApps(this); + } + + if (Build.VERSION.SDK_INT >= 21) { + finishAndRemoveTask(); + } else { + finish(); + } + } +} From 6deb67437798738e0d27a8a353e027023b6c775f Mon Sep 17 00:00:00 2001 From: Greg Date: Tue, 29 Dec 2015 22:23:26 +0100 Subject: [PATCH 07/57] Translated using Weblate (Hebrew) Currently translated at 16.6% (8 of 48 strings) --- app/src/main/res/values-he/strings.xml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index a6b3daec9..a11e14119 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -1,2 +1,10 @@ - - \ No newline at end of file + +%1$s צפיות + הועלה בתאריך %1$s + שתף + חפש + הבא + הורדה + הגדרות + הגדרות + From 5533f6ba86a4c8b51b20469e03cece12aef48e63 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 22:09:36 +0100 Subject: [PATCH 08/57] use the standard "Movies" folder for downloads On all of the devices that I've checked, there is a folder called "Movies" on the SD Card by default. NewPipe should use that standard location since it is always downloading movies :). People can always change that via the preferences. Also, this makes the defaults the same when creating the dir and when setting the destination URL. --- .../java/org/schabi/newpipe/DownloadDialog.java | 14 ++++++-------- .../org/schabi/newpipe/SettingsActivity.java | 17 ----------------- .../schabi/newpipe/VideoItemListActivity.java | 3 ++- app/src/main/res/xml/settings_screen.xml | 5 ++--- 4 files changed, 10 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java index 903251e58..a943ad423 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java @@ -57,7 +57,7 @@ public class DownloadDialog extends DialogFragment { @Override public void onClick(DialogInterface dialog, int which) { Context context = getActivity(); - SharedPreferences defaultPreferences = PreferenceManager.getDefaultSharedPreferences(context); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); String suffix = ""; String title = arguments.getString(TITLE); String url = ""; @@ -73,10 +73,10 @@ public class DownloadDialog extends DialogFragment { default: Log.d(TAG, "lolz"); } - //to avoid hard-coded string like "/storage/emulated/0/NewPipe" - final File dir = new File(defaultPreferences.getString( - "download_path_preference", - Environment.getExternalStorageDirectory().getAbsolutePath() + "/NewPipe")); + //to avoid hard-coded string like "/storage/emulated/0/Movies" + String downloadPath = prefs.getString(getString(R.string.downloadPathPreference), + Environment.getExternalStorageDirectory().getAbsolutePath() + "/Movies"); + final File dir = new File(downloadPath); if(!dir.exists()) { boolean mkdir = dir.mkdir(); //attempt to create directory if(!mkdir && !dir.isDirectory()) { @@ -87,9 +87,7 @@ public class DownloadDialog extends DialogFragment { DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); DownloadManager.Request request = new DownloadManager.Request( Uri.parse(url)); - request.setDestinationUri(Uri.fromFile(new File( - defaultPreferences.getString("download_path_preference", "/storage/emulated/0/NewPipe") - + "/" + title + suffix))); + request.setDestinationUri(Uri.fromFile(new File(dir + "/" + title + suffix))); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); try { dm.enqueue(request); diff --git a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java index b434b53d8..c8a548ab6 100644 --- a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java @@ -1,13 +1,9 @@ package org.schabi.newpipe; -import android.content.Context; -import android.content.SharedPreferences; import android.content.res.Configuration; import android.os.Bundle; -import android.os.Environment; import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; -import android.preference.PreferenceManager; import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; @@ -148,17 +144,4 @@ public class SettingsActivity extends PreferenceActivity { } return true; } - - public static void initSettings(Context context) { - PreferenceManager.setDefaultValues(context, R.xml.settings_screen, false); - SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - if(sp.getString(context.getString(R.string.downloadPathPreference), "").isEmpty()){ - SharedPreferences.Editor spEditor = sp.edit(); - String newPipeDownloadStorage = - Environment.getExternalStorageDirectory().getAbsolutePath() + "/NewPipe"; - spEditor.putString(context.getString(R.string.downloadPathPreference) - , newPipeDownloadStorage); - spEditor.apply(); - } - } } diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java index 6aaf10d41..d15709b23 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java @@ -3,6 +3,7 @@ package org.schabi.newpipe; import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.preference.PreferenceManager; import android.support.v4.app.NavUtils; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SearchView; @@ -171,7 +172,7 @@ public class VideoItemListActivity extends AppCompatActivity } } - SettingsActivity.initSettings(this); + PreferenceManager.setDefaultValues(this, R.xml.settings_screen, false); } /** diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml index 98399f778..d4b21426f 100644 --- a/app/src/main/res/xml/settings_screen.xml +++ b/app/src/main/res/xml/settings_screen.xml @@ -64,8 +64,7 @@ android:key="@string/downloadPathPreference" android:title="@string/downloadLocation" android:summary="@string/downloadLocationSummary" - android:dialogTitle="@string/downloadLocationDialogTitle" - android:defaultValue=""/> + android:dialogTitle="@string/downloadLocationDialogTitle" /> - \ No newline at end of file + From b31490c4e34e7256bf270cb255ec2ffc51f5701a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 22:23:00 +0100 Subject: [PATCH 09/57] make all strings translatable --- app/src/main/AndroidManifest.xml | 6 ++---- app/src/main/res/layout/paginate_footer.xml | 2 +- app/src/main/res/values/strings.xml | 2 ++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ae3f5f056..8f562698d 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -74,12 +74,10 @@ android:parentActivityName=".VideoItemDetailActivity" tools:ignore="UnusedAttribute"> - - + android:label="@string/background_player_name" + android:exported="false" /> diff --git a/app/src/main/res/layout/paginate_footer.xml b/app/src/main/res/layout/paginate_footer.xml index 8e5d7571d..b3757c1af 100644 --- a/app/src/main/res/layout/paginate_footer.xml +++ b/app/src/main/res/layout/paginate_footer.xml @@ -8,7 +8,7 @@ NewPipe + NewPipe Background Player NewPipe %1$s views Uploaded on %1$s @@ -10,6 +11,7 @@ https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc Open in browser Share + Loading Download Search Settings From 4fe3cb2bca146aa35848a7530641b4273b73c107 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 22:26:25 +0100 Subject: [PATCH 10/57] use symlinks to provide alternate folders for Hebrew and Indonesian These two languages must be included twice (iw/he and id/in) For a full discussion of why, see: https://gitlab.com/fdroid/fdroidclient/issues/139 https://stackoverflow.com/questions/5074769/cyanogenmod-translate-a-project/8470980#8470980 https://stackoverflow.com/questions/8393771/android-not-using-finding-my-hebrew-localization I included a blank placeholder file for Indonesian, it can be simply replaced by the real one, whenever that comes along. --- app/src/main/res/values-id | 1 + app/src/main/res/values-in/strings.xml | 3 +++ app/src/main/res/values-iw | 1 + 3 files changed, 5 insertions(+) create mode 120000 app/src/main/res/values-id create mode 100644 app/src/main/res/values-in/strings.xml create mode 120000 app/src/main/res/values-iw diff --git a/app/src/main/res/values-id b/app/src/main/res/values-id new file mode 120000 index 000000000..9ea8dda4b --- /dev/null +++ b/app/src/main/res/values-id @@ -0,0 +1 @@ +values-in \ No newline at end of file diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml new file mode 100644 index 000000000..9c5ad89af --- /dev/null +++ b/app/src/main/res/values-in/strings.xml @@ -0,0 +1,3 @@ + + + diff --git a/app/src/main/res/values-iw b/app/src/main/res/values-iw new file mode 120000 index 000000000..57bf91954 --- /dev/null +++ b/app/src/main/res/values-iw @@ -0,0 +1 @@ +values-he \ No newline at end of file From 3c1e64d8dc35e22b5327fbd1e2664c7826067c8c Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 23:17:39 +0100 Subject: [PATCH 11/57] simplify youtube URL IntentFilters Each elements applies to the whole IntentFilter, so there is no need to declare the host, scheme, etc. multiple times within a single IntentFilter. Also, pathPrefix="/" will match all paths, so it is unnecessary. --- app/src/main/AndroidManifest.xml | 53 ++++++++++++-------------------- 1 file changed, 20 insertions(+), 33 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8f562698d..ab3ceaf9b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -29,43 +29,30 @@ + - + + - - - - - - - - + + + + + + + + + + + + + + + + + Date: Fri, 1 Jan 2016 23:29:50 +0100 Subject: [PATCH 12/57] support another youtube URL format: https://www.youtube.com/v/mS1gstS6YS8 https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/YouTubeLinks/YouTubeLinks.html --- app/src/main/AndroidManifest.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ab3ceaf9b..3cd85adec 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -41,6 +41,7 @@ + From 2a93e9bd2e15ca33ef11ea89e414c99604e676fc Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 23:32:09 +0100 Subject: [PATCH 13/57] precisely target these URLs https://www.youtube.com/watch?v=mS1gstS6YS8 These URLs have a Path that always starts with "/watch" so no need for a pattern. Also, everything after the "?" is considered the "Query String", not the Path. Anything after a "#" is the "Feature String". The path matching in IntentFilters only see the Path, and nothing from the "Query String" or "Feature String". these are the available kinds of URLs: https://developer.apple.com/library/ios/featuredarticles/iPhoneURLScheme_Reference/YouTubeLinks/YouTubeLinks.html --- app/src/main/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3cd85adec..861f773ff 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -42,7 +42,7 @@ - + From efe5de4c7526bbc50c79f09c5522f10bd8dc7502 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 23:51:34 +0100 Subject: [PATCH 14/57] support youtube's custom URL schemes (vnd.youtube: and vnd.youtube.launch:) --- app/src/main/AndroidManifest.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 861f773ff..54894f679 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -55,6 +55,15 @@ + + + + + + + + + Date: Fri, 1 Jan 2016 23:52:22 +0100 Subject: [PATCH 15/57] youtube URLs can also come from media searches and NFC sends --- app/src/main/AndroidManifest.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 54894f679..d028886b1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -32,6 +32,8 @@ + + @@ -46,6 +48,8 @@ + + @@ -57,6 +61,8 @@ + + From d715eae0d1fc2893aed4a7c057a01d3a6409b08a Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 2 Jan 2016 01:33:08 +0100 Subject: [PATCH 16/57] route video downloads to "Movies" and audio to "Music" use the standard Android folders when downloading files. --- app/src/main/java/org/schabi/newpipe/DownloadDialog.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java index a943ad423..3001455f9 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java @@ -61,21 +61,24 @@ public class DownloadDialog extends DialogFragment { String suffix = ""; String title = arguments.getString(TITLE); String url = ""; + String downloadFolder = "Download"; switch(which) { case 0: // Video suffix = arguments.getString(FILE_SUFFIX_VIDEO); url = arguments.getString(VIDEO_URL); + downloadFolder = "Movies"; break; case 1: suffix = arguments.getString(FILE_SUFFIX_AUDIO); url = arguments.getString(AUDIO_URL); + downloadFolder = "Music"; break; default: Log.d(TAG, "lolz"); } //to avoid hard-coded string like "/storage/emulated/0/Movies" String downloadPath = prefs.getString(getString(R.string.downloadPathPreference), - Environment.getExternalStorageDirectory().getAbsolutePath() + "/Movies"); + Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + downloadFolder); final File dir = new File(downloadPath); if(!dir.exists()) { boolean mkdir = dir.mkdir(); //attempt to create directory From 966ac0673c07c3fa6ef178f9f63f085890d8ac01 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 2 Jan 2016 01:29:31 +0100 Subject: [PATCH 17/57] gradle.properties is only commented out defaults, so remove from git For anyone who tweaks this file for local settings, it becomes painful to have it committed in git because those changes which are only relevant to the local setup will show up in git as changed. --- .gitignore | 1 + gradle.properties | 18 ------------------ 2 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 gradle.properties diff --git a/.gitignore b/.gitignore index 42caadb93..2b3c40d66 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ /app/app.iml /.idea /*.iml +gradle.properties diff --git a/gradle.properties b/gradle.properties deleted file mode 100644 index 1d3591c8a..000000000 --- a/gradle.properties +++ /dev/null @@ -1,18 +0,0 @@ -# Project-wide Gradle settings. - -# IDE (e.g. Android Studio) users: -# Gradle settings configured through the IDE *will override* -# any settings specified in this file. - -# For more details on how to configure your build environment visit -# http://www.gradle.org/docs/current/userguide/build_environment.html - -# Specifies the JVM arguments used for the daemon process. -# The setting is particularly useful for tweaking memory settings. -# Default value: -Xmx10248m -XX:MaxPermSize=256m -# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 - -# When configured, Gradle will run in incubating parallel mode. -# This option should only be used with decoupled projects. More details, visit -# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects -# org.gradle.parallel=true \ No newline at end of file From 7cbb135f286727adf02e77b0114cdf541c1eda87 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 2 Jan 2016 11:59:28 +0100 Subject: [PATCH 18/57] include Tibetan as a language option The Tibetan alphabet was only recently included on Android, so the language name needs to also have the English there. Otherwise it'll appear blank on devices without Tibetan. --- app/src/main/res/values/settings_keys.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 8d33b8cbe..0ff359a46 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -71,6 +71,7 @@ sl fi sv + bo vi tr bg @@ -149,6 +150,7 @@ Slovenščina Suomi Svenska + Tibetan བོད་སྐད། Tiếng Việt Türkçe Български From 7dadb2b26c7b3409527da3d1a0dc5fca58e9c99a Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Sat, 2 Jan 2016 16:08:18 +0100 Subject: [PATCH 19/57] fixed close notification problem --- .../org/schabi/newpipe/BackgroundPlayer.java | 144 +++++++++++------- .../res/drawable-hdpi/ic_close_white_24dp.png | Bin 0 -> 221 bytes .../res/drawable-mdpi/ic_close_white_24dp.png | Bin 0 -> 175 bytes .../drawable-xhdpi/ic_close_white_24dp.png | Bin 0 -> 257 bytes .../drawable-xxhdpi/ic_close_white_24dp.png | Bin 0 -> 347 bytes .../drawable-xxxhdpi/ic_close_white_24dp.png | Bin 0 -> 436 bytes .../main/res/layout/player_notification.xml | 66 ++++++++ .../layout/player_notification_expanded.xml | 80 ++++++++++ app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/strings.xml | 1 + 10 files changed, 240 insertions(+), 52 deletions(-) create mode 100644 app/src/main/res/drawable-hdpi/ic_close_white_24dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_close_white_24dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_close_white_24dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_close_white_24dp.png create mode 100644 app/src/main/res/layout/player_notification.xml create mode 100644 app/src/main/res/layout/player_notification_expanded.xml diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java index 5573e2771..f9caef26a 100644 --- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -17,6 +17,7 @@ import android.os.IBinder; import android.os.PowerManager; import android.support.v7.app.NotificationCompat; import android.util.Log; +import android.widget.RemoteViews; import android.widget.Toast; import java.io.IOException; @@ -113,9 +114,9 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare private int noteID = TAG.hashCode(); private BackgroundPlayer owner; private NotificationManager noteMgr; - private NotificationCompat.Builder noteBuilder; private WifiManager.WifiLock wifiLock; private Bitmap videoThumbnail = null; + private NotificationCompat.Builder noteBuilder; public PlayerThread(String src, String title, BackgroundPlayer owner) { this.source = src; @@ -124,10 +125,9 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare mediaPlayer = new MediaPlayer(); mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); } + @Override public void run() { - Resources res = getApplicationContext().getResources(); - mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);//cpu lock try { mediaPlayer.setDataSource(source); @@ -177,54 +177,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare filter.addAction(ACTION_STOP); registerReceiver(broadcastReceiver, filter); - PendingIntent playPI = PendingIntent.getBroadcast(owner, noteID, - new Intent(ACTION_PLAYPAUSE), PendingIntent.FLAG_UPDATE_CURRENT); - - NotificationCompat.Action playButton = new NotificationCompat.Action.Builder - (R.drawable.ic_play_arrow_white_48dp, "Play", playPI).build(); - - /* - NotificationCompat.Action pauseButton = new NotificationCompat.Action.Builder - (R.drawable.ic_pause_white_24dp, "Pause", playPI).build(); - */ - - PendingIntent stopPI = PendingIntent.getBroadcast(owner, noteID, - new Intent(ACTION_STOP), PendingIntent.FLAG_UPDATE_CURRENT); - - noteBuilder = new NotificationCompat.Builder(owner); - noteBuilder - .setContentTitle(title) - //really? Id like to put something more helpful here. - //.setContentText("NewPipe is playing in the background") - .setContentText(channelName) - //.setAutoCancel(!mediaPlayer.isPlaying()) - .setOngoing(true) - .setDeleteIntent(stopPI) - //doesn't fit with Notification.MediaStyle - //.setProgress(vidLength, 0, false) - .setSmallIcon(R.drawable.ic_play_circle_filled_white_24dp) - .setLargeIcon(videoThumbnail) - .setTicker( - String.format(res.getString( - R.string.backgroundPlayerTickerText), title)) - .addAction(playButton); - //.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - //.setLargeIcon(cover) - if(android.os.Build.VERSION.SDK_INT >= 16) - noteBuilder.setPriority(Notification.PRIORITY_LOW); - if(android.os.Build.VERSION.SDK_INT >= 21) - noteBuilder.setCategory(Notification.CATEGORY_TRANSPORT); - - noteBuilder.setStyle(new NotificationCompat.MediaStyle() - //.setMediaSession(mMediaSession.getSessionToken()) - .setShowActionsInCompactView(new int[]{0}) - .setShowCancelButton(true) - .setCancelButtonIntent(stopPI)); - if(videoThumbnail != null) { - noteBuilder.setLargeIcon(videoThumbnail); - } - - Notification note = noteBuilder.build(); + Notification note = buildNotification(); Intent openDetailView = new Intent(getApplicationContext(), VideoItemDetailActivity.class); @@ -252,7 +205,6 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare Log.d(TAG, "sleep failure"); } }*/ - } private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @@ -306,5 +258,93 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare afterPlayCleanup(); } } + + private Notification buildNotification() { + Notification note; + Resources res = getApplicationContext().getResources(); + noteBuilder = new NotificationCompat.Builder(owner); + + PendingIntent playPI = PendingIntent.getBroadcast(owner, noteID, + new Intent(ACTION_PLAYPAUSE), PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent stopPI = PendingIntent.getBroadcast(owner, noteID, + new Intent(ACTION_STOP), PendingIntent.FLAG_UPDATE_CURRENT); + /* + NotificationCompat.Action pauseButton = new NotificationCompat.Action.Builder + (R.drawable.ic_pause_white_24dp, "Pause", playPI).build(); + */ + + noteBuilder + .setOngoing(true) + .setDeleteIntent(stopPI) + //doesn't fit with Notification.MediaStyle + //.setProgress(vidLength, 0, false) + .setSmallIcon(R.drawable.ic_play_circle_filled_white_24dp) + .setTicker( + String.format(res.getString( + R.string.backgroundPlayerTickerText), title)); + + if (android.os.Build.VERSION.SDK_INT < 21) { + + NotificationCompat.Action playButton = new NotificationCompat.Action.Builder + (R.drawable.ic_play_arrow_white_48dp, + res.getString(R.string.play), playPI).build(); + + noteBuilder + .setContentTitle(title) + //really? Id like to put something more helpful here. + //.setContentText("NewPipe is playing in the background") + .setContentText(channelName) + //.setAutoCancel(!mediaPlayer.isPlaying()) + .setDeleteIntent(stopPI) + //doesn't fit with Notification.MediaStyle + //.setProgress(vidLength, 0, false) + .setLargeIcon(videoThumbnail) + .addAction(playButton); + //.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + //.setLargeIcon(cover) + + if (android.os.Build.VERSION.SDK_INT >= 16) + noteBuilder.setPriority(Notification.PRIORITY_LOW); + + noteBuilder.setStyle(new NotificationCompat.MediaStyle() + //.setMediaSession(mMediaSession.getSessionToken()) + .setShowActionsInCompactView(new int[]{0}) + .setShowCancelButton(true) + .setCancelButtonIntent(stopPI)); + if (videoThumbnail != null) { + noteBuilder.setLargeIcon(videoThumbnail); + } + note = noteBuilder.build(); + } else { + RemoteViews view = + new RemoteViews(BuildConfig.APPLICATION_ID, R.layout.player_notification); + view.setImageViewBitmap(R.id.backgroundCover, videoThumbnail); + view.setTextViewText(R.id.backgroundSongName, title); + view.setTextViewText(R.id.backgroundArtist, channelName); + view.setOnClickPendingIntent(R.id.backgroundStop, stopPI); + view.setOnClickPendingIntent(R.id.backgroundPlayPause, playPI); + + RemoteViews expandedView = + new RemoteViews(BuildConfig.APPLICATION_ID, R.layout.player_notification); + expandedView.setImageViewBitmap(R.id.backgroundCover, videoThumbnail); + expandedView.setTextViewText(R.id.backgroundSongName, title); + expandedView.setTextViewText(R.id.backgroundArtist, channelName); + expandedView.setOnClickPendingIntent(R.id.backgroundStop, stopPI); + expandedView.setOnClickPendingIntent(R.id.backgroundPlayPause, playPI); + + noteBuilder.setCategory(Notification.CATEGORY_TRANSPORT); + + //Make notification appear on lockscreen + noteBuilder.setVisibility(Notification.VISIBILITY_PUBLIC); + + note = noteBuilder.build(); + note.contentView = view; + + //todo: This never shows up. I was not able to figure out why: + note.bigContentView = expandedView; + } + + return note; + } } } diff --git a/app/src/main/res/drawable-hdpi/ic_close_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_close_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..ceb1a1eebf2b2cc9a008f42010e144f4dab968de GIT binary patch literal 221 zcmV<303!d1P)og+*{ z>6z1@lfD*AYSPav72B5kK^|J))MUC zlz7ydwCsb8xn}W?^r?}5wtsjdmvX{3=JbT!J9sKPrYmk={m|7^>A|Z*7j^D$`>}ry Zqi^Z9GQN4ct^!@a;OXk;vd$@?2>?I&LQeny literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_close_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_close_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..b7c7ffd0e795ba76ed3a062566c9016448795f7a GIT binary patch literal 257 zcmV+c0sj7pP) zOA5m<3jYBNi%A&<@ZO?$P9};P4Y5CjG5$M&YXI45J{s}~# zf|&?x1_gn4B7+hS@X!l}&!voFhmZP^sujifL@~PKMMM~{6xH}^g$q7WOzwCQ5vHTU z6`v~H@rlA8e;CUh_(b84zg=+ih`wG<)HiJjzSlQx5#CnjMR;A)R^jtaTa9;7rSy)7O%~`cm?ZjXImW?6TYRT<;U^@VKiSj`soFk00000NkvXX Hu0mjfhD&W| literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_close_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..6b717e0dda8649aa3b5f1d6851ba0dd20cc4ea66 GIT binary patch literal 347 zcmV-h0i^zkP)vMkH8EXyh{JTRaptiwcq@D(P;=ehLbl?EMKm*m7(@7_siS}}k zNFtnck{HL4mc!ypcyUoqJV~4rM^fS3C#iAnkyJU3biCmDy`VZLOv=LXld^HVq32ETvhYyB39D^lU%DgQgv&#U%8l^-CA%qY@2qA=!B5=cm zUgehujQG*l{{`@rPr!f|fEk^>KI9WteE@ilV6HEl&_rJ@p_zU*;T}RirIc{5NocNLm*7JGdV(AM zYYDFOvk5~8{Z*t_>U=!XvoehUSEh=adIga45oe)B9kGgT}7UT3Cirmr(oHPv^YQ1-p=Hlh5u;xggf zX{&yw+El-OrrKQJRl@b7x{HLmNkj95`a#LLnW{Veb2C+!`ppt#r)=g4@?c8RY{yJj~W@W|h^mU4q`i)2y~Rw@J`jIh$1%|In!~{Tb{nMqaxlgb+dq eA%qY@zJ@mriVM?qfwL0;0000 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/player_notification_expanded.xml b/app/src/main/res/layout/player_notification_expanded.xml new file mode 100644 index 000000000..3fd379a6b --- /dev/null +++ b/app/src/main/res/layout/player_notification_expanded.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index e14ee9606..7e0d71406 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -7,4 +7,5 @@ #efff #6000 #EEEEEE + #323232 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 177280277..ffa004d91 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -53,6 +53,7 @@ %1$s - NewPipe Playing in background https://www.c3s.cc/ + Play Video preview thumbnail From adcb8c64699f78c99444af035605753077b92d12 Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Sat, 2 Jan 2016 17:40:58 +0100 Subject: [PATCH 20/57] add c3s thumbnail and moved on to 0.7.1 --- README.md | 1 + app/build.gradle | 4 +- .../newpipe/VideoItemDetailFragment.java | 4 +- .../res/drawable-nodpi/gruese_die_gema.png | Bin 0 -> 91384 bytes .../gruese_die_gema_unangebracht.png | Bin 15826 -> 0 bytes assets/gruese_die_gema.svg | 288 ++++++++++-------- 6 files changed, 163 insertions(+), 134 deletions(-) create mode 100644 app/src/main/res/drawable-nodpi/gruese_die_gema.png delete mode 100644 app/src/main/res/drawable-nodpi/gruese_die_gema_unangebracht.png diff --git a/README.md b/README.md index e6d1d9498..e7ce4f965 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only * Open a video in Kodi * Show Next/Related videos * Search YouTube in a specific language +* Orbot support (no streaming yet) ### Coming Features diff --git a/app/build.gradle b/app/build.gradle index 871a98a9d..fb4598597 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "org.schabi.newpipe" minSdkVersion 15 targetSdkVersion 23 - versionCode 9 - versionName "0.7.0" + versionCode 10 + versionName "0.7.1" } buildTypes { release { diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java index 92c25e2aa..ddec1e36e 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java @@ -287,7 +287,7 @@ public class VideoItemDetailFragment extends Fragment { VideoItemDetailFragment.ARG_ITEM_ID, currentVideoInfo.nextVideo.id); */ detailIntent.putExtra( VideoItemDetailFragment.VIDEO_URL, currentVideoInfo.nextVideo.webpage_url); - //todo: make id dynamic the following line is crap + detailIntent.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, streamingServiceId); startActivity(detailIntent); } @@ -296,7 +296,7 @@ public class VideoItemDetailFragment extends Fragment { break; case VideoInfo.ERROR_BLOCKED_BY_GEMA: thumbnailView.setImageBitmap(BitmapFactory.decodeResource( - getResources(), R.drawable.gruese_die_gema_unangebracht)); + getResources(), R.drawable.gruese_die_gema)); backgroundButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { diff --git a/app/src/main/res/drawable-nodpi/gruese_die_gema.png b/app/src/main/res/drawable-nodpi/gruese_die_gema.png new file mode 100644 index 0000000000000000000000000000000000000000..d6e2af3d5a2e1db00249e6e07d2a5894ed4e3723 GIT binary patch literal 91384 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

pv{t=0v@uYO2e~9jcj>>re z*Kg4)wC->k%Pp))Pgq7lDA1$jSNC3z6NHTM-Us(J=8-ez1{uAsYNa$ZE+_RYg(r3V zId%-Qhq?+aQIrt7>51)j-N8W5nQJcHtM1r#%Rc(JJ&nJlfwaa?ziH5lwsFrQ5#FX8 zy~u~wN)RXxQgJY`*aOk0*3@$lgcmZk#bXt&eVy=^YAN9xR;?NHSk>lDri64mgDHB)gGjDi*EX2}w zpC<3$+N4!zSQtNhqU!v0X2xb^Vx{X4ExgSR zH41!UCro=lEwiVs4GlHeLbuDyw_jL&7M}c0>;1vK(12p(Oa)dF&pH~Y+zxD`-A|E3D+2~T`d zdqwQTElt+w3E2!>AIu0|CPlDCr4qhC4&5&t4?^*qUv4!muqdN`GCS!j0-pqhv7YGtFsDKMSfRQEC$a)g7lkI_%G!-q9X-4W?Mm!wisbLDrfx2+j%%j*aE^XcrBt z1A`%V)KigiMzh6{JF->31iUXJw)=R#E7*q~JbZY+wOy<89^qV}$k=(V|J$k=&m*~z zcNo6<184IYtVXkU5ueee9jab^7UWmbkq({(X1fOnZct7W3(zi5OfxjR(Ap7}cm*#N z?QkyJzS&PWkU~(CGACFILOhwOY({e<@=zLC`N^BG%=VIrzGdI%Mf6z8pYZ+c*xsq) z_~R+D7&&nbGaG=p|5DGgm`?4#z7Vyu+P>$2F;ZoM1{FsRMm`38i~)sAmpfSj zkVVSZWR$f)o|2_R^xzb*hHho0VR%9d2RvGmce`+cvJbCh)=@Nv3H!r9!VjF-o~uD3 z5X*MymmrU+13yXYomxT&lF4mdclA%d|aucQgUULjn7 zfuK(aq^mcJh}ON6qX0qWK5)B$=oNE1h6e{J$aanP-vQUW>+AYG?k!}>@WG?!q3b?r zFoJ{Z2x{&S3&?wSEY$SzxSKck z3oe7smgjSybptJU_89=+=qY@wz&9Zc9`!#+^4;M7i9APhsu8D5Y!zvHL@X@K&qo7l zXX)G_E*=6|SPbk4qS22maY6#7*DWC}O^uR8Z`gHk4?_iEf`|443xN>ICK8?Osj!`kauSWigP)6gM=^)Rs^ zTXL!ep~7j(Oz*Fb|3yhz*+$?o8^DbYSO7&$9I5KvffbZJ7=*j3rv&3s3fpV&jw#>2 z{`g_)-A~yAyPz=G4{VfERlN=Bn&Bw9`OWr<2N%LwUVpQ7a-u@e+G24KQ8=2KN%ey| z7?>Ik=?Ee%aKQA0Sd0ZKNIVh@zFi3n!ioKe9V}%lZvngrP{k;pfO7^+Sm}3{JkhQ( zJXMQz+I5LoQ>d$7?u2-uAhY}cjN>ziXBLk=*ujM8C6f5#+Qjj-oU=c?(pr#s7ufWo zk7e8o;*Ngrb`g=weWu_|l$@QNoehKSQfqN7;HQ)V7gP|&N{D(JP_m`ickqG77vPMv zzut{SL=3$*JR_;*pFe*}pi5>Vc^*OtG_BIVSEGU6w5*OmiS>SnzQqrG;(45p;piPC zZ9A19sqCJan(B|3cgH&tOq~%t$4}Zc9|~PXCWwS z1`4^4$eY<^3F11BK6VTEDY{lxx2YAd2>5Gt1jbFo4#UyEbI#%N9Q;fym~t zv9PKt1yYk};0ICAeUx6=bo4??_z(r|7bA$%c8f2O4mCeIJFE-uWEn5q2Qe&yO-ITj zFqf_T$|hfO8M;_b#sk0OpP`=8p8N^8E8-8vJ13Fx5+gXoM^F(Eei{R~*z~jIWK;zqT+;;F@pr1;VcA5J8ISlA*fL;N+KVT9VTxoX~5>^WmAF

    KlgYg1=QQ_k^ENpU8)$FF)5tSZlC2W-yYjGko> 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 E14e80X8-^I literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/gruese_die_gema_unangebracht.png b/app/src/main/res/drawable-nodpi/gruese_die_gema_unangebracht.png deleted file mode 100644 index e19491b7be43d2334b20dd16f96d3350de96a6dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15826 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

    vb?iYs?kC&; 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 HFMR$7*qOZg diff --git a/assets/gruese_die_gema.svg b/assets/gruese_die_gema.svg index 48ebc8db0..eace7bf44 100644 --- a/assets/gruese_die_gema.svg +++ b/assets/gruese_die_gema.svg @@ -7,7 +7,6 @@ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" - xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="426" @@ -16,7 +15,10 @@ id="svg2" version="1.1" inkscape:version="0.91 r13725" - sodipodi:docname="gruese_die_gema_unangebracht.svg"> + sodipodi:docname="gruese_die_gema.svg" + inkscape:export-filename="/home/the-scrabi/Projects/NewPipe/assets/gruese_die_gema.png" + inkscape:export-xdpi="216.33803" + inkscape:export-ydpi="216.33803"> + inkscape:window-width="1015" + inkscape:window-height="417" + inkscape:window-x="287" + inkscape:window-y="491" + inkscape:window-maximized="0" /> @@ -46,7 +48,7 @@ image/svg+xml - + @@ -56,129 +58,155 @@ id="layer1" transform="translate(0,-812.36212)"> - - - - - - - - - - - - - - - - - - - - - + id="g4230" + transform="matrix(0.67525011,0,0,0.67525011,-14.086916,282.00859)"> + + + + + + + + + + + + + + + + + + + + + + + + + - + Genervt? Gib der Alternative c3s + + eine Chance. From d3500e90360b284d789e01b3ec95ada0a735345f Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Sat, 2 Jan 2016 17:41:33 +0100 Subject: [PATCH 21/57] removed onion routing from readme --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index e7ce4f965..e6d1d9498 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,6 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only * Open a video in Kodi * Show Next/Related videos * Search YouTube in a specific language -* Orbot support (no streaming yet) ### Coming Features From dfcb4edb8127ea3b3c40243d48890261ce0de79b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mladen=20Pejakovi=C4=87?= Date: Sat, 2 Jan 2016 18:03:57 +0100 Subject: [PATCH 22/57] Translated using Weblate (Serbian) Currently translated at 100.0% (51 of 51 strings) --- app/src/main/res/values-sr/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 7ab3d8eaa..107434167 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -54,4 +54,8 @@ Користи спољашњи аудио плејер Пуштам у позадини + Позадински плејер за Јутјуб цев + Учитавам + Пусти + From eeb612f9a2014418b2211c012ee81cc849624c45 Mon Sep 17 00:00:00 2001 From: Matej U Date: Sat, 2 Jan 2016 19:48:46 +0100 Subject: [PATCH 23/57] Translated using Weblate (Slovenian) Currently translated at 100.0% (51 of 51 strings) --- app/src/main/res/values-sl/strings.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index 91f54dc11..412d9a56c 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -47,4 +47,9 @@ Všeč mi je Ni mi všeč + Ozadnji predvajalnik NewPipe + Nalaganje ... + Predvajanje v ozadju + Predvajaj + From ef255d12ae3704b94441d7ac4bcacc4e2ad40f6f Mon Sep 17 00:00:00 2001 From: GDR! Date: Thu, 24 Dec 2015 14:55:33 +0100 Subject: [PATCH 24/57] Test tor code --- app/build.gradle | 3 +- .../java/org/schabi/newpipe/Downloader.java | 8 +++-- .../org/schabi/newpipe/PlayVideoActivity.java | 30 ++++++++++++++++++- app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/settings_screen.xml | 5 ++++ 5 files changed, 44 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index fb4598597..9eb3ccef7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -17,7 +17,7 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - + lintOptions { checkReleaseBuilds false // Or, if you prefer, you can continue to check for errors in release builds, @@ -35,4 +35,5 @@ dependencies { compile 'com.android.support:recyclerview-v7:23.1.1' 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/java/org/schabi/newpipe/Downloader.java b/app/src/main/java/org/schabi/newpipe/Downloader.java index f0a19cfc5..c15c2ddc3 100644 --- a/app/src/main/java/org/schabi/newpipe/Downloader.java +++ b/app/src/main/java/org/schabi/newpipe/Downloader.java @@ -7,6 +7,8 @@ import java.net.HttpURLConnection; import java.net.URL; import java.net.UnknownHostException; +import info.guardianproject.netcipher.NetCipher; + /** * Created by Christian Schabesberger on 14.08.15. * @@ -37,10 +39,11 @@ public class Downloader { * @param language the language (usually a 2-character code) to set as the preferred language * @return the contents of the specified text file*/ public static String download(String siteUrl, String language) { + NetCipher.useTor(); String ret = ""; try { URL url = new URL(siteUrl); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); + HttpURLConnection con = (HttpURLConnection) NetCipher.getHttpURLConnection(url); con.setRequestProperty("Accept-Language", language); ret = dl(con); } @@ -81,10 +84,11 @@ public class Downloader { * @return the contents of the specified text file*/ public static String download(String siteUrl) { String ret = ""; + NetCipher.useTor(); try { URL url = new URL(siteUrl); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); + HttpURLConnection con = (HttpURLConnection) NetCipher.getHttpURLConnection(url); ret = dl(con); } catch(Exception e) { diff --git a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java index d5fea8c3e..a7aeda10f 100644 --- a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java +++ b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java @@ -3,6 +3,7 @@ package org.schabi.newpipe; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.pm.ActivityInfo; import android.content.res.Configuration; import android.media.MediaPlayer; @@ -25,6 +26,7 @@ import android.widget.Button; import android.widget.MediaController; import android.widget.ProgressBar; import android.widget.VideoView; +import info.guardianproject.netcipher.NetCipher; /** * Copyright (C) Christian Schabesberger 2015 @@ -44,7 +46,7 @@ import android.widget.VideoView; * along with NewPipe. If not, see . */ -public class PlayVideoActivity extends AppCompatActivity { +public class PlayVideoActivity extends AppCompatActivity implements OnSharedPreferenceChangeListener { //// TODO: 11.09.15 add "choose stream" menu @@ -170,6 +172,9 @@ public class PlayVideoActivity extends AppCompatActivity { if(prefs.getBoolean(PREF_IS_LANDSCAPE, false) && !isLandscape) { toggleOrientation(); } + + setTorPreference(prefs); + prefs.registerOnSharedPreferenceChangeListener(this); } @Override @@ -187,6 +192,13 @@ public class PlayVideoActivity extends AppCompatActivity { videoView.pause(); } + @Override + protected void onDestroy() { + super.onDestroy(); + prefs = getPreferences(Context.MODE_PRIVATE); + prefs.unregisterOnSharedPreferenceChangeListener(this); + } + @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); @@ -348,4 +360,20 @@ public class PlayVideoActivity extends AppCompatActivity { editor.putBoolean(PREF_IS_LANDSCAPE, isLandscape); editor.apply(); } + + private void setTorPreference(SharedPreferences prefs) { + if(prefs.getBoolean(getString(R.string.useTor), false)) { + NetCipher.useTor(); + } else { + NetCipher.setProxy(null); + } + } + + @Override + public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { + if(key.equals(getString(R.string.useTor))) { + setTorPreference(prefs); + } + } + } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 12fb9275d..c2d1becdd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -63,4 +63,6 @@ Uploader thumbnail Dislikes Likes + Use Tor + Proxy connections via The Onion Router diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml index d4b21426f..953ded807 100644 --- a/app/src/main/res/xml/settings_screen.xml +++ b/app/src/main/res/xml/settings_screen.xml @@ -72,5 +72,10 @@ android:summary="@string/autoPlayThroughIntentSummary" android:defaultValue="false" /> + + From 0265da4ae61286b8137185108bdd10a1cde51931 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Thu, 24 Dec 2015 14:55:33 +0100 Subject: [PATCH 25/57] use HttpsURLConnections since youtube.com always uses HTTPS This helps enforce that the connection is encrypted. If for whatever reason an unencrypted connection is created, an Exception will be thrown. --- app/src/main/java/org/schabi/newpipe/Downloader.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/Downloader.java b/app/src/main/java/org/schabi/newpipe/Downloader.java index c15c2ddc3..9e33ce322 100644 --- a/app/src/main/java/org/schabi/newpipe/Downloader.java +++ b/app/src/main/java/org/schabi/newpipe/Downloader.java @@ -7,6 +7,8 @@ import java.net.HttpURLConnection; import java.net.URL; import java.net.UnknownHostException; +import javax.net.ssl.HttpsURLConnection; + import info.guardianproject.netcipher.NetCipher; /** @@ -43,7 +45,7 @@ public class Downloader { String ret = ""; try { URL url = new URL(siteUrl); - HttpURLConnection con = (HttpURLConnection) NetCipher.getHttpURLConnection(url); + HttpsURLConnection con = NetCipher.getHttpsURLConnection(url); con.setRequestProperty("Accept-Language", language); ret = dl(con); } @@ -88,7 +90,7 @@ public class Downloader { try { URL url = new URL(siteUrl); - HttpURLConnection con = (HttpURLConnection) NetCipher.getHttpURLConnection(url); + HttpsURLConnection con = NetCipher.getHttpsURLConnection(url); ret = dl(con); } catch(Exception e) { From e63d43151b711bdc032ae851c5eb053939026b77 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 19:45:41 +0100 Subject: [PATCH 26/57] add a title plus summary to "Use Tor" preference --- app/src/main/res/values/strings.xml | 2 +- app/src/main/res/xml/settings_screen.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c2d1becdd..c7058759e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -64,5 +64,5 @@ Dislikes Likes Use Tor - Proxy connections via The Onion Router + Force download traffic through Tor for increased privacy (streaming videos not yet supported) diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml index 953ded807..f7ab99a53 100644 --- a/app/src/main/res/xml/settings_screen.xml +++ b/app/src/main/res/xml/settings_screen.xml @@ -74,7 +74,8 @@ From 6bd2468d44b09df89d95c999a98f7045c246303e Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 20:29:21 +0100 Subject: [PATCH 27/57] if Orbot is installed, then default to using Tor If the user has not changed the "Use Tor" preference, then the default should be to use Tor if Orbot is installed. The user can still override it by going an unchecking "Use Tor". --- app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java index a7aeda10f..f5e595624 100644 --- a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java +++ b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java @@ -27,6 +27,7 @@ import android.widget.MediaController; import android.widget.ProgressBar; import android.widget.VideoView; import info.guardianproject.netcipher.NetCipher; +import info.guardianproject.netcipher.proxy.OrbotHelper; /** * Copyright (C) Christian Schabesberger 2015 @@ -362,7 +363,8 @@ public class PlayVideoActivity extends AppCompatActivity implements OnSharedPref } private void setTorPreference(SharedPreferences prefs) { - if(prefs.getBoolean(getString(R.string.useTor), false)) { + // if Orbot is installed, then default to using Tor, the user can still override + if(prefs.getBoolean(getString(R.string.useTor), OrbotHelper.isOrbotInstalled(this))) { NetCipher.useTor(); } else { NetCipher.setProxy(null); From d3879a03982f3e8da4831704fb0ef280b884405f Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 22:16:41 +0100 Subject: [PATCH 28/57] setup Tor at app start, and config immediately when pref is changed This adds an Application subclass to get the onCreate() method, which is called once at the first start up of the app, before any Activity starts. Tor is configured there to ensure it is setup before anything happens. This also moves the "Use Tor" pref listener to a more appropriate place. --- app/src/main/AndroidManifest.xml | 1 + app/src/main/java/org/schabi/newpipe/App.java | 32 +++++++++++++++++++ .../java/org/schabi/newpipe/Downloader.java | 2 -- .../org/schabi/newpipe/PlayVideoActivity.java | 26 +-------------- .../org/schabi/newpipe/SettingsActivity.java | 19 +++++++++++ app/src/main/res/xml/settings_screen.xml | 3 +- 6 files changed, 54 insertions(+), 29 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/App.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d028886b1..ef84c57b3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -7,6 +7,7 @@ @@ -47,7 +44,7 @@ import info.guardianproject.netcipher.proxy.OrbotHelper; * along with NewPipe. If not, see . */ -public class PlayVideoActivity extends AppCompatActivity implements OnSharedPreferenceChangeListener { +public class PlayVideoActivity extends AppCompatActivity { //// TODO: 11.09.15 add "choose stream" menu @@ -173,9 +170,6 @@ public class PlayVideoActivity extends AppCompatActivity implements OnSharedPref if(prefs.getBoolean(PREF_IS_LANDSCAPE, false) && !isLandscape) { toggleOrientation(); } - - setTorPreference(prefs); - prefs.registerOnSharedPreferenceChangeListener(this); } @Override @@ -197,7 +191,6 @@ public class PlayVideoActivity extends AppCompatActivity implements OnSharedPref protected void onDestroy() { super.onDestroy(); prefs = getPreferences(Context.MODE_PRIVATE); - prefs.unregisterOnSharedPreferenceChangeListener(this); } @Override @@ -361,21 +354,4 @@ public class PlayVideoActivity extends AppCompatActivity implements OnSharedPref editor.putBoolean(PREF_IS_LANDSCAPE, isLandscape); editor.apply(); } - - private void setTorPreference(SharedPreferences prefs) { - // if Orbot is installed, then default to using Tor, the user can still override - if(prefs.getBoolean(getString(R.string.useTor), OrbotHelper.isOrbotInstalled(this))) { - NetCipher.useTor(); - } else { - NetCipher.setProxy(null); - } - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { - if(key.equals(getString(R.string.useTor))) { - setTorPreference(prefs); - } - } - } diff --git a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java index c8a548ab6..c8c089a98 100644 --- a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java @@ -2,6 +2,8 @@ package org.schabi.newpipe; import android.content.res.Configuration; import android.os.Bundle; +import android.preference.CheckBoxPreference; +import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; import android.support.annotation.LayoutRes; @@ -13,6 +15,8 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; +import info.guardianproject.netcipher.proxy.OrbotHelper; + /** * Created by Christian Schabesberger on 31.08.15. * @@ -52,10 +56,25 @@ public class SettingsActivity extends PreferenceActivity { } public static class SettingsFragment extends PreferenceFragment { + private CheckBoxPreference useTorCheckBox; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings_screen); + + // if Orbot is installed, then default to using Tor, the user can still override + useTorCheckBox = (CheckBoxPreference) findPreference(getString(R.string.useTor)); + boolean useTor = OrbotHelper.isOrbotInstalled(getActivity()); + useTorCheckBox.setDefaultValue(useTor); + useTorCheckBox.setChecked(useTor); + useTorCheckBox.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { + @Override + public boolean onPreferenceChange(Preference preference, Object useTor) { + App.configureTor((Boolean) useTor); + return true; + } + }); } } diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml index f7ab99a53..4d21b457b 100644 --- a/app/src/main/res/xml/settings_screen.xml +++ b/app/src/main/res/xml/settings_screen.xml @@ -75,8 +75,7 @@ + android:summary="@string/useTorSummary" /> From 5663e543a47eb90af320e5ebb09fcd2b8243c36d Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 23:04:29 +0100 Subject: [PATCH 29/57] whenever an Activity resumes and tor is enabled, request it start This makes sure that Orbot is running when the user expects it to be. If NewPipe is configured to use Tor, then going to a NewPipe screen should ensure Tor is running. --- app/src/main/java/org/schabi/newpipe/App.java | 12 +++++++++++- .../java/org/schabi/newpipe/PlayVideoActivity.java | 6 ++++++ .../org/schabi/newpipe/VideoItemDetailActivity.java | 6 ++++++ .../org/schabi/newpipe/VideoItemListActivity.java | 6 ++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index a8afccd4a..95127d7fe 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -1,6 +1,7 @@ package org.schabi.newpipe; import android.app.Application; +import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; @@ -9,6 +10,8 @@ import info.guardianproject.netcipher.proxy.OrbotHelper; public class App extends Application { + private static boolean useTor; + @Override public void onCreate() { super.onCreate(); @@ -22,11 +25,18 @@ public class App extends Application { /** * Set the proxy settings based on whether Tor should be enabled or not. */ - static void configureTor(boolean useTor) { + static void configureTor(boolean enabled) { + useTor = enabled; if (useTor) { NetCipher.useTor(); } else { NetCipher.setProxy(null); } } + + static void checkStartTor(Context context) { + if (useTor) { + OrbotHelper.requestStartTor(context); + } + } } diff --git a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java index 2500c7dfe..13a1cefed 100644 --- a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java +++ b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java @@ -187,6 +187,12 @@ public class PlayVideoActivity extends AppCompatActivity { videoView.pause(); } + @Override + public void onResume() { + super.onResume(); + App.checkStartTor(this); + } + @Override protected void onDestroy() { super.onDestroy(); diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java index 4a553241f..f93ca4b9e 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java @@ -113,6 +113,12 @@ public class VideoItemDetailActivity extends AppCompatActivity { .commit(); } + @Override + public void onResume() { + super.onResume(); + App.checkStartTor(this); + } + @Override public void onSaveInstanceState(Bundle outState) { outState.putString(VideoItemDetailFragment.VIDEO_URL, videoUrl); diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java index d15709b23..8c4f5c57e 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java @@ -175,6 +175,12 @@ public class VideoItemListActivity extends AppCompatActivity PreferenceManager.setDefaultValues(this, R.xml.settings_screen, false); } + @Override + public void onResume() { + super.onResume(); + App.checkStartTor(this); + } + /** * Callback method from {@link VideoItemListFragment.Callbacks} * indicating that the item with the given ID was selected. From 984dd1cc25d6add07d136a6a602e836fb99f8462 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Fri, 1 Jan 2016 23:06:16 +0100 Subject: [PATCH 30/57] checking on "Use Tor" when Orbot is not installed starts install If the user turns on "Use Tor" and they are missing Orbot, bring them to the screen to install Tor. --- .../org/schabi/newpipe/SettingsActivity.java | 30 +++++++++++++++++-- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java index c8c089a98..f599ebd8b 100644 --- a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java @@ -1,5 +1,8 @@ package org.schabi.newpipe; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; import android.preference.CheckBoxPreference; @@ -39,6 +42,7 @@ import info.guardianproject.netcipher.proxy.OrbotHelper; public class SettingsActivity extends PreferenceActivity { + private static final int REQUEST_INSTALL_ORBOT = 0x1234; private AppCompatDelegate mDelegate = null; @Override @@ -65,19 +69,39 @@ public class SettingsActivity extends PreferenceActivity { // if Orbot is installed, then default to using Tor, the user can still override useTorCheckBox = (CheckBoxPreference) findPreference(getString(R.string.useTor)); - boolean useTor = OrbotHelper.isOrbotInstalled(getActivity()); + final Activity activity = getActivity(); + final boolean useTor = OrbotHelper.isOrbotInstalled(activity); useTorCheckBox.setDefaultValue(useTor); useTorCheckBox.setChecked(useTor); useTorCheckBox.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { @Override - public boolean onPreferenceChange(Preference preference, Object useTor) { - App.configureTor((Boolean) useTor); + public boolean onPreferenceChange(Preference preference, Object o) { + boolean useTor = (Boolean) o; + if (useTor) { + if (OrbotHelper.isOrbotInstalled(activity)) { + App.configureTor(true); + } else { + Intent intent = OrbotHelper.getOrbotInstallIntent(activity); + activity.startActivityForResult(intent, REQUEST_INSTALL_ORBOT); + } + } else { + App.configureTor(false); + } return true; } }); } } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + // try to start tor regardless of resultCode since clicking back after + // installing the app does not necessarily return RESULT_OK + App.configureTor(requestCode == REQUEST_INSTALL_ORBOT + && OrbotHelper.requestStartTor(this)); + } + @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); From b3a1a5dcc23ebc9de26137bdc31a3700ca22d43d Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 2 Jan 2016 21:53:48 +0100 Subject: [PATCH 31/57] Android provides global vars for the actual download directories --- app/src/main/java/org/schabi/newpipe/DownloadDialog.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java index 3001455f9..dd2f2c9d6 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java @@ -61,17 +61,17 @@ public class DownloadDialog extends DialogFragment { String suffix = ""; String title = arguments.getString(TITLE); String url = ""; - String downloadFolder = "Download"; + String downloadFolder = Environment.DIRECTORY_DOWNLOADS; switch(which) { case 0: // Video suffix = arguments.getString(FILE_SUFFIX_VIDEO); url = arguments.getString(VIDEO_URL); - downloadFolder = "Movies"; + downloadFolder = Environment.DIRECTORY_MOVIES; break; case 1: suffix = arguments.getString(FILE_SUFFIX_AUDIO); url = arguments.getString(AUDIO_URL); - downloadFolder = "Music"; + downloadFolder = Environment.DIRECTORY_MUSIC; break; default: Log.d(TAG, "lolz"); From 0bb0226bc2d0d8e90ccc91ce9252d3db6410bf85 Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sat, 2 Jan 2016 22:47:21 +0100 Subject: [PATCH 32/57] download files via Tor when Tor is enabled DownloadManager does not let you set its proxy or change how it connects to the internet. So we have to make a custom one, unfortunately. This is a very basic downloader with none of the special sauce that makes the built-in DownloadManager handy. --- app/src/main/java/org/schabi/newpipe/App.java | 4 ++ .../org/schabi/newpipe/DownloadDialog.java | 24 +++++--- .../java/org/schabi/newpipe/Downloader.java | 56 +++++++++++++++++++ 3 files changed, 75 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index 95127d7fe..877000e61 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -39,4 +39,8 @@ public class App extends Application { OrbotHelper.requestStartTor(context); } } + + static boolean isUsingTor() { + return useTor; + } } diff --git a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java index dd2f2c9d6..c53ab8512 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java @@ -87,15 +87,21 @@ public class DownloadDialog extends DialogFragment { //TODO notify user "download directory should be changed" ? } } - DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); - DownloadManager.Request request = new DownloadManager.Request( - Uri.parse(url)); - request.setDestinationUri(Uri.fromFile(new File(dir + "/" + title + suffix))); - request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); - try { - dm.enqueue(request); - } catch (Exception e) { - e.printStackTrace(); + String saveFilePath = dir + "/" + title + suffix; + if (App.isUsingTor()) { + // if using Tor, do not use DownloadManager because the proxy cannot be set + Downloader.downloadFile(url, saveFilePath); + } else { + DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); + DownloadManager.Request request = new DownloadManager.Request( + Uri.parse(url)); + request.setDestinationUri(Uri.fromFile(new File(saveFilePath))); + request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); + try { + dm.enqueue(request); + } catch (Exception e) { + e.printStackTrace(); + } } } }); diff --git a/app/src/main/java/org/schabi/newpipe/Downloader.java b/app/src/main/java/org/schabi/newpipe/Downloader.java index f0fe75582..b1ada078c 100644 --- a/app/src/main/java/org/schabi/newpipe/Downloader.java +++ b/app/src/main/java/org/schabi/newpipe/Downloader.java @@ -1,9 +1,17 @@ package org.schabi.newpipe; +import android.os.AsyncTask; +import android.util.Log; + +import java.io.BufferedInputStream; import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; +import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; @@ -32,6 +40,7 @@ import info.guardianproject.netcipher.NetCipher; */ public class Downloader { + public static final String TAG = "Downloader"; private static final String USER_AGENT = "Mozilla/5.0"; @@ -97,4 +106,51 @@ public class Downloader { return ret; } + + /** + * Downloads a file from a URL in the background using an {@link AsyncTask}. + * + * @param fileURL HTTP URL of the file to be downloaded + * @param saveFilePath path of the directory to save the file + * @throws IOException + */ + public static void downloadFile(final String fileURL, final String saveFilePath) { + new AsyncTask() { + @Override + protected Void doInBackground(Void... voids) { + HttpsURLConnection con = null; + try { + con = NetCipher.getHttpsURLConnection(fileURL); + int responseCode = con.getResponseCode(); + + // always check HTTP response code first + if (responseCode == HttpURLConnection.HTTP_OK) { + InputStream inputStream = new BufferedInputStream(con.getInputStream()); + FileOutputStream outputStream = new FileOutputStream(saveFilePath); + + int bytesRead = -1; + byte[] buffer = new byte[8192]; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + + outputStream.close(); + inputStream.close(); + + } else { + Log.i(TAG, "No file to download. Server replied HTTP code: " + responseCode); + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (con != null) { + con.disconnect(); + con = null; + } + } + return null; + } + }.execute(); + } + } From 9127f7f0c22591353a4ba3da8737872a2502eb4e Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Sun, 3 Jan 2016 00:04:55 +0100 Subject: [PATCH 33/57] make progress notification for Tor downloader (closes #39) --- .../org/schabi/newpipe/DownloadDialog.java | 2 +- .../java/org/schabi/newpipe/Downloader.java | 53 +++++++++++++++++-- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java index c53ab8512..1f018618a 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java @@ -90,7 +90,7 @@ public class DownloadDialog extends DialogFragment { String saveFilePath = dir + "/" + title + suffix; if (App.isUsingTor()) { // if using Tor, do not use DownloadManager because the proxy cannot be set - Downloader.downloadFile(url, saveFilePath); + Downloader.downloadFile(getContext(), url, saveFilePath); } else { DownloadManager dm = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE); DownloadManager.Request request = new DownloadManager.Request( diff --git a/app/src/main/java/org/schabi/newpipe/Downloader.java b/app/src/main/java/org/schabi/newpipe/Downloader.java index b1ada078c..8a296c61e 100644 --- a/app/src/main/java/org/schabi/newpipe/Downloader.java +++ b/app/src/main/java/org/schabi/newpipe/Downloader.java @@ -1,6 +1,12 @@ package org.schabi.newpipe; +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Context; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.os.AsyncTask; +import android.support.v4.app.NotificationCompat; import android.util.Log; import java.io.BufferedInputStream; @@ -114,8 +120,28 @@ public class Downloader { * @param saveFilePath path of the directory to save the file * @throws IOException */ - public static void downloadFile(final String fileURL, final String saveFilePath) { - new AsyncTask() { + public static void downloadFile(final Context context, final String fileURL, final String saveFilePath) { + new AsyncTask() { + + private NotificationManager nm; + private NotificationCompat.Builder builder; + private int notifyId = 0x1234; + private int fileSize = 0xffffffff; + + @Override + protected void onPreExecute() { + super.onPreExecute(); + nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + Drawable icon = context.getResources().getDrawable(R.mipmap.ic_launcher); + builder = new NotificationCompat.Builder(context) + .setSmallIcon(android.R.drawable.stat_sys_download) + .setLargeIcon(((BitmapDrawable) icon).getBitmap()) + .setContentTitle(saveFilePath.substring(saveFilePath.lastIndexOf('/') + 1)) + .setContentText(saveFilePath) + .setProgress(fileSize, 0, false); + nm.notify(notifyId, builder.build()); + } + @Override protected Void doInBackground(Void... voids) { HttpsURLConnection con = null; @@ -125,17 +151,26 @@ public class Downloader { // always check HTTP response code first if (responseCode == HttpURLConnection.HTTP_OK) { + fileSize = con.getContentLength(); InputStream inputStream = new BufferedInputStream(con.getInputStream()); FileOutputStream outputStream = new FileOutputStream(saveFilePath); + int bufferSize = 8192; + int downloaded = 0; + int bytesRead = -1; - byte[] buffer = new byte[8192]; + byte[] buffer = new byte[bufferSize]; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); + downloaded += bytesRead; + if (downloaded % 50000 < bufferSize) { + publishProgress(downloaded); + } } outputStream.close(); inputStream.close(); + publishProgress(bufferSize); } else { Log.i(TAG, "No file to download. Server replied HTTP code: " + responseCode); @@ -150,6 +185,18 @@ public class Downloader { } return null; } + + @Override + protected void onProgressUpdate(Integer... progress) { + builder.setProgress(fileSize, progress[0], false); + nm.notify(notifyId, builder.build()); + } + + @Override + protected void onPostExecute(Void aVoid) { + super.onPostExecute(aVoid); + nm.cancel(notifyId); + } }.execute(); } From 94d2f03e9bb34c298779ef8e0e9ad712443536fb Mon Sep 17 00:00:00 2001 From: naofum Date: Sun, 3 Jan 2016 10:31:33 +0100 Subject: [PATCH 34/57] Translated using Weblate (Japanese) Currently translated at 100.0% (51 of 51 strings) --- app/src/main/res/values-ja/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index 558918270..c09605941 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -50,4 +50,8 @@ 外部オーディオ プレイヤーを使用する バックグラウンドで再生しています + NewPipe バックグラウンド プレーヤー + 読み込み中 + 再生 + From 0a334804a31c8df5ef14cdec2df15e55a8ccdbfb Mon Sep 17 00:00:00 2001 From: M2ck Date: Sun, 3 Jan 2016 16:56:41 +0100 Subject: [PATCH 35/57] Translated using Weblate (French) Currently translated at 100.0% (51 of 51 strings) --- app/src/main/res/values-fr/strings.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index e1cfeeff0..227877c52 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -50,4 +50,8 @@ Utiliser un lecteur vidéo externe Utiliser un lecteur audio externe Lecture en arrière-plan + Lecteur en arrière-plan NewPipe + Chargement + Lecture + From 9804bb95cc36891fc80b76f0ffeae2465885d800 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mladen=20Pejakovi=C4=87?= Date: Sun, 3 Jan 2016 19:11:18 +0100 Subject: [PATCH 36/57] Translated using Weblate (Serbian) Currently translated at 100.0% (53 of 53 strings) --- app/src/main/res/values-sr/strings.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index 107434167..e0c092d25 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -58,4 +58,6 @@ Учитавам Пусти - + Користи Тор + Принудно преусмерење саобраћаја кроз Тор за доданту приватност (токови још нису подржани) + From a8830e2ede6eed37145eb745507dbc595aac1a3c Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Sun, 3 Jan 2016 19:55:04 +0100 Subject: [PATCH 37/57] preference screen previews set values --- .../java/org/schabi/newpipe/Localization.java | 4 +- .../org/schabi/newpipe/SettingsActivity.java | 75 ++++++++++++++++++- .../schabi/newpipe/VideoItemListFragment.java | 5 +- app/src/main/res/values/settings_keys.xml | 4 +- app/src/main/res/xml/settings_screen.xml | 6 +- 5 files changed, 82 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/Localization.java b/app/src/main/java/org/schabi/newpipe/Localization.java index b38c52a90..796b7878d 100644 --- a/app/src/main/java/org/schabi/newpipe/Localization.java +++ b/app/src/main/java/org/schabi/newpipe/Localization.java @@ -1,6 +1,5 @@ package org.schabi.newpipe; -import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.content.res.Resources; @@ -22,7 +21,8 @@ public class Localization { public static Locale getPreferredLocale(Context context) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - String languageCode = sp.getString(String.valueOf(R.string.searchLanguage), "en"); + String languageCode = sp.getString(String.valueOf(R.string.searchLanguagePreference), + context.getString(R.string.defaultLanguageItem)); if(languageCode.length() == 2) { return new Locale(languageCode); diff --git a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java index f599ebd8b..bfc2a158c 100644 --- a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java @@ -1,14 +1,19 @@ package org.schabi.newpipe; import android.app.Activity; +import android.app.SharedElementCallback; import android.content.Context; import android.content.Intent; +import android.content.SharedPreferences; import android.content.res.Configuration; import android.os.Bundle; import android.preference.CheckBoxPreference; +import android.preference.EditTextPreference; +import android.preference.ListPreference; import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; +import android.preference.PreferenceManager; import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; @@ -40,7 +45,7 @@ import info.guardianproject.netcipher.proxy.OrbotHelper; * along with NewPipe. If not, see . */ -public class SettingsActivity extends PreferenceActivity { +public class SettingsActivity extends PreferenceActivity { private static final int REQUEST_INSTALL_ORBOT = 0x1234; private AppCompatDelegate mDelegate = null; @@ -59,17 +64,52 @@ public class SettingsActivity extends PreferenceActivity { } - public static class SettingsFragment extends PreferenceFragment { + public static class SettingsFragment extends PreferenceFragment{ + SharedPreferences.OnSharedPreferenceChangeListener prefListener; + + // get keys + String DEFAULT_RESOLUTION_PREFERENCE; + String DEFAULT_AUDIO_FORMAT_PREFERENCE; + String SEARCH_LANGUAGE_PREFERENCE; + String DOWNLOAD_PATH_PREFERENCE; + String USE_TOR_KEY; + + private ListPreference defaultResolutionPreference; + private ListPreference defaultAudioFormatPreference; + private ListPreference searchLanguagePreference; + private EditTextPreference downloadPathPreference; private CheckBoxPreference useTorCheckBox; + private SharedPreferences defaultPreferences; + @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings_screen); - // if Orbot is installed, then default to using Tor, the user can still override - useTorCheckBox = (CheckBoxPreference) findPreference(getString(R.string.useTor)); final Activity activity = getActivity(); + + defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity); + + // get keys + DEFAULT_RESOLUTION_PREFERENCE =getString(R.string.defaultResolutionPreference); + DEFAULT_AUDIO_FORMAT_PREFERENCE =getString(R.string.defaultAudioFormatPreference); + SEARCH_LANGUAGE_PREFERENCE =getString(R.string.searchLanguagePreference); + DOWNLOAD_PATH_PREFERENCE = getString(R.string.downloadPathPreference); + USE_TOR_KEY = getString(R.string.useTorKey); + + // get pref objects + defaultResolutionPreference = + (ListPreference) findPreference(DEFAULT_RESOLUTION_PREFERENCE); + defaultAudioFormatPreference = + (ListPreference) findPreference(DEFAULT_AUDIO_FORMAT_PREFERENCE); + searchLanguagePreference = + (ListPreference) findPreference(SEARCH_LANGUAGE_PREFERENCE); + downloadPathPreference = + (EditTextPreference) findPreference(DOWNLOAD_PATH_PREFERENCE); + useTorCheckBox = (CheckBoxPreference) findPreference(USE_TOR_KEY); + + // if Orbot is installed, then default to using Tor, the user can still override final boolean useTor = OrbotHelper.isOrbotInstalled(activity); useTorCheckBox.setDefaultValue(useTor); useTorCheckBox.setChecked(useTor); @@ -90,6 +130,33 @@ public class SettingsActivity extends PreferenceActivity { return true; } }); + + prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() { + @Override + public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, + String key) { + updateSummary(); + } + }; + defaultPreferences.registerOnSharedPreferenceChangeListener(prefListener); + + updateSummary(); + } + + // This is used to show the status of some preference in the description + private void updateSummary() { + defaultResolutionPreference.setSummary( + defaultPreferences.getString(DEFAULT_RESOLUTION_PREFERENCE, + getString(R.string.defaultResolutionListItem))); + defaultAudioFormatPreference.setSummary( + defaultPreferences.getString(DEFAULT_AUDIO_FORMAT_PREFERENCE, + getString(R.string.defaultAudioFormat))); + searchLanguagePreference.setSummary( + defaultPreferences.getString(SEARCH_LANGUAGE_PREFERENCE, + getString(R.string.defaultLanguageItem))); + downloadPathPreference.setSummary( + defaultPreferences.getString(DOWNLOAD_PATH_PREFERENCE, + getString(R.string.downloadLocationSummary))); } } diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java index 93c6074b2..8c9c61456 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java @@ -99,8 +99,9 @@ public class VideoItemListFragment extends ListFragment { public void run() { try { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); - String searchLanguageKey = getContext().getString(R.string.searchLanguage); - String searchLanguage = sp.getString(searchLanguageKey, "en"); + String searchLanguageKey = getContext().getString(R.string.searchLanguagePreference); + String searchLanguage = sp.getString(searchLanguageKey, + getString(R.string.defaultLanguageItem)); SearchEngine.Result result = engine.search(query, page, searchLanguage); Log.i(TAG, "language code passed:\""+searchLanguage+"\""); if(run) { diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index 0ff359a46..a909953ae 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -29,7 +29,8 @@ m4a show_next_video - search_language + search_language + use_tor @@ -111,6 +112,7 @@ ja ko + en Afrikaans Azərbaycan diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml index 4d21b457b..f4de87d49 100644 --- a/app/src/main/res/xml/settings_screen.xml +++ b/app/src/main/res/xml/settings_screen.xml @@ -43,11 +43,11 @@ android:defaultValue="false" /> + android:defaultValue="@string/defaultLanguageItem" /> From 58147e9e12d893bb623da3f87abae5f3f527ec45 Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Sun, 3 Jan 2016 19:44:04 +0000 Subject: [PATCH 38/57] removed commented code in BackgroundPlayer --- app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java index 5573e2771..88e5fad9f 100644 --- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -135,9 +135,6 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare //so calling the blocking prepare() method should be ok mediaPlayer.prepare(); - //alternatively: - //mediaPlayer.setOnPreparedListener(this); - //mediaPlayer.prepareAsync(); //prepare async to not block main thread } catch (IOException ioe) { ioe.printStackTrace(); Log.e(TAG, "video source:" + source); From f451e11f82fe5de0fb6cfb6a9f760bd4fa503325 Mon Sep 17 00:00:00 2001 From: M2ck Date: Sun, 3 Jan 2016 20:51:48 +0100 Subject: [PATCH 39/57] Translated using Weblate (French) Currently translated at 100.0% (53 of 53 strings) --- app/src/main/res/values-fr/strings.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 227877c52..9e241c54c 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -54,4 +54,6 @@ Chargement Lecture - + Utiliser Tor + Forcer le trafic de téléchargement via Tor pour plus de confidentialité (vidéos streaming non supporté) + From 5c492c01a174a0e509cceebc1312a0c9a6272095 Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Mon, 4 Jan 2016 00:10:51 +0100 Subject: [PATCH 40/57] adjusted orbot support and moved on to 0.7.2 --- README.md | 1 + app/build.gradle | 4 +-- app/src/main/java/org/schabi/newpipe/App.java | 11 +++--- .../java/org/schabi/newpipe/Downloader.java | 12 +++---- .../org/schabi/newpipe/SettingsActivity.java | 35 +++++++------------ .../newpipe/services/VideoExtractor.java | 1 + app/src/main/res/xml/settings_screen.xml | 3 +- 7 files changed, 32 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index e6d1d9498..b24ed14af 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ NewPipe does not use any Google framework libraries, or the YouTube API. It only * Open a video in Kodi * Show Next/Related videos * Search YouTube in a specific language +* Orbot/Tor support (no streaming yet) ### Coming Features diff --git a/app/build.gradle b/app/build.gradle index 9eb3ccef7..5eaf3a6c4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "org.schabi.newpipe" minSdkVersion 15 targetSdkVersion 23 - versionCode 10 - versionName "0.7.1" + versionCode 11 + versionName "0.7.2" } buildTypes { release { diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index 877000e61..debb1a2a5 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -15,10 +15,13 @@ public class App extends Application { @Override public void onCreate() { super.onCreate(); - // if Orbot is installed, then default to using Tor, the user can still override - if (OrbotHelper.requestStartTor(this)) { - SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - configureTor(prefs.getBoolean(getString(R.string.useTor), true)); + + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + if(prefs.getBoolean(getString(R.string.useTorKey), false)) { + OrbotHelper.requestStartTor(this); + configureTor(true); + } else { + configureTor(false); } } diff --git a/app/src/main/java/org/schabi/newpipe/Downloader.java b/app/src/main/java/org/schabi/newpipe/Downloader.java index 8a296c61e..cbc4c26c2 100644 --- a/app/src/main/java/org/schabi/newpipe/Downloader.java +++ b/app/src/main/java/org/schabi/newpipe/Downloader.java @@ -1,23 +1,23 @@ package org.schabi.newpipe; -import android.app.Notification; + import android.app.NotificationManager; import android.content.Context; +import android.content.SharedPreferences; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.AsyncTask; +import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; import android.util.Log; import java.io.BufferedInputStream; import java.io.BufferedReader; -import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; -import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; @@ -47,7 +47,6 @@ import info.guardianproject.netcipher.NetCipher; public class Downloader { public static final String TAG = "Downloader"; - private static final String USER_AGENT = "Mozilla/5.0"; /**Download the text file at the supplied URL as in download(String), @@ -59,7 +58,7 @@ public class Downloader { String ret = ""; try { URL url = new URL(siteUrl); - HttpsURLConnection con = NetCipher.getHttpsURLConnection(url); + HttpsURLConnection con = (HttpsURLConnection) url.openConnection(); con.setRequestProperty("Accept-Language", language); ret = dl(con); } @@ -68,8 +67,9 @@ public class Downloader { } return ret; } + /**Common functionality between download(String url) and download(String url, String language)*/ - private static String dl(HttpURLConnection con) throws IOException { + private static String dl(HttpsURLConnection con) throws IOException { StringBuilder response = new StringBuilder(); try { diff --git a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java index bfc2a158c..3f747c2da 100644 --- a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java @@ -109,33 +109,24 @@ public class SettingsActivity extends PreferenceActivity { (EditTextPreference) findPreference(DOWNLOAD_PATH_PREFERENCE); useTorCheckBox = (CheckBoxPreference) findPreference(USE_TOR_KEY); - // if Orbot is installed, then default to using Tor, the user can still override - final boolean useTor = OrbotHelper.isOrbotInstalled(activity); - useTorCheckBox.setDefaultValue(useTor); - useTorCheckBox.setChecked(useTor); - useTorCheckBox.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object o) { - boolean useTor = (Boolean) o; - if (useTor) { - if (OrbotHelper.isOrbotInstalled(activity)) { - App.configureTor(true); - } else { - Intent intent = OrbotHelper.getOrbotInstallIntent(activity); - activity.startActivityForResult(intent, REQUEST_INSTALL_ORBOT); - } - } else { - App.configureTor(false); - } - return true; - } - }); - prefListener = new SharedPreferences.OnSharedPreferenceChangeListener() { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { + Activity a = getActivity(); updateSummary(); + + if (defaultPreferences.getBoolean(USE_TOR_KEY, false)) { + if (OrbotHelper.isOrbotInstalled(a)) { + App.configureTor(true); + OrbotHelper.requestStartTor(a); + } else { + Intent intent = OrbotHelper.getOrbotInstallIntent(a); + a.startActivityForResult(intent, REQUEST_INSTALL_ORBOT); + } + } else { + App.configureTor(false); + } } }; defaultPreferences.registerOnSharedPreferenceChangeListener(prefListener); diff --git a/app/src/main/java/org/schabi/newpipe/services/VideoExtractor.java b/app/src/main/java/org/schabi/newpipe/services/VideoExtractor.java index 9da25fc92..e9735b32e 100644 --- a/app/src/main/java/org/schabi/newpipe/services/VideoExtractor.java +++ b/app/src/main/java/org/schabi/newpipe/services/VideoExtractor.java @@ -107,6 +107,7 @@ public abstract class VideoExtractor { } + //todo: add licence field protected abstract int getErrorCode(); protected abstract String getErrorMessage(); protected abstract String getVideoUrl(String videoId); diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml index f4de87d49..46ad3ecb9 100644 --- a/app/src/main/res/xml/settings_screen.xml +++ b/app/src/main/res/xml/settings_screen.xml @@ -75,7 +75,8 @@ + android:summary="@string/useTorSummary" + android:defaultValue="false"/> From fb4bf0dde41801e8ef757cb6398572e2f03ee354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benedikt=20Gei=C3=9Fler?= Date: Sun, 3 Jan 2016 21:32:40 +0100 Subject: [PATCH 41/57] Translated using Weblate (German) Currently translated at 98.1% (52 of 53 strings) --- app/src/main/res/values-de/strings.xml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index d17fae7bd..11478a6f7 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -44,10 +44,18 @@ VIDEO & AUDIO INFO ETC -Bevorzugte Sprache +Bevorzugte Sprache des Inhalts Video-Vorschau-Bild Video-Vorschau-Bild Nutzerbild - gefällt nicht - gefällt + Gefällt nicht + Gefällt +Lade + Benutze externen Videoabspieler + Benutze externen Audioabspieler + Spiele im Hintergrund ab + Abspielen + + Benutze TOR + Erzwinge das Herunterladen durch TOR für verbesserte Privatsphäre (Videostream noch nicht unterstützt) From c07686576ae3ded4d73e450fd17598d0033f06ca Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Mon, 4 Jan 2016 01:15:13 +0000 Subject: [PATCH 42/57] possible fix for expandedView bug in BackgroundPlayer --- .../org/schabi/newpipe/BackgroundPlayer.java | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java index 58823dcb2..45a5eee9c 100644 --- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -181,6 +181,8 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare openDetailView.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, serviceId); openDetailView.putExtra(VideoItemDetailFragment.VIDEO_URL, webUrl); openDetailView.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + + note.contentIntent = PendingIntent.getActivity(getApplicationContext(), noteID, openDetailView, PendingIntent.FLAG_UPDATE_CURRENT); @@ -204,6 +206,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare }*/ } + /**Handles button presses from the notification. */ private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -214,7 +217,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare mediaPlayer.pause(); } else { - //reacquire CPU lock after releasing it on pause + //reacquire CPU lock after auto-releasing it on pause mediaPlayer.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK); mediaPlayer.start(); } @@ -228,8 +231,9 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare }; private void afterPlayCleanup() { - //noteBuilder.setProgress(0, 0, false); //remove progress bar + //noteBuilder.setProgress(0, 0, false); + //remove notification noteMgr.cancel(noteID); unregisterReceiver(broadcastReceiver); @@ -238,7 +242,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare //release wifilock wifiLock.release(); - //remove foreground status of service; make us killable + //remove foreground status of service; make BackgroundPlayer killable stopForeground(true); stopSelf(); @@ -289,6 +293,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare noteBuilder .setContentTitle(title) //really? Id like to put something more helpful here. + //was more of a placeholder than anything else. -medavox //.setContentText("NewPipe is playing in the background") .setContentText(channelName) //.setAutoCancel(!mediaPlayer.isPlaying()) @@ -300,6 +305,8 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare //.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) //.setLargeIcon(cover) + //is wrapping this in an SDK version check really necessary, + // if we're using NotificationCompat? -medavox if (android.os.Build.VERSION.SDK_INT >= 16) noteBuilder.setPriority(Notification.PRIORITY_LOW); @@ -313,6 +320,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare } note = noteBuilder.build(); } else { + //Log.i(TAG, "API is version 21 or above"); RemoteViews view = new RemoteViews(BuildConfig.APPLICATION_ID, R.layout.player_notification); view.setImageViewBitmap(R.id.backgroundCover, videoThumbnail); @@ -321,8 +329,10 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare view.setOnClickPendingIntent(R.id.backgroundStop, stopPI); view.setOnClickPendingIntent(R.id.backgroundPlayPause, playPI); + //possibly found the expandedView problem, + //but can't test it as I don't have a 5.0 device. -medavox RemoteViews expandedView = - new RemoteViews(BuildConfig.APPLICATION_ID, R.layout.player_notification); + new RemoteViews(BuildConfig.APPLICATION_ID, R.layout.player_notification_expanded); expandedView.setImageViewBitmap(R.id.backgroundCover, videoThumbnail); expandedView.setTextViewText(R.id.backgroundSongName, title); expandedView.setTextViewText(R.id.backgroundArtist, channelName); From d610e4b19b8271c76f16ac188fa0ab15a30f8a48 Mon Sep 17 00:00:00 2001 From: Adam Howard Date: Mon, 4 Jan 2016 01:51:24 +0000 Subject: [PATCH 43/57] minor code tweaks to BackgroundPlayer --- .../org/schabi/newpipe/BackgroundPlayer.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java index 45a5eee9c..bb14afeba 100644 --- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -176,17 +176,6 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare Notification note = buildNotification(); - Intent openDetailView = new Intent(getApplicationContext(), - VideoItemDetailActivity.class); - openDetailView.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, serviceId); - openDetailView.putExtra(VideoItemDetailFragment.VIDEO_URL, webUrl); - openDetailView.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - - - note.contentIntent = PendingIntent.getActivity(getApplicationContext(), - noteID, openDetailView, - PendingIntent.FLAG_UPDATE_CURRENT); - startForeground(noteID, note); //currently decommissioned progressbar looping update code - works, but doesn't fit inside @@ -274,6 +263,13 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare (R.drawable.ic_pause_white_24dp, "Pause", playPI).build(); */ + //build intent to return to video, on tapping notification + Intent openDetailView = new Intent(getApplicationContext(), + VideoItemDetailActivity.class); + openDetailView.putExtra(VideoItemDetailFragment.STREAMING_SERVICE, serviceId); + openDetailView.putExtra(VideoItemDetailFragment.VIDEO_URL, webUrl); + openDetailView.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + noteBuilder .setOngoing(true) .setDeleteIntent(stopPI) @@ -282,7 +278,11 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare .setSmallIcon(R.drawable.ic_play_circle_filled_white_24dp) .setTicker( String.format(res.getString( - R.string.backgroundPlayerTickerText), title)); + R.string.backgroundPlayerTickerText), title)) + .setContentIntent(PendingIntent.getActivity(getApplicationContext(), + noteID, openDetailView, + PendingIntent.FLAG_UPDATE_CURRENT)); + if (android.os.Build.VERSION.SDK_INT < 21) { @@ -306,7 +306,8 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare //.setLargeIcon(cover) //is wrapping this in an SDK version check really necessary, - // if we're using NotificationCompat? -medavox + // if we're using NotificationCompat? + // the compat libraries should handle this, right? -medavox if (android.os.Build.VERSION.SDK_INT >= 16) noteBuilder.setPriority(Notification.PRIORITY_LOW); @@ -320,7 +321,6 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare } note = noteBuilder.build(); } else { - //Log.i(TAG, "API is version 21 or above"); RemoteViews view = new RemoteViews(BuildConfig.APPLICATION_ID, R.layout.player_notification); view.setImageViewBitmap(R.id.backgroundCover, videoThumbnail); From 1a56382112ff1a7e983d8ccf09090bce3d8deff0 Mon Sep 17 00:00:00 2001 From: naofum Date: Mon, 4 Jan 2016 11:49:08 +0100 Subject: [PATCH 44/57] Translated using Weblate (Japanese) Currently translated at 100.0% (53 of 53 strings) --- app/src/main/res/values-ja/strings.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index c09605941..decc2ecba 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -54,4 +54,6 @@ 読み込み中 再生 - + Tor を使用する + 強制的に Tor を経由したプライバシーを高めたトラフィックでダウンロードします (ビデオのストリーミングはまだサポートされていません) + From 95949fd1ab67b7d4c0fd225c141fb77ae87e0982 Mon Sep 17 00:00:00 2001 From: Aitor Beriain Date: Mon, 4 Jan 2016 19:35:11 +0100 Subject: [PATCH 45/57] Translated using Weblate (Basque) Currently translated at 100% (0 of 0 strings) Created new translation. --- app/src/main/res/values-eu/strings.xml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 app/src/main/res/values-eu/strings.xml diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml new file mode 100644 index 000000000..a6b3daec9 --- /dev/null +++ b/app/src/main/res/values-eu/strings.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file From 0aade598ffc95083bd62815721fe5da8a2980bd8 Mon Sep 17 00:00:00 2001 From: Aitor Beriain Date: Mon, 4 Jan 2016 20:01:47 +0100 Subject: [PATCH 46/57] Translated using Weblate (Basque) Currently translated at 100.0% (53 of 53 strings) --- app/src/main/res/values-eu/strings.xml | 58 +++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index a6b3daec9..9ebf236ea 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -1,2 +1,56 @@ - - \ No newline at end of file + +%1$s ikustaldi + Argitaratze-data: %1$s + Instalatu + Utzi + Nabigatzailean ireki + Partekatu + Kargatzen + Deskargatu + Bilatu + Ezarpenak + Partekatu honekin: + Nabigatzailea aukeratu: + biratzea + Ezarpenak + Deskargatzeko kokapena + Deskargatutako bideoak gordetzeko lekua. + Sar ezazu deskargatzeko lekua + Lehenetsitako bereizmena + Kodirekin erreproduzitu + Kore aplikazioa ez da aurkitu. Kore beharrezkoa da Kodi multimedia zentroarekin bideoak erreproduzitzeko. + Kore instalatu + \"Kodirekin erreproduzitu\" aukera erakutsi + Kodi multimedia zentroarekin bideoa erreproduzitzeko aukera erakusten du. + Audioa + Audio formatu lehenetsia + WebM - formatu askea + m4a - kalitate hobea + Deskargatu + Hurrengo bideoa + Hurrengo bideoa eta antzekoak erakutsi + URLa ez da onartzen. + Antzeko bideoak + Edukiaren hizkuntz lehenetsia + BIDEOA ETA AUDIOA + INFORMAZIOA + ETAB + Erreproduzitu + + Bideoaren aurreikuspen argazkitxoa + Bideoaren aurreikuspen argazkitxoa + Igotzailearen argazkitxoa + Ez dute gustoko + Gustoko dute + Tor erabili + Trafikoa Tor bidez deskargatzea behartzen du pribatutasuna hobetzeko (jario bideoak ez daude oraindik onartuta) +NewPipe atzeko planoko erreproduzitzailea + Jario erreproduzitzailerik ez da aurkitu. Agian bat instalatu nahi dezakezu. + "Hau esan nahi al zenuen: " + "Orrialdea bilatu: " + Kanpoko bideo erreproduzitzailea erabili + Kanpoko audio erreproduzitzailea erabili + Intent bidez automatikoki erreproduzitu + Bideoa automatikoki hasten du beste aplikazio batetik deitu denean. + Atzeko planoan erreproduzitzen + From 8ced68430d4e9067e5c388191dff86a1f0dc7c14 Mon Sep 17 00:00:00 2001 From: chschtsch Date: Tue, 5 Jan 2016 22:56:40 +0300 Subject: [PATCH 47/57] update resources names to match naming convention & cleanup & start working on themes --- CONTRIBUTING.md | 8 +- app/src/main/AndroidManifest.xml | 2 +- .../org/schabi/newpipe/ActionBarHandler.java | 34 +++--- app/src/main/java/org/schabi/newpipe/App.java | 2 +- .../org/schabi/newpipe/BackgroundPlayer.java | 6 +- .../org/schabi/newpipe/DownloadDialog.java | 6 +- .../java/org/schabi/newpipe/Localization.java | 8 +- .../org/schabi/newpipe/PlayVideoActivity.java | 2 +- .../org/schabi/newpipe/SettingsActivity.java | 23 ++-- .../newpipe/VideoItemDetailActivity.java | 4 +- .../newpipe/VideoItemDetailFragment.java | 4 +- .../schabi/newpipe/VideoItemListActivity.java | 2 +- .../schabi/newpipe/VideoItemListFragment.java | 8 +- .../org/schabi/newpipe/VideoListAdapter.java | 2 +- .../layout-v18/fragment_videoitem_detail.xml | 16 +-- .../layout-v21/fragment_videoitem_detail.xml | 18 +-- .../res/layout/fragment_videoitem_detail.xml | 16 +-- app/src/main/res/layout/video_item.xml | 6 +- app/src/main/res/menu/video_player.xml | 2 +- app/src/main/res/menu/videoitem_detail.xml | 4 +- app/src/main/res/values-de/strings.xml | 88 ++++++++------- app/src/main/res/values-es/strings.xml | 56 +++++----- app/src/main/res/values-eu/strings.xml | 90 ++++++++------- app/src/main/res/values-fa/strings.xml | 54 ++++----- app/src/main/res/values-fr/strings.xml | 87 ++++++++------- app/src/main/res/values-he/strings.xml | 8 +- app/src/main/res/values-hu/strings.xml | 58 +++++----- app/src/main/res/values-it/strings.xml | 72 ++++++------ app/src/main/res/values-ja/strings.xml | 86 +++++++-------- app/src/main/res/values-ko/strings.xml | 72 ++++++------ app/src/main/res/values-nl/strings.xml | 76 +++++++------ app/src/main/res/values-pl/strings.xml | 81 +++++++------- app/src/main/res/values-pt/strings.xml | 76 ++++++------- app/src/main/res/values-ru/strings.xml | 82 +++++++------- app/src/main/res/values-sl/strings.xml | 81 +++++++------- app/src/main/res/values-sr/strings.xml | 87 ++++++++------- app/src/main/res/values-v21/styles.xml | 22 ++-- app/src/main/res/values/colors.xml | 23 ++-- app/src/main/res/values/settings_keys.xml | 61 +++++++---- app/src/main/res/values/strings.xml | 103 +++++++++--------- app/src/main/res/values/styles.xml | 18 +-- app/src/main/res/xml/settings.xml | 95 ++++++++++++++++ app/src/main/res/xml/settings_screen.xml | 82 -------------- 43 files changed, 878 insertions(+), 853 deletions(-) create mode 100644 app/src/main/res/xml/settings.xml delete mode 100644 app/src/main/res/xml/settings_screen.xml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 149c4ba54..ede4461a9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,11 +1,11 @@ -#Contributing +#Contribution This document contains guidelines on making contributions to NewPipe. ## Programming * Follow the [Google Style Guidelines](https://google.github.io/styleguide/javaguide.html) -* Make a new feature on a seperate branch, not on the master branch +* Make a new feature on a separate branch, not on the master branch * Make a [pull request](https://github.com/theScrabi/NewPipe/pulls) if you're done with your changes * When submitting changes, you agree that your code will be GPLv3 licensed @@ -16,7 +16,7 @@ This document contains guidelines on making contributions to NewPipe. compatibility with all git tools * [This guide](http://chris.beams.io/posts/git-commit/) goes more in depth on what makes a good commit message -## Translating +## Translation * NewPipe can be translated on [weblate](https://hosted.weblate.org/projects/newpipe/strings/) @@ -30,4 +30,4 @@ This document contains guidelines on making contributions to NewPipe. ## Communication * For the time being, [Slack](http://invite.chschtsch.ml/) is being used for project communication -* Feel free to post suggestions, changes ideas etc! +* Feel free to post suggestions, changes, ideas etc! diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index ef84c57b3..2f2ec061b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -84,7 +84,7 @@ android:exported="false" /> + android:label="@string/settings_activity_title" > = 18) { @@ -355,13 +355,13 @@ class ActionBarHandler { } catch (Exception e) { e.printStackTrace(); AlertDialog.Builder builder = new AlertDialog.Builder(activity); - builder.setMessage(R.string.noPlayerFound) - .setPositiveButton(R.string.installStreamPlayer, new DialogInterface.OnClickListener() { + builder.setMessage(R.string.no_player_found) + .setPositiveButton(R.string.install, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); - intent.setData(Uri.parse(activity.getString(R.string.fdroidVLCurl))); + intent.setData(Uri.parse(activity.getString(R.string.fdroid_vlc_url))); activity.startActivity(intent); } }) diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index debb1a2a5..71aca041b 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -17,7 +17,7 @@ public class App extends Application { super.onCreate(); SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - if(prefs.getBoolean(getString(R.string.useTorKey), false)) { + if(prefs.getBoolean(getString(R.string.use_tor_key), false)) { OrbotHelper.requestStartTor(this); configureTor(true); } else { diff --git a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java index bb14afeba..cf0f88d05 100644 --- a/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java +++ b/app/src/main/java/org/schabi/newpipe/BackgroundPlayer.java @@ -75,7 +75,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare } @Override public int onStartCommand(Intent intent, int flags, int startId) { - Toast.makeText(this, R.string.backgroundPlayerStartPlayingToast, + Toast.makeText(this, R.string.background_player_playing_toast, Toast.LENGTH_SHORT).show(); String source = intent.getDataString(); @@ -278,7 +278,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare .setSmallIcon(R.drawable.ic_play_circle_filled_white_24dp) .setTicker( String.format(res.getString( - R.string.backgroundPlayerTickerText), title)) + R.string.background_player_time_text), title)) .setContentIntent(PendingIntent.getActivity(getApplicationContext(), noteID, openDetailView, PendingIntent.FLAG_UPDATE_CURRENT)); @@ -288,7 +288,7 @@ public class BackgroundPlayer extends Service /*implements MediaPlayer.OnPrepare NotificationCompat.Action playButton = new NotificationCompat.Action.Builder (R.drawable.ic_play_arrow_white_48dp, - res.getString(R.string.play), playPI).build(); + res.getString(R.string.play_btn_text), playPI).build(); noteBuilder .setContentTitle(title) diff --git a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java index 1f018618a..ba289f013 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java @@ -52,8 +52,8 @@ public class DownloadDialog extends DialogFragment { arguments = getArguments(); super.onCreateDialog(savedInstanceState); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); - builder.setTitle(R.string.downloadDialogTitle) - .setItems(R.array.downloadOptions, new DialogInterface.OnClickListener() { + builder.setTitle(R.string.download_dialog_title) + .setItems(R.array.download_options, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Context context = getActivity(); @@ -77,7 +77,7 @@ public class DownloadDialog extends DialogFragment { Log.d(TAG, "lolz"); } //to avoid hard-coded string like "/storage/emulated/0/Movies" - String downloadPath = prefs.getString(getString(R.string.downloadPathPreference), + String downloadPath = prefs.getString(getString(R.string.download_path_key), Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + downloadFolder); final File dir = new File(downloadPath); if(!dir.exists()) { diff --git a/app/src/main/java/org/schabi/newpipe/Localization.java b/app/src/main/java/org/schabi/newpipe/Localization.java index 796b7878d..fb3e09ed1 100644 --- a/app/src/main/java/org/schabi/newpipe/Localization.java +++ b/app/src/main/java/org/schabi/newpipe/Localization.java @@ -21,8 +21,8 @@ public class Localization { public static Locale getPreferredLocale(Context context) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - String languageCode = sp.getString(String.valueOf(R.string.searchLanguagePreference), - context.getString(R.string.defaultLanguageItem)); + String languageCode = sp.getString(String.valueOf(R.string.search_language_key), + context.getString(R.string.default_language_value)); if(languageCode.length() == 2) { return new Locale(languageCode); @@ -39,7 +39,7 @@ public class Localization { Locale locale = getPreferredLocale(context); Resources res = context.getResources(); - String viewsString = res.getString(R.string.viewCountText); + String viewsString = res.getString(R.string.view_count_text); NumberFormat nf = NumberFormat.getInstance(locale); String formattedViewCount = nf.format(viewCount); @@ -69,7 +69,7 @@ public class Localization { public static String localizeDate(String date, Context context) { Resources res = context.getResources(); - String dateString = res.getString(R.string.uploadDateText); + String dateString = res.getString(R.string.upload_date_text); String formattedDate = formatDate(date, context); return String.format(dateString, formattedDate); diff --git a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java index 13a1cefed..ce1cf64cd 100644 --- a/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java +++ b/app/src/main/java/org/schabi/newpipe/PlayVideoActivity.java @@ -211,7 +211,7 @@ public class PlayVideoActivity extends AppCompatActivity { intent.setAction(Intent.ACTION_SEND); intent.putExtra(Intent.EXTRA_TEXT, videoUrl); intent.setType("text/plain"); - startActivity(Intent.createChooser(intent, getString(R.string.shareDialogTitle))); + startActivity(Intent.createChooser(intent, getString(R.string.share_dialog_title))); break; case R.id.menu_item_screen_rotation: toggleOrientation(); diff --git a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java index 3f747c2da..47a11e31f 100644 --- a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java @@ -1,8 +1,6 @@ package org.schabi.newpipe; import android.app.Activity; -import android.app.SharedElementCallback; -import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; @@ -10,7 +8,6 @@ import android.os.Bundle; import android.preference.CheckBoxPreference; import android.preference.EditTextPreference; import android.preference.ListPreference; -import android.preference.Preference; import android.preference.PreferenceActivity; import android.preference.PreferenceFragment; import android.preference.PreferenceManager; @@ -85,18 +82,18 @@ public class SettingsActivity extends PreferenceActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - addPreferencesFromResource(R.xml.settings_screen); + addPreferencesFromResource(R.xml.settings); final Activity activity = getActivity(); defaultPreferences = PreferenceManager.getDefaultSharedPreferences(activity); // get keys - DEFAULT_RESOLUTION_PREFERENCE =getString(R.string.defaultResolutionPreference); - DEFAULT_AUDIO_FORMAT_PREFERENCE =getString(R.string.defaultAudioFormatPreference); - SEARCH_LANGUAGE_PREFERENCE =getString(R.string.searchLanguagePreference); - DOWNLOAD_PATH_PREFERENCE = getString(R.string.downloadPathPreference); - USE_TOR_KEY = getString(R.string.useTorKey); + DEFAULT_RESOLUTION_PREFERENCE =getString(R.string.default_resolution_key); + DEFAULT_AUDIO_FORMAT_PREFERENCE =getString(R.string.default_audio_format_key); + SEARCH_LANGUAGE_PREFERENCE =getString(R.string.search_language_key); + DOWNLOAD_PATH_PREFERENCE = getString(R.string.download_path_key); + USE_TOR_KEY = getString(R.string.use_tor_key); // get pref objects defaultResolutionPreference = @@ -138,16 +135,16 @@ public class SettingsActivity extends PreferenceActivity { private void updateSummary() { defaultResolutionPreference.setSummary( defaultPreferences.getString(DEFAULT_RESOLUTION_PREFERENCE, - getString(R.string.defaultResolutionListItem))); + getString(R.string.default_resolution_value))); defaultAudioFormatPreference.setSummary( defaultPreferences.getString(DEFAULT_AUDIO_FORMAT_PREFERENCE, - getString(R.string.defaultAudioFormat))); + getString(R.string.default_audio_format_value))); searchLanguagePreference.setSummary( defaultPreferences.getString(SEARCH_LANGUAGE_PREFERENCE, - getString(R.string.defaultLanguageItem))); + getString(R.string.default_language_value))); downloadPathPreference.setSummary( defaultPreferences.getString(DOWNLOAD_PATH_PREFERENCE, - getString(R.string.downloadLocationSummary))); + getString(R.string.download_path_summary))); } } diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java index f93ca4b9e..bf28549b3 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailActivity.java @@ -80,7 +80,7 @@ public class VideoItemDetailActivity extends AppCompatActivity { } } if(currentStreamingService == -1) { - Toast.makeText(this, R.string.urlNotSupportedText, Toast.LENGTH_LONG) + Toast.makeText(this, R.string.url_not_supported_toast, Toast.LENGTH_LONG) .show(); } //arguments.putString(VideoItemDetailFragment.VIDEO_URL, @@ -89,7 +89,7 @@ public class VideoItemDetailActivity extends AppCompatActivity { arguments.putBoolean(VideoItemDetailFragment.AUTO_PLAY, PreferenceManager.getDefaultSharedPreferences(this) - .getBoolean(getString(R.string.autoPlayThroughIntent), false)); + .getBoolean(getString(R.string.autoplay_through_intent_key), false)); } else { videoUrl = getIntent().getStringExtra(VideoItemDetailFragment.VIDEO_URL); currentStreamingService = getIntent().getIntExtra(VideoItemDetailFragment.STREAMING_SERVICE, -1); diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java index ddec1e36e..03ec4e5aa 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemDetailFragment.java @@ -302,7 +302,7 @@ public class VideoItemDetailFragment extends Fragment { public void onClick(View v) { Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); - intent.setData(Uri.parse(activity.getString(R.string.c3sUrl))); + intent.setData(Uri.parse(activity.getString(R.string.c3s_url))); activity.startActivity(intent); } }); @@ -345,7 +345,7 @@ public class VideoItemDetailFragment extends Fragment { super.onCreate(savedInstanceState); activity = (AppCompatActivity) getActivity(); showNextVideoItem = PreferenceManager.getDefaultSharedPreferences(getActivity()) - .getBoolean(activity.getString(R.string.showNextVideo), true); + .getBoolean(activity.getString(R.string.show_next_video_key), true); } diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java index 8c4f5c57e..446b916b5 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListActivity.java @@ -172,7 +172,7 @@ public class VideoItemListActivity extends AppCompatActivity } } - PreferenceManager.setDefaultValues(this, R.xml.settings_screen, false); + PreferenceManager.setDefaultValues(this, R.xml.settings, false); } @Override diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java index 8c9c61456..4373a1697 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java @@ -99,9 +99,9 @@ public class VideoItemListFragment extends ListFragment { public void run() { try { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext()); - String searchLanguageKey = getContext().getString(R.string.searchLanguagePreference); + String searchLanguageKey = getContext().getString(R.string.search_language_key); String searchLanguage = sp.getString(searchLanguageKey, - getString(R.string.defaultLanguageItem)); + getString(R.string.default_language_value)); SearchEngine.Result result = engine.search(query, page, searchLanguage); Log.i(TAG, "language code passed:\""+searchLanguage+"\""); if(run) { @@ -205,7 +205,7 @@ public class VideoItemListFragment extends ListFragment { private void nextPage() { lastPage++; - Log.d(TAG, getString(R.string.searchPage) + Integer.toString(lastPage)); + Log.d(TAG, getString(R.string.search_page) + Integer.toString(lastPage)); startSearch(query, lastPage); } @@ -229,7 +229,7 @@ public class VideoItemListFragment extends ListFragment { Toast.makeText(getActivity(), result.errorMessage, Toast.LENGTH_LONG).show(); } else { if (!result.suggestion.isEmpty()) { - Toast.makeText(getActivity(), getString(R.string.didYouMean) + result.suggestion + " ?", + Toast.makeText(getActivity(), getString(R.string.did_you_mean) + result.suggestion + " ?", Toast.LENGTH_LONG).show(); } updateList(result.resultList); diff --git a/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java b/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java index 70672d040..de08b2f03 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java +++ b/app/src/main/java/org/schabi/newpipe/VideoListAdapter.java @@ -99,7 +99,7 @@ class VideoListAdapter extends BaseAdapter { convertView = viewCreator.getViewFromVideoInfoItem(convertView, parent, videoList.get(position), context); if(listView.isItemChecked(position)) { - convertView.setBackgroundColor(ContextCompat.getColor(context,R.color.primaryColorYoutube)); + convertView.setBackgroundColor(ContextCompat.getColor(context,R.color.light_youtube_primary_color)); } else { convertView.setBackgroundColor(0); } diff --git a/app/src/main/res/layout-v18/fragment_videoitem_detail.xml b/app/src/main/res/layout-v18/fragment_videoitem_detail.xml index 91cfea986..cbb5652ca 100644 --- a/app/src/main/res/layout-v18/fragment_videoitem_detail.xml +++ b/app/src/main/res/layout-v18/fragment_videoitem_detail.xml @@ -11,7 +11,7 @@ android:id="@+id/videoitem_detail"> @@ -69,7 +69,7 @@ android:layout_height="wrap_content" android:padding="@dimen/video_item_detail_info_text_padding" android:layout_below="@id/detailVideoThumbnailWindowLayout" - android:background="@color/background_gray"> + android:background="@color/light_background_color"> + android:text="@string/similar_videos_btn_text"/> diff --git a/app/src/main/res/layout-v21/fragment_videoitem_detail.xml b/app/src/main/res/layout-v21/fragment_videoitem_detail.xml index 8d19e1fee..b7919dbe8 100644 --- a/app/src/main/res/layout-v21/fragment_videoitem_detail.xml +++ b/app/src/main/res/layout-v21/fragment_videoitem_detail.xml @@ -11,7 +11,7 @@ android:id="@+id/videoitem_detail"> @@ -71,7 +71,7 @@ android:layout_height="wrap_content" android:padding="@dimen/video_item_detail_info_text_padding" android:layout_below="@id/detailVideoThumbnailWindowLayout" - android:background="@color/background_gray"> + android:background="@color/light_background_color"> + android:text="@string/similar_videos_btn_text"/> diff --git a/app/src/main/res/layout/fragment_videoitem_detail.xml b/app/src/main/res/layout/fragment_videoitem_detail.xml index 987c416ec..3ef048e46 100644 --- a/app/src/main/res/layout/fragment_videoitem_detail.xml +++ b/app/src/main/res/layout/fragment_videoitem_detail.xml @@ -28,7 +28,7 @@ android:background="?attr/selectableItemBackground"> @@ -69,7 +69,7 @@ android:layout_height="wrap_content" android:padding="@dimen/video_item_detail_info_text_padding" android:layout_below="@id/detailVideoThumbnailWindowLayout" - android:background="@color/background_gray"> + android:background="@color/light_background_color"> + android:text="@string/similar_videos_btn_text"/> diff --git a/app/src/main/res/layout/video_item.xml b/app/src/main/res/layout/video_item.xml index 1c7caac60..cff3a4224 100644 --- a/app/src/main/res/layout/video_item.xml +++ b/app/src/main/res/layout/video_item.xml @@ -32,7 +32,7 @@ tools:ignore="RtlHardcoded"> + android:background="@color/duration_dackground_color" + android:textColor="@color/duration_text_color"/> diff --git a/app/src/main/res/menu/video_player.xml b/app/src/main/res/menu/video_player.xml index f82730139..c79217adc 100644 --- a/app/src/main/res/menu/video_player.xml +++ b/app/src/main/res/menu/video_player.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> \ No newline at end of file diff --git a/app/src/main/res/menu/videoitem_detail.xml b/app/src/main/res/menu/videoitem_detail.xml index 4fed67637..f10a0a63e 100644 --- a/app/src/main/res/menu/videoitem_detail.xml +++ b/app/src/main/res/menu/videoitem_detail.xml @@ -3,7 +3,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> @@ -18,7 +18,7 @@ android:icon="@drawable/ic_share_black"/> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 11478a6f7..fdef2ba3e 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -1,61 +1,59 @@ - %1$s Aufrufe - Hochgeladen am %1$s - Keinen Streamplayer gefunden. Vielleicht möchtest du einen installieren. - Jetzt installieren + %1$s Aufrufe + Hochgeladen am %1$s + Keinen Streamplayer gefunden. Vielleicht möchtest du einen installieren. + Jetzt installieren Abbrechen In Browser öffnen Teilen Download Suchen Einstellungen - Meintest du: - Suchseite: - Teilen mit: - Browser: - Rotation - Einstellungen + Meintest du: + Suchseite: + Teilen mit: + Browser: + Rotation + Einstellungen Externen Player benutzen - Downloadverzeichnis - Verzeichnis in dem heruntergeladene Videos gespeichert werden. - Download Verzeichnis eingeben - Automatisches Abspielen durch Intent - Startet ein Video automatisch wenn es von einer anderen App aufgerufen wurde. - Standard Auflösung - Mit Kodi abspielen - Kore app wurde nicht gefunden. Kore wird benötigt, um Videos mit Kodi wieder zu geben. + Downloadverzeichnis + Verzeichnis in dem heruntergeladene Videos gespeichert werden. + Download Verzeichnis eingeben + Automatisches Abspielen durch Intent + Startet ein Video automatisch wenn es von einer anderen App aufgerufen wurde. + Standard Auflösung + Mit Kodi abspielen + Kore app wurde nicht gefunden. Kore wird benötigt, um Videos mit Kodi wieder zu geben. Kore installieren - Zeige \"Mit Kodi abspielen\" Option - Zeigt eine Option an, über die man Videos mit dem Kodi Mediacenter abspielen kann. - Audio - Bevorzugtes Audio Format - WebM - freies Format - m4a - bessere Qualität - Herunterladen + Zeige \"Mit Kodi abspielen\" Option + Zeigt eine Option an, über die man Videos mit dem Kodi Mediacenter abspielen kann. + Audio + Bevorzugtes Audio Format + WebM — freies Format + m4a — bessere Qualität + Herunterladen Video Audio - Nächstes Video - Zeige nächstes und ähnliche Videos - URL wird nicht unterstützt. - Ähnliche Videos - VIDEO & AUDIO - INFO - ETC -Bevorzugte Sprache des Inhalts - Video-Vorschau-Bild - Video-Vorschau-Bild - Nutzerbild - Gefällt nicht - Gefällt -Lade - Benutze externen Videoabspieler - Benutze externen Audioabspieler - Spiele im Hintergrund ab - Abspielen + Nächstes Video + Zeige nächstes und ähnliche Videos + URL wird nicht unterstützt. + Ähnliche Videos + Video & Audio + Bevorzugte Sprache des Inhalts + Video-Vorschau-Bild + Video-Vorschau-Bild + Nutzerbild + Gefällt nicht + Gefällt + Lade + Benutze externen Videoabspieler + Benutze externen Audioabspieler + Spiele im Hintergrund ab + Abspielen - Benutze TOR - Erzwinge das Herunterladen durch TOR für verbesserte Privatsphäre (Videostream noch nicht unterstützt) + Benutze TOR + Erzwinge das Herunterladen durch TOR für verbesserte Privatsphäre (Videostream noch nicht unterstützt) diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index bcf25e8fa..3b91eb0d4 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1,39 +1,39 @@ - %1$s visitas - Subido el %1$s - No se ha encontrado ningún reproductor de vídeo. Quizás quieras instalar alguno. - Instalarlo + %1$s visitas + Subido el %1$s + No se ha encontrado ningún reproductor de vídeo. Quizás quieras instalar alguno. + Instalarlo Cancelar Abrir en el navegador Compartir Descargar Buscar Ajustes - "¿Querías decir?: " - Buscar página: - Compartir con: - Selecciona navegador: - rotación - Ajustes + "¿Querías decir?: " + Buscar página: + Compartir con: + Selecciona navegador: + rotación + Ajustes Usar reproductor externo - Descargar en… - Ruta donde guardar los vídeos descargados. - Localización del directorio de descargas - Reproducción automática - Reproducir los vídeos automaticamente cuando se llama desde otra aplicación. - Resolución por defecto - Reproducir con Kodi - Aplicación Kore no encontrada. Kore es necesario para reproducir vídeos con Kodi media center. + Descargar en… + Ruta donde guardar los vídeos descargados. + Localización del directorio de descargas + Reproducción automática + Reproducir los vídeos automaticamente cuando se llama desde otra aplicación. + Resolución por defecto + Reproducir con Kodi + Aplicación Kore no encontrada. Kore es necesario para reproducir vídeos con Kodi media center. Instalar Kore - Mostrar la opción \"Reproducir con Kodi\" - Muestra una opción para reproducir el vídeo con Kodi media center. - Audio - Formato de audio por defecto - WebM - formato libre - m4a - mejor calidad - Descargar - Siguiente vídeo - URL no soportada. - Vídeos similares + Mostrar la opción \"Reproducir con Kodi\" + Muestra una opción para reproducir el vídeo con Kodi media center. + Audio + Formato de audio por defecto + WebM — formato libre + m4a — mejor calidad + Descargar + Siguiente vídeo + URL no soportada. + Vídeos similares diff --git a/app/src/main/res/values-eu/strings.xml b/app/src/main/res/values-eu/strings.xml index 9ebf236ea..7d0a7710e 100644 --- a/app/src/main/res/values-eu/strings.xml +++ b/app/src/main/res/values-eu/strings.xml @@ -1,7 +1,7 @@ -%1$s ikustaldi - Argitaratze-data: %1$s - Instalatu +%1$s ikustaldi + Argitaratze-data: %1$s + Instalatu Utzi Nabigatzailean ireki Partekatu @@ -9,48 +9,46 @@ Deskargatu Bilatu Ezarpenak - Partekatu honekin: - Nabigatzailea aukeratu: - biratzea - Ezarpenak - Deskargatzeko kokapena - Deskargatutako bideoak gordetzeko lekua. - Sar ezazu deskargatzeko lekua - Lehenetsitako bereizmena - Kodirekin erreproduzitu - Kore aplikazioa ez da aurkitu. Kore beharrezkoa da Kodi multimedia zentroarekin bideoak erreproduzitzeko. + Partekatu honekin: + Nabigatzailea aukeratu: + biratzea + Ezarpenak + Deskargatzeko kokapena + Deskargatutako bideoak gordetzeko lekua. + Sar ezazu deskargatzeko lekua + Lehenetsitako bereizmena + Kodirekin erreproduzitu + Kore aplikazioa ez da aurkitu. Kore beharrezkoa da Kodi multimedia zentroarekin bideoak erreproduzitzeko. Kore instalatu - \"Kodirekin erreproduzitu\" aukera erakutsi - Kodi multimedia zentroarekin bideoa erreproduzitzeko aukera erakusten du. - Audioa - Audio formatu lehenetsia - WebM - formatu askea - m4a - kalitate hobea - Deskargatu - Hurrengo bideoa - Hurrengo bideoa eta antzekoak erakutsi - URLa ez da onartzen. - Antzeko bideoak - Edukiaren hizkuntz lehenetsia - BIDEOA ETA AUDIOA - INFORMAZIOA - ETAB - Erreproduzitu + \"Kodirekin erreproduzitu\" aukera erakutsi + Kodi multimedia zentroarekin bideoa erreproduzitzeko aukera erakusten du. + Audioa + Audio formatu lehenetsia + WebM — formatu askea + m4a — kalitate hobea + Deskargatu + Hurrengo bideoa + Hurrengo bideoa eta antzekoak erakutsi + URLa ez da onartzen. + Antzeko bideoak + Edukiaren hizkuntz lehenetsia + Bideoa eta Audioa + Erreproduzitu - Bideoaren aurreikuspen argazkitxoa - Bideoaren aurreikuspen argazkitxoa - Igotzailearen argazkitxoa - Ez dute gustoko - Gustoko dute - Tor erabili - Trafikoa Tor bidez deskargatzea behartzen du pribatutasuna hobetzeko (jario bideoak ez daude oraindik onartuta) -NewPipe atzeko planoko erreproduzitzailea - Jario erreproduzitzailerik ez da aurkitu. Agian bat instalatu nahi dezakezu. - "Hau esan nahi al zenuen: " - "Orrialdea bilatu: " - Kanpoko bideo erreproduzitzailea erabili - Kanpoko audio erreproduzitzailea erabili - Intent bidez automatikoki erreproduzitu - Bideoa automatikoki hasten du beste aplikazio batetik deitu denean. - Atzeko planoan erreproduzitzen - + Bideoaren aurreikuspen argazkitxoa + Bideoaren aurreikuspen argazkitxoa + Igotzailearen argazkitxoa + Ez dute gustoko + Gustoko dute + Tor erabili + Trafikoa Tor bidez deskargatzea behartzen du pribatutasuna hobetzeko (jario bideoak ez daude oraindik onartuta) + NewPipe atzeko planoko erreproduzitzailea + Jario erreproduzitzailerik ez da aurkitu. Agian bat instalatu nahi dezakezu. + "Hau esan nahi al zenuen: " + "Orrialdea bilatu: " + Kanpoko bideo erreproduzitzailea erabili + Kanpoko audio erreproduzitzailea erabili + Intent bidez automatikoki erreproduzitu + Bideoa automatikoki hasten du beste aplikazio batetik deitu denean. + Atzeko planoan erreproduzitzen + diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index 8951a6ee4..0d9b54a04 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -1,42 +1,42 @@ - %1$s نماها - بارگذاری‌شده در: %1$s - هیچ پخش‌کننده‌ی جریانی یافت نشد. ممکن است بخواهید یکی نصب کنید. - نصب کنید + %1$s نماها + بارگذاری‌شده در: %1$s + هیچ پخش‌کننده‌ی جریانی یافت نشد. ممکن است بخواهید یکی نصب کنید. + نصب کنید انصراف بازکردن در مرورگر هم‌رسانی بارگیری جستجو تنظیمات - منظورتان این است: - صفحه‌ی جستجو: - هم‌رسانی با: - مرورگر را برگزینید: - چرخش - تنظیمات + منظورتان این است: + صفحه‌ی جستجو: + هم‌رسانی با: + مرورگر را برگزینید: + چرخش + تنظیمات استفاده از پخش‌کننده‌ی خارجی - محل بارگیری - مسیری که ویدئوهای دریافت شده در آن ذخیره می‌شوند. - مسیر دریافت را وارد کنید - پخش خودکار از Intent - ویدئو هنگامی که از برنامه‌ی دیگری فراخوانده شد خودکار پخش می‌شود. - وضوح پیش‌فرض - پخش با Kodi - برنامه‌ی Kore نصب نیست. برای پخش کردن ویدئوها با مرکز رسانه‌ی Kodi، به Kore نیاز دارید. + محل بارگیری + مسیری که ویدئوهای دریافت شده در آن ذخیره می‌شوند. + مسیر دریافت را وارد کنید + پخش خودکار از Intent + ویدئو هنگامی که از برنامه‌ی دیگری فراخوانده شد خودکار پخش می‌شود. + وضوح پیش‌فرض + پخش با Kodi + برنامه‌ی Kore نصب نیست. برای پخش کردن ویدئوها با مرکز رسانه‌ی Kodi، به Kore نیاز دارید. نصب Kore - نمایش گزینه‌ی «پخش با Kodi» - گزینه‌ای برای پخش کردن ویدئو با مرکز رسانه‌ی Kodi نشان می‌دهد. - صدا - قالب پیش‌فرض صدا - WebM - قالبی آزاد - m4a - کیفیت بهتر - دریافت + نمایش گزینه‌ی «پخش با Kodi» + گزینه‌ای برای پخش کردن ویدئو با مرکز رسانه‌ی Kodi نشان می‌دهد. + صدا + قالب پیش‌فرض صدا + WebM — قالبی آزاد + m4a — کیفیت بهتر + دریافت ویدئو صدا - ویدئوی بعدی - پیوند پشتیبانی نمی‌شود. + ویدئوی بعدی + پیوند پشتیبانی نمی‌شود. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 9e241c54c..d0d04db68 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1,59 +1,58 @@ - Démarrer automatiquement la vidéo si elle a été appelée depuis une autre application. + Démarrer automatiquement la vidéo si elle a été appelée depuis une autre application. Annuler - Choisir un navigateur : - Résolution par défaut - "S\'agirait-il de : " + Choisir un navigateur : + Résolution par défaut + "S\'agirait-il de : " Télécharger - Emplacement des téléchargements - Entrez l\'emplacement du téléchargement - Emplacement des vidéos téléchargées. - Installer + Emplacement des téléchargements + Entrez l\'emplacement du téléchargement + Emplacement des vidéos téléchargées. + Installer Installer Kore - L\'application Kore est introuvable. Kore est nécessaire afin de lire des vidéos dans Kodi media center. - Aucun lecteur de streaming détecté. Vous devriez en installer un. + L\'application Kore est introuvable. Kore est nécessaire afin de lire des vidéos dans Kodi media center. + Aucun lecteur de streaming détecté. Vous devriez en installer un. Ouvrir dans le navigateur - Lecture automatique via Intent - Lire avec Kodi - rotation + Lecture automatique via Intent + Lire avec Kodi + rotation Rechercher - "Rechercher dans la page : " + "Rechercher dans la page : " Paramètres Partager - Partager avec : - Afficher une option pour lire la vidéo avec Kodi media center. - Afficher l\'option \"Lire avec Kodi\" - Paramètres - Mise en ligne le %1$s + Partager avec : + Afficher une option pour lire la vidéo avec Kodi media center. + Afficher l\'option \"Lire avec Kodi\" + Paramètres + Mise en ligne le %1$s Utiliser un lecteur externe - %1$s vues - Audio - Format audio par défaut - WebM- format libre - m4a - meilleur qualité - Télécharger - Vidéo suivante - Afficher les vidéos suivantes et similaires - URL non supportée. - Vidéos similaires - VIDÉO & AUDIO - INFORMATION - DIVERS + %1$s vues + Audio + Format audio par défaut + WebM — format libre + m4a — meilleur qualité + Télécharger + Vidéo suivante + Afficher les vidéos suivantes et similaires + URL non supportée. + Vidéos similaires + Vidéo & Audio + Divers - Miniature d\'aperçu vidéo - Miniature d\'aperçu vidéo - Je n\'aime pas - J\'aime -Langue du contenu - Avatar de l\'utilisateur - Utiliser un lecteur vidéo externe - Utiliser un lecteur audio externe - Lecture en arrière-plan + Miniature d\'aperçu vidéo + Miniature d\'aperçu vidéo + Je n\'aime pas + J\'aime + Langue du contenu + Avatar de l\'utilisateur + Utiliser un lecteur vidéo externe + Utiliser un lecteur audio externe + Lecture en arrière-plan Lecteur en arrière-plan NewPipe Chargement - Lecture + Lecture - Utiliser Tor - Forcer le trafic de téléchargement via Tor pour plus de confidentialité (vidéos streaming non supporté) + Utiliser Tor + Forcer le trafic de téléchargement via Tor pour plus de confidentialité (vidéos streaming non supporté) diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index a11e14119..060b70ede 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -1,10 +1,10 @@ -%1$s צפיות - הועלה בתאריך %1$s +%1$s צפיות + הועלה בתאריך %1$s שתף חפש - הבא + הבא הורדה הגדרות - הגדרות + הגדרות diff --git a/app/src/main/res/values-hu/strings.xml b/app/src/main/res/values-hu/strings.xml index d6dc6d25f..330b387ff 100644 --- a/app/src/main/res/values-hu/strings.xml +++ b/app/src/main/res/values-hu/strings.xml @@ -1,43 +1,43 @@ - %1$s megtekintés - Feltöltve: %1$s - Nem található lejátszó. Telepítsen egyet! - Telepítsen egyet + %1$s megtekintés + Feltöltve: %1$s + Nem található lejátszó. Telepítsen egyet! + Telepítsen egyet Mégse Megnyitás böngészőben Megosztás Letöltés Keresés Beállítások - Erre gondolt: - Keresési lap: - Megosztás ezzel: - Válasszon böngészőt: - forgatás - Beállítások + Erre gondolt: + Keresési lap: + Megosztás ezzel: + Válasszon böngészőt: + forgatás + Beállítások Külső lejátszó használata - Letöltések helye - Útvonal a letöltött videók tárolásához - Adja meg a letöltési útvonalat - Automatikus lejátszás Intent-en keresztül - Automatikusan elindítja a videót, ha az külső alkalmazásból volt hívva - Alapértelmezett felbontás - Lejátszás Kodi-val - A Kore alkalmazás nem található. A Kore szükséges a videók Kodi médiaközponttal való lejátszásához. + Letöltések helye + Útvonal a letöltött videók tárolásához + Adja meg a letöltési útvonalat + Automatikus lejátszás Intent-en keresztül + Automatikusan elindítja a videót, ha az külső alkalmazásból volt hívva + Alapértelmezett felbontás + Lejátszás Kodi-val + A Kore alkalmazás nem található. A Kore szükséges a videók Kodi médiaközponttal való lejátszásához. Kore telepítése - \"Lejátszás Kodi-val\" opció mutatása - Mutat egy opciót a videók Kodi médiaközponttal való lejátszására - Hang - Alapértelmezett hang formátum - WebM - szabad formátum - m4a - jobb minőség - Letöltés + \"Lejátszás Kodi-val\" opció mutatása + Mutat egy opciót a videók Kodi médiaközponttal való lejátszására + Hang + Alapértelmezett hang formátum + WebM — szabad formátum + m4a — jobb minőség + Letöltés Videó Hang -Következő videó - A webcím nem támogatott. -Hasonló videók - + Következő videó + A webcím nem támogatott. + Hasonló videók + diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 931afc6c2..95c7815c3 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -1,49 +1,49 @@ -%1$s visite - Caricato in %1$s - Nessun riproduttore trovato. Dovresti installarne uno. - Installa +%1$s visite + Caricato in %1$s + Nessun riproduttore trovato. Dovresti installarne uno. + Installa Cancella Apri nel browser Condividi Scarica Cerca Impostazioni - "Intendevi: " - "Cerca pagina: " - Condividi con: - Scegli browser: - rotazione - Impostazioni + "Intendevi: " + "Cerca pagina: " + Condividi con: + Scegli browser: + rotazione + Impostazioni Usa un riproduttore video esterno - Cartella di download - Percorso dove memorizzare i video scaricati. - Inserisci il percorso di download - Auto riproduzione attraverso internet - Avvia automaticamente un video quando è stato chiamato da un\'altra applicazione. - Risoluzione predefinita - Riproduci con Kodi - Kore app non trovata. Kore è richiesto per riprodurre video con Kodi media center. + Cartella di download + Percorso dove memorizzare i video scaricati. + Inserisci il percorso di download + Auto riproduzione attraverso internet + Avvia automaticamente un video quando è stato chiamato da un\'altra applicazione. + Risoluzione predefinita + Riproduci con Kodi + Kore app non trovata. Kore è richiesto per riprodurre video con Kodi media center. Installa Kore - Mostra l\'opzione \"Riproduci con Kodi\" - Mostra un opzione per riprodurre un video attraverso Kodi media center. - Audio - Formato audio predefinito - WedM - formato libero - m4a - qualità migliore - Scarica - Prossimo video - Mostra i video successivi e simili - URL non supportato. - Video simili - Lingua preferita dei contenuti - VIDEO & AUDIO + Mostra l\'opzione \"Riproduci con Kodi\" + Mostra un opzione per riprodurre un video attraverso Kodi media center. + Audio + Formato audio predefinito + WedM — formato libero + m4a — qualità migliore + Scarica + Prossimo video + Mostra i video successivi e simili + URL non supportato. + Video simili + Lingua preferita dei contenuti + VIDEO & AUDIO INFO ETC - Anteprima video - Anteprima video - Miniatura caricata - Non mi piace - Mi piace + Anteprima video + Anteprima video + Miniatura caricata + Non mi piace + Mi piace diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index decc2ecba..aca6ff616 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -1,59 +1,57 @@ - "アップロード: "%1$s - StreamPlayer が見つかりませんでした。インストールが必要になるかもしれません。 - インストール + "アップロード: "%1$s + StreamPlayer が見つかりませんでした。インストールが必要になるかもしれません。 + インストール 取り消し ブラウザーで開く 共有 ダウンロード 検索 設定 - "この意味ですか: " - "検索ページ: " - …共有: - ブラウザーを選択: - 回転 - 設定 + "この意味ですか: " + "検索ページ: " + …共有: + ブラウザーを選択: + 回転 + 設定 外部プレーヤーを使用する - ダウンロードする場所 - ダウンロードした動画を保存する場所のパス。 - ダウンロードのパスを入力してください。 - インテントで自動再生 - 他のアプリケーションから呼び出されたとき、自動的に動画再生を開始します。 - 基本の解像度 - Kodi で再生 - Kore アプリが見つかりません。 Kodi メディアセンターで動画を再生するには、 Kore が必要です。 + ダウンロードする場所 + ダウンロードした動画を保存する場所のパス。 + ダウンロードのパスを入力してください。 + インテントで自動再生 + 他のアプリケーションから呼び出されたとき、自動的に動画再生を開始します。 + 基本の解像度 + Kodi で再生 + Kore アプリが見つかりません。 Kodi メディアセンターで動画を再生するには、 Kore が必要です。 Kore をインストール - \"Kodi で再生\" 設定を表示 - Kodi メディアセンター経由で動画を再生するための設定を表示します. - オーディオ - 基本のオーディオフォーマット - .WebM - フリーフォーマット - .m4a - より良い品質 - ダウンロード - 次の動画 - 次の同様の動画を表示します。 - URL は使用できません。 - 同様の動画 - 優先される言語 - 動画とオーディオ - 情報 - その他 -%1$s ビュー - ビデオ プレビュー サムネイル - ビデオ プレビュー サムネイル - アップローダー サムネイル - 残念だね - いいね -外部ビデオ プレイヤーを使用する - 外部オーディオ プレイヤーを使用する - バックグラウンドで再生しています + \"Kodi で再生\" 設定を表示 + Kodi メディアセンター経由で動画を再生するための設定を表示します. + オーディオ + 基本のオーディオフォーマット + WebM — フリーフォーマット + m4a — より良い品質 + ダウンロード + 次の動画 + 次の同様の動画を表示します。 + URL は使用できません。 + 同様の動画 + 優先される言語 + 動画とオーディオ + %1$s ビュー + ビデオ プレビュー サムネイル + ビデオ プレビュー サムネイル + アップローダー サムネイル + 残念だね + いいね + 外部ビデオ プレイヤーを使用する + 外部オーディオ プレイヤーを使用する + バックグラウンドで再生しています NewPipe バックグラウンド プレーヤー 読み込み中 - 再生 + 再生 - Tor を使用する - 強制的に Tor を経由したプライバシーを高めたトラフィックでダウンロードします (ビデオのストリーミングはまだサポートされていません) + Tor を使用する + 強制的に Tor を経由したプライバシーを高めたトラフィックでダウンロードします (ビデオのストリーミングはまだサポートされていません) diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index bdb8b1084..ceaf8df6f 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -1,49 +1,49 @@ -시청 횟수 %1$s - %1$s에 업로드됨 - 스트리밍 플레이어가 발견되지 않았습니다. 플레이어를 설치하시기 바랍니다. - 설치 +시청 횟수 %1$s + %1$s에 업로드됨 + 스트리밍 플레이어가 발견되지 않았습니다. 플레이어를 설치하시기 바랍니다. + 설치 취소 브라우저에서 열기 공유 다운로드 검색 설정 - "혹시 이것을 검색하셨습니까? " - "검색 페이지: " - 다음으로 공유: - 브라우저 선택: - 회전 - 설정 + "혹시 이것을 검색하셨습니까? " + "검색 페이지: " + 다음으로 공유: + 브라우저 선택: + 회전 + 설정 외부 플레이어 사용 - 다운로드 위치 - 다운로드된 비디오가 저장될 경로를 선택하세요. - 다운로드 경로 입력 - 인텐트로 경유할 경우 자동 재생 - 다른 앱으로부터 호출되었을 경우에 비디오를 자동으로 재생합니다. - 기본 해상도 - Kodi로 재생 - Kore 앱이 발견되지 않았습니다. Kodi media center로 비디오를 재생하려면 Kore가 필요합니다. + 다운로드 위치 + 다운로드된 비디오가 저장될 경로를 선택하세요. + 다운로드 경로 입력 + 인텐트로 경유할 경우 자동 재생 + 다른 앱으로부터 호출되었을 경우에 비디오를 자동으로 재생합니다. + 기본 해상도 + Kodi로 재생 + Kore 앱이 발견되지 않았습니다. Kodi media center로 비디오를 재생하려면 Kore가 필요합니다. Kore 설치 - \"Kodi로 재생\" 옵션 표시 - 비디오를 Kodi media center를 사용해 재생하는 옵션을 표시합니다. - 오디오 - 기본 오디오 포맷 - WebM - 무료 자유 포맷입니다 - m4a - 보다 나은 품질 - 다운로드 - 다음 비디오 - 다음 및 유사한 비디오 표시 - 지원하지 않는 URL 입니다. - 유사한 비디오 - 선호하는 컨텐츠 언어 - 비디오 & 오디오 + \"Kodi로 재생\" 옵션 표시 + 비디오를 Kodi media center를 사용해 재생하는 옵션을 표시합니다. + 오디오 + 기본 오디오 포맷 + WebM — 무료 자유 포맷입니다 + m4a — 보다 나은 품질 + 다운로드 + 다음 비디오 + 다음 및 유사한 비디오 표시 + 지원하지 않는 URL 입니다. + 유사한 비디오 + 선호하는 컨텐츠 언어 + 비디오 & 오디오 정보 기타 - 비디오 미리보기 썸네일 - 비디오 미리보기 썸네일 - 업로더 썸네일 - 싫어요 - 좋아요 + 비디오 미리보기 썸네일 + 비디오 미리보기 썸네일 + 업로더 썸네일 + 싫어요 + 좋아요 diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml index 0cf3b0dec..b63369b49 100644 --- a/app/src/main/res/values-nl/strings.xml +++ b/app/src/main/res/values-nl/strings.xml @@ -1,51 +1,49 @@ - %1$s keer bekeken - Geüpload op %1$s - Geen speler met streaming ondersteuning gevonden. Misschien wil je er een installeren. - Installeer speler + %1$s keer bekeken + Geüpload op %1$s + Geen speler met streaming ondersteuning gevonden. Misschien wil je er een installeren. + Installeer speler Annuleer Open in browser Deel Download Zoek Instellingen - Bedoelde je: - Zoekpagina: - Deel met: - Kies browser: - rotatie - Instellingen + Bedoelde je: + Zoekpagina: + Deel met: + Kies browser: + rotatie + Instellingen Gebruik externe speler - Downloadlocatie - Locatie om gedownloadde videos in op te slaan. - Voer downloadlocatie is - Speel automatisch via Intent - Speel een video automatisch af indien geopend vanuit een andere app. - Standaardresolutie - Speel af met Kodi - Kore app niet gevonden. Kore is nodig om videos op Kodi af te spelen. + Downloadlocatie + Locatie om gedownloadde videos in op te slaan. + Voer downloadlocatie is + Speel automatisch via Intent + Speel een video automatisch af indien geopend vanuit een andere app. + Standaardresolutie + Speel af met Kodi + Kore app niet gevonden. Kore is nodig om videos op Kodi af te spelen. Installeer Kore - Toon \"Speel af met Kodi\" optie - Toont een optie om een video op een Kodi media center af te spelen. - Audio - Standaard audio formaat - Webam - open formaat - m4a - betere kwaliteit - Download - Volgende video - URL wordt niet ondersteund. - Vergelijkbare videos - Laat volgende en vergelijkbare videos zien - Voorkeurs content taal -Gebruik externe videospeler - Gebruik externe audiospeler - VIDEO & GELUID - INFO - ETC. + Toon \"Speel af met Kodi\" optie + Toont een optie om een video op een Kodi media center af te spelen. + Audio + Standaard audio formaat + WebM — open formaat + m4a — betere kwaliteit + Download + Volgende video + URL wordt niet ondersteund. + Vergelijkbare videos + Laat volgende en vergelijkbare videos zien + Voorkeurs content taal + Gebruik externe videospeler + Gebruik externe audiospeler + Video & Geluid - Videovoorbeeld thumbnail - Videovoorbeeld thumbnail - Uploader miniatuur - Dislikes + Videovoorbeeld thumbnail + Videovoorbeeld thumbnail + Uploader miniatuur + Dislikes diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 348a2e689..9142bca7f 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -1,51 +1,50 @@ - Nie znaleziono odtwarzacza strumieniowego. - Zainstaluj + Nie znaleziono odtwarzacza strumieniowego. + Zainstaluj Anuluj Otwórz w przeglądarce Udostępnij Pobierz Szukaj Ustawienia - "Czy chodziło Ci o: " - Udostępnij za pośrednictwem: - Wybierz przeglądarkę: - obrót - Ustawienia + "Czy chodziło Ci o: " + Udostępnij za pośrednictwem: + Wybierz przeglądarkę: + obrót + Ustawienia Użyj zewnętrznego odtwarzacza - Miejsce zapisu pobieranych plików - Ścieżka folderu do zapisywania pobieranego wideo. - Wprowadź ścieżkę folderu dla pobieranych plików - Automatycznie odtwarzaj przez Intent - Automatycznie odtwarza wideo po wywołaniu z innej aplikacji. - Domyślna rozdzielczość - Odtwarzaj za pośrednictwem Kodi - Aplikacja Kore nie została znaleziona. Wymagana jest do odtwarzania w Kodi. + Miejsce zapisu pobieranych plików + Ścieżka folderu do zapisywania pobieranego wideo. + Wprowadź ścieżkę folderu dla pobieranych plików + Automatycznie odtwarzaj przez Intent + Automatycznie odtwarza wideo po wywołaniu z innej aplikacji. + Domyślna rozdzielczość + Odtwarzaj za pośrednictwem Kodi + Aplikacja Kore nie została znaleziona. Wymagana jest do odtwarzania w Kodi. Zainstaluj Kore - Wyświetlaj opcję \"Odtwarzaj za pośrednictwem Kodi\" - Wyświetla opcję do odtwarzania wideo przez aplikację Kodi. - Dźwięk - Domyślny format dźwięku - WebM - otwarty format - m4a - lepsza jakość - Pobierz - Następne wideo - Wyświetl następne i podobne wideo - Niewspierany URL. - Podobne wideo - Preferowany język zawartości - WIDEO & DŹWIĘK - INFO - INNE -"Szukaj strony: " - %1$s wyświetleń - Opublikowany %1$s - Miniaturka podglądowa wideo - Miniaturka podglądowa wideo - Miniaturka wysyłającego - łapek w dół - Polubień -Użyj zewnętrznego odtwarzacza wideo - Użyj zewnętrznego odtwarzacza audio - + Wyświetlaj opcję \"Odtwarzaj za pośrednictwem Kodi\" + Wyświetla opcję do odtwarzania wideo przez aplikację Kodi. + Dźwięk + Domyślny format dźwięku + WebM — otwarty format + m4a — lepsza jakość + Pobierz + Następne wideo + Wyświetl następne i podobne wideo + Niewspierany URL. + Podobne wideo + Preferowany język zawartości + Wideo & Dźwięk + + "Szukaj strony: " + %1$s wyświetleń + Opublikowany %1$s + Miniaturka podglądowa wideo + Miniaturka podglądowa wideo + Miniaturka wysyłającego + łapek w dół + Polubień + Użyj zewnętrznego odtwarzacza wideo + Użyj zewnętrznego odtwarzacza audio + diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml index 0a6cbe3c4..d78107d70 100644 --- a/app/src/main/res/values-pt/strings.xml +++ b/app/src/main/res/values-pt/strings.xml @@ -1,50 +1,50 @@ -%1$s visualizações - Carregado em %1$s - Reprodutor não disponível. Deve instalar um reprodutor. - Instalar +%1$s visualizações + Carregado em %1$s + Reprodutor não disponível. Deve instalar um reprodutor. + Instalar Cancelar Abrir no navegador Partilhar Descarregar Pesquisar Definições - "Será que queria dizer: " - "Página de pesquisa: " - Partilhar com: - Escolher navegador: - rotação - Definições - Utilizar reprodutor de vídeo externo - Utilizar reprodutor de áudio externo - Local para a descarga - Local para guardar os vídeos descarregados. - Digite o caminho - Reproduzir via Intent - Iniciar automaticamente o vídeo se for invocado por outra aplicação. - Resolução padrão - Reproduzir com Kodi - Aplicação não encontrada. Necessita do Kore para reproduzir vídeos no Kodi. + "Será que queria dizer: " + "Página de pesquisa: " + Partilhar com: + Escolher navegador: + rotação + Definições + Utilizar reprodutor de vídeo externo + Utilizar reprodutor de áudio externo + Local para a descarga + Local para guardar os vídeos descarregados. + Digite o caminho + Reproduzir via Intent + Iniciar automaticamente o vídeo se for invocado por outra aplicação. + Resolução padrão + Reproduzir com Kodi + Aplicação não encontrada. Necessita do Kore para reproduzir vídeos no Kodi. Instalar o Kore - Mostrar opção \"Reproduzir com Kodi\" - Mostra uma opção para reproduzir o vídeo com o Kodi. - Áudio - Formato áudio padrão - WebM - formato livre - m4a - melhor qualidade - Descarregar - Vídeo seguinte - Mostrar vídeos seguintes e similares - URL não suportado. - Vídeos similares - Idioma preferencial do conteúdo - Vídeo e áudio + Mostrar opção \"Reproduzir com Kodi\" + Mostra uma opção para reproduzir o vídeo com o Kodi. + Áudio + Formato áudio padrão + WebM — formato livre + m4a — melhor qualidade + Descarregar + Vídeo seguinte + Mostrar vídeos seguintes e similares + URL não suportado. + Vídeos similares + Idioma preferencial do conteúdo + Vídeo e áudio Informações Outras - Miniatura de vídeos - Miniatura de vídeos - Carregador de miniaturas - Não gosto - Gosto + Miniatura de vídeos + Miniatura de vídeos + Carregador de miniaturas + Não gosto + Gosto diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 36368fe09..8d8da5a8e 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1,57 +1,57 @@ - %1$s просмотров - Опубликовано %1$s - Ни одного потокового проигрывателя не было найдено. Установить? - Установить + %1$s просмотров + Опубликовано %1$s + Ни одного потокового проигрывателя не было найдено. Установить? + Установить Отмена Открыть в браузере Поделиться Скачать Найти Настройки - Возможно, вы имели в виду: - Страница поиска: - Поделиться с помощью: - Выбрать браузер: - поворот - Настройки + Возможно, вы имели в виду: + Страница поиска: + Поделиться с помощью: + Выбрать браузер: + поворот + Настройки Использовать внешний проигрыватель - Место для загрузок - Папка для хранения загруженных файлов. - Введите путь к папке для загрузок - Автопроигрывание через интернет - Автоматически воспроизводить видео когда оно открыто через другое приложение. - Разрешение по-умолчанию - Воспроизвести с помощью Kodi - Приложение Kore не наидено. Чтобы проигрывать видео через Kodi media center, нужен Kore. + Место для загрузок + Папка для хранения загруженных файлов. + Введите путь к папке для загрузок + Автопроигрывание через интернет + Автоматически воспроизводить видео когда оно открыто через другое приложение. + Разрешение по-умолчанию + Воспроизвести с помощью Kodi + Приложение Kore не наидено. Чтобы проигрывать видео через Kodi media center, нужен Kore. Установить Kore - Показывать опцию \"Воспроизвести с помощью Kodi\" - Показать опцию воспроизведения видео через Kodi media center. - Аудио - Формат аудио по-умолчанию - WebM - свободный формат - m4a - лучшее качество - Скачать + Показывать опцию \"Воспроизвести с помощью Kodi\" + Показать опцию воспроизведения видео через Kodi media center. + Аудио + Формат аудио по-умолчанию + WebM — свободный формат + m4a — лучшее качество + Скачать Видео Аудио - Следующее видео - URL не поддерживается. - Похожие видео - Показывать следующее и предложенные видео - Предпочитаемый язык контента -ВИДЕО И АУДИО - ИНФОРМАЦИЯ - ПРОЧЕЕ + Следующее видео + URL не поддерживается. + Похожие видео + Показывать следующее и предложенные видео + Предпочитаемый язык контента + Видео и Аудио + Внешний вид + Другое - Миниатюра видео-превью - Миниатюра видео-превью - Миниатюра аватара пользователся - Дислайки - Лайки -Использовать внешний проигрыватель для видео - Использовать внешний проигрыватель для аудио - Проигрывание в фоновом режиме + Миниатюра видео-превью + Миниатюра видео-превью + Миниатюра аватара пользователся + Дислайки + Лайки +Использовать внешний проигрыватель для видео + Использовать внешний проигрыватель для аудио + Проигрывание в фоновом режиме diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index 412d9a56c..13266f519 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -1,55 +1,54 @@ -%1$s pogledov - Poslano %1$s - Predvajalnika pretoka ni mogoče najti. Tak program lahko namestite ločeno. - Namesti +%1$s pogledov + Poslano %1$s + Predvajalnika pretoka ni mogoče najti. Tak program lahko namestite ločeno. + Namesti Prekliči Odpri v brskalniku Omogoči souporabo Prejmi Poišči Nastavitve - "Ste mislili vpisati: " - "Stran iskanja: " - Omogoči souporabo z: - Izbor brskalnika: - usmerjenost - Nastavitve - Uporabi zunanji predvajalnik videa - Uporabi zunanji predvajalnik zvoka - Mapa za prejem - Pot do mape za prejem datotek. - Vpis poti za prejem - Privzeta ločljivost - Predvajaj s Kodi - Programa Kore ni mogoče najti. Program omogoča predvajanje video posnetkov prek predstavnega središča Kodi. + "Ste mislili vpisati: " + "Stran iskanja: " + Omogoči souporabo z: + Izbor brskalnika: + usmerjenost + Nastavitve + Uporabi zunanji predvajalnik videa + Uporabi zunanji predvajalnik zvoka + Mapa za prejem + Pot do mape za prejem datotek. + Vpis poti za prejem + Privzeta ločljivost + Predvajaj s Kodi + Programa Kore ni mogoče najti. Program omogoča predvajanje video posnetkov prek predstavnega središča Kodi. Namesti program Kore - Pokaži možnost \"Predvajaj s Kodi\" - Privzet zapis zvoka - Zvok - WebM - prost zapis - m4a - višja kakovost posnetkov - Prejem - Naslednji video - Pokaži naslednji video in podobne posnetke - Zapis naslova URL ni podprt. - Podobni posnetki - Prednostni jezik vsebine - Video in Zvok - Podrobnosti - Sličica predogleda videa - Sličica predogleda videa - Sličica pošiljalnika - Samodejno predvajaj prek vmesnika Intent - Začne samodejno predvajanje videa, ko je zagnan prek drugega programa. - Pokaže možnost predvajanja videa preko predstavnega središča Kodi. + Pokaži možnost \"Predvajaj s Kodi\" + Privzet zapis zvoka + Zvok + WebM — prost zapis + m4a — višja kakovost posnetkov + Prejem + Naslednji video + Pokaži naslednji video in podobne posnetke + Zapis naslova URL ni podprt. + Podobni posnetki + Prednostni jezik vsebine + Video in Zvok + Sličica predogleda videa + Sličica predogleda videa + Sličica pošiljalnika + Samodejno predvajaj prek vmesnika Intent + Začne samodejno predvajanje videa, ko je zagnan prek drugega programa. + Pokaže možnost predvajanja videa preko predstavnega središča Kodi. Drugo - Všeč mi je -Ni mi všeč + Všeč mi je +Ni mi všeč Ozadnji predvajalnik NewPipe Nalaganje ... - Predvajanje v ozadju - Predvajaj + Predvajanje v ozadju + Predvajaj diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index e0c092d25..cecce2f05 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -1,63 +1,62 @@ - %1$s приказа - "Отпремљен "%1$s - Нема плејера токова. Можда желите да га инсталирате. - Инсталирај + %1$s приказа + "Отпремљен "%1$s + Нема плејера токова. Можда желите да га инсталирате. + Инсталирај Одустани Отвори у прегледачу Дели Преузми Тражи Поставке - Да ли сте мислили: - Страница претраге: - Подели помоћу: - Отвори помоћу: - ротација - Поставке + Да ли сте мислили: + Страница претраге: + Подели помоћу: + Отвори помоћу: + ротација + Поставке Користи спољашњи плејер - Одредиште преузимања - Путања за упис преузетих видеа. - Унесите путању за преузимања - Аутопуштање преко Интента - Аутоматски почиње пушта видео по позиву из друге апликације. - Подразумевана резолуција - Пусти помоћу Кодија - Апликација Кор није нађена. Кор (Kore) је потребан да бисте пуштали видее у Коди медија центру. + Одредиште преузимања + Путања за упис преузетих видеа. + Унесите путању за преузимања + Аутопуштање преко Интента + Аутоматски почиње пушта видео по позиву из друге апликације. + Подразумевана резолуција + Пусти помоћу Кодија + Апликација Кор није нађена. Кор (Kore) је потребан да бисте пуштали видее у Коди медија центру. Инсталирај Кор - Прикажи „Пусти помоћу Кодија“ - Приказ опције за пуштање видеа у Коди медија центру. - Аудио - Подразумевани формат звука - WebM - слободни формат - m4a - бољи квалитет - Преузми + Прикажи „Пусти помоћу Кодија“ + Приказ опције за пуштање видеа у Коди медија центру. + Аудио + Подразумевани формат звука + WebM — слободни формат + m4a — бољи квалитет + Преузми Видео Аудио - Следећи видео - УРЛ није подржан. - Прикажи следећи и слични видео - Слични видео - Пожељни језик садржаја -ВИДЕО И АУДИО - ПОДАЦИ - ОСТАЛО -Сличица видео прегледа - Сличица видео прегледа - Сличица отпремаоца - Несвиђања - Свиђања -Користи спољашњи видео плејер - Користи спољашњи аудио плејер - Пуштам у позадини + Следећи видео + УРЛ није подржан. + Прикажи следећи и слични видео + Слични видео + Пожељни језик садржаја + Видео и Аудио + Остало + Сличица видео прегледа + Сличица видео прегледа + Сличица отпремаоца + Несвиђања + Свиђања + Користи спољашњи видео плејер + Користи спољашњи аудио плејер + Пуштам у позадини Позадински плејер за Јутјуб цев Учитавам - Пусти + Пусти - Користи Тор - Принудно преусмерење саобраћаја кроз Тор за доданту приватност (токови још нису подржани) + Користи Тор + Принудно преусмерење саобраћаја кроз Тор за доданту приватност (токови још нису подржани) diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml index 1f056cfb5..75d058e50 100644 --- a/app/src/main/res/values-v21/styles.xml +++ b/app/src/main/res/values-v21/styles.xml @@ -3,18 +3,18 @@ \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 7e0d71406..963a49bcc 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -1,11 +1,20 @@ - #cd322e - #bc211d - #000 - #a000 - #efff - #6000 - #EEEEEE + + #EEEEEE + #CD322E + #BC211D + #000000 + + + #222222 + #CD322E + #BC211D + #FFFFFF + + + #AA000000 + #EEFFFFFF + #66000000 #323232 \ No newline at end of file diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index a909953ae..6f83e31a5 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -1,39 +1,54 @@ - settings_categoery_video_audio - settings_category_video_info - settings_category_etc + settings_category_video_audio + settings_category_appearance + settings_category_other - download_path_preference - use_external_video_player - use_external_audio_player - autoplay_through_intent - default_resolution_preference - + download_path + use_external_video_player + use_external_audio_player + autoplay_through_intent + + default_resolution_preference + 360p + 720p 360p 240p 144p - 360p - show_play_with_kodi_preference - default_audio_format - - @string/webMAudioDescription - @string/m4aAudioDescription + + show_play_with_kodi + + theme + 0 + + @string/dark_theme_title + @string/light_theme_title - + + 0 + 1 + + + default_audio_format + m4a + + @string/webm_description + @string/m4a_description + + webm m4a - m4a - show_next_video - search_language - use_tor + + show_next_video + en + search_language - + af az id @@ -112,8 +127,7 @@ ja ko - en - + Afrikaans Azərbaycan Bahasa Indonesia @@ -192,4 +206,5 @@ 日本語 한국어 + use_tor \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c7058759e..004a41712 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,66 +3,69 @@ NewPipe NewPipe Background Player NewPipe - %1$s views - Uploaded on %1$s - No stream player found. You may want to install one. - Install + %1$s views + Uploaded on %1$s + No stream player found. Install VLC? + Install Cancel - https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc + https://f-droid.org/repository/browse/?fdfilter=vlc&fdid=org.videolan.vlc Open in browser Share Loading Download Search Settings - Did you mean: - Search page: - Share with: - Choose browser: - rotation - Settings - Use external video player - Use external audio player - Download location - Path to store downloaded videos in. - Enter download path - Autoplay through Intent - Automatically starts a video when it was called from another app. - Default Resolution - Play with Kodi - Kore app not found. Kore is needed to play videos with Kodi media center. - Install Kore - https://f-droid.org/repository/browse/?fdfilter=Kore&fdid=org.xbmc.kore - Show \"Play with Kodi\" option - Displays an option to play a video via Kodi media center. - Audio - Default audio format - WebM - free format - m4a - better quality - Download - + Did you mean: + Search page: + Share with: + Choose browser: + rotation + Settings + Use external video player + Use external audio player + Download path + Path to store downloaded videos in + Enter download path + Autoplay through Intent + Automatically play a video when it\'s called from another app + Default Resolution + Play with Kodi + Kore app not found. Install Kore? + https://f-droid.org/repository/browse/?fdfilter=Kore&fdid=org.xbmc.kore + Show \"Play with Kodi\" option + Display an option to play a video via Kodi media center + Audio + Default audio format + WebM — free format + m4a — better quality + Theme + Dark + Light + + Download + Video Audio - Next video - Show next and similar videos - URL not supported. - Similar videos - Preferable content language - VIDEO & AUDIO - INFO - ETC - %1$s - NewPipe - Playing in background - https://www.c3s.cc/ - Play + Next video + Show next and similar videos + URL not supported + Similar videos + Preferable content language + Video & Audio + Appearance + Other + %1$s - NewPipe + Playing in background + https://www.c3s.cc/ + Play - Video preview thumbnail - Video preview thumbnail - Uploader thumbnail - Dislikes - Likes - Use Tor - Force download traffic through Tor for increased privacy (streaming videos not yet supported) + Video preview thumbnail + Video preview thumbnail + Uploader\'s userpic thumbnail + Likes + Dislikes + Use Tor + Force download traffic through Tor for increased privacy (streaming videos not yet supported) diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 8d27cc3df..8abacc2e8 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -3,17 +3,17 @@ \ No newline at end of file diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml new file mode 100644 index 000000000..045e95599 --- /dev/null +++ b/app/src/main/res/xml/settings.xml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/xml/settings_screen.xml b/app/src/main/res/xml/settings_screen.xml deleted file mode 100644 index 46ad3ecb9..000000000 --- a/app/src/main/res/xml/settings_screen.xml +++ /dev/null @@ -1,82 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 6c178cfb7e8ad2e6004d7ff0a5f1fd214ff05637 Mon Sep 17 00:00:00 2001 From: chschtsch Date: Tue, 5 Jan 2016 23:09:15 +0300 Subject: [PATCH 48/57] add back missing like button margin --- app/src/main/res/layout/fragment_videoitem_detail.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/res/layout/fragment_videoitem_detail.xml b/app/src/main/res/layout/fragment_videoitem_detail.xml index 3ef048e46..611a5aa14 100644 --- a/app/src/main/res/layout/fragment_videoitem_detail.xml +++ b/app/src/main/res/layout/fragment_videoitem_detail.xml @@ -124,6 +124,7 @@ android:layout_below="@id/detailViewCountView" android:layout_toLeftOf="@id/detailThumbsDownCountView" android:layout_toStartOf="@id/detailThumbsDownCountView" + android:layout_marginLeft="@dimen/video_item_detail_like_margin" android:src="@drawable/thumbs_down" /> Date: Tue, 5 Jan 2016 21:11:15 +0100 Subject: [PATCH 49/57] set download path on startup --- app/src/main/java/org/schabi/newpipe/App.java | 4 ++++ .../java/org/schabi/newpipe/DownloadDialog.java | 4 +++- .../java/org/schabi/newpipe/SettingsActivity.java | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index debb1a2a5..55e782259 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -23,6 +23,10 @@ public class App extends Application { } else { configureTor(false); } + + // DO NOT REMOVE THIS FUNCTION!!! + // Otherwise downloadPathPreference has invalid value. + SettingsActivity.initSettings(this); } /** diff --git a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java index 1f018618a..dbada86a6 100644 --- a/app/src/main/java/org/schabi/newpipe/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/DownloadDialog.java @@ -81,12 +81,14 @@ public class DownloadDialog extends DialogFragment { Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + downloadFolder); final File dir = new File(downloadPath); if(!dir.exists()) { - boolean mkdir = dir.mkdir(); //attempt to create directory + //attempt to create directory + boolean mkdir = dir.mkdir(); if(!mkdir && !dir.isDirectory()) { Log.e(TAG, "Cant' create directory named " + dir.toString()); //TODO notify user "download directory should be changed" ? } } + String saveFilePath = dir + "/" + title + suffix; if (App.isUsingTor()) { // if using Tor, do not use DownloadManager because the proxy cannot be set diff --git a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java index 3f747c2da..680c8996d 100644 --- a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java @@ -7,6 +7,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.os.Bundle; +import android.os.Environment; import android.preference.CheckBoxPreference; import android.preference.EditTextPreference; import android.preference.ListPreference; @@ -245,4 +246,17 @@ public class SettingsActivity extends PreferenceActivity { } return true; } + + public static void initSettings(Context context) { + PreferenceManager.setDefaultValues(context, R.xml.settings_screen, false); + SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); + if(sp.getString(context.getString(R.string.downloadPathPreference), "").isEmpty()){ + SharedPreferences.Editor spEditor = sp.edit(); + String newPipeDownloadStorage = + Environment.getExternalStorageDirectory().getAbsolutePath() + "/NewPipe"; + spEditor.putString(context.getString(R.string.downloadPathPreference) + , newPipeDownloadStorage); + spEditor.apply(); + } + } } From f89d405226b211a92389ae681d5ecc187f3074ae Mon Sep 17 00:00:00 2001 From: chschtsch Date: Tue, 5 Jan 2016 23:13:52 +0300 Subject: [PATCH 50/57] merging with eb0df2b --- app/src/main/java/org/schabi/newpipe/SettingsActivity.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java index a4b429852..5a1e11372 100644 --- a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java @@ -245,13 +245,13 @@ public class SettingsActivity extends PreferenceActivity { } public static void initSettings(Context context) { - PreferenceManager.setDefaultValues(context, R.xml.settings_screen, false); + PreferenceManager.setDefaultValues(context, R.xml.settings, false); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); - if(sp.getString(context.getString(R.string.downloadPathPreference), "").isEmpty()){ + if(sp.getString(context.getString(R.string.download_path_key), "").isEmpty()){ SharedPreferences.Editor spEditor = sp.edit(); String newPipeDownloadStorage = Environment.getExternalStorageDirectory().getAbsolutePath() + "/NewPipe"; - spEditor.putString(context.getString(R.string.downloadPathPreference) + spEditor.putString(context.getString(R.string.download_path_key) , newPipeDownloadStorage); spEditor.apply(); } From 2f060f0f529f11660062b56e4c79a0aa534d2f65 Mon Sep 17 00:00:00 2001 From: chschtsch Date: Tue, 5 Jan 2016 23:16:50 +0300 Subject: [PATCH 51/57] merging with eb0df2b --- app/src/main/java/org/schabi/newpipe/SettingsActivity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java index 5a1e11372..52f4a17a3 100644 --- a/app/src/main/java/org/schabi/newpipe/SettingsActivity.java +++ b/app/src/main/java/org/schabi/newpipe/SettingsActivity.java @@ -1,6 +1,7 @@ package org.schabi.newpipe; import android.app.Activity; +import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; From 7f32857e00f874336f838f297a49a1d24b6eaacf Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Tue, 5 Jan 2016 21:23:16 +0100 Subject: [PATCH 52/57] buxfix --- .../schabi/newpipe/VideoItemListFragment.java | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java index 8c9c61456..58c622f1a 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java @@ -66,6 +66,9 @@ public class VideoItemListFragment extends ListFragment { private View footer; + // used to suppress request for loading a new page while another page is already loading. + private boolean loadingNextPage = true; + private class ResultRunnable implements Runnable { private final SearchEngine.Result result; private final int requestId; @@ -76,6 +79,9 @@ public class VideoItemListFragment extends ListFragment { @Override public void run() { updateListOnResult(result, requestId); + if (android.os.Build.VERSION.SDK_INT >= 19) { + getListView().removeFooterView(footer); + } } } @@ -84,7 +90,7 @@ public class VideoItemListFragment extends ListFragment { private final String query; private final int page; final Handler h = new Handler(); - private volatile boolean run = true; + private volatile boolean runs = true; private final int requestId; public SearchRunnable(SearchEngine engine, String query, int page, int requestId) { this.engine = engine; @@ -93,7 +99,7 @@ public class VideoItemListFragment extends ListFragment { this.requestId = requestId; } void terminate() { - run = false; + runs = false; } @Override public void run() { @@ -104,7 +110,7 @@ public class VideoItemListFragment extends ListFragment { getString(R.string.defaultLanguageItem)); SearchEngine.Result result = engine.search(query, page, searchLanguage); Log.i(TAG, "language code passed:\""+searchLanguage+"\""); - if(run) { + if(runs) { h.post(new ResultRunnable(result, requestId)); } } catch(Exception e) { @@ -116,15 +122,6 @@ public class VideoItemListFragment extends ListFragment { } }); } - getActivity().runOnUiThread(new Runnable() { - @Override - public void run() { - if (android.os.Build.VERSION.SDK_INT >= 19) { - getListView().removeFooterView(footer); - } - } - }); - } } @@ -204,6 +201,7 @@ public class VideoItemListFragment extends ListFragment { } private void nextPage() { + loadingNextPage = true; lastPage++; Log.d(TAG, getString(R.string.searchPage) + Integer.toString(lastPage)); startSearch(query, lastPage); @@ -249,6 +247,8 @@ public class VideoItemListFragment extends ListFragment { Log.w(TAG, "Trying to set value while activity doesn't exist anymore."); } catch(Exception e) { e.printStackTrace(); + } finally { + loadingNextPage = false; } } @@ -325,7 +325,8 @@ public class VideoItemListFragment extends ListFragment { && list.getLastVisiblePosition() == list.getAdapter().getCount() - 1 && list.getChildAt(list.getChildCount() - 1).getBottom() <= list.getHeight()) { long time = System.currentTimeMillis(); - if ((time - lastScrollDate) > 200) { + if ((time - lastScrollDate) > 200 + && !loadingNextPage) { lastScrollDate = time; getListView().addFooterView(footer); nextPage(); From 27d06eaa6b6170a07d2f5c5e9be8caab8a3980da Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Tue, 5 Jan 2016 21:41:55 +0100 Subject: [PATCH 53/57] removed hardcoded string, and add licece to some files. --- app/src/main/java/org/schabi/newpipe/App.java | 18 ++++++++++++++++++ .../java/org/schabi/newpipe/ExitActivity.java | 18 ++++++++++++++++++ .../java/org/schabi/newpipe/Localization.java | 16 ++++++++++++++++ .../schabi/newpipe/PanicResponderActivity.java | 18 ++++++++++++++++++ .../schabi/newpipe/VideoItemListFragment.java | 9 ++++++--- app/src/main/res/values/strings.xml | 1 + 6 files changed, 77 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index 55e782259..d976e0a59 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -8,6 +8,24 @@ import android.preference.PreferenceManager; import info.guardianproject.netcipher.NetCipher; import info.guardianproject.netcipher.proxy.OrbotHelper; +/** + * Copyright (C) Hans-Christoph Steiner 2016 + * App.java is part of NewPipe. + * + * NewPipe is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NewPipe is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NewPipe. If not, see . + */ + public class App extends Application { private static boolean useTor; diff --git a/app/src/main/java/org/schabi/newpipe/ExitActivity.java b/app/src/main/java/org/schabi/newpipe/ExitActivity.java index c193ffbde..6e14cfd9f 100644 --- a/app/src/main/java/org/schabi/newpipe/ExitActivity.java +++ b/app/src/main/java/org/schabi/newpipe/ExitActivity.java @@ -7,6 +7,24 @@ import android.content.Intent; import android.os.Build; import android.os.Bundle; +/** + * Copyright (C) Hans-Christoph Steiner 2016 + * ExitActivity.java is part of NewPipe. + * + * NewPipe is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NewPipe is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NewPipe. If not, see . + */ + public class ExitActivity extends Activity { @SuppressLint("NewApi") diff --git a/app/src/main/java/org/schabi/newpipe/Localization.java b/app/src/main/java/org/schabi/newpipe/Localization.java index 796b7878d..221c7a2a9 100644 --- a/app/src/main/java/org/schabi/newpipe/Localization.java +++ b/app/src/main/java/org/schabi/newpipe/Localization.java @@ -14,6 +14,22 @@ import java.util.Locale; /** * Created by chschtsch on 12/29/15. + * + * Copyright (C) Gregory Arkhipov 2015 + * Localization.java is part of NewPipe. + * + * NewPipe is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NewPipe is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NewPipe. If not, see . */ public class Localization { diff --git a/app/src/main/java/org/schabi/newpipe/PanicResponderActivity.java b/app/src/main/java/org/schabi/newpipe/PanicResponderActivity.java index e9bf0e985..8a36f5d5e 100644 --- a/app/src/main/java/org/schabi/newpipe/PanicResponderActivity.java +++ b/app/src/main/java/org/schabi/newpipe/PanicResponderActivity.java @@ -7,6 +7,24 @@ import android.content.Intent; import android.os.Build; import android.os.Bundle; +/** + * Copyright (C) Hans-Christoph Steiner 2016 + * PanicResponderActivity.java is part of NewPipe. + * + * NewPipe is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * NewPipe is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with NewPipe. If not, see . + */ + public class PanicResponderActivity extends Activity { public static final String PANIC_TRIGGER_ACTION = "info.guardianproject.panic.action.TRIGGER"; diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java index 58c622f1a..a06d99985 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java @@ -118,7 +118,8 @@ public class VideoItemListFragment extends ListFragment { h.post(new Runnable() { @Override public void run() { - Toast.makeText(getActivity(), "Network Error", Toast.LENGTH_SHORT).show(); + Toast.makeText(getActivity(), getString(R.string.networkError), + Toast.LENGTH_SHORT).show(); } }); } @@ -298,7 +299,8 @@ public class VideoItemListFragment extends ListFragment { super.onViewCreated(view, savedInstanceState); list = getListView(); videoListAdapter = new VideoListAdapter(getActivity(), this); - footer = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.paginate_footer, null, false); + footer = ((LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE)) + .inflate(R.layout.paginate_footer, null, false); setListAdapter(videoListAdapter); @@ -319,7 +321,8 @@ public class VideoItemListFragment extends ListFragment { } @Override - public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { + public void onScroll(AbsListView view, int firstVisibleItem, + int visibleItemCount, int totalItemCount) { if (mode != PRESENT_VIDEOS_MODE && list.getChildAt(0) != null && list.getLastVisiblePosition() == list.getAdapter().getCount() - 1 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c7058759e..0eb72fb38 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -56,6 +56,7 @@ Playing in background https://www.c3s.cc/ Play + Network Error Video preview thumbnail From 02d8463e15673b73732717864a81997b8fb0112f Mon Sep 17 00:00:00 2001 From: chschtsch Date: Wed, 6 Jan 2016 00:02:10 +0300 Subject: [PATCH 54/57] rename resource --- app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java | 2 +- app/src/main/res/values/strings.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java index b2d0988c7..bea1c6111 100644 --- a/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/VideoItemListFragment.java @@ -118,7 +118,7 @@ public class VideoItemListFragment extends ListFragment { h.post(new Runnable() { @Override public void run() { - Toast.makeText(getActivity(), getString(R.string.networkError), + Toast.makeText(getActivity(), getString(R.string.network_error), Toast.LENGTH_SHORT).show(); } }); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 99b36dd56..d7a551fcd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -59,7 +59,7 @@ Playing in background https://www.c3s.cc/ Play - Network Error + Network Error Video preview thumbnail From 367c434010b1e24aedf4f0aa939406b29c76d75e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mladen=20Pejakovi=C4=87?= Date: Tue, 5 Jan 2016 23:54:24 +0100 Subject: [PATCH 55/57] Translated using Weblate (Serbian) Currently translated at 100.0% (56 of 56 strings) --- app/src/main/res/values-sr/strings.xml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-sr/strings.xml b/app/src/main/res/values-sr/strings.xml index cecce2f05..d58914743 100644 --- a/app/src/main/res/values-sr/strings.xml +++ b/app/src/main/res/values-sr/strings.xml @@ -30,8 +30,8 @@ Приказ опције за пуштање видеа у Коди медија центру. Аудио Подразумевани формат звука - WebM — слободни формат - m4a — бољи квалитет + WebM — слободни формат + m4a — бољи квалитет Преузми Видео @@ -59,4 +59,11 @@ Користи Тор Принудно преусмерење саобраћаја кроз Тор за доданту приватност (токови још нису подржани) - +Тема + Тамна + Светла + + Изглед + Грешка мреже + + From e25c93bae2c7089ff7998deeb40c5e5502f3c010 Mon Sep 17 00:00:00 2001 From: Matej U Date: Wed, 6 Jan 2016 09:07:59 +0100 Subject: [PATCH 56/57] Translated using Weblate (Slovenian) Currently translated at 100.0% (56 of 56 strings) --- app/src/main/res/values-sl/strings.xml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/values-sl/strings.xml b/app/src/main/res/values-sl/strings.xml index 13266f519..7a557d8a7 100644 --- a/app/src/main/res/values-sl/strings.xml +++ b/app/src/main/res/values-sl/strings.xml @@ -27,8 +27,8 @@ Pokaži možnost \"Predvajaj s Kodi\" Privzet zapis zvoka Zvok - WebM — prost zapis - m4a — višja kakovost posnetkov + WebM — prost zapis + m4a — višja kakovost posnetkov Prejem Naslednji video Pokaži naslednji video in podobne posnetke @@ -51,4 +51,14 @@ Predvajanje v ozadju Predvajaj - + Tema + Temna + Svetla + + Videz + Drugo + Omrežna napaka + + Uporabi Tor + Vsili prenos prejema preko sistema Tor za povečanje zasebnosti (pretakanje videa ni še podprto) + From 93620371772cf6d441c5d3de61bb36ac5f08edb4 Mon Sep 17 00:00:00 2001 From: Christian Schabesberger Date: Wed, 6 Jan 2016 15:00:33 +0100 Subject: [PATCH 57/57] remove theme option since it's not yet working --- app/src/main/res/xml/settings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml index 045e95599..22f9644fe 100644 --- a/app/src/main/res/xml/settings.xml +++ b/app/src/main/res/xml/settings.xml @@ -39,6 +39,7 @@ android:title="@string/settings_category_appearance_title" android:textAllCaps="true"> +