Converted the about package to Kotlin

This commit is contained in:
TacoTheDank 2021-03-29 19:06:32 -04:00
parent cc72fa4793
commit fb1aab2a49
8 changed files with 470 additions and 465 deletions

View File

@ -1,192 +0,0 @@
package org.schabi.newpipe.about;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import com.google.android.material.tabs.TabLayoutMediator;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.R;
import org.schabi.newpipe.databinding.ActivityAboutBinding;
import org.schabi.newpipe.databinding.FragmentAboutBinding;
import org.schabi.newpipe.util.ThemeHelper;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
import static org.schabi.newpipe.util.ShareUtils.openUrlInBrowser;
public class AboutActivity extends AppCompatActivity {
/**
* List of all software components.
*/
private static final SoftwareComponent[] SOFTWARE_COMPONENTS = {
new SoftwareComponent("ACRA", "2013", "Kevin Gaudin",
"https://github.com/ACRA/acra", StandardLicenses.APACHE2),
new SoftwareComponent("AndroidX", "2005 - 2011", "The Android Open Source Project",
"https://developer.android.com/jetpack", StandardLicenses.APACHE2),
new SoftwareComponent("CircleImageView", "2014 - 2020", "Henning Dodenhof",
"https://github.com/hdodenhof/CircleImageView",
StandardLicenses.APACHE2),
new SoftwareComponent("ExoPlayer", "2014 - 2020", "Google, Inc.",
"https://github.com/google/ExoPlayer", StandardLicenses.APACHE2),
new SoftwareComponent("GigaGet", "2014 - 2015", "Peter Cai",
"https://github.com/PaperAirplane-Dev-Team/GigaGet", StandardLicenses.GPL3),
new SoftwareComponent("Groupie", "2016", "Lisa Wray",
"https://github.com/lisawray/groupie", StandardLicenses.MIT),
new SoftwareComponent("Icepick", "2015", "Frankie Sardo",
"https://github.com/frankiesardo/icepick", StandardLicenses.EPL1),
new SoftwareComponent("Jsoup", "2009 - 2020", "Jonathan Hedley",
"https://github.com/jhy/jsoup", StandardLicenses.MIT),
new SoftwareComponent("Markwon", "2019", "Dimitry Ivanov",
"https://github.com/noties/Markwon", StandardLicenses.APACHE2),
new SoftwareComponent("Material Components for Android", "2016 - 2020", "Google, Inc.",
"https://github.com/material-components/material-components-android",
StandardLicenses.APACHE2),
new SoftwareComponent("NewPipe Extractor", "2017 - 2020", "Christian Schabesberger",
"https://github.com/TeamNewPipe/NewPipeExtractor", StandardLicenses.GPL3),
new SoftwareComponent("NoNonsense-FilePicker", "2016", "Jonas Kalderstam",
"https://github.com/spacecowboy/NoNonsense-FilePicker",
StandardLicenses.MPL2),
new SoftwareComponent("OkHttp", "2019", "Square, Inc.",
"https://square.github.io/okhttp/", StandardLicenses.APACHE2),
new SoftwareComponent("PrettyTime", "2012 - 2020", "Lincoln Baxter, III",
"https://github.com/ocpsoft/prettytime", StandardLicenses.APACHE2),
new SoftwareComponent("RxAndroid", "2015", "The RxAndroid authors",
"https://github.com/ReactiveX/RxAndroid", StandardLicenses.APACHE2),
new SoftwareComponent("RxBinding", "2015", "Jake Wharton",
"https://github.com/JakeWharton/RxBinding", StandardLicenses.APACHE2),
new SoftwareComponent("RxJava", "2016 - 2020", "RxJava Contributors",
"https://github.com/ReactiveX/RxJava", StandardLicenses.APACHE2),
new SoftwareComponent("Universal Image Loader", "2011 - 2015", "Sergey Tarasevich",
"https://github.com/nostra13/Android-Universal-Image-Loader",
StandardLicenses.APACHE2),
};
private static final int POS_ABOUT = 0;
private static final int POS_LICENSE = 1;
private static final int TOTAL_COUNT = 2;
@Override
protected void onCreate(final Bundle savedInstanceState) {
assureCorrectAppLanguage(this);
super.onCreate(savedInstanceState);
ThemeHelper.setTheme(this);
setTitle(getString(R.string.title_activity_about));
final ActivityAboutBinding aboutBinding = ActivityAboutBinding.inflate(getLayoutInflater());
setContentView(aboutBinding.getRoot());
setSupportActionBar(aboutBinding.aboutToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
final AboutStateAdapter mAboutStateAdapter = new AboutStateAdapter(this);
// Set up the ViewPager with the sections adapter.
aboutBinding.aboutViewPager2.setAdapter(mAboutStateAdapter);
new TabLayoutMediator(aboutBinding.aboutTabLayout, aboutBinding.aboutViewPager2, (tab, position) -> {
switch (position) {
default:
case POS_ABOUT:
tab.setText(R.string.tab_about);
break;
case POS_LICENSE:
tab.setText(R.string.tab_licenses);
break;
}
}).attach();
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
final int id = item.getItemId();
switch (id) {
case android.R.id.home:
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* A placeholder fragment containing a simple view.
*/
public static class AboutFragment extends Fragment {
public AboutFragment() {
}
/**
* Created a new instance of this fragment for the given section number.
*
* @return New instance of {@link AboutFragment}
*/
public static AboutFragment newInstance() {
return new AboutFragment();
}
@Override
public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container,
final Bundle savedInstanceState) {
final FragmentAboutBinding aboutBinding =
FragmentAboutBinding.inflate(inflater, container, false);
final Context context = getContext();
aboutBinding.aboutAppVersion.setText(BuildConfig.VERSION_NAME);
aboutBinding.aboutGithubLink.setOnClickListener(nv ->
openUrlInBrowser(context, context.getString(R.string.github_url), false));
aboutBinding.aboutDonationLink.setOnClickListener(v ->
openUrlInBrowser(context, context.getString(R.string.donation_url), false));
aboutBinding.aboutWebsiteLink.setOnClickListener(nv ->
openUrlInBrowser(context, context.getString(R.string.website_url), false));
aboutBinding.aboutPrivacyPolicyLink.setOnClickListener(v ->
openUrlInBrowser(context, context.getString(R.string.privacy_policy_url),
false));
return aboutBinding.getRoot();
}
}
/**
* A {@link FragmentStateAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
private static class AboutStateAdapter extends FragmentStateAdapter {
AboutStateAdapter(final FragmentActivity fa) {
super(fa);
}
@NonNull
@Override
public Fragment createFragment(final int position) {
switch (position) {
default:
case POS_ABOUT:
return AboutFragment.newInstance();
case POS_LICENSE:
return LicenseFragment.newInstance(SOFTWARE_COMPONENTS);
}
}
@Override
public int getItemCount() {
// Show 2 total pages.
return TOTAL_COUNT;
}
}
}

View File

@ -0,0 +1,204 @@
package org.schabi.newpipe.about
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import org.schabi.newpipe.BuildConfig
import org.schabi.newpipe.R
import org.schabi.newpipe.databinding.ActivityAboutBinding
import org.schabi.newpipe.databinding.FragmentAboutBinding
import org.schabi.newpipe.util.Localization
import org.schabi.newpipe.util.ShareUtils
import org.schabi.newpipe.util.ThemeHelper
class AboutActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
Localization.assureCorrectAppLanguage(this)
super.onCreate(savedInstanceState)
ThemeHelper.setTheme(this)
title = getString(R.string.title_activity_about)
val aboutBinding = ActivityAboutBinding.inflate(layoutInflater)
setContentView(aboutBinding.root)
setSupportActionBar(aboutBinding.aboutToolbar)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
// Create the adapter that will return a fragment for each of the three
// primary sections of the activity.
val mAboutStateAdapter = AboutStateAdapter(this)
// Set up the ViewPager with the sections adapter.
aboutBinding.aboutViewPager2.adapter = mAboutStateAdapter
TabLayoutMediator(
aboutBinding.aboutTabLayout,
aboutBinding.aboutViewPager2
) { tab: TabLayout.Tab, position: Int ->
when (position) {
POS_ABOUT -> tab.setText(R.string.tab_about)
POS_LICENSE -> tab.setText(R.string.tab_licenses)
else -> throw IllegalArgumentException("Unknown position for ViewPager2")
}
}.attach()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
finish()
return true
}
return super.onOptionsItemSelected(item)
}
/**
* A placeholder fragment containing a simple view.
*/
class AboutFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val aboutBinding = FragmentAboutBinding.inflate(inflater, container, false)
val context = context
aboutBinding.aboutAppVersion.text = BuildConfig.VERSION_NAME
aboutBinding.aboutGithubLink.setOnClickListener {
ShareUtils.openUrlInBrowser(
context,
context!!.getString(R.string.github_url),
false
)
}
aboutBinding.aboutDonationLink.setOnClickListener {
ShareUtils.openUrlInBrowser(
context,
context!!.getString(R.string.donation_url),
false
)
}
aboutBinding.aboutWebsiteLink.setOnClickListener {
ShareUtils.openUrlInBrowser(
context,
context!!.getString(R.string.website_url),
false
)
}
aboutBinding.aboutPrivacyPolicyLink.setOnClickListener {
ShareUtils.openUrlInBrowser(
context, context!!.getString(R.string.privacy_policy_url),
false
)
}
return aboutBinding.root
}
}
/**
* A [FragmentStateAdapter] that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
private class AboutStateAdapter(fa: FragmentActivity) : FragmentStateAdapter(fa) {
override fun createFragment(position: Int): Fragment {
return when (position) {
POS_ABOUT -> AboutFragment()
POS_LICENSE -> LicenseFragment.newInstance(SOFTWARE_COMPONENTS)
else -> throw IllegalArgumentException("Unknown position for ViewPager2")
}
}
override fun getItemCount(): Int {
// Show 2 total pages.
return TOTAL_COUNT
}
}
companion object {
/**
* List of all software components.
*/
private val SOFTWARE_COMPONENTS = arrayOf(
SoftwareComponent(
"ACRA", "2013", "Kevin Gaudin",
"https://github.com/ACRA/acra", StandardLicenses.APACHE2
),
SoftwareComponent(
"AndroidX", "2005 - 2011", "The Android Open Source Project",
"https://developer.android.com/jetpack", StandardLicenses.APACHE2
),
SoftwareComponent(
"CircleImageView", "2014 - 2020", "Henning Dodenhof",
"https://github.com/hdodenhof/CircleImageView", StandardLicenses.APACHE2
),
SoftwareComponent(
"ExoPlayer", "2014 - 2020", "Google, Inc.",
"https://github.com/google/ExoPlayer", StandardLicenses.APACHE2
),
SoftwareComponent(
"GigaGet", "2014 - 2015", "Peter Cai",
"https://github.com/PaperAirplane-Dev-Team/GigaGet", StandardLicenses.GPL3
),
SoftwareComponent(
"Groupie", "2016", "Lisa Wray",
"https://github.com/lisawray/groupie", StandardLicenses.MIT
),
SoftwareComponent(
"Icepick", "2015", "Frankie Sardo",
"https://github.com/frankiesardo/icepick", StandardLicenses.EPL1
),
SoftwareComponent(
"Jsoup", "2009 - 2020", "Jonathan Hedley",
"https://github.com/jhy/jsoup", StandardLicenses.MIT
),
SoftwareComponent(
"Markwon", "2019", "Dimitry Ivanov",
"https://github.com/noties/Markwon", StandardLicenses.APACHE2
),
SoftwareComponent(
"Material Components for Android", "2016 - 2020", "Google, Inc.",
"https://github.com/material-components/material-components-android",
StandardLicenses.APACHE2
),
SoftwareComponent(
"NewPipe Extractor", "2017 - 2020", "Christian Schabesberger",
"https://github.com/TeamNewPipe/NewPipeExtractor", StandardLicenses.GPL3
),
SoftwareComponent(
"NoNonsense-FilePicker", "2016", "Jonas Kalderstam",
"https://github.com/spacecowboy/NoNonsense-FilePicker", StandardLicenses.MPL2
),
SoftwareComponent(
"OkHttp", "2019", "Square, Inc.",
"https://square.github.io/okhttp/", StandardLicenses.APACHE2
),
SoftwareComponent(
"PrettyTime", "2012 - 2020", "Lincoln Baxter, III",
"https://github.com/ocpsoft/prettytime", StandardLicenses.APACHE2
),
SoftwareComponent(
"RxAndroid", "2015", "The RxAndroid authors",
"https://github.com/ReactiveX/RxAndroid", StandardLicenses.APACHE2
),
SoftwareComponent(
"RxBinding", "2015", "Jake Wharton",
"https://github.com/JakeWharton/RxBinding", StandardLicenses.APACHE2
),
SoftwareComponent(
"RxJava", "2016 - 2020", "RxJava Contributors",
"https://github.com/ReactiveX/RxJava", StandardLicenses.APACHE2
),
SoftwareComponent(
"Universal Image Loader", "2011 - 2015", "Sergey Tarasevich",
"https://github.com/nostra13/Android-Universal-Image-Loader",
StandardLicenses.APACHE2
)
)
private const val POS_ABOUT = 0
private const val POS_LICENSE = 1
private const val TOTAL_COUNT = 2
}
}

