From fc31458cc408e0f3cfba310553aee0e54f46b6af Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Fri, 12 Oct 2018 02:34:30 +0530 Subject: [PATCH 01/19] added peertube --- app/build.gradle | 2 +- app/src/main/java/org/schabi/newpipe/App.java | 3 ++- app/src/main/java/org/schabi/newpipe/Downloader.java | 7 ++++--- .../java/org/schabi/newpipe/util/ExtractorHelper.java | 8 +++----- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 2104d2023..5e634d9b9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,7 +55,7 @@ dependencies { exclude module: 'support-annotations' } - implementation 'com.github.yausername:NewPipeExtractor:d1ff1c7' + implementation 'com.github.yausername:NewPipeExtractor:c9fba9c' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.8.9' diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index dfce8f100..c0af70efb 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -21,6 +21,7 @@ import org.acra.config.ConfigurationBuilder; import org.acra.sender.ReportSenderFactory; import org.schabi.newpipe.extractor.Downloader; import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.utils.Localization; import org.schabi.newpipe.report.AcraReportSenderFactory; import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.UserAction; @@ -88,7 +89,7 @@ public class App extends Application { // Initialize settings first because others inits can use its values SettingsActivity.initSettings(this); - NewPipe.init(getDownloader()); + NewPipe.init(getDownloader(), new Localization("GB", "en")); StateSaver.init(this); initNotificationChannel(); diff --git a/app/src/main/java/org/schabi/newpipe/Downloader.java b/app/src/main/java/org/schabi/newpipe/Downloader.java index 16f2ed4ae..8ff2b839a 100644 --- a/app/src/main/java/org/schabi/newpipe/Downloader.java +++ b/app/src/main/java/org/schabi/newpipe/Downloader.java @@ -6,6 +6,7 @@ import android.text.TextUtils; import org.schabi.newpipe.extractor.DownloadRequest; import org.schabi.newpipe.extractor.DownloadResponse; import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; +import org.schabi.newpipe.extractor.utils.Localization; import java.io.IOException; import java.io.InputStream; @@ -109,13 +110,13 @@ public class Downloader implements org.schabi.newpipe.extractor.Downloader { * but set the HTTP header field "Accept-Language" to the supplied string. * * @param siteUrl the URL of the text file to return the contents of - * @param language the language (usually a 2-character code) to set as the preferred language + * @param localization the language and country (usually a 2-character code for both values) * @return the contents of the specified text file */ @Override - public String download(String siteUrl, String language) throws IOException, ReCaptchaException { + public String download(String siteUrl, Localization localization) throws IOException, ReCaptchaException { Map requestProperties = new HashMap<>(); - requestProperties.put("Accept-Language", language); + requestProperties.put("Accept-Language", localization.getLanguage()); return download(siteUrl, requestProperties); } diff --git a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java index 5a9911a67..e328ad23e 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ExtractorHelper.java @@ -76,8 +76,7 @@ public final class ExtractorHelper { SearchInfo.getInfo(NewPipe.getService(serviceId), NewPipe.getService(serviceId) .getSearchQHFactory() - .fromQuery(searchString, contentFilter, sortFilter), - contentCountry)); + .fromQuery(searchString, contentFilter, sortFilter))); } public static Single getMoreSearchItems(final int serviceId, @@ -92,7 +91,6 @@ public final class ExtractorHelper { NewPipe.getService(serviceId) .getSearchQHFactory() .fromQuery(searchString, contentFilter, sortFilter), - contentCountry, pageUrl)); } @@ -104,7 +102,7 @@ public final class ExtractorHelper { return Single.fromCallable(() -> NewPipe.getService(serviceId) .getSuggestionExtractor() - .suggestionList(query, contentCountry)); + .suggestionList(query)); } public static Single getStreamInfo(final int serviceId, @@ -128,7 +126,7 @@ public final class ExtractorHelper { final String nextStreamsUrl) { checkServiceId(serviceId); return Single.fromCallable(() -> - ChannelInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl)); + ChannelInfo.getMoreItems(NewPipe.getService(serviceId), url, nextStreamsUrl, NewPipe.getLocalization())); } public static Single getCommentsInfo(final int serviceId, From cc6989b4f961aa2199c38ce31430d231a9649f3a Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Fri, 12 Oct 2018 13:16:16 +0530 Subject: [PATCH 02/19] updated extractor --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 5e634d9b9..7ba0ef803 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -55,7 +55,7 @@ dependencies { exclude module: 'support-annotations' } - implementation 'com.github.yausername:NewPipeExtractor:c9fba9c' + implementation 'com.github.yausername:NewPipeExtractor:4883b6f' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.8.9' From 845663f80fe6aa5aee0c1e43ee35c7d599a564ba Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Sat, 29 Dec 2018 23:06:39 +0530 Subject: [PATCH 03/19] added themeing for peertube, change peertube instance --- app/build.gradle | 2 +- .../java/org/schabi/newpipe/MainActivity.java | 3 ++ .../settings/ContentSettingsFragment.java | 39 ++++++++++++++++++ .../schabi/newpipe/util/KioskTranslator.java | 4 ++ .../schabi/newpipe/util/ServiceHelper.java | 24 ++++++++++- .../org/schabi/newpipe/util/ThemeHelper.java | 9 +++- .../ic_kiosklocal_black_24dp.png | Bin 0 -> 208 bytes .../ic_kiosklocal_white_24dp.png | Bin 0 -> 206 bytes .../ic_kioskrecent_black_24dp.png | Bin 0 -> 475 bytes .../ic_kioskrecent_white_24dp.png | Bin 0 -> 460 bytes .../ic_kiosklocal_black_24dp.png | Bin 0 -> 166 bytes .../ic_kiosklocal_white_24dp.png | Bin 0 -> 166 bytes .../ic_kioskrecent_black_24dp.png | Bin 0 -> 311 bytes .../ic_kioskrecent_white_24dp.png | Bin 0 -> 312 bytes .../res/drawable-nodpi/place_holder_cloud.png | Bin 0 -> 8032 bytes .../drawable-nodpi/place_holder_peertube.png | Bin 0 -> 15722 bytes .../ic_kiosklocal_black_24dp.png | Bin 0 -> 235 bytes .../ic_kiosklocal_white_24dp.png | Bin 0 -> 226 bytes .../ic_kioskrecent_black_24dp.png | Bin 0 -> 597 bytes .../ic_kioskrecent_white_24dp.png | Bin 0 -> 588 bytes .../ic_kiosklocal_black_24dp.png | Bin 0 -> 291 bytes .../ic_kiosklocal_white_24dp.png | Bin 0 -> 284 bytes .../ic_kioskrecent_black_24dp.png | Bin 0 -> 856 bytes .../ic_kioskrecent_white_24dp.png | Bin 0 -> 835 bytes .../ic_kiosklocal_black_24dp.png | Bin 0 -> 344 bytes .../ic_kiosklocal_white_24dp.png | Bin 0 -> 345 bytes .../ic_kioskrecent_black_24dp.png | Bin 0 -> 1178 bytes .../ic_kioskrecent_white_24dp.png | Bin 0 -> 1157 bytes .../main/res/values-v21/styles_services.xml | 19 +++++++++ app/src/main/res/values/attrs.xml | 2 + app/src/main/res/values/colors_services.xml | 11 +++++ app/src/main/res/values/settings_keys.xml | 2 + app/src/main/res/values/strings.xml | 1 + app/src/main/res/values/styles.xml | 4 ++ app/src/main/res/values/styles_services.xml | 19 +++++++++ app/src/main/res/xml/content_settings.xml | 5 +++ 36 files changed, 140 insertions(+), 4 deletions(-) create mode 100755 app/src/main/res/drawable-hdpi/ic_kiosklocal_black_24dp.png create mode 100755 app/src/main/res/drawable-hdpi/ic_kiosklocal_white_24dp.png create mode 100755 app/src/main/res/drawable-hdpi/ic_kioskrecent_black_24dp.png create mode 100755 app/src/main/res/drawable-hdpi/ic_kioskrecent_white_24dp.png create mode 100755 app/src/main/res/drawable-mdpi/ic_kiosklocal_black_24dp.png create mode 100755 app/src/main/res/drawable-mdpi/ic_kiosklocal_white_24dp.png create mode 100755 app/src/main/res/drawable-mdpi/ic_kioskrecent_black_24dp.png create mode 100755 app/src/main/res/drawable-mdpi/ic_kioskrecent_white_24dp.png create mode 100644 app/src/main/res/drawable-nodpi/place_holder_cloud.png create mode 100644 app/src/main/res/drawable-nodpi/place_holder_peertube.png create mode 100755 app/src/main/res/drawable-xhdpi/ic_kiosklocal_black_24dp.png create mode 100755 app/src/main/res/drawable-xhdpi/ic_kiosklocal_white_24dp.png create mode 100755 app/src/main/res/drawable-xhdpi/ic_kioskrecent_black_24dp.png create mode 100755 app/src/main/res/drawable-xhdpi/ic_kioskrecent_white_24dp.png create mode 100755 app/src/main/res/drawable-xxhdpi/ic_kiosklocal_black_24dp.png create mode 100755 app/src/main/res/drawable-xxhdpi/ic_kiosklocal_white_24dp.png create mode 100755 app/src/main/res/drawable-xxhdpi/ic_kioskrecent_black_24dp.png create mode 100755 app/src/main/res/drawable-xxhdpi/ic_kioskrecent_white_24dp.png create mode 100755 app/src/main/res/drawable-xxxhdpi/ic_kiosklocal_black_24dp.png create mode 100755 app/src/main/res/drawable-xxxhdpi/ic_kiosklocal_white_24dp.png create mode 100755 app/src/main/res/drawable-xxxhdpi/ic_kioskrecent_black_24dp.png create mode 100755 app/src/main/res/drawable-xxxhdpi/ic_kioskrecent_white_24dp.png diff --git a/app/build.gradle b/app/build.gradle index 31ec4776a..f88a43ffc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -54,7 +54,7 @@ dependencies { exclude module: 'support-annotations' }) - implementation 'com.github.yausername:NewPipeExtractor:df0db84' + implementation 'com.github.yausername:NewPipeExtractor:b1a77fa' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.23.0' diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index a9f2e9622..729bb2bd4 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -50,6 +50,7 @@ import android.widget.ImageView; import android.widget.TextView; import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.fragments.BackPressable; @@ -95,6 +96,8 @@ public class MainActivity extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]"); + ServiceHelper.initServices(this); + ThemeHelper.setTheme(this, ServiceHelper.getSelectedServiceId(this)); super.onCreate(savedInstanceState); diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java index 82604f7da..5388d1821 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java @@ -18,9 +18,11 @@ import com.nostra13.universalimageloader.core.ImageLoader; import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.utils.Localization; import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.UserAction; +import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.FilePickerActivityHelper; import org.schabi.newpipe.util.ZipHelper; @@ -39,6 +41,9 @@ import java.util.Map; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; +import io.reactivex.Single; +import io.reactivex.schedulers.Schedulers; + public class ContentSettingsFragment extends BasePreferenceFragment { private static final int REQUEST_IMPORT_PATH = 8945; @@ -122,6 +127,40 @@ public class ContentSettingsFragment extends BasePreferenceFragment { NewPipe.setLocalization(new Localization((String) newCountry, oldLocal.getLanguage())); return true; }); + + + Preference peerTubeInstance = findPreference(getString(R.string.peertube_instance_url_key)); + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); + peerTubeInstance.setDefaultValue(sharedPreferences.getString(getString(R.string.peertube_instance_url_key), ServiceList.PeerTube.getBaseUrl())); + peerTubeInstance.setSummary(sharedPreferences.getString(getString(R.string.peertube_instance_url_key), ServiceList.PeerTube.getBaseUrl())); + + peerTubeInstance.setOnPreferenceChangeListener((Preference p, Object newInstance) -> { + String url = (String) newInstance; + if(!url.startsWith("https://")){ + Toast.makeText(getActivity(), "instance url should start with https://", + Toast.LENGTH_SHORT).show(); + return false; + }else{ + boolean shouldUpdate = Single.fromCallable(() -> { + ServiceList.PeerTube.setInstance(url); + return true; + }).subscribeOn(Schedulers.io()) + .onErrorReturnItem(false) + .blockingGet(); + + if (shouldUpdate) { + p.setSummary(url); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString(getString(R.string.peertube_instance_name_key), ServiceList.PeerTube.getServiceInfo().getName()).apply(); + editor.putString(getString(R.string.current_service_key), ServiceList.PeerTube.getServiceInfo().getName()).apply(); + editor.putBoolean(Constants.KEY_MAIN_PAGE_CHANGE, true).apply(); + }else{ + Toast.makeText(getActivity(), "unable to update instance", + Toast.LENGTH_SHORT).show(); + } + return shouldUpdate; + } + }); } @Override diff --git a/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java index 392892cef..61bd2323d 100644 --- a/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java +++ b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java @@ -44,6 +44,10 @@ public class KioskTranslator { return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_hot); case "New & hot": return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_hot); + case "Local": + return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_kiosk_local); + case "Recently added": + return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_kiosk_recent); default: return 0; } diff --git a/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java b/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java index 7c781eb14..ab2d7c6b9 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java @@ -1,6 +1,7 @@ package org.schabi.newpipe.util; import android.content.Context; +import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.support.annotation.DrawableRes; import android.support.annotation.StringRes; @@ -10,7 +11,9 @@ import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.services.peertube.PeertubeInstance; +import java.io.IOException; import java.util.concurrent.TimeUnit; import static org.schabi.newpipe.extractor.ServiceList.SoundCloud; @@ -24,9 +27,11 @@ public class ServiceHelper { case 0: return R.drawable.place_holder_youtube; case 1: - return R.drawable.place_holder_circle; + return R.drawable.place_holder_cloud; + case 2: + return R.drawable.place_holder_peertube; default: - return R.drawable.service; + return R.drawable.place_holder_circle; } } @@ -127,4 +132,19 @@ public class ServiceHelper { default: return true; } } + + public static void initService(Context context, int serviceId) { + if(serviceId == 2){ + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + String peerTubeInstanceUrl = sharedPreferences.getString(context.getString(R.string.peertube_instance_url_key), ServiceList.PeerTube.getBaseUrl()); + String peerTubeInstanceName = sharedPreferences.getString(context.getString(R.string.peertube_instance_name_key), ServiceList.PeerTube.getServiceInfo().getName()); + ServiceList.PeerTube.setInstance(peerTubeInstanceUrl, peerTubeInstanceName); + } + } + + public static void initServices(Context context){ + for(StreamingService s : ServiceList.all()){ + initService(context, s.getServiceId()); + } + } } diff --git a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java index 1d1b66bf9..b8fba6ce5 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java @@ -136,7 +136,14 @@ public class ThemeHelper { else if (selectedTheme.equals(blackTheme)) themeName = "BlackTheme"; else if (selectedTheme.equals(darkTheme)) themeName = "DarkTheme"; - themeName += "." + service.getServiceInfo().getName(); + switch (serviceId) { + case 2: + //service name for peertube depends on the instance + themeName += ".PeerTube"; + break; + default: + themeName += "." + service.getServiceInfo().getName(); + } int resourceId = context.getResources().getIdentifier(themeName, "style", context.getPackageName()); if (resourceId > 0) { diff --git a/app/src/main/res/drawable-hdpi/ic_kiosklocal_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_kiosklocal_black_24dp.png new file mode 100755 index 0000000000000000000000000000000000000000..a9e2993ebeaea19899781fcac3bd118f00f38e66 GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8LpbWaz@kP61Pmlg^(J4m=Z6mLAZ zSkRNP#6eV~FgAc;>IGKO3rte=Y@0hBQj9qN$1)r|Q+s}W6yL-dIncC2Q> zkeYOEy`3{({8{*|k0wldT1B8LpR8JSjkP61PmjroQ9b_6lR!?|R z_+j4rm~*w3^M6m%FF#j%T5J7_%c2C^MSaXU~e@mSHPv-ZfPWDEx?)w8B$l&Sf=d#Wz Gp$P!p(pG=~ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_kioskrecent_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_kioskrecent_black_24dp.png new file mode 100755 index 0000000000000000000000000000000000000000..13813ff829c92dc913fb2f6cf003ef768f6cf74a GIT binary patch literal 475 zcmV<10VMv3P)< z18A;c7>2Le%QgiCwLi?ZvzwQ-Wh`^H?JZ4DPk4TOd%s%T^``f}?_Pte zNjCKiGQ|=5Ofg6u+4v-ppGzg=3MU?Ag;zL`%ZZkCT6xM%Qc2?m&uL`? z^$6e%jT)Th8*x}5p0CVmq7e@YG}P^}4vBPVs(=W**FY5)QLV}M;d@#WvyUjF-zGqS z+eV9`N3yFV5kihwbEIGigk9WZ=0wjSgher4gHuEBTJ%M*WQsgVv~xqzdSo*(6p2^~ z&J97OI7JxxMSSF|p@-u1V;B+fy4fiy42Uy;)XWZE7iSp5zKH2&6k&=PUAolvFzkw$ z>Z_qtsqJ3Y)J8B!oQJ*^`+;_0C>F8YS3~9Dwm(}Bq>qO5KxScxVnO7W&JDd3eSs(} z{MSpH?09MCMgLC-Nvw+1?-5#Jz<2%yMF1ORH;Ozl2L RuKfT2002ovPDHLkV1iXF)xH1# literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_kioskrecent_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_kioskrecent_white_24dp.png new file mode 100755 index 0000000000000000000000000000000000000000..9054e0042dcc677cf55075666fd1b71d4d452060 GIT binary patch literal 460 zcmV;-0W41wT{E^(#Lgn9-PoyZ$LbAg+p$wO*4`K!v$pLvd}{nVli8W1;l3yQPVycj z8ItIAM87+}_~?#)hxL|KG+X7CEN)q?xu|BgXYzPvb`i}c056>~%_!|Uj5Nb3uK-jB z(;NfbwOm80w$U>80mt$*TLBj|=gi+(z}6%i3jq6*L2v-DAiJd(;Ic}{$Ed0r6S9hn z;JKExXd`%_E#|6OldIJOurV!q4CaI|h$7~I#{=VTaNDrLqG4`Z}MvejR04p=p*P1y+{*|hfeSzir$0vQlfV7{(lYa zS`^j5q*9YT5!7P11MDd!+LN{Xz2J5!(Jjyu!-_{>R#A~z;E~F}iVfg_)`ExjA=r@a zXp86IVxeo~a=bSlQ=%z%MzijW2GLcov$O0vx|U_mR@2~k|K+3H?bywIvWjI^QeR{=N-j9xJ@~0TM3+>Q=Zc_59|is#ZjbTE*yy^`rrii= OF@vY8pUXO@geCy$(K~bi literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_kiosklocal_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_kiosklocal_white_24dp.png new file mode 100755 index 0000000000000000000000000000000000000000..23d8145f5d6749cc189d6ab14ce2072cbd9ebbc0 GIT binary patch literal 166 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 B-o^j` literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-nodpi/place_holder_peertube.png b/app/src/main/res/drawable-nodpi/place_holder_peertube.png new file mode 100644 index 0000000000000000000000000000000000000000..68850054d27d6d7518d6c62e9a28388e3051b929 GIT binary patch literal 15722 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_kiosklocal_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_kiosklocal_black_24dp.png new file mode 100755 index 0000000000000000000000000000000000000000..e20865ab0b15605d8c51d2386cecfaf674080a89 GIT binary patch literal 235 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DO`a}}Ar*{C3#=tr7bh?YT;kba zv?l2Xf6M9y9VrIAwq~CH3qL4Ka8Fg>%9!8NE78)(u#9KoEYTYcni5U1H+n^5F7ICW zbBksCp_e_Ur?Um9@;y4;Y|cDW!zDQ}Nx)eB&b=;`TVenJ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_kiosklocal_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_kiosklocal_white_24dp.png new file mode 100755 index 0000000000000000000000000000000000000000..2d3474832d420c541225548569aba317a0ede07c GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0Dm7Xq+Ar*{oFE12qb`WrT*n8l? z#Vro(A&!DynilZwTEGrPAko^B0V9bB1fa&Kjb_1b)`yN=Iidrg1Qy0Yj{O;1P5Pl1`@T^te1G8C8uI~-V? aIQ&Z&u5O4^zOxMIXa-MLKbLh*2~7amL|PgE literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_kioskrecent_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_kioskrecent_black_24dp.png new file mode 100755 index 0000000000000000000000000000000000000000..54e81598012322cc3c06622fe2597cde8610b028 GIT binary patch literal 597 zcmV-b0;>IqP)uZrpewH=uD1?YC;c^D@nD-&Gbfc)nx)c?8!-e)%> j{?9e`5UUwVo1l{l8^BdtbC;&P00000NkvXXu0mjfTHO)h literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_kioskrecent_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_kioskrecent_white_24dp.png new file mode 100755 index 0000000000000000000000000000000000000000..3141a790d7100e25ca4be716c91e15ca93092f65 GIT binary patch literal 588 zcmV-S0<-;zP)HQ)4A=4-jdiCEDW-ZSn$mg}b}EBv*c9;b(5faQNDhH9l+G zpW#1xGM^1x1LP_jnMY5Hk3Ov848@#bC4DR^5>)dVKd-4KVc}82Rf4)oN!VlGfXGXB zGm{bYCP9*(3}+6zc!kJ@z~@0{4kG|}SwPA>kYWLM5rD&VF@LmWKLT0mNLw>VQ%4g5 z`)Fr=*nq%8CRzYY<{<*>{Z^ijzy7-I`I^_7w-9{FZYnAbhctxgS=v- z=W@Yw*=SxOYt0+oXhh0P0tN_WNF&|N3pL0c5|IKD+(v55MN94@OH4up2uqNAv~(9v zL~ZDukejqL7uCq^$e-&wNR4@+JB>(rq=0gyk#0ZY zmpPJG$lB&ASJa<=ALpm87V|?p_5qTm3jgYu4O|_C zE>8LN3?a>8xBNz}?|YcV2zrwuNiRk)huyr6Sl^=$AU}PCia!LNjXnhWjjoanv^bivy@(76}`YDB`;iD)0iM}Xii0p(c#;<30ISP44;|Lnbn4h3!22o7)XgFg2J7Y!Kd^}C zW)Z&td+)z2+-Z_kCm$=YTV^!ba}`Z!mU#kXpK# My85}Sb4q9e05FAaVgLXD literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_kiosklocal_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_kiosklocal_white_24dp.png new file mode 100755 index 0000000000000000000000000000000000000000..6b27fb23cb9c70d3538bee222ad7925ffe7b37cf GIT binary patch literal 284 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhaw9(%ethEy=Vy|R$EnL)($VtnJl z#gUD?Gny1{uwJyh(Zm_S*n2!7FLd&<%-Q)B6TZylT(>K+-N5+qIoowjO@a**mCm`J zJaXAZ^7*2qXIFhhpD#>%c-Kkx`GUl!lc%bE$+-C=Z85K|RaxE5mrm{TdhA4Y7)~&K zp*F)bXa$f6Tm>Y8SE|j}8n7BjTmp)1y$BTBdikZ=jH|DKk}uRe>ZYyYoHT!FR@0O8 zm9rFnMy^5;syx8by7>vi#AgcZmKyth%mz{?9QleSG|N0uV2_mdKI;Vst0DS9xwg3PC literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_kioskrecent_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_kioskrecent_black_24dp.png new file mode 100755 index 0000000000000000000000000000000000000000..92fc748ec842d6660d15baa0cd921ff7dc2beb46 GIT binary patch literal 856 zcmV-e1E>6nP)cD5BbpwFoy(YKFBH)wZKG!rHdmur^k&LGkBi=MC?x-go0U=btma z7=i=|^2ZWR5zE;@C1-iW7e4WrbCk1#6%-Lp0Lfq}ckr3C+bkmm%`_*U^Z0DEa}>}F zO%(6|pM&;*0z9V^NAS65N9cry4B`nsm+c9I@PtlmH`v8}_Ar6|wBiS?>Bl7YaL>T8 zoldxYTOfEYJi{?$ zrtAf44J3Q$GcjbFkWJGXXsYmR!;q6gHcD%t(bnGA4}>fp6`zZy5+}!P81h2MdT0&Q z-P+^RC}eH525Kd?HDE}skhKa}pjr%hC1l+LcFA60$dli4Q$N9w<3ct%V2}MV4B0BX z9$EuU6P~TsJ{{8G*B|Nc8Ah1AaIin&SrAT zXpR>&SLV^SJD;%Hg%|8X)_g+`Y%tREDZL#^#o^dwsZyYf_Bf?IrAoD>*rpj(sMEr6 zI3bQ(UQ7!^dv0i(ICn@0ckrQxTJ3UaAp{q6=W>&aFWX7QAL+)6FFKc}_KM}HjwCUN zLT0gt`v#63bixw`@f4rS_LM>Y<`So%fX9x)Jf;9mG^daYw!)mJkmhJ6on;n&B)G#e iQvTClE$k2^NRV#`WILA%PrLL00000wH)9K5Bb15QaH;#)-spDRFmYPIkUKpms`xHv6w|(25^ob&N7fZVg>`b zPZ;+ZC~>0%JBeZ^B_uv{B9*98=@i$0vxeN=V}Ej)Z5qnn)|4Fk^>P)4%9{67biSHl`|St*4O1jHmb1EpaQ5YaY8z( zK+=NJ#R<<)Ws`Quo{1Auf5}OmDo!|t>YcR9{-`)%6>5yppwXyR{vI9Mj0SD<_vq-F zw1?|6R9C;RAFWIU(bD7fLvaGN$XL)K)bZc#6?UB0^f??RJP}|h(k&J3_2`c z=!(_k*n_5cd?n_1C3%k7$hMq;)gWaq!zv&=$H>oQjP?wt##=?rCT>mWw=ZebQhJ>gE z5myV9qb*-9k?139Xd*6XW@P!|xt`jj>nV!UkWLI@JR7-3?$%Nwt_5BiQKix8?_6;z z29iP;DGW5XCLhFkf;h(@@`_nByu#-0md3EaG3Hn%CG$(k1ry__FKnSCi*tePnMYlE_L&P@G(Z_BF4Sz;%6mpm=5o(Q5@iIy$m`{LkxibZwFEj0I+~Sa@pgTd@gZl~FB{+As@9F1d8*cxL5ny0A%)s;c{V%?A yd$w>H*)lLR=rS`*VFHE-7+7$^SQAt{CoN$)b3@cq)zN+mNYvBS&t;ucLK6VShk<$k literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_kiosklocal_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_kiosklocal_white_24dp.png new file mode 100755 index 0000000000000000000000000000000000000000..b04fd7a885c3778ceaf8438d0ea1845193f2fa53 GIT binary patch literal 345 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7z^LHq;uuoF_~zh3-ev{?h6Cmj zHnT);G-%%Fw!G2A8Nt|lJYn4`&&yj%eSbW8zi3L3m*&zx-8W?-Gj$R!y4XdnULGpF z^F>Zv?yeKg`QP)dyYsQN`|~;9nSb%+?8_40(~5pRHL{(tx|q2kQKBR9+>TqW*4lTk zro|<3>a1URGw^gq-^-guc3-6c)I$ztaD0e0ssYYmtp__ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_kioskrecent_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_kioskrecent_black_24dp.png new file mode 100755 index 0000000000000000000000000000000000000000..152259fabb9cf9b5b7b21c033fb6ac5f291f11d1 GIT binary patch literal 1178 zcmV;L1ZDe)P);6h-$dK9#?1+qP%lwyn0UQQPiG+nTp++qP{+L{%~}ve(KT)4ccQNd`_35fKp) z5#b}Z^B(`voWV?BKI=Kmem1ax2@Iw=|M4ET5=zp1MkiKq%tl*IXFeg1(C{E_*uyc0 zZ5Qo$2*YIaDPuY2p^fD;vN1vtHQ2y0AKE%L_c^RaE>dtwB{eN5n(hBkrw z2!Qw4%P~!DFYlq14C-5+#6d>Wo_~3phq<0O39jQI-r--`F`9#x@ePQfi8w>bEWME0 zyiBe|j+dy-!ZPy=C5{FzXHuypx6_aZaKimGVtc9iCQ*#f+`@8oF;?&=N!*a)4_2zP zvY1=&k*n2(I7%B*cp*(2wFFjj4L)(X`k7@luiyu-s4ou-xB?%DGfkPkANlx20lkzp zrV+<8EtQYXANb8*992|miAP>jp8i+p;5(&+H}Jq^Y*M8B5ncSGsJ4;Ia7_aFT=J44SqpU2Oi}e^T#&_5DbYw`*hP%BON`-C>=LqZ%x{XmP8zfefHVuF=-+Ti z7Hg$%&jS#M0C-6H9xWpaM|>-tKzj&G0CbSzzrhg;gzz0)7N~&B*&%f-9Ppx4z7_;3 z0BT7YUcffpr8%6!zy%bt%kBRl#eN~Q2?Q3#aQyH5V8%734pCamRFtkf%+O1&`0bO zIq%NaGAcm)oi)RfkwVC4Mg@E(b?7abDTF+ZnqxjUHIEBN&BT)BLdeZV1>7vIuQ`A3 zFEc9Oa^a}0SRxK3;zk9;g`3 zz6flQPd1nQfn&0nFQpkyhIRoNjFe*MlZ6YOabdpDV=j3bmvmPotAtJ}`)M_R%h(vG z+2aSLCH68r@P^WE^Bp?)QE9h%O^@N}FZ|{Yj_G;l;!M?UIm@S?vc^>6_&^B@P@Dc< z#t&X*HEPpe2|jU6skY13o^6+{tZbM1jjz9x#0^P)E7kbAoLj?fJ$}H#dVIMF^Y>!v zSem~Ryi8pdmzie>aWoOLWxpRod;U9PzfY3j`ZMt7>42h+FskXZ5P+JcgMC}8rxG?8@G(LjdRAft-Nb=C-(*?on)%=lyUII>Hb>6 zlS-vhsT9X^8|@g$TYSc^tY8m2SV@M@c#Dy=<2H_!B%+f0n8HH5Sin^7p-Pg1Ga1KL z{MyU}&XRah#Jzk>Ei$@7WcQ$JhdNK=qw?!AMkJ#unf! zR3rDTVU=To4y#nK9o5iS0t`j9g9`D6>4_X#oGxB*1-ibG2k3|H^4x~k>!J)mEgMi} za-HCq5NUu3=pGe6C}b%ri?gB%z!_MmmQg7F&;ng1vPr%yx)wn?p}(Sgk9^Ys$fptA zuM~=ZTw`|R?7E0Sbj_`5pkY5&MOyZF0=w1hC&6(8b{3C`0X&I?-F0RP zPpu?mv;ZUL9Ho41ymD5}t2p_ZQpp_+WN@;Ct0e?n%@UksXpnGlNRze8u{qZ+$GFul z%@<#v4_JIH=Q$SPYyrn6yLx@color/dark_soundcloud_accent_color + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml index 7b879fb4c..c03defcd3 100644 --- a/app/src/main/res/values/attrs.xml +++ b/app/src/main/res/values/attrs.xml @@ -28,6 +28,8 @@ + + diff --git a/app/src/main/res/values/colors_services.xml b/app/src/main/res/values/colors_services.xml index 761b721d0..2aaa2d4e6 100644 --- a/app/src/main/res/values/colors_services.xml +++ b/app/src/main/res/values/colors_services.xml @@ -22,4 +22,15 @@ #FFFFFF #ff9100 + + #f97d46 + #c04e19 + #000000 + #f97d46 + + #f97d46 + #c04e19 + #FFFFFF + #f97d46 + \ 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 be0709b66..7530bd8e8 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -143,6 +143,8 @@ en GB content_language + peertube_instance_url + peertube_instance_name content_country show_age_restricted_content use_tor diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 12a5d8ca7..ff9c04737 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -107,6 +107,7 @@ Default content country Service Default content language + PeerTube instance Player Behavior Video & audio diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 87e19cede..1ba7699eb 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -44,6 +44,8 @@ @drawable/ic_play_arrow_black_24dp @drawable/ic_settings_black_24dp @drawable/ic_whatshot_black_24dp + @drawable/ic_kiosklocal_black_24dp + @drawable/ic_kioskrecent_black_24dp @drawable/ic_channel_black_24dp @drawable/ic_bookmark_black_24dp @drawable/ic_playlist_add_black_24dp @@ -104,6 +106,8 @@ @drawable/ic_play_arrow_white_24dp @drawable/ic_settings_white_24dp @drawable/ic_whatshot_white_24dp + @drawable/ic_kiosklocal_white_24dp + @drawable/ic_kioskrecent_white_24dp @drawable/ic_channel_white_24dp @drawable/ic_bookmark_white_24dp @drawable/ic_playlist_add_white_24dp diff --git a/app/src/main/res/values/styles_services.xml b/app/src/main/res/values/styles_services.xml index 7ca9dacde..82eac26ab 100644 --- a/app/src/main/res/values/styles_services.xml +++ b/app/src/main/res/values/styles_services.xml @@ -28,4 +28,23 @@ @color/dark_soundcloud_accent_color + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/content_settings.xml b/app/src/main/res/xml/content_settings.xml index bd623f833..e998c96ab 100644 --- a/app/src/main/res/xml/content_settings.xml +++ b/app/src/main/res/xml/content_settings.xml @@ -18,6 +18,11 @@ android:summary="%s" android:title="@string/content_language_title"/> + + Date: Sun, 10 Mar 2019 17:30:21 +0530 Subject: [PATCH 04/19] init services in app onCreate --- app/src/main/java/org/schabi/newpipe/App.java | 5 +++-- app/src/main/java/org/schabi/newpipe/MainActivity.java | 3 --- .../org/schabi/newpipe/settings/ContentSettingsFragment.java | 4 +--- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index 3ac2d5014..fed38f1eb 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -6,7 +6,6 @@ import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; import android.os.Build; -import android.preference.PreferenceManager; import android.support.annotation.Nullable; import android.util.Log; @@ -23,12 +22,12 @@ import org.acra.config.ConfigurationBuilder; import org.acra.sender.ReportSenderFactory; import org.schabi.newpipe.extractor.Downloader; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.utils.Localization; import org.schabi.newpipe.report.AcraReportSenderFactory; import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.settings.SettingsActivity; import org.schabi.newpipe.util.ExtractorHelper; +import org.schabi.newpipe.util.ServiceHelper; import org.schabi.newpipe.util.StateSaver; import java.io.IOException; @@ -100,6 +99,8 @@ public class App extends Application { StateSaver.init(this); initNotificationChannel(); + ServiceHelper.initServices(this); + // Initialize image loader ImageLoader.getInstance().init(getImageLoaderConfigurations(10, 50)); diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index cdb948436..3821af896 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -95,8 +95,6 @@ public class MainActivity extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]"); - ServiceHelper.initServices(this); - ThemeHelper.setTheme(this, ServiceHelper.getSelectedServiceId(this)); super.onCreate(savedInstanceState); @@ -302,7 +300,6 @@ public class MainActivity extends AppCompatActivity { drawerItems.getMenu() .add(R.id.menu_services_group, s.getServiceId(), ORDER, title) .setIcon(ServiceHelper.getIcon(s.getServiceId())); - } drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this)).setChecked(true); } diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java index da6d372f4..801a55fd7 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java @@ -147,7 +147,6 @@ public class ContentSettingsFragment extends BasePreferenceFragment { if (!url.startsWith("https://")) { Toast.makeText(getActivity(), "instance url should start with https://", Toast.LENGTH_SHORT).show(); - return false; } else { pEt.setSummary("fetching instance details.."); Disposable disposable = Single.fromCallable(() -> { @@ -174,8 +173,8 @@ public class ContentSettingsFragment extends BasePreferenceFragment { Toast.LENGTH_SHORT).show(); }); disposables.add(disposable); - return false; } + return false; }); } @@ -360,5 +359,4 @@ public class ContentSettingsFragment extends BasePreferenceFragment { ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR, "none", "", R.string.app_ui_crash)); } - } From a8b5534838328f4e5c20dab48790411e2a7fcda9 Mon Sep 17 00:00:00 2001 From: Ritvik Saraf <13ritvik@gmail.com> Date: Sun, 10 Mar 2019 19:08:08 +0530 Subject: [PATCH 05/19] darker color for peertube --- app/src/main/res/values/colors_services.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/res/values/colors_services.xml b/app/src/main/res/values/colors_services.xml index d2d759bc0..d38df003e 100644 --- a/app/src/main/res/values/colors_services.xml +++ b/app/src/main/res/values/colors_services.xml @@ -23,15 +23,15 @@ #ff9100 - #f97d46 - #c04e19 + #e65100 + #ac1900 #000000 - #f97d46 + #ff833a - #f97d46 - #c04e19 + #e65100 + #ac1900 #FFFFFF - #f97d46 + #ff833a #9e9e9e From 039a8e0b87eec61c9c6885818529fe7aaf04adbe Mon Sep 17 00:00:00 2001 From: yausername <13ritvik@gmail.com> Date: Sat, 23 Mar 2019 19:49:37 +0530 Subject: [PATCH 06/19] reordered services --- app/build.gradle | 2 +- app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 41c397d64..d037127d9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -57,7 +57,7 @@ dependencies { exclude module: 'support-annotations' }) - implementation 'com.github.yausername:NewPipeExtractor:c220700' + implementation 'com.github.yausername:NewPipeExtractor:f60c973' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.23.0' diff --git a/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java b/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java index 582f3590b..6a4f65bcb 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java @@ -27,9 +27,9 @@ public class ServiceHelper { case 1: return R.drawable.place_holder_cloud; case 2: - return R.drawable.place_holder_peertube; - case 3: return R.drawable.place_holder_gadse; + case 3: + return R.drawable.place_holder_peertube; default: return R.drawable.place_holder_circle; } From ceabfd1a8b5d526e2af98e87668c0a05e2dfbf87 Mon Sep 17 00:00:00 2001 From: yausername <13ritvik@gmail.com> Date: Thu, 21 Nov 2019 05:41:14 +0530 Subject: [PATCH 07/19] updated extractor --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 7d51a392a..fbd9a7c8c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -62,7 +62,7 @@ dependencies { exclude module: 'support-annotations' }) - implementation 'com.github.yausername:NewPipeExtractor:f3a59a6' + implementation 'com.github.yausername:NewPipeExtractor:4e0adbe' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.23.0' From ac2543d0a1e5b18acc8372cefbbe827e4dcf6c87 Mon Sep 17 00:00:00 2001 From: yausername <13ritvik@gmail.com> Date: Sat, 23 Nov 2019 00:31:35 +0530 Subject: [PATCH 08/19] validate peertube instance. changed peertube color --- app/build.gradle | 2 +- .../settings/ContentSettingsFragment.java | 34 +++++++----------- .../schabi/newpipe/util/ServiceHelper.java | 4 ++- ...24dp.png => ic_kiosk_local_black_24dp.png} | Bin ...24dp.png => ic_kiosk_local_white_24dp.png} | Bin ...4dp.png => ic_kiosk_recent_black_24dp.png} | Bin ...4dp.png => ic_kiosk_recent_white_24dp.png} | Bin ...24dp.png => ic_kiosk_local_black_24dp.png} | Bin ...24dp.png => ic_kiosk_local_white_24dp.png} | Bin ...4dp.png => ic_kiosk_recent_black_24dp.png} | Bin ...4dp.png => ic_kiosk_recent_white_24dp.png} | Bin ...24dp.png => ic_kiosk_local_black_24dp.png} | Bin ...24dp.png => ic_kiosk_local_white_24dp.png} | Bin ...4dp.png => ic_kiosk_recent_black_24dp.png} | Bin ...4dp.png => ic_kiosk_recent_white_24dp.png} | Bin ...24dp.png => ic_kiosk_local_black_24dp.png} | Bin ...24dp.png => ic_kiosk_local_white_24dp.png} | Bin ...4dp.png => ic_kiosk_recent_black_24dp.png} | Bin ...4dp.png => ic_kiosk_recent_white_24dp.png} | Bin ...24dp.png => ic_kiosk_local_black_24dp.png} | Bin ...24dp.png => ic_kiosk_local_white_24dp.png} | Bin ...4dp.png => ic_kiosk_recent_black_24dp.png} | Bin ...4dp.png => ic_kiosk_recent_white_24dp.png} | Bin app/src/main/res/values/colors_services.xml | 8 ++--- app/src/main/res/values/settings_keys.xml | 1 - app/src/main/res/values/strings.xml | 1 + app/src/main/res/values/styles.xml | 8 ++--- 27 files changed, 26 insertions(+), 32 deletions(-) rename app/src/main/res/drawable-hdpi/{ic_kiosklocal_black_24dp.png => ic_kiosk_local_black_24dp.png} (100%) rename app/src/main/res/drawable-hdpi/{ic_kiosklocal_white_24dp.png => ic_kiosk_local_white_24dp.png} (100%) rename app/src/main/res/drawable-hdpi/{ic_kioskrecent_black_24dp.png => ic_kiosk_recent_black_24dp.png} (100%) rename app/src/main/res/drawable-hdpi/{ic_kioskrecent_white_24dp.png => ic_kiosk_recent_white_24dp.png} (100%) rename app/src/main/res/drawable-mdpi/{ic_kiosklocal_black_24dp.png => ic_kiosk_local_black_24dp.png} (100%) rename app/src/main/res/drawable-mdpi/{ic_kiosklocal_white_24dp.png => ic_kiosk_local_white_24dp.png} (100%) rename app/src/main/res/drawable-mdpi/{ic_kioskrecent_black_24dp.png => ic_kiosk_recent_black_24dp.png} (100%) rename app/src/main/res/drawable-mdpi/{ic_kioskrecent_white_24dp.png => ic_kiosk_recent_white_24dp.png} (100%) rename app/src/main/res/drawable-xhdpi/{ic_kiosklocal_black_24dp.png => ic_kiosk_local_black_24dp.png} (100%) rename app/src/main/res/drawable-xhdpi/{ic_kiosklocal_white_24dp.png => ic_kiosk_local_white_24dp.png} (100%) rename app/src/main/res/drawable-xhdpi/{ic_kioskrecent_black_24dp.png => ic_kiosk_recent_black_24dp.png} (100%) rename app/src/main/res/drawable-xhdpi/{ic_kioskrecent_white_24dp.png => ic_kiosk_recent_white_24dp.png} (100%) rename app/src/main/res/drawable-xxhdpi/{ic_kiosklocal_black_24dp.png => ic_kiosk_local_black_24dp.png} (100%) rename app/src/main/res/drawable-xxhdpi/{ic_kiosklocal_white_24dp.png => ic_kiosk_local_white_24dp.png} (100%) rename app/src/main/res/drawable-xxhdpi/{ic_kioskrecent_black_24dp.png => ic_kiosk_recent_black_24dp.png} (100%) rename app/src/main/res/drawable-xxhdpi/{ic_kioskrecent_white_24dp.png => ic_kiosk_recent_white_24dp.png} (100%) rename app/src/main/res/drawable-xxxhdpi/{ic_kiosklocal_black_24dp.png => ic_kiosk_local_black_24dp.png} (100%) rename app/src/main/res/drawable-xxxhdpi/{ic_kiosklocal_white_24dp.png => ic_kiosk_local_white_24dp.png} (100%) rename app/src/main/res/drawable-xxxhdpi/{ic_kioskrecent_black_24dp.png => ic_kiosk_recent_black_24dp.png} (100%) rename app/src/main/res/drawable-xxxhdpi/{ic_kioskrecent_white_24dp.png => ic_kiosk_recent_white_24dp.png} (100%) diff --git a/app/build.gradle b/app/build.gradle index fbd9a7c8c..4259d45a2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -62,7 +62,7 @@ dependencies { exclude module: 'support-annotations' }) - implementation 'com.github.yausername:NewPipeExtractor:4e0adbe' + implementation 'com.github.yausername:NewPipeExtractor:bc75c66' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.23.0' diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java index c14aac4b5..5e3562c7e 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java @@ -24,6 +24,7 @@ import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.localization.ContentCountry; import org.schabi.newpipe.extractor.localization.Localization; +import org.schabi.newpipe.extractor.services.peertube.PeertubeInstance; import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.util.FilePickerActivityHelper; @@ -45,9 +46,8 @@ import java.util.Map; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; -import io.reactivex.Single; +import io.reactivex.Completable; import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; import io.reactivex.schedulers.Schedulers; @@ -68,8 +68,6 @@ public class ContentSettingsFragment extends BasePreferenceFragment { private Localization initialSelectedLocalization; private ContentCountry initialSelectedContentCountry; - private CompositeDisposable disposables = new CompositeDisposable(); - @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -142,30 +140,24 @@ public class ContentSettingsFragment extends BasePreferenceFragment { Toast.LENGTH_SHORT).show(); } else { pEt.setSummary("fetching instance details.."); - Disposable disposable = Single.fromCallable(() -> { - ServiceList.PeerTube.setInstance(url); - return true; + Disposable disposable = Completable.fromAction(() -> { + PeertubeInstance instance = new PeertubeInstance(url); + instance.fetchInstanceMetaData(); + ServiceList.PeerTube.setInstance(instance); }).subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) - .subscribe(result -> { - if (result) { - pEt.setSummary(url); - pEt.setText(url); - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(App.getApp().getString(R.string.peertube_instance_name_key), ServiceList.PeerTube.getServiceInfo().getName()).apply(); - editor.putString(App.getApp().getString(R.string.current_service_key), ServiceList.PeerTube.getServiceInfo().getName()).apply(); - NavigationHelper.openMainActivity(App.getApp()); - } else { - pEt.setSummary(ServiceList.PeerTube.getBaseUrl()); - Toast.makeText(getActivity(), "unable to update instance", - Toast.LENGTH_SHORT).show(); - } + .subscribe(() -> { + pEt.setSummary(url); + pEt.setText(url); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putString(App.getApp().getString(R.string.peertube_instance_name_key), ServiceList.PeerTube.getServiceInfo().getName()).apply(); + editor.putString(App.getApp().getString(R.string.current_service_key), ServiceList.PeerTube.getServiceInfo().getName()).apply(); + NavigationHelper.openMainActivity(App.getApp()); }, error -> { pEt.setSummary(ServiceList.PeerTube.getBaseUrl()); Toast.makeText(getActivity(), "unable to update instance", Toast.LENGTH_SHORT).show(); }); - disposables.add(disposable); } return false; }); diff --git a/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java b/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java index 429331dfd..084ab5878 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java @@ -11,6 +11,7 @@ import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.services.peertube.PeertubeInstance; import java.util.concurrent.TimeUnit; @@ -140,7 +141,8 @@ public class ServiceHelper { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); String peerTubeInstanceUrl = sharedPreferences.getString(context.getString(R.string.peertube_instance_url_key), ServiceList.PeerTube.getBaseUrl()); String peerTubeInstanceName = sharedPreferences.getString(context.getString(R.string.peertube_instance_name_key), ServiceList.PeerTube.getServiceInfo().getName()); - ServiceList.PeerTube.setInstance(peerTubeInstanceUrl, peerTubeInstanceName); + PeertubeInstance instance = new PeertubeInstance(peerTubeInstanceUrl, peerTubeInstanceName); + ServiceList.PeerTube.setInstance(instance); } } diff --git a/app/src/main/res/drawable-hdpi/ic_kiosklocal_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_kiosk_local_black_24dp.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_kiosklocal_black_24dp.png rename to app/src/main/res/drawable-hdpi/ic_kiosk_local_black_24dp.png diff --git a/app/src/main/res/drawable-hdpi/ic_kiosklocal_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_kiosk_local_white_24dp.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_kiosklocal_white_24dp.png rename to app/src/main/res/drawable-hdpi/ic_kiosk_local_white_24dp.png diff --git a/app/src/main/res/drawable-hdpi/ic_kioskrecent_black_24dp.png b/app/src/main/res/drawable-hdpi/ic_kiosk_recent_black_24dp.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_kioskrecent_black_24dp.png rename to app/src/main/res/drawable-hdpi/ic_kiosk_recent_black_24dp.png diff --git a/app/src/main/res/drawable-hdpi/ic_kioskrecent_white_24dp.png b/app/src/main/res/drawable-hdpi/ic_kiosk_recent_white_24dp.png similarity index 100% rename from app/src/main/res/drawable-hdpi/ic_kioskrecent_white_24dp.png rename to app/src/main/res/drawable-hdpi/ic_kiosk_recent_white_24dp.png diff --git a/app/src/main/res/drawable-mdpi/ic_kiosklocal_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_kiosk_local_black_24dp.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_kiosklocal_black_24dp.png rename to app/src/main/res/drawable-mdpi/ic_kiosk_local_black_24dp.png diff --git a/app/src/main/res/drawable-mdpi/ic_kiosklocal_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_kiosk_local_white_24dp.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_kiosklocal_white_24dp.png rename to app/src/main/res/drawable-mdpi/ic_kiosk_local_white_24dp.png diff --git a/app/src/main/res/drawable-mdpi/ic_kioskrecent_black_24dp.png b/app/src/main/res/drawable-mdpi/ic_kiosk_recent_black_24dp.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_kioskrecent_black_24dp.png rename to app/src/main/res/drawable-mdpi/ic_kiosk_recent_black_24dp.png diff --git a/app/src/main/res/drawable-mdpi/ic_kioskrecent_white_24dp.png b/app/src/main/res/drawable-mdpi/ic_kiosk_recent_white_24dp.png similarity index 100% rename from app/src/main/res/drawable-mdpi/ic_kioskrecent_white_24dp.png rename to app/src/main/res/drawable-mdpi/ic_kiosk_recent_white_24dp.png diff --git a/app/src/main/res/drawable-xhdpi/ic_kiosklocal_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_kiosk_local_black_24dp.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_kiosklocal_black_24dp.png rename to app/src/main/res/drawable-xhdpi/ic_kiosk_local_black_24dp.png diff --git a/app/src/main/res/drawable-xhdpi/ic_kiosklocal_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_kiosk_local_white_24dp.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_kiosklocal_white_24dp.png rename to app/src/main/res/drawable-xhdpi/ic_kiosk_local_white_24dp.png diff --git a/app/src/main/res/drawable-xhdpi/ic_kioskrecent_black_24dp.png b/app/src/main/res/drawable-xhdpi/ic_kiosk_recent_black_24dp.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_kioskrecent_black_24dp.png rename to app/src/main/res/drawable-xhdpi/ic_kiosk_recent_black_24dp.png diff --git a/app/src/main/res/drawable-xhdpi/ic_kioskrecent_white_24dp.png b/app/src/main/res/drawable-xhdpi/ic_kiosk_recent_white_24dp.png similarity index 100% rename from app/src/main/res/drawable-xhdpi/ic_kioskrecent_white_24dp.png rename to app/src/main/res/drawable-xhdpi/ic_kiosk_recent_white_24dp.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_kiosklocal_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_kiosk_local_black_24dp.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_kiosklocal_black_24dp.png rename to app/src/main/res/drawable-xxhdpi/ic_kiosk_local_black_24dp.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_kiosklocal_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_kiosk_local_white_24dp.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_kiosklocal_white_24dp.png rename to app/src/main/res/drawable-xxhdpi/ic_kiosk_local_white_24dp.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_kioskrecent_black_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_kiosk_recent_black_24dp.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_kioskrecent_black_24dp.png rename to app/src/main/res/drawable-xxhdpi/ic_kiosk_recent_black_24dp.png diff --git a/app/src/main/res/drawable-xxhdpi/ic_kioskrecent_white_24dp.png b/app/src/main/res/drawable-xxhdpi/ic_kiosk_recent_white_24dp.png similarity index 100% rename from app/src/main/res/drawable-xxhdpi/ic_kioskrecent_white_24dp.png rename to app/src/main/res/drawable-xxhdpi/ic_kiosk_recent_white_24dp.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_kiosklocal_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_kiosk_local_black_24dp.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_kiosklocal_black_24dp.png rename to app/src/main/res/drawable-xxxhdpi/ic_kiosk_local_black_24dp.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_kiosklocal_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_kiosk_local_white_24dp.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_kiosklocal_white_24dp.png rename to app/src/main/res/drawable-xxxhdpi/ic_kiosk_local_white_24dp.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_kioskrecent_black_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_kiosk_recent_black_24dp.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_kioskrecent_black_24dp.png rename to app/src/main/res/drawable-xxxhdpi/ic_kiosk_recent_black_24dp.png diff --git a/app/src/main/res/drawable-xxxhdpi/ic_kioskrecent_white_24dp.png b/app/src/main/res/drawable-xxxhdpi/ic_kiosk_recent_white_24dp.png similarity index 100% rename from app/src/main/res/drawable-xxxhdpi/ic_kioskrecent_white_24dp.png rename to app/src/main/res/drawable-xxxhdpi/ic_kiosk_recent_white_24dp.png diff --git a/app/src/main/res/values/colors_services.xml b/app/src/main/res/values/colors_services.xml index d38df003e..0126ee9ae 100644 --- a/app/src/main/res/values/colors_services.xml +++ b/app/src/main/res/values/colors_services.xml @@ -23,13 +23,13 @@ #ff9100 - #e65100 - #ac1900 + #ff6f00 + #c43e00 #000000 #ff833a - #e65100 - #ac1900 + #ff6f00 + #c43e00 #FFFFFF #ff833a diff --git a/app/src/main/res/values/settings_keys.xml b/app/src/main/res/values/settings_keys.xml index c5f5cde78..dcf39b488 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -145,7 +145,6 @@ GB content_language peertube_instance_url - Find the instance that best suits you on https://instances.joinpeertube.org peertube_instance_name content_country show_age_restricted_content diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 08978e014..52b56a7b8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -110,6 +110,7 @@ Service Default content language PeerTube instance + Find the instance that best suits you on https://instances.joinpeertube.org Player Behavior Video & audio diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index caa332261..ba3fe78d5 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -44,8 +44,8 @@ @drawable/ic_pause_black_24dp @drawable/ic_settings_black_24dp @drawable/ic_whatshot_black_24dp - @drawable/ic_kiosklocal_black_24dp - @drawable/ic_kioskrecent_black_24dp + @drawable/ic_kiosk_local_black_24dp + @drawable/ic_kiosk_recent_black_24dp @drawable/ic_channel_black_24dp @drawable/ic_bookmark_black_24dp @drawable/ic_playlist_add_black_24dp @@ -110,8 +110,8 @@ @drawable/ic_play_arrow_white_24dp @drawable/ic_settings_white_24dp @drawable/ic_whatshot_white_24dp - @drawable/ic_kiosklocal_white_24dp - @drawable/ic_kioskrecent_white_24dp + @drawable/ic_kiosk_local_white_24dp + @drawable/ic_kiosk_recent_white_24dp @drawable/ic_channel_white_24dp @drawable/ic_bookmark_white_24dp @drawable/ic_playlist_add_white_24dp From afef8d8d0b97f022b62c6241bcc3dcb408a01c3f Mon Sep 17 00:00:00 2001 From: yausername <13ritvik@gmail.com> Date: Sat, 23 Nov 2019 00:53:14 +0530 Subject: [PATCH 09/19] removed extra white spaces --- .../schabi/newpipe/settings/ContentSettingsFragment.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java index 5e3562c7e..dd40f0d60 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java @@ -235,7 +235,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); - } finally { + }finally { try { if (output != null) { output.flush(); @@ -259,8 +259,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment { } finally { try { zipFile.close(); - } catch (Exception ignored) { - } + } catch (Exception ignored){} } try { @@ -283,7 +282,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment { } //If settings file exist, ask if it should be imported. - if (ZipHelper.extractFileFromZip(filePath, newpipe_settings.getPath(), "newpipe.settings")) { + if(ZipHelper.extractFileFromZip(filePath, newpipe_settings.getPath(), "newpipe.settings")) { AlertDialog.Builder alert = new AlertDialog.Builder(getContext()); alert.setTitle(R.string.import_settings); @@ -338,7 +337,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); - } finally { + }finally { try { if (input != null) { input.close(); From 0fb7eab2f9fb22c454b94543a7d147a1e50081a9 Mon Sep 17 00:00:00 2001 From: TobiGr Date: Sat, 23 Nov 2019 20:04:40 +0100 Subject: [PATCH 10/19] Fix code formatting --- .../list/channel/ChannelFragment.java | 20 +++++++++---------- .../schabi/newpipe/util/ServiceHelper.java | 10 +++++----- .../org/schabi/newpipe/util/ThemeHelper.java | 4 ++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java index 32bc6aeb3..ade96bdc4 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java @@ -99,7 +99,7 @@ public class ChannelFragment extends BaseListInfoFragment { @Override public void setUserVisibleHint(boolean isVisibleToUser) { super.setUserVisibleHint(isVisibleToUser); - if(activity != null + if (activity != null && useAsFrontPage && isVisibleToUser) { setTitle(currentInfo != null ? currentInfo.getName() : name); @@ -153,7 +153,7 @@ public class ChannelFragment extends BaseListInfoFragment { public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); ActionBar supportActionBar = activity.getSupportActionBar(); - if(useAsFrontPage && supportActionBar != null) { + if (useAsFrontPage && supportActionBar != null) { supportActionBar.setDisplayHomeAsUpEnabled(false); } else { inflater.inflate(R.menu.menu_channel, menu); @@ -166,7 +166,7 @@ public class ChannelFragment extends BaseListInfoFragment { private void openRssFeed() { final ChannelInfo info = currentInfo; - if(info != null) { + if (info != null) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(info.getFeedUrl())); startActivity(intent); } @@ -219,7 +219,7 @@ public class ChannelFragment extends BaseListInfoFragment { .debounce(100, TimeUnit.MILLISECONDS) .observeOn(AndroidSchedulers.mainThread()) .subscribe((List subscriptionEntities) -> - updateSubscribeButton(!subscriptionEntities.isEmpty()) + updateSubscribeButton(!subscriptionEntities.isEmpty()) , onError)); } @@ -360,9 +360,9 @@ public class ChannelFragment extends BaseListInfoFragment { headerRootLayout.setVisibility(View.VISIBLE); imageLoader.displayImage(result.getBannerUrl(), headerChannelBanner, - ImageDisplayConstants.DISPLAY_BANNER_OPTIONS); + ImageDisplayConstants.DISPLAY_BANNER_OPTIONS); imageLoader.displayImage(result.getAvatarUrl(), headerAvatarView, - ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); + ImageDisplayConstants.DISPLAY_AVATAR_OPTIONS); headerSubscribersTextView.setVisibility(View.VISIBLE); if (result.getSubscriberCount() >= 0) { @@ -398,8 +398,8 @@ public class ChannelFragment extends BaseListInfoFragment { private PlayQueue getPlayQueue(final int index) { final List streamItems = new ArrayList<>(); - for(InfoItem i : infoListAdapter.getItemsList()) { - if(i instanceof StreamInfoItem) { + for (InfoItem i : infoListAdapter.getItemsList()) { + if (i instanceof StreamInfoItem) { streamItems.add((StreamInfoItem) i); } } @@ -433,9 +433,9 @@ public class ChannelFragment extends BaseListInfoFragment { protected boolean onError(Throwable exception) { if (super.onError(exception)) return true; - if(exception instanceof ContentNotAvailableException){ + if (exception instanceof ContentNotAvailableException) { showError(getString(R.string.content_not_available), false); - }else{ + } else { int errorId = exception instanceof ExtractionException ? R.string.parsing_error : R.string.general_error; onUnrecoverableError(exception, UserAction.REQUESTED_CHANNEL, diff --git a/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java b/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java index 084ab5878..066128ab9 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java @@ -37,7 +37,7 @@ public class ServiceHelper { } public static String getTranslatedFilterString(String filter, Context c) { - switch(filter) { + switch (filter) { case "all": return c.getString(R.string.all); case "videos": return c.getString(R.string.videos); case "channels": return c.getString(R.string.channels); @@ -130,14 +130,14 @@ public class ServiceHelper { } public static boolean isBeta(final StreamingService s) { - switch(s.getServiceInfo().getName()) { + switch (s.getServiceInfo().getName()) { case "YouTube": return false; default: return true; } } public static void initService(Context context, int serviceId) { - if(serviceId == ServiceList.PeerTube.getServiceId()){ + if (serviceId == ServiceList.PeerTube.getServiceId()) { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); String peerTubeInstanceUrl = sharedPreferences.getString(context.getString(R.string.peertube_instance_url_key), ServiceList.PeerTube.getBaseUrl()); String peerTubeInstanceName = sharedPreferences.getString(context.getString(R.string.peertube_instance_name_key), ServiceList.PeerTube.getServiceInfo().getName()); @@ -146,8 +146,8 @@ public class ServiceHelper { } } - public static void initServices(Context context){ - for(StreamingService s : ServiceList.all()){ + public static void initServices(Context context) { + for (StreamingService s : ServiceList.all()) { initService(context, s.getServiceId()); } } diff --git a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java index f476cf66b..6d888a91d 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java @@ -137,10 +137,10 @@ public class ThemeHelper { else if (selectedTheme.equals(blackTheme)) themeName = "BlackTheme"; else if (selectedTheme.equals(darkTheme)) themeName = "DarkTheme"; - if(serviceId == ServiceList.PeerTube.getServiceId()){ + if (serviceId == ServiceList.PeerTube.getServiceId()) { //service name for peertube depends on the instance themeName += ".PeerTube"; - }else{ + } else { themeName += "." + service.getServiceInfo().getName(); } From 527c38adf9ac1c43cd33dd371f7e37efaecb4e9f Mon Sep 17 00:00:00 2001 From: yausername <13ritvik@gmail.com> Date: Sun, 24 Nov 2019 21:08:06 +0530 Subject: [PATCH 11/19] easily switch between multiple peertube instances --- app/build.gradle | 2 +- .../java/org/schabi/newpipe/MainActivity.java | 57 ++- .../settings/ContentSettingsFragment.java | 46 +- .../PeertubeInstanceListFragment.java | 418 ++++++++++++++++++ .../schabi/newpipe/util/PeertubeHelper.java | 65 +++ .../schabi/newpipe/util/ServiceHelper.java | 24 +- .../org/schabi/newpipe/util/ThemeHelper.java | 7 +- .../res/layout/fragment_instance_list.xml | 51 +++ .../main/res/layout/instance_spinner_item.xml | 6 + .../res/layout/instance_spinner_layout.xml | 9 + app/src/main/res/layout/item_instance.xml | 83 ++++ app/src/main/res/values/settings_keys.xml | 5 +- app/src/main/res/values/strings.xml | 7 +- app/src/main/res/xml/content_settings.xml | 8 +- 14 files changed, 724 insertions(+), 64 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java create mode 100644 app/src/main/java/org/schabi/newpipe/util/PeertubeHelper.java create mode 100644 app/src/main/res/layout/fragment_instance_list.xml create mode 100644 app/src/main/res/layout/instance_spinner_item.xml create mode 100644 app/src/main/res/layout/instance_spinner_layout.xml create mode 100644 app/src/main/res/layout/item_instance.xml diff --git a/app/build.gradle b/app/build.gradle index 4259d45a2..a128d8841 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -62,7 +62,7 @@ dependencies { exclude module: 'support-annotations' }) - implementation 'com.github.yausername:NewPipeExtractor:bc75c66' + implementation 'com.github.yausername:NewPipeExtractor:6a7680c' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.23.0' diff --git a/app/src/main/java/org/schabi/newpipe/MainActivity.java b/app/src/main/java/org/schabi/newpipe/MainActivity.java index 82d4e4063..927fc1589 100644 --- a/app/src/main/java/org/schabi/newpipe/MainActivity.java +++ b/app/src/main/java/org/schabi/newpipe/MainActivity.java @@ -29,14 +29,18 @@ import android.os.Handler; import android.os.Looper; import android.preference.PreferenceManager; import android.util.Log; +import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.Window; import android.view.WindowManager; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.ImageView; +import android.widget.Spinner; import android.widget.TextView; import androidx.annotation.NonNull; @@ -47,12 +51,15 @@ import androidx.appcompat.widget.Toolbar; import androidx.core.view.GravityCompat; import androidx.drawerlayout.widget.DrawerLayout; import androidx.fragment.app.Fragment; +import androidx.fragment.app.FragmentManager; import com.google.android.material.navigation.NavigationView; import org.schabi.newpipe.extractor.NewPipe; +import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.exceptions.ExtractionException; +import org.schabi.newpipe.extractor.services.peertube.PeertubeInstance; import org.schabi.newpipe.fragments.BackPressable; import org.schabi.newpipe.fragments.MainFragment; import org.schabi.newpipe.fragments.detail.VideoDetailFragment; @@ -61,11 +68,15 @@ import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.KioskTranslator; import org.schabi.newpipe.util.NavigationHelper; +import org.schabi.newpipe.util.PeertubeHelper; import org.schabi.newpipe.util.PermissionHelper; import org.schabi.newpipe.util.ServiceHelper; import org.schabi.newpipe.util.StateSaver; import org.schabi.newpipe.util.ThemeHelper; +import java.util.ArrayList; +import java.util.List; + public class MainActivity extends AppCompatActivity { private static final String TAG = "MainActivity"; public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release"); @@ -300,13 +311,57 @@ public class MainActivity extends AppCompatActivity { final String title = s.getServiceInfo().getName() + (ServiceHelper.isBeta(s) ? " (beta)" : ""); - drawerItems.getMenu() + MenuItem menuItem = drawerItems.getMenu() .add(R.id.menu_services_group, s.getServiceId(), ORDER, title) .setIcon(ServiceHelper.getIcon(s.getServiceId())); + + // peertube specifics + if(s.getServiceId() == 3){ + enhancePeertubeMenu(s, menuItem); + } } drawerItems.getMenu().getItem(ServiceHelper.getSelectedServiceId(this)).setChecked(true); } + private void enhancePeertubeMenu(StreamingService s, MenuItem menuItem) { + PeertubeInstance currentInstace = PeertubeHelper.getCurrentInstance(); + menuItem.setTitle(currentInstace.getName() + (ServiceHelper.isBeta(s) ? " (beta)" : "")); + Spinner spinner = (Spinner) LayoutInflater.from(this).inflate(R.layout.instance_spinner_layout, null); + List instances = PeertubeHelper.getInstanceList(this); + List items = new ArrayList<>(); + int defaultSelect = 0; + for(PeertubeInstance instance: instances){ + items.add(instance.getName()); + if(instance.getUrl().equals(currentInstace.getUrl())){ + defaultSelect = items.size()-1; + } + } + ArrayAdapter adapter = new ArrayAdapter<>(this, R.layout.instance_spinner_item, items); + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + spinner.setAdapter(adapter); + spinner.setSelection(defaultSelect, false); + spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView parent, View view, int position, long id) { + PeertubeInstance newInstance = instances.get(position); + if(newInstance.getUrl().equals(PeertubeHelper.getCurrentInstance().getUrl())) return; + PeertubeHelper.selectInstance(newInstance, getApplicationContext()); + changeService(menuItem); + drawer.closeDrawers(); + new Handler(Looper.getMainLooper()).postDelayed(() -> { + getSupportFragmentManager().popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE); + recreate(); + }, 300); + } + + @Override + public void onNothingSelected(AdapterView parent) { + + } + }); + menuItem.setActionView(spinner); + } + private void showTabs() throws ExtractionException { serviceArrow.setImageResource(R.drawable.ic_arrow_down_white); diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java index dd40f0d60..67098964d 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java @@ -12,23 +12,18 @@ import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import androidx.preference.EditTextPreference; import androidx.preference.Preference; import com.nononsenseapps.filepicker.Utils; import com.nostra13.universalimageloader.core.ImageLoader; -import org.schabi.newpipe.App; import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.localization.ContentCountry; import org.schabi.newpipe.extractor.localization.Localization; -import org.schabi.newpipe.extractor.services.peertube.PeertubeInstance; import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.util.FilePickerActivityHelper; -import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.ZipHelper; import java.io.BufferedOutputStream; @@ -46,11 +41,6 @@ import java.util.Map; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; -import io.reactivex.Completable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; - public class ContentSettingsFragment extends BasePreferenceFragment { private static final int REQUEST_IMPORT_PATH = 8945; @@ -127,41 +117,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment { return true; }); - Preference peerTubeInstance = findPreference(getString(R.string.peertube_instance_url_key)); - SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext()); - peerTubeInstance.setDefaultValue(sharedPreferences.getString(getString(R.string.peertube_instance_url_key), ServiceList.PeerTube.getBaseUrl())); - peerTubeInstance.setSummary(sharedPreferences.getString(getString(R.string.peertube_instance_url_key), ServiceList.PeerTube.getBaseUrl())); - - peerTubeInstance.setOnPreferenceChangeListener((Preference p, Object newInstance) -> { - EditTextPreference pEt = (EditTextPreference) p; - String url = (String) newInstance; - if (!url.startsWith("https://")) { - Toast.makeText(getActivity(), "instance url should start with https://", - Toast.LENGTH_SHORT).show(); - } else { - pEt.setSummary("fetching instance details.."); - Disposable disposable = Completable.fromAction(() -> { - PeertubeInstance instance = new PeertubeInstance(url); - instance.fetchInstanceMetaData(); - ServiceList.PeerTube.setInstance(instance); - }).subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(() -> { - pEt.setSummary(url); - pEt.setText(url); - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(App.getApp().getString(R.string.peertube_instance_name_key), ServiceList.PeerTube.getServiceInfo().getName()).apply(); - editor.putString(App.getApp().getString(R.string.current_service_key), ServiceList.PeerTube.getServiceInfo().getName()).apply(); - NavigationHelper.openMainActivity(App.getApp()); - }, error -> { - pEt.setSummary(ServiceList.PeerTube.getBaseUrl()); - Toast.makeText(getActivity(), "unable to update instance", - Toast.LENGTH_SHORT).show(); - }); - } - return false; - }); - } + } @Override public void onDestroy() { diff --git a/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java b/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java new file mode 100644 index 000000000..097d96d20 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java @@ -0,0 +1,418 @@ +package org.schabi.newpipe.settings; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.RadioButton; +import android.widget.TextView; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.ActionBar; +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; +import androidx.appcompat.content.res.AppCompatResources; +import androidx.appcompat.widget.AppCompatImageView; +import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.ItemTouchHelper; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import com.google.android.material.floatingactionbutton.FloatingActionButton; +import com.grack.nanojson.JsonStringWriter; +import com.grack.nanojson.JsonWriter; + +import org.schabi.newpipe.R; +import org.schabi.newpipe.extractor.ServiceList; +import org.schabi.newpipe.extractor.services.peertube.PeertubeInstance; +import org.schabi.newpipe.util.Constants; +import org.schabi.newpipe.util.PeertubeHelper; +import org.schabi.newpipe.util.ThemeHelper; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import io.reactivex.Single; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.CompositeDisposable; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; + +public class PeertubeInstanceListFragment extends Fragment { + + private List instanceList = new ArrayList<>(); + private PeertubeInstance selectedInstance; + private String savedInstanceListKey; + public InstanceListAdapter instanceListAdapter; + + private ProgressBar progressBar; + private SharedPreferences sharedPreferences; + + private CompositeDisposable disposables = new CompositeDisposable(); + + /*////////////////////////////////////////////////////////////////////////// + // Lifecycle + //////////////////////////////////////////////////////////////////////////*/ + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext()); + savedInstanceListKey = getString(R.string.peertube_instance_list_key); + selectedInstance = PeertubeHelper.getCurrentInstance(); + updateInstanceList(); + + setHasOptionsMenu(true); + } + + @Override + public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_instance_list, container, false); + } + + @Override + public void onViewCreated(@NonNull View rootView, @Nullable Bundle savedInstanceState) { + super.onViewCreated(rootView, savedInstanceState); + + initButton(rootView); + + RecyclerView listInstances = rootView.findViewById(R.id.instances); + listInstances.setLayoutManager(new LinearLayoutManager(requireContext())); + + ItemTouchHelper itemTouchHelper = new ItemTouchHelper(getItemTouchCallback()); + itemTouchHelper.attachToRecyclerView(listInstances); + + instanceListAdapter = new InstanceListAdapter(requireContext(), itemTouchHelper); + listInstances.setAdapter(instanceListAdapter); + + progressBar = rootView.findViewById(R.id.loading_progress_bar); + } + + @Override + public void onResume() { + super.onResume(); + updateTitle(); + } + + @Override + public void onPause() { + super.onPause(); + saveChanges(); + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (disposables != null) disposables.clear(); + disposables = null; + } + /*////////////////////////////////////////////////////////////////////////// + // Menu + //////////////////////////////////////////////////////////////////////////*/ + + private final int MENU_ITEM_RESTORE_ID = 123456; + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + super.onCreateOptionsMenu(menu, inflater); + + final MenuItem restoreItem = menu.add(Menu.NONE, MENU_ITEM_RESTORE_ID, Menu.NONE, R.string.restore_defaults); + restoreItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); + + final int restoreIcon = ThemeHelper.resolveResourceIdFromAttr(requireContext(), R.attr.ic_restore_defaults); + restoreItem.setIcon(AppCompatResources.getDrawable(requireContext(), restoreIcon)); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (item.getItemId() == MENU_ITEM_RESTORE_ID) { + restoreDefaults(); + return true; + } + + return super.onOptionsItemSelected(item); + } + + /*////////////////////////////////////////////////////////////////////////// + // Utils + //////////////////////////////////////////////////////////////////////////*/ + + private void updateInstanceList() { + instanceList.clear(); + instanceList.addAll(PeertubeHelper.getInstanceList(requireContext())); + } + + private void selectInstance(PeertubeInstance instance) { + selectedInstance = PeertubeHelper.selectInstance(instance, requireContext()); + sharedPreferences.edit().putBoolean(Constants.KEY_MAIN_PAGE_CHANGE, true).apply(); + } + + private void updateTitle() { + if (getActivity() instanceof AppCompatActivity) { + ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar(); + if (actionBar != null) actionBar.setTitle(R.string.peertube_instance_url_title); + } + } + + private void saveChanges() { + JsonStringWriter jsonWriter = JsonWriter.string().object().array("instances"); + for (PeertubeInstance instance : instanceList) { + jsonWriter.object(); + jsonWriter.value("name", instance.getName()); + jsonWriter.value("url", instance.getUrl()); + jsonWriter.end(); + } + String jsonToSave = jsonWriter.end().end().done(); + sharedPreferences.edit().putString(savedInstanceListKey, jsonToSave).apply(); + } + + private void restoreDefaults() { + new AlertDialog.Builder(requireContext(), ThemeHelper.getDialogTheme(requireContext())) + .setTitle(R.string.restore_defaults) + .setMessage(R.string.restore_defaults_confirmation) + .setNegativeButton(R.string.cancel, null) + .setPositiveButton(R.string.yes, (dialog, which) -> { + sharedPreferences.edit().remove(savedInstanceListKey).apply(); + selectInstance(PeertubeInstance.defaultInstance); + updateInstanceList(); + instanceListAdapter.notifyDataSetChanged(); + }) + .show(); + } + + private void initButton(View rootView) { + final FloatingActionButton fab = rootView.findViewById(R.id.addInstanceButton); + fab.setOnClickListener(v -> { + showAddItemDialog(requireContext()); + }); + } + + private void showAddItemDialog(Context c) { + final EditText urlET = new EditText(c); + urlET.setHint(R.string.peertube_instance_add_help); + AlertDialog dialog = new AlertDialog.Builder(c) + .setTitle(R.string.peertube_instance_add_title) + .setIcon(R.drawable.place_holder_peertube) + .setView(urlET) + .setNegativeButton(R.string.cancel, null) + .setPositiveButton(R.string.finish, (dialog1, which) -> { + String url = urlET.getText().toString(); + addInstance(url); + }) + .create(); + dialog.show(); + } + + private void addInstance(String url) { + String cleanUrl = verifyUrl(url); + if(null == cleanUrl) return; + progressBar.setVisibility(View.VISIBLE); + Disposable disposable = Single.fromCallable(() -> { + PeertubeInstance instance = new PeertubeInstance(cleanUrl); + instance.fetchInstanceMetaData(); + return instance; + }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe((instance) -> { + progressBar.setVisibility(View.GONE); + add(instance); + }, e -> { + progressBar.setVisibility(View.GONE); + Toast.makeText(getActivity(), "failed to validate instance", Toast.LENGTH_SHORT).show(); + }); + disposables.add(disposable); + } + + @Nullable + private String verifyUrl(String url){ + // if protocol not present, add https + if(!url.startsWith("http")){ + url = "https://" + url; + } + // remove trailing slash + url = url.replaceAll("/$", ""); + // only allow https + if (!url.startsWith("https://")) { + Toast.makeText(getActivity(), "instance url should start with https://", Toast.LENGTH_SHORT).show(); + return null; + } + // only allow if not already exists + for (PeertubeInstance instance : instanceList) { + if (instance.getUrl().equals(url)) { + Toast.makeText(getActivity(), "instance already exists", Toast.LENGTH_SHORT).show(); + return null; + } + } + return url; + } + + private void add(final PeertubeInstance instance) { + instanceList.add(instance); + instanceListAdapter.notifyDataSetChanged(); + } + + /*////////////////////////////////////////////////////////////////////////// + // List Handling + //////////////////////////////////////////////////////////////////////////*/ + + private class InstanceListAdapter extends RecyclerView.Adapter { + private ItemTouchHelper itemTouchHelper; + private final LayoutInflater inflater; + private RadioButton lastChecked; + + InstanceListAdapter(Context context, ItemTouchHelper itemTouchHelper) { + this.itemTouchHelper = itemTouchHelper; + this.inflater = LayoutInflater.from(context); + } + + public void swapItems(int fromPosition, int toPosition) { + Collections.swap(instanceList, fromPosition, toPosition); + notifyItemMoved(fromPosition, toPosition); + } + + @NonNull + @Override + public InstanceListAdapter.TabViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View view = inflater.inflate(R.layout.item_instance, parent, false); + return new InstanceListAdapter.TabViewHolder(view); + } + + @Override + public void onBindViewHolder(@NonNull InstanceListAdapter.TabViewHolder holder, int position) { + holder.bind(position, holder); + } + + @Override + public int getItemCount() { + return instanceList.size(); + } + + class TabViewHolder extends RecyclerView.ViewHolder { + private AppCompatImageView instanceIconView; + private TextView instanceNameView; + private TextView instanceUrlView; + private RadioButton instanceRB; + private ImageView handle; + + TabViewHolder(View itemView) { + super(itemView); + + instanceIconView = itemView.findViewById(R.id.instanceIcon); + instanceNameView = itemView.findViewById(R.id.instanceName); + instanceUrlView = itemView.findViewById(R.id.instanceUrl); + instanceRB = itemView.findViewById(R.id.selectInstanceRB); + handle = itemView.findViewById(R.id.handle); + } + + @SuppressLint("ClickableViewAccessibility") + void bind(int position, TabViewHolder holder) { + handle.setOnTouchListener(getOnTouchListener(holder)); + + final PeertubeInstance instance = instanceList.get(position); + instanceNameView.setText(instance.getName()); + instanceUrlView.setText(instance.getUrl()); + instanceRB.setOnCheckedChangeListener(null); + if (selectedInstance.getUrl().equals(instance.getUrl())) { + if (lastChecked != null && lastChecked != instanceRB) { + lastChecked.setChecked(false); + } + instanceRB.setChecked(true); + lastChecked = instanceRB; + } + instanceRB.setOnCheckedChangeListener((buttonView, isChecked) -> { + if (isChecked) { + selectInstance(instance); + if (lastChecked != null && lastChecked != instanceRB) { + lastChecked.setChecked(false); + } + lastChecked = instanceRB; + } + }); + instanceIconView.setImageResource(R.drawable.place_holder_peertube); + } + + @SuppressLint("ClickableViewAccessibility") + private View.OnTouchListener getOnTouchListener(final RecyclerView.ViewHolder item) { + return (view, motionEvent) -> { + if (motionEvent.getActionMasked() == MotionEvent.ACTION_DOWN) { + if (itemTouchHelper != null && getItemCount() > 1) { + itemTouchHelper.startDrag(item); + return true; + } + } + return false; + }; + } + } + } + + private ItemTouchHelper.SimpleCallback getItemTouchCallback() { + return new ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP | ItemTouchHelper.DOWN, + ItemTouchHelper.START | ItemTouchHelper.END) { + @Override + public int interpolateOutOfBoundsScroll(RecyclerView recyclerView, int viewSize, + int viewSizeOutOfBounds, int totalSize, + long msSinceStartScroll) { + final int standardSpeed = super.interpolateOutOfBoundsScroll(recyclerView, viewSize, + viewSizeOutOfBounds, totalSize, msSinceStartScroll); + final int minimumAbsVelocity = Math.max(12, + Math.abs(standardSpeed)); + return minimumAbsVelocity * (int) Math.signum(viewSizeOutOfBounds); + } + + @Override + public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, + RecyclerView.ViewHolder target) { + if (source.getItemViewType() != target.getItemViewType() || + instanceListAdapter == null) { + return false; + } + + final int sourceIndex = source.getAdapterPosition(); + final int targetIndex = target.getAdapterPosition(); + instanceListAdapter.swapItems(sourceIndex, targetIndex); + return true; + } + + @Override + public boolean isLongPressDragEnabled() { + return false; + } + + @Override + public boolean isItemViewSwipeEnabled() { + return true; + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) { + int position = viewHolder.getAdapterPosition(); + // do not allow swiping the selected instance + if(instanceList.get(position).getUrl().equals(selectedInstance.getUrl())) { + instanceListAdapter.notifyItemChanged(position); + return; + } + instanceList.remove(position); + instanceListAdapter.notifyItemRemoved(position); + + if (instanceList.isEmpty()) { + instanceList.add(selectedInstance); + instanceListAdapter.notifyItemInserted(0); + } + } + }; + } +} diff --git a/app/src/main/java/org/schabi/newpipe/util/PeertubeHelper.java b/app/src/main/java/org/schabi/newpipe/util/PeertubeHelper.java new file mode 100644 index 000000000..0d695e275 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/util/PeertubeHelper.java @@ -0,0 +1,65 @@ +package org.schabi.newpipe.util; + +import android.content.Context; +import android.content.SharedPreferences; +import android.preference.PreferenceManager; + +import com.grack.nanojson.JsonArray; +import com.grack.nanojson.JsonObject; +import com.grack.nanojson.JsonParser; +import com.grack.nanojson.JsonParserException; +import com.grack.nanojson.JsonStringWriter; +import com.grack.nanojson.JsonWriter; + +import org.schabi.newpipe.R; +import org.schabi.newpipe.extractor.ServiceList; +import org.schabi.newpipe.extractor.services.peertube.PeertubeInstance; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class PeertubeHelper { + + public static List getInstanceList(Context context) { + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + String savedInstanceListKey = context.getString(R.string.peertube_instance_list_key); + final String savedJson = sharedPreferences.getString(savedInstanceListKey, null); + if (null == savedJson) { + return Collections.singletonList(getCurrentInstance()); + } + + try { + JsonArray array = JsonParser.object().from(savedJson).getArray("instances"); + List result = new ArrayList<>(); + for (Object o : array) { + if (o instanceof JsonObject) { + JsonObject instance = (JsonObject) o; + String name = instance.getString("name"); + String url = instance.getString("url"); + result.add(new PeertubeInstance(url, name)); + } + } + return result; + } catch (JsonParserException e) { + return Collections.singletonList(getCurrentInstance()); + } + + } + + public static PeertubeInstance selectInstance(PeertubeInstance instance, Context context) { + SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); + String selectedInstanceKey = context.getString(R.string.peertube_selected_instance_key); + JsonStringWriter jsonWriter = JsonWriter.string().object(); + jsonWriter.value("name", instance.getName()); + jsonWriter.value("url", instance.getUrl()); + String jsonToSave = jsonWriter.end().done(); + sharedPreferences.edit().putString(selectedInstanceKey, jsonToSave).apply(); + ServiceList.PeerTube.setInstance(instance); + return instance; + } + + public static PeertubeInstance getCurrentInstance(){ + return ServiceList.PeerTube.getInstance(); + } +} diff --git a/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java b/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java index 084ab5878..a25d4c9ec 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ServiceHelper.java @@ -3,9 +3,14 @@ package org.schabi.newpipe.util; import android.content.Context; import android.content.SharedPreferences; import android.preference.PreferenceManager; + import androidx.annotation.DrawableRes; import androidx.annotation.StringRes; +import com.grack.nanojson.JsonObject; +import com.grack.nanojson.JsonParser; +import com.grack.nanojson.JsonParserException; + import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.ServiceList; @@ -137,11 +142,22 @@ public class ServiceHelper { } public static void initService(Context context, int serviceId) { - if(serviceId == ServiceList.PeerTube.getServiceId()){ + if (serviceId == ServiceList.PeerTube.getServiceId()) { SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context); - String peerTubeInstanceUrl = sharedPreferences.getString(context.getString(R.string.peertube_instance_url_key), ServiceList.PeerTube.getBaseUrl()); - String peerTubeInstanceName = sharedPreferences.getString(context.getString(R.string.peertube_instance_name_key), ServiceList.PeerTube.getServiceInfo().getName()); - PeertubeInstance instance = new PeertubeInstance(peerTubeInstanceUrl, peerTubeInstanceName); + String json = sharedPreferences.getString(context.getString(R.string.peertube_selected_instance_key), null); + if (null == json) { + return; + } + + JsonObject jsonObject = null; + try { + jsonObject = JsonParser.object().from(json); + } catch (JsonParserException e) { + return; + } + String name = jsonObject.getString("name"); + String url = jsonObject.getString("url"); + PeertubeInstance instance = new PeertubeInstance(url, name); ServiceList.PeerTube.setInstance(instance); } } diff --git a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java index f476cf66b..530c8cefe 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java @@ -137,12 +137,7 @@ public class ThemeHelper { else if (selectedTheme.equals(blackTheme)) themeName = "BlackTheme"; else if (selectedTheme.equals(darkTheme)) themeName = "DarkTheme"; - if(serviceId == ServiceList.PeerTube.getServiceId()){ - //service name for peertube depends on the instance - themeName += ".PeerTube"; - }else{ - themeName += "." + service.getServiceInfo().getName(); - } + themeName += "." + service.getServiceInfo().getName(); int resourceId = context .getResources() diff --git a/app/src/main/res/layout/fragment_instance_list.xml b/app/src/main/res/layout/fragment_instance_list.xml new file mode 100644 index 000000000..970b67c26 --- /dev/null +++ b/app/src/main/res/layout/fragment_instance_list.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/instance_spinner_item.xml b/app/src/main/res/layout/instance_spinner_item.xml new file mode 100644 index 000000000..1edac71af --- /dev/null +++ b/app/src/main/res/layout/instance_spinner_item.xml @@ -0,0 +1,6 @@ + + diff --git a/app/src/main/res/layout/instance_spinner_layout.xml b/app/src/main/res/layout/instance_spinner_layout.xml new file mode 100644 index 000000000..63e910d96 --- /dev/null +++ b/app/src/main/res/layout/instance_spinner_layout.xml @@ -0,0 +1,9 @@ + + diff --git a/app/src/main/res/layout/item_instance.xml b/app/src/main/res/layout/item_instance.xml new file mode 100644 index 000000000..b0e4e25bd --- /dev/null +++ b/app/src/main/res/layout/item_instance.xml @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + \ 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 dcf39b488..2249d1ec0 100644 --- a/app/src/main/res/values/settings_keys.xml +++ b/app/src/main/res/values/settings_keys.xml @@ -144,8 +144,9 @@ en GB content_language - peertube_instance_url - peertube_instance_name + peertube_instance_setup + peertube_selected_instance + peertube_instance_list content_country show_age_restricted_content use_tor diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 52b56a7b8..c652b7f65 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -109,8 +109,11 @@ Default content country Service Default content language - PeerTube instance + PeerTube instances + Set your favorite peertube instances Find the instance that best suits you on https://instances.joinpeertube.org + Add instance + enter instance url Player Behavior Video & audio @@ -578,4 +581,6 @@ You will be asked where to save each download.\nChoose SAF if you want to download to an external SD card Use SAF The Storage Access Framework allows downloads to an external SD card.\nNote: some devices are not compatible + Choose an instance + diff --git a/app/src/main/res/xml/content_settings.xml b/app/src/main/res/xml/content_settings.xml index 6d2329310..0d579ba35 100644 --- a/app/src/main/res/xml/content_settings.xml +++ b/app/src/main/res/xml/content_settings.xml @@ -12,12 +12,12 @@ android:summary="%s" android:title="@string/content_language_title"/> - + android:summary="@string/peertube_instance_url_summary"/> Date: Sun, 24 Nov 2019 21:42:05 +0530 Subject: [PATCH 12/19] white space changes --- .../schabi/newpipe/settings/ContentSettingsFragment.java | 8 +++----- .../main/java/org/schabi/newpipe/util/ThemeHelper.java | 2 -- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java index 67098964d..0c7a4b46e 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java @@ -7,12 +7,11 @@ import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; -import android.util.Log; -import android.widget.Toast; - import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.preference.Preference; +import android.util.Log; +import android.widget.Toast; import com.nononsenseapps.filepicker.Utils; import com.nostra13.universalimageloader.core.ImageLoader; @@ -116,8 +115,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment { startActivityForResult(i, REQUEST_EXPORT_PATH); return true; }); - - } + } @Override public void onDestroy() { diff --git a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java index 530c8cefe..661aa47c1 100644 --- a/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/ThemeHelper.java @@ -30,7 +30,6 @@ import android.view.ContextThemeWrapper; import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.NewPipe; -import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.exceptions.ExtractionException; @@ -138,7 +137,6 @@ public class ThemeHelper { else if (selectedTheme.equals(darkTheme)) themeName = "DarkTheme"; themeName += "." + service.getServiceInfo().getName(); - int resourceId = context .getResources() .getIdentifier(themeName, "style", context.getPackageName()); From 890d1cb50b5764659be870c5cbff2732666e828f Mon Sep 17 00:00:00 2001 From: yausername Date: Tue, 3 Dec 2019 01:50:23 +0530 Subject: [PATCH 13/19] update extractor, kiosk names and icons --- app/build.gradle | 2 +- .../java/org/schabi/newpipe/util/KioskTranslator.java | 8 ++++++++ app/src/main/res/values/strings.xml | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index a128d8841..0abaf44f7 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -62,7 +62,7 @@ dependencies { exclude module: 'support-annotations' }) - implementation 'com.github.yausername:NewPipeExtractor:6a7680c' + implementation 'com.github.yausername:NewPipeExtractor:00c2368' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.23.0' diff --git a/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java index 1f32383d0..18c95e394 100644 --- a/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java +++ b/app/src/main/java/org/schabi/newpipe/util/KioskTranslator.java @@ -31,6 +31,12 @@ public class KioskTranslator { return c.getString(R.string.top_50); case "New & hot": return c.getString(R.string.new_and_hot); + case "Local": + return c.getString(R.string.local); + case "Recently added": + return c.getString(R.string.recently_added); + case "Most liked": + return c.getString(R.string.most_liked); case "conferences": return c.getString(R.string.conferences); default: @@ -50,6 +56,8 @@ public class KioskTranslator { return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_kiosk_local); case "Recently added": return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_kiosk_recent); + case "Most liked": + return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.thumbs_up); case "conferences": return ThemeHelper.resolveResourceIdFromAttr(c, R.attr.ic_hot); default: diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c652b7f65..772421a53 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -405,6 +405,9 @@ Trending Top 50 New & hot + Local + Recently added + Most liked Conferences %1$s/%2$s From 17c5e73994e6f68418712d8d0785a649208da1fd Mon Sep 17 00:00:00 2001 From: yausername Date: Tue, 3 Dec 2019 02:04:52 +0530 Subject: [PATCH 14/19] null check on share --- .../newpipe/fragments/list/channel/ChannelFragment.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java index ade96bdc4..c20ff0fc2 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java @@ -179,10 +179,14 @@ public class ChannelFragment extends BaseListInfoFragment { openRssFeed(); break; case R.id.menu_item_openInBrowser: - ShareUtils.openUrlInBrowser(this.getContext(), currentInfo.getOriginalUrl()); + if (currentInfo != null) { + ShareUtils.openUrlInBrowser(this.getContext(), currentInfo.getOriginalUrl()); + } break; case R.id.menu_item_share: - ShareUtils.shareUrl(this.getContext(), name, currentInfo.getOriginalUrl()); + if (currentInfo != null) { + ShareUtils.shareUrl(this.getContext(), name, currentInfo.getOriginalUrl()); + } break; default: return super.onOptionsItemSelected(item); From 0c40a45075dc2bb0811c5ba23dfcae8ed56c4f03 Mon Sep 17 00:00:00 2001 From: yausername Date: Tue, 3 Dec 2019 02:08:59 +0530 Subject: [PATCH 15/19] use plurals --- app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 772421a53..bcd4aedcc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -111,7 +111,7 @@ Default content language PeerTube instances Set your favorite peertube instances - Find the instance that best suits you on https://instances.joinpeertube.org + Find the instances that best suit you on https://instances.joinpeertube.org Add instance enter instance url Player From d32ad36f3d13fe3212019fac0cc1f3e5b3c23473 Mon Sep 17 00:00:00 2001 From: yausername Date: Tue, 3 Dec 2019 07:16:25 +0530 Subject: [PATCH 16/19] reorder peertube settings entry --- app/src/main/res/xml/content_settings.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/src/main/res/xml/content_settings.xml b/app/src/main/res/xml/content_settings.xml index 0d579ba35..4044e92d8 100644 --- a/app/src/main/res/xml/content_settings.xml +++ b/app/src/main/res/xml/content_settings.xml @@ -12,13 +12,6 @@ android:summary="%s" android:title="@string/content_language_title"/> - - + + Date: Tue, 3 Dec 2019 07:22:14 +0530 Subject: [PATCH 17/19] updated extractor --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 0abaf44f7..3b0b8fe6c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -62,7 +62,7 @@ dependencies { exclude module: 'support-annotations' }) - implementation 'com.github.yausername:NewPipeExtractor:00c2368' + implementation 'com.github.TeamNewPipe:NewPipeExtractor:43b54cc' testImplementation 'junit:junit:4.12' testImplementation 'org.mockito:mockito-core:2.23.0' From d2a59ecc62bf3fe97b6515ce6701ff5761b73495 Mon Sep 17 00:00:00 2001 From: yausername Date: Thu, 5 Dec 2019 05:11:05 +0530 Subject: [PATCH 18/19] grammar fix --- .../schabi/newpipe/settings/PeertubeInstanceListFragment.java | 2 +- app/src/main/res/values/strings.xml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java b/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java index 097d96d20..cfb3fe8a4 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java @@ -231,7 +231,7 @@ public class PeertubeInstanceListFragment extends Fragment { add(instance); }, e -> { progressBar.setVisibility(View.GONE); - Toast.makeText(getActivity(), "failed to validate instance", Toast.LENGTH_SHORT).show(); + Toast.makeText(getActivity(), R.string.peertube_instance_add_fail, Toast.LENGTH_SHORT).show(); }); disposables.add(disposable); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bcd4aedcc..ecffa0db2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -114,6 +114,7 @@ Find the instances that best suit you on https://instances.joinpeertube.org Add instance enter instance url + Failed to validate instance Player Behavior Video & audio From a0151f2a68592ee53df8fd10db1a022eac034394 Mon Sep 17 00:00:00 2001 From: yausername Date: Tue, 10 Dec 2019 12:36:56 +0530 Subject: [PATCH 19/19] more grammar fix --- .../newpipe/settings/PeertubeInstanceListFragment.java | 9 ++++----- app/src/main/res/values/strings.xml | 6 ++++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java b/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java index cfb3fe8a4..d8c36e5cb 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/PeertubeInstanceListFragment.java @@ -36,7 +36,6 @@ import com.grack.nanojson.JsonStringWriter; import com.grack.nanojson.JsonWriter; import org.schabi.newpipe.R; -import org.schabi.newpipe.extractor.ServiceList; import org.schabi.newpipe.extractor.services.peertube.PeertubeInstance; import org.schabi.newpipe.util.Constants; import org.schabi.newpipe.util.PeertubeHelper; @@ -219,7 +218,7 @@ public class PeertubeInstanceListFragment extends Fragment { } private void addInstance(String url) { - String cleanUrl = verifyUrl(url); + String cleanUrl = cleanUrl(url); if(null == cleanUrl) return; progressBar.setVisibility(View.VISIBLE); Disposable disposable = Single.fromCallable(() -> { @@ -237,7 +236,7 @@ public class PeertubeInstanceListFragment extends Fragment { } @Nullable - private String verifyUrl(String url){ + private String cleanUrl(String url){ // if protocol not present, add https if(!url.startsWith("http")){ url = "https://" + url; @@ -246,13 +245,13 @@ public class PeertubeInstanceListFragment extends Fragment { url = url.replaceAll("/$", ""); // only allow https if (!url.startsWith("https://")) { - Toast.makeText(getActivity(), "instance url should start with https://", Toast.LENGTH_SHORT).show(); + Toast.makeText(getActivity(), R.string.peertube_instance_add_https_only, Toast.LENGTH_SHORT).show(); return null; } // only allow if not already exists for (PeertubeInstance instance : instanceList) { if (instance.getUrl().equals(url)) { - Toast.makeText(getActivity(), "instance already exists", Toast.LENGTH_SHORT).show(); + Toast.makeText(getActivity(), R.string.peertube_instance_add_exists, Toast.LENGTH_SHORT).show(); return null; } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 18b11db02..5e47f875c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -111,10 +111,12 @@ Default content language PeerTube instances Set your favorite peertube instances - Find the instances that best suit you on https://instances.joinpeertube.org + Find the instances that best suit you on https://joinpeertube.org/instances#instances-list Add instance - enter instance url + Enter instance url Failed to validate instance + Only https urls are supported + Instance already exists Player Behavior Video & audio