diff --git a/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java b/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java deleted file mode 100644 index ec28be237..000000000 --- a/app/src/main/java/org/schabi/newpipe/about/AboutActivity.java +++ /dev/null @@ -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.toolbar); - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - // Create the adapter that will return a fragment for each of the three - // primary sections of the activity. - final SectionsPagerAdapter mSectionsPagerAdapter = new SectionsPagerAdapter(this); - - // Set up the ViewPager with the sections adapter. - aboutBinding.container.setAdapter(mSectionsPagerAdapter); - - new TabLayoutMediator(aboutBinding.tabs, aboutBinding.container, (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.appVersion.setText(BuildConfig.VERSION_NAME); - - aboutBinding.githubLink.setOnClickListener(nv -> - openUrlInBrowser(context, context.getString(R.string.github_url), false)); - - aboutBinding.donationLink.setOnClickListener(v -> - openUrlInBrowser(context, context.getString(R.string.donation_url), false)); - - aboutBinding.websiteLink.setOnClickListener(nv -> - openUrlInBrowser(context, context.getString(R.string.website_url), false)); - - aboutBinding.privacyPolicyLink.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. - */ - public static class SectionsPagerAdapter extends FragmentStateAdapter { - public SectionsPagerAdapter(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; - } - } -} diff --git a/app/src/main/java/org/schabi/newpipe/about/AboutActivity.kt b/app/src/main/java/org/schabi/newpipe/about/AboutActivity.kt new file mode 100644 index 000000000..2f015a049 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/about/AboutActivity.kt @@ -0,0 +1,191 @@ +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 android.widget.Button +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() { + private fun Button.openLink(url: Int) { + setOnClickListener { + ShareUtils.openUrlInBrowser( + context, + requireContext().getString(url), + false + ) + } + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View { + val aboutBinding = FragmentAboutBinding.inflate(inflater, container, false) + aboutBinding.aboutAppVersion.text = BuildConfig.VERSION_NAME + aboutBinding.aboutGithubLink.openLink(R.string.github_url) + aboutBinding.aboutDonationLink.openLink(R.string.donation_url) + aboutBinding.aboutWebsiteLink.openLink(R.string.website_url) + aboutBinding.aboutPrivacyPolicyLink.openLink(R.string.privacy_policy_url) + 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 + } +} diff --git a/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.java b/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.java deleted file mode 100644 index f5bf4df19..000000000 --- a/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.java +++ /dev/null @@ -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.appReadLicense.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.softwareComponents.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.action_website: - ShareUtils.openUrlInBrowser(getActivity(), component.getLink()); - return true; - case R.id.action_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); - } - } -} diff --git a/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.kt b/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.kt new file mode 100644 index 000000000..d72ecf894 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/about/LicenseFragment.kt @@ -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 + 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 + 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): LicenseFragment { + val fragment = LicenseFragment() + fragment.arguments = + bundleOf(ARG_COMPONENTS to Objects.requireNonNull(softwareComponents)) + return fragment + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/about/LicenseFragmentHelper.java b/app/src/main/java/org/schabi/newpipe/about/LicenseFragmentHelper.java deleted file mode 100644 index b0241049d..000000000 --- a/app/src/main/java/org/schabi/newpipe/about/LicenseFragmentHelper.java +++ /dev/null @@ -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("", - ""); - } 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(); - }); - } -} diff --git a/app/src/main/java/org/schabi/newpipe/about/LicenseFragmentHelper.kt b/app/src/main/java/org/schabi/newpipe/about/LicenseFragmentHelper.kt new file mode 100644 index 000000000..89e356a42 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/about/LicenseFragmentHelper.kt @@ -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( + "", + "" + ) + } + } 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() + } + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/about/StandardLicenses.java b/app/src/main/java/org/schabi/newpipe/about/StandardLicenses.java deleted file mode 100644 index 60b1e168c..000000000 --- a/app/src/main/java/org/schabi/newpipe/about/StandardLicenses.java +++ /dev/null @@ -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() { } -} diff --git a/app/src/main/java/org/schabi/newpipe/about/StandardLicenses.kt b/app/src/main/java/org/schabi/newpipe/about/StandardLicenses.kt new file mode 100644 index 000000000..c5b9618fe --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/about/StandardLicenses.kt @@ -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") +} diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml index 525b2371f..937fcf977 100644 --- a/app/src/main/res/layout/activity_about.xml +++ b/app/src/main/res/layout/activity_about.xml @@ -2,14 +2,12 @@ diff --git a/app/src/main/res/layout/fragment_about.xml b/app/src/main/res/layout/fragment_about.xml index 77f940685..3211f3bd9 100644 --- a/app/src/main/res/layout/fragment_about.xml +++ b/app/src/main/res/layout/fragment_about.xml @@ -15,16 +15,14 @@ android:paddingBottom="@dimen/activity_vertical_margin">