View File

@ -1,145 +0,0 @@
package org.schabi.newpipe.about;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import org.schabi.newpipe.R;
import org.schabi.newpipe.databinding.FragmentLicensesBinding;
import org.schabi.newpipe.databinding.ItemSoftwareComponentBinding;
import org.schabi.newpipe.util.ShareUtils;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
/**
* Fragment containing the software licenses.
*/
public class LicenseFragment extends Fragment {
private static final String ARG_COMPONENTS = "components";
private static final String LICENSE_KEY = "ACTIVE_LICENSE";
private SoftwareComponent[] softwareComponents;
private SoftwareComponent componentForContextMenu;
private License activeLicense;
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
public static LicenseFragment newInstance(final SoftwareComponent[] softwareComponents) {
final Bundle bundle = new Bundle();
bundle.putParcelableArray(ARG_COMPONENTS, Objects.requireNonNull(softwareComponents));
final LicenseFragment fragment = new LicenseFragment();
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
softwareComponents = (SoftwareComponent[]) getArguments()
.getParcelableArray(ARG_COMPONENTS);
if (savedInstanceState != null) {
final Serializable license = savedInstanceState.getSerializable(LICENSE_KEY);
if (license != null) {
activeLicense = (License) license;
}
}
// Sort components by name
Arrays.sort(softwareComponents, Comparator.comparing(SoftwareComponent::getName));
}
@Override
public void onDestroy() {
compositeDisposable.dispose();
super.onDestroy();
}
@Nullable
@Override
public View onCreateView(@NonNull final LayoutInflater inflater,
@Nullable final ViewGroup container,
@Nullable final Bundle savedInstanceState) {
final FragmentLicensesBinding binding = FragmentLicensesBinding
.inflate(inflater, container, false);
binding.licensesAppReadLicense.setOnClickListener(v -> {
activeLicense = StandardLicenses.GPL3;
compositeDisposable.add(LicenseFragmentHelper.showLicense(getActivity(),
StandardLicenses.GPL3));
});
for (final SoftwareComponent component : softwareComponents) {
final ItemSoftwareComponentBinding componentBinding = ItemSoftwareComponentBinding
.inflate(inflater, container, false);
componentBinding.name.setText(component.getName());
componentBinding.copyright.setText(getString(R.string.copyright,
component.getYears(),
component.getCopyrightOwner(),
component.getLicense().getAbbreviation()));
final View root = componentBinding.getRoot();
root.setTag(component);
root.setOnClickListener(v -> {
activeLicense = component.getLicense();
compositeDisposable.add(LicenseFragmentHelper.showLicense(getActivity(),
component.getLicense()));
});
binding.licensesSoftwareComponents.addView(root);
registerForContextMenu(root);
}
if (activeLicense != null) {
compositeDisposable.add(LicenseFragmentHelper.showLicense(getActivity(),
activeLicense));
}
return binding.getRoot();
}
@Override
public void onCreateContextMenu(final ContextMenu menu, final View v,
final ContextMenu.ContextMenuInfo menuInfo) {
final MenuInflater inflater = getActivity().getMenuInflater();
final SoftwareComponent component = (SoftwareComponent) v.getTag();
menu.setHeaderTitle(component.getName());
inflater.inflate(R.menu.software_component, menu);
super.onCreateContextMenu(menu, v, menuInfo);
componentForContextMenu = (SoftwareComponent) v.getTag();
}
@Override
public boolean onContextItemSelected(@NonNull final MenuItem item) {
// item.getMenuInfo() is null so we use the tag of the view
final SoftwareComponent component = componentForContextMenu;
if (component == null) {
return false;
}
switch (item.getItemId()) {
case R.id.menu_software_website:
ShareUtils.openUrlInBrowser(getActivity(), component.getLink());
return true;
case R.id.menu_software_show_license:
compositeDisposable.add(LicenseFragmentHelper.showLicense(getActivity(),
component.getLicense()));
}
return false;
}
@Override
public void onSaveInstanceState(@NonNull final Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
if (activeLicense != null) {
savedInstanceState.putSerializable(LICENSE_KEY, activeLicense);
}
}
}

