Merge pull request #5881 from TacoTheDank/about_revamp
About package internal revamp
This commit is contained in:
commit
84e3f6ca18
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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() { }
|
|
||||||
}
|
|
|
@ -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")
|
||||||
|
}
|
|
@ -2,14 +2,12 @@
|
||||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/main_content"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fitsSystemWindows="true"
|
android:fitsSystemWindows="true"
|
||||||
tools:context="org.schabi.newpipe.about.AboutActivity">
|
tools:context="org.schabi.newpipe.about.AboutActivity">
|
||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:id="@+id/appbar"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingTop="@dimen/appbar_padding_top"
|
android:paddingTop="@dimen/appbar_padding_top"
|
||||||
|
@ -17,21 +15,21 @@
|
||||||
app:popupTheme="@style/ThemeOverlay.AppCompat.ActionBar">
|
app:popupTheme="@style/ThemeOverlay.AppCompat.ActionBar">
|
||||||
|
|
||||||
<androidx.appcompat.widget.Toolbar
|
<androidx.appcompat.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/about_toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:background="?attr/colorPrimary"
|
android:background="?attr/colorPrimary"
|
||||||
app:layout_scrollFlags="scroll|enterAlways" />
|
app:layout_scrollFlags="scroll|enterAlways" />
|
||||||
|
|
||||||
<com.google.android.material.tabs.TabLayout
|
<com.google.android.material.tabs.TabLayout
|
||||||
android:id="@+id/tabs"
|
android:id="@+id/about_tabLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content" />
|
android:layout_height="wrap_content" />
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
<androidx.viewpager2.widget.ViewPager2
|
<androidx.viewpager2.widget.ViewPager2
|
||||||
android:id="@+id/container"
|
android:id="@+id/about_viewPager2"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
|
||||||
|
|
|
@ -15,16 +15,14 @@
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin">
|
android:paddingBottom="@dimen/activity_vertical_margin">
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/logo"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:contentDescription="TODO"
|
android:contentDescription="@string/app_name"
|
||||||
app:srcCompat="@mipmap/ic_launcher" />
|
app:srcCompat="@mipmap/ic_launcher" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/app_name"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
|
@ -33,7 +31,7 @@
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/app_version"
|
android:id="@+id/about_app_version"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center_horizontal"
|
android:layout_gravity="center_horizontal"
|
||||||
|
@ -42,14 +40,12 @@
|
||||||
tools:text="0.9.9" />
|
tools:text="0.9.9" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/app_description"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingBottom="5dp"
|
android:paddingBottom="5dp"
|
||||||
android:text="@string/app_description" />
|
android:text="@string/app_description" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/title_contribution"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingTop="10dp"
|
android:paddingTop="10dp"
|
||||||
|
@ -62,7 +58,7 @@
|
||||||
android:text="@string/contribution_encouragement" />
|
android:text="@string/contribution_encouragement" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/github_link"
|
android:id="@+id/about_github_link"
|
||||||
style="@style/Base.Widget.AppCompat.Button.Borderless"
|
style="@style/Base.Widget.AppCompat.Button.Borderless"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -70,7 +66,6 @@
|
||||||
android:text="@string/view_on_github" />
|
android:text="@string/view_on_github" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/title_donate"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingTop="10dp"
|
android:paddingTop="10dp"
|
||||||
|
@ -83,7 +78,7 @@
|
||||||
android:text="@string/donation_encouragement" />
|
android:text="@string/donation_encouragement" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/donation_link"
|
android:id="@+id/about_donation_link"
|
||||||
style="@style/Base.Widget.AppCompat.Button.Borderless"
|
style="@style/Base.Widget.AppCompat.Button.Borderless"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -91,7 +86,6 @@
|
||||||
android:text="@string/give_back" />
|
android:text="@string/give_back" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/title_website"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingTop="10dp"
|
android:paddingTop="10dp"
|
||||||
|
@ -104,7 +98,7 @@
|
||||||
android:text="@string/website_encouragement" />
|
android:text="@string/website_encouragement" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/website_link"
|
android:id="@+id/about_website_link"
|
||||||
style="@style/Base.Widget.AppCompat.Button.Borderless"
|
style="@style/Base.Widget.AppCompat.Button.Borderless"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -112,7 +106,6 @@
|
||||||
android:text="@string/open_in_browser" />
|
android:text="@string/open_in_browser" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/title_privacy_policy"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:paddingTop="10dp"
|
android:paddingTop="10dp"
|
||||||
|
@ -125,7 +118,7 @@
|
||||||
android:text="@string/privacy_policy_encouragement" />
|
android:text="@string/privacy_policy_encouragement" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/privacy_policy_link"
|
android:id="@+id/about_privacy_policy_link"
|
||||||
style="@style/Base.Widget.AppCompat.Button.Borderless"
|
style="@style/Base.Widget.AppCompat.Button.Borderless"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
android:paddingBottom="@dimen/activity_vertical_margin">
|
android:paddingBottom="@dimen/activity_vertical_margin">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/app_license_title"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||||
|
@ -23,7 +22,6 @@
|
||||||
android:textAppearance="@android:style/TextAppearance.Large" />
|
android:textAppearance="@android:style/TextAppearance.Large" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/app_license"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
android:layout_marginLeft="@dimen/activity_horizontal_margin"
|
||||||
|
@ -31,7 +29,7 @@
|
||||||
android:text="@string/app_license" />
|
android:text="@string/app_license" />
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/app_read_license"
|
android:id="@+id/licenses_app_read_license"
|
||||||
style="@style/Base.Widget.AppCompat.Button.Borderless"
|
style="@style/Base.Widget.AppCompat.Button.Borderless"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -49,7 +47,7 @@
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/software_components"
|
android:id="@+id/licenses_software_components"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical" />
|
android:orientation="vertical" />
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_website"
|
android:id="@+id/menu_software_website"
|
||||||
android:title="@string/action_open_website" />
|
android:title="@string/action_open_website" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_show_license"
|
android:id="@+id/menu_software_show_license"
|
||||||
android:title="@string/read_full_license"></item>
|
android:title="@string/read_full_license" />
|
||||||
</menu>
|
</menu>
|
||||||
|
|
Loading…
Reference in New Issue