View File

@ -0,0 +1,131 @@
package org.schabi.newpipe.about
import android.os.Bundle
import android.view.ContextMenu
import android.view.ContextMenu.ContextMenuInfo
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import io.reactivex.rxjava3.disposables.CompositeDisposable
import org.schabi.newpipe.R
import org.schabi.newpipe.about.LicenseFragmentHelper.showLicense
import org.schabi.newpipe.databinding.FragmentLicensesBinding
import org.schabi.newpipe.databinding.ItemSoftwareComponentBinding
import org.schabi.newpipe.util.ShareUtils
import java.util.Arrays
import java.util.Objects
/**
* Fragment containing the software licenses.
*/
class LicenseFragment : Fragment() {
private lateinit var softwareComponents: Array<SoftwareComponent>
private var componentForContextMenu: SoftwareComponent? = null
private var activeLicense: License? = null
private val compositeDisposable = CompositeDisposable()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
softwareComponents =
arguments?.getParcelableArray(ARG_COMPONENTS) as Array<SoftwareComponent>
if (savedInstanceState != null) {
val license = savedInstanceState.getSerializable(LICENSE_KEY)
if (license != null) {
activeLicense = license as License?
}
}
// Sort components by name
Arrays.sort(softwareComponents, Comparator.comparing(SoftwareComponent::name))
}
override fun onDestroy() {
compositeDisposable.dispose()
super.onDestroy()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val binding = FragmentLicensesBinding.inflate(inflater, container, false)
binding.licensesAppReadLicense.setOnClickListener {
activeLicense = StandardLicenses.GPL3
compositeDisposable.add(
showLicense(activity, StandardLicenses.GPL3)
)
}
for (component in softwareComponents) {
val componentBinding = ItemSoftwareComponentBinding
.inflate(inflater, container, false)
componentBinding.name.text = component.name
componentBinding.copyright.text = getString(
R.string.copyright,
component.years,
component.copyrightOwner,
component.license.abbreviation
)
val root: View = componentBinding.root
root.tag = component
root.setOnClickListener {
activeLicense = component.license
compositeDisposable.add(
showLicense(activity, component.license)
)
}
binding.licensesSoftwareComponents.addView(root)
registerForContextMenu(root)
}
if (activeLicense != null) {
compositeDisposable.add(
showLicense(activity, activeLicense!!)
)
}
return binding.root
}
override fun onCreateContextMenu(menu: ContextMenu, v: View, menuInfo: ContextMenuInfo?) {
val inflater = requireActivity().menuInflater
val component = v.tag as SoftwareComponent
menu.setHeaderTitle(component.name)
inflater.inflate(R.menu.software_component, menu)
super.onCreateContextMenu(menu, v, menuInfo)
componentForContextMenu = component
}
override fun onContextItemSelected(item: MenuItem): Boolean {
// item.getMenuInfo() is null so we use the tag of the view
val component = componentForContextMenu ?: return false
when (item.itemId) {
R.id.menu_software_website -> {
ShareUtils.openUrlInBrowser(activity, component.link)
return true
}
R.id.menu_software_show_license -> compositeDisposable.add(
showLicense(activity, component.license)
)
}
return false
}
override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState)
if (activeLicense != null) {
savedInstanceState.putSerializable(LICENSE_KEY, activeLicense)
}
}
companion object {
private const val ARG_COMPONENTS = "components"
private const val LICENSE_KEY = "ACTIVE_LICENSE"
fun newInstance(softwareComponents: Array<SoftwareComponent>): LicenseFragment {
val fragment = LicenseFragment()
fragment.arguments =
bundleOf(ARG_COMPONENTS to Objects.requireNonNull(softwareComponents))
return fragment
}
}
}

View File

@ -1,109 +0,0 @@
package org.schabi.newpipe.about;
import android.content.Context;
import android.util.Base64;
import android.webkit.WebView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import org.schabi.newpipe.R;
import org.schabi.newpipe.util.ThemeHelper;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import static org.schabi.newpipe.util.Localization.assureCorrectAppLanguage;
public final class LicenseFragmentHelper {
private LicenseFragmentHelper() { }
/**
* @param context the context to use
* @param license the license
* @return String which contains a HTML formatted license page
* styled according to the context's theme
*/
private static String getFormattedLicense(@NonNull final Context context,
@NonNull final License license) {
final StringBuilder licenseContent = new StringBuilder();
final String webViewData;
try (BufferedReader in = new BufferedReader(new InputStreamReader(
context.getAssets().open(license.getFilename()), StandardCharsets.UTF_8))) {
String str;
while ((str = in.readLine()) != null) {
licenseContent.append(str);
}
// split the HTML file and insert the stylesheet into the HEAD of the file
webViewData = licenseContent.toString().replace("</head>",
"<style>" + getLicenseStylesheet(context) + "</style></head>");
} catch (final IOException e) {
throw new IllegalArgumentException(
"Could not get license file: " + license.getFilename(), e);
}
return webViewData;
}
/**
* @param context the Android context
* @return String which is a CSS stylesheet according to the context's theme
*/
private static String getLicenseStylesheet(@NonNull final Context context) {
final boolean isLightTheme = ThemeHelper.isLightThemeSelected(context);
return "body{padding:12px 15px;margin:0;"
+ "background:#" + getHexRGBColor(context, isLightTheme
? R.color.light_license_background_color
: R.color.dark_license_background_color) + ";"
+ "color:#" + getHexRGBColor(context, isLightTheme
? R.color.light_license_text_color
: R.color.dark_license_text_color) + "}"
+ "a[href]{color:#" + getHexRGBColor(context, isLightTheme
? R.color.light_youtube_primary_color
: R.color.dark_youtube_primary_color) + "}"
+ "pre{white-space:pre-wrap}";
}
/**
* Cast R.color to a hexadecimal color value.
*
* @param context the context to use
* @param color the color number from R.color
* @return a six characters long String with hexadecimal RGB values
*/
private static String getHexRGBColor(@NonNull final Context context, final int color) {
return context.getResources().getString(color).substring(3);
}
static Disposable showLicense(@Nullable final Context context, @NonNull final License license) {
if (context == null) {
return Disposable.empty();
}
return Observable.fromCallable(() -> getFormattedLicense(context, license))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(formattedLicense -> {
final String webViewData = Base64.encodeToString(formattedLicense
.getBytes(StandardCharsets.UTF_8), Base64.NO_PADDING);
final WebView webView = new WebView(context);
webView.loadData(webViewData, "text/html; charset=UTF-8", "base64");
final AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.setTitle(license.getName());
alert.setView(webView);
assureCorrectAppLanguage(context);
alert.setNegativeButton(context.getString(R.string.finish),
(dialog, which) -> dialog.dismiss());
alert.show();
});
}
}

View File

@ -0,0 +1,114 @@
package org.schabi.newpipe.about
import android.content.Context
import android.util.Base64
import android.webkit.WebView
import androidx.appcompat.app.AlertDialog
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.schedulers.Schedulers
import org.schabi.newpipe.R
import org.schabi.newpipe.util.Localization
import org.schabi.newpipe.util.ThemeHelper
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
object LicenseFragmentHelper {
/**
* @param context the context to use
* @param license the license
* @return String which contains a HTML formatted license page
* styled according to the context's theme
*/
private fun getFormattedLicense(context: Context, license: License): String {
val licenseContent = StringBuilder()
val webViewData: String
try {
BufferedReader(
InputStreamReader(
context.assets.open(license.filename),
StandardCharsets.UTF_8
)
).use { `in` ->
var str: String?
while (`in`.readLine().also { str = it } != null) {
licenseContent.append(str)
}
// split the HTML file and insert the stylesheet into the HEAD of the file
webViewData = "$licenseContent".replace(
"</head>",
"<style>" + getLicenseStylesheet(context) + "</style></head>"
)
}
} catch (e: IOException) {
throw IllegalArgumentException(
"Could not get license file: " + license.filename, e
)
}
return webViewData
}
/**
* @param context the Android context
* @return String which is a CSS stylesheet according to the context's theme
*/
private fun getLicenseStylesheet(context: Context): String {
val isLightTheme = ThemeHelper.isLightThemeSelected(context)
return ("body{padding:12px 15px;margin:0;" + "background:#" + getHexRGBColor(
context,
if (isLightTheme) R.color.light_license_background_color
else R.color.dark_license_background_color
) + ";" + "color:#" + getHexRGBColor(
context,
if (isLightTheme) R.color.light_license_text_color
else R.color.dark_license_text_color
) + "}" + "a[href]{color:#" + getHexRGBColor(
context,
if (isLightTheme) R.color.light_youtube_primary_color
else R.color.dark_youtube_primary_color
) + "}" + "pre{white-space:pre-wrap}")
}
/**
* Cast R.color to a hexadecimal color value.
*
* @param context the context to use
* @param color the color number from R.color
* @return a six characters long String with hexadecimal RGB values
*/
private fun getHexRGBColor(context: Context, color: Int): String {
return context.getString(color).substring(3)
}
@JvmStatic
fun showLicense(context: Context?, license: License): Disposable {
return if (context == null) {
Disposable.empty()
} else {
Observable.fromCallable { getFormattedLicense(context, license) }
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { formattedLicense: String ->
val webViewData = Base64.encodeToString(
formattedLicense
.toByteArray(StandardCharsets.UTF_8),
Base64.NO_PADDING
)
val webView = WebView(context)
webView.loadData(webViewData, "text/html; charset=UTF-8", "base64")
val alert = AlertDialog.Builder(context)
alert.setTitle(license.name)
alert.setView(webView)
Localization.assureCorrectAppLanguage(context)
alert.setNegativeButton(
context.getString(R.string.finish)
) { dialog, _ -> dialog.dismiss() }
alert.show()
}
}
}
}

View File

@ -1,19 +0,0 @@
package org.schabi.newpipe.about;
/**
* Class containing information about standard software licenses.
*/
public final class StandardLicenses {
public static final License GPL3
= new License("GNU General Public License, Version 3.0", "GPLv3", "gpl_3.html");
public static final License APACHE2
= new License("Apache License, Version 2.0", "ALv2", "apache2.html");
public static final License MPL2
= new License("Mozilla Public License, Version 2.0", "MPL 2.0", "mpl2.html");
public static final License MIT
= new License("MIT License", "MIT", "mit.html");
public static final License EPL1
= new License("Eclipse Public License, Version 1.0", "EPL 1.0", "epl1.html");
private StandardLicenses() { }
}

View File

@ -0,0 +1,21 @@
package org.schabi.newpipe.about
/**
* Class containing information about standard software licenses.
*/
object StandardLicenses {
@JvmField
val GPL3 = License("GNU General Public License, Version 3.0", "GPLv3", "gpl_3.html")
@JvmField
val APACHE2 = License("Apache License, Version 2.0", "ALv2", "apache2.html")
@JvmField
val MPL2 = License("Mozilla Public License, Version 2.0", "MPL 2.0", "mpl2.html")
@JvmField
val MIT = License("MIT License", "MIT", "mit.html")
@JvmField
val EPL1 = License("Eclipse Public License, Version 1.0", "EPL 1.0", "epl1.html")
}