diff options
author | H. Lehmann <ByteHamster@users.noreply.github.com> | 2019-11-09 10:15:18 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-11-09 10:15:18 +0100 |
commit | 60a070b56c223cc5c02e98ef078dc9179a9c0ffb (patch) | |
tree | a18eeeaa39f62330f8e8fb61955be5616916d930 /app/src/main/java/de | |
parent | a48172fb4279b5cd31a7f60b643a4e7491d3ac4e (diff) | |
parent | 8f8ac04ffd6669ecf4e0bae0cbdf5e168788fcc8 (diff) | |
download | AntennaPod-60a070b56c223cc5c02e98ef078dc9179a9c0ffb.zip |
Merge pull request #3597 from ByteHamster/rework-about-screen
Rework about screen
Diffstat (limited to 'app/src/main/java/de')
7 files changed, 372 insertions, 160 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java deleted file mode 100644 index ef7ea2b16..000000000 --- a/app/src/main/java/de/danoeh/antennapod/activity/AboutActivity.java +++ /dev/null @@ -1,158 +0,0 @@ -package de.danoeh.antennapod.activity; - -import android.content.res.TypedArray; -import android.graphics.Color; -import android.os.Build; -import android.os.Bundle; -import androidx.appcompat.app.AppCompatActivity; -import android.util.Log; -import android.view.MenuItem; -import android.view.View; -import android.webkit.WebSettings; -import android.webkit.WebView; -import android.webkit.WebViewClient; -import android.widget.LinearLayout; - -import de.danoeh.antennapod.core.util.IntentUtils; -import org.apache.commons.io.IOUtils; - -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; - -import de.danoeh.antennapod.R; -import de.danoeh.antennapod.core.preferences.UserPreferences; -import io.reactivex.Single; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; - -/** - * Displays the 'about' screen - */ -public class AboutActivity extends AppCompatActivity { - - private static final String TAG = AboutActivity.class.getSimpleName(); - - private WebView webView; - private LinearLayout webViewContainer; - private Disposable disposable; - - @Override - protected void onCreate(Bundle savedInstanceState) { - setTheme(UserPreferences.getTheme()); - super.onCreate(savedInstanceState); - getSupportActionBar().setDisplayShowHomeEnabled(true); - setContentView(R.layout.about); - webViewContainer = findViewById(R.id.webViewContainer); - webView = findViewById(R.id.webViewAbout); - webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); - if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) { - webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null); - } - webView.setBackgroundColor(Color.TRANSPARENT); - webView.setWebViewClient(new WebViewClient() { - - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - if (url.startsWith("http")) { - IntentUtils.openInBrowser(AboutActivity.this, url); - return true; - } else { - url = url.replace("file:///android_asset/", ""); - loadAsset(url); - return true; - } - } - - }); - loadAsset("about.html"); - } - - private void loadAsset(String filename) { - disposable = Single.create(subscriber -> { - InputStream input = null; - try { - TypedArray res = AboutActivity.this.getTheme().obtainStyledAttributes( - new int[] { R.attr.about_screen_font_color, R.attr.about_screen_background, - R.attr.about_screen_card_background, R.attr.about_screen_card_border}); - String fontColor = String.format("#%06X", 0xFFFFFF & res.getColor(0, 0)); - String backgroundColor = String.format("#%06X", 0xFFFFFF & res.getColor(1, 0)); - String cardBackground = String.format("#%06X", 0xFFFFFF & res.getColor(2, 0)); - String cardBorder = String.format("#%06X", 0xFFFFFF & res.getColor(3, 0)); - res.recycle(); - input = getAssets().open(filename); - String webViewData = IOUtils.toString(input, Charset.defaultCharset()); - if (!webViewData.startsWith("<!DOCTYPE html>")) { - webViewData = webViewData.replace("%", "%"); - webViewData = - "<!DOCTYPE html>" + - "<html>" + - "<head>" + - " <meta http-equiv=\"Content-Type\" content=\"text/html;charset=UTF-8\">" + - " <style type=\"text/css\">" + - " @font-face {" + - " font-family: 'Roboto-Light';" + - " src: url('file:///android_asset/Roboto-Light.ttf');" + - " }" + - " * {" + - " color: @fontcolor@;" + - " font-family: roboto-Light;" + - " font-size: 8pt;" + - " }" + - " </style>" + - "</head><body><p>" + webViewData + "</p></body></html>"; - webViewData = webViewData.replace("\n", "<br/>"); - } - webViewData = webViewData.replace("@fontcolor@", fontColor); - webViewData = webViewData.replace("@background@", backgroundColor); - webViewData = webViewData.replace("@card_background@", cardBackground); - webViewData = webViewData.replace("@card_border@", cardBorder); - subscriber.onSuccess(webViewData); - } catch (IOException e) { - Log.e(TAG, Log.getStackTraceString(e)); - subscriber.onError(e); - } finally { - IOUtils.closeQuietly(input); - } - }) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe( - webViewData -> - webView.loadDataWithBaseURL("file:///android_asset/", webViewData.toString(), "text/html", "utf-8", "file:///android_asset/" + filename.toString()), - error -> Log.e(TAG, Log.getStackTraceString(error)) - ); - } - - @Override - public void onBackPressed() { - if (webView.canGoBack()) { - webView.goBack(); - } else { - super.onBackPressed(); - } - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == android.R.id.home) { - onBackPressed(); - return true; - } else { - return super.onOptionsItemSelected(item); - } - } - - @Override - protected void onDestroy() { - super.onDestroy(); - if (disposable != null) { - disposable.dispose(); - } - if (webViewContainer != null && webView != null) { - webViewContainer.removeAllViews(); - webView.destroy(); - } - } -} diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/SimpleIconListAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/SimpleIconListAdapter.java new file mode 100644 index 000000000..10bda4efa --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/adapter/SimpleIconListAdapter.java @@ -0,0 +1,59 @@ +package de.danoeh.antennapod.adapter; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; +import com.bumptech.glide.Glide; +import com.bumptech.glide.load.engine.DiskCacheStrategy; +import com.bumptech.glide.request.RequestOptions; +import de.danoeh.antennapod.R; + +import java.util.List; + +/** + * Displays a list of items that have a subtitle and an icon. + */ +public class SimpleIconListAdapter<T extends SimpleIconListAdapter.ListItem> extends ArrayAdapter<T> { + private final Context context; + private final List<T> listItems; + + public SimpleIconListAdapter(Context context, List<T> listItems) { + super(context, R.layout.simple_icon_list_item, listItems); + this.context = context; + this.listItems = listItems; + } + + @Override + public View getView(int position, View view, ViewGroup parent) { + if (view == null) { + view = View.inflate(context, R.layout.simple_icon_list_item, null); + } + + ListItem item = listItems.get(position); + ((TextView) view.findViewById(R.id.title)).setText(item.title); + ((TextView) view.findViewById(R.id.subtitle)).setText(item.subtitle); + Glide.with(context) + .load(item.imageUrl) + .apply(new RequestOptions() + .diskCacheStrategy(DiskCacheStrategy.NONE) + .fitCenter() + .dontAnimate()) + .into(((ImageView) view.findViewById(R.id.icon))); + return view; + } + + public static class ListItem { + public final String title; + public final String subtitle; + public final String imageUrl; + + public ListItem(String title, String subtitle, String imageUrl) { + this.title = title; + this.subtitle = subtitle; + this.imageUrl = imageUrl; + } + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutDevelopersFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutDevelopersFragment.java new file mode 100644 index 000000000..62a5eb306 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutDevelopersFragment.java @@ -0,0 +1,65 @@ +package de.danoeh.antennapod.fragment.preferences; + +import android.os.Bundle; +import android.view.View; +import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.ListFragment; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.PreferenceActivity; +import de.danoeh.antennapod.adapter.SimpleIconListAdapter; +import io.reactivex.Single; +import io.reactivex.SingleOnSubscribe; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.ArrayList; + +public class AboutDevelopersFragment extends ListFragment { + private Disposable developersLoader; + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + getListView().setDivider(null); + getListView().setSelector(android.R.color.transparent); + + developersLoader = Single.create((SingleOnSubscribe<ArrayList<SimpleIconListAdapter.ListItem>>) emitter -> { + ArrayList<SimpleIconListAdapter.ListItem> developers = new ArrayList<>(); + BufferedReader reader = new BufferedReader(new InputStreamReader( + getContext().getAssets().open("developers.csv"))); + String line; + while ((line = reader.readLine()) != null) { + String[] info = line.split(";"); + developers.add(new SimpleIconListAdapter.ListItem(info[0], info[2], + "https://avatars2.githubusercontent.com/u/" + info[1] + "?s=60&v=4")); + } + emitter.onSuccess(developers); + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + developers -> setListAdapter(new SimpleIconListAdapter<>(getContext(), developers)), + error -> Toast.makeText(getContext(), "Error while loading developers", Toast.LENGTH_LONG).show() + ); + + } + + @Override + public void onStop() { + super.onStop(); + if (developersLoader != null) { + developersLoader.dispose(); + } + } + + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.developers); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutFragment.java new file mode 100644 index 000000000..0fa7bd4bb --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutFragment.java @@ -0,0 +1,56 @@ +package de.danoeh.antennapod.fragment.preferences; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.os.Bundle; +import androidx.preference.PreferenceFragmentCompat; +import com.google.android.material.snackbar.Snackbar; +import de.danoeh.antennapod.BuildConfig; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.PreferenceActivity; +import de.danoeh.antennapod.core.util.IntentUtils; + +public class AboutFragment extends PreferenceFragmentCompat { + + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + addPreferencesFromResource(R.xml.preferences_about); + + findPreference("about_version").setSummary(String.format( + "%s (%s)", BuildConfig.VERSION_NAME, BuildConfig.COMMIT_HASH)); + findPreference("about_version").setOnPreferenceClickListener((preference) -> { + ClipboardManager clipboard = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE); + ClipData clip = ClipData.newPlainText(getString(R.string.bug_report_title), + findPreference("about_version").getSummary()); + clipboard.setPrimaryClip(clip); + Snackbar.make(getView(), R.string.copied_to_clipboard, Snackbar.LENGTH_SHORT).show(); + return true; + }); + findPreference("about_developers").setOnPreferenceClickListener((preference) -> { + getFragmentManager().beginTransaction().replace(R.id.content, new AboutDevelopersFragment()) + .addToBackStack(getString(R.string.developers)).commit(); + return true; + }); + findPreference("about_translators").setOnPreferenceClickListener((preference) -> { + getFragmentManager().beginTransaction().replace(R.id.content, new AboutTranslatorsFragment()) + .addToBackStack(getString(R.string.translators)).commit(); + return true; + }); + findPreference("about_privacy_policy").setOnPreferenceClickListener((preference) -> { + IntentUtils.openInBrowser(getContext(), "https://antennapod.org/privacy.html"); + return true; + }); + findPreference("about_licenses").setOnPreferenceClickListener((preference) -> { + getFragmentManager().beginTransaction().replace(R.id.content, new AboutLicensesFragment()) + .addToBackStack(getString(R.string.translators)).commit(); + return true; + }); + } + + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.about_pref); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutLicensesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutLicensesFragment.java new file mode 100644 index 000000000..536d11e01 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutLicensesFragment.java @@ -0,0 +1,126 @@ +package de.danoeh.antennapod.fragment.preferences; + +import android.os.Bundle; +import android.view.View; +import android.widget.ListView; +import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.ListFragment; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.PreferenceActivity; +import de.danoeh.antennapod.adapter.SimpleIconListAdapter; +import de.danoeh.antennapod.core.util.IntentUtils; +import io.reactivex.Single; +import io.reactivex.SingleOnSubscribe; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.NodeList; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; + +public class AboutLicensesFragment extends ListFragment { + private Disposable licensesLoader; + private final ArrayList<LicenseItem> licenses = new ArrayList<>(); + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + getListView().setDivider(null); + + licensesLoader = Single.create((SingleOnSubscribe<ArrayList<LicenseItem>>) emitter -> { + licenses.clear(); + InputStream stream = getContext().getAssets().open("licenses.xml"); + DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + NodeList libraryList = docBuilder.parse(stream).getElementsByTagName("library"); + for (int i = 0; i < libraryList.getLength(); i++) { + NamedNodeMap lib = libraryList.item(i).getAttributes(); + licenses.add(new LicenseItem( + lib.getNamedItem("name").getTextContent(), + String.format("By %s, %s license", + lib.getNamedItem("author").getTextContent(), + lib.getNamedItem("license").getTextContent()), + null, + lib.getNamedItem("website").getTextContent(), + lib.getNamedItem("licenseText").getTextContent())); + } + emitter.onSuccess(licenses); + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + developers -> setListAdapter(new SimpleIconListAdapter<LicenseItem>(getContext(), developers)), + error -> Toast.makeText(getContext(), "Error while loading licenses", Toast.LENGTH_LONG).show() + ); + + } + + private static class LicenseItem extends SimpleIconListAdapter.ListItem { + final String licenseUrl; + final String licenseTextFile; + + LicenseItem(String title, String subtitle, String imageUrl, String licenseUrl, String licenseTextFile) { + super(title, subtitle, imageUrl); + this.licenseUrl = licenseUrl; + this.licenseTextFile = licenseTextFile; + } + } + + @Override + public void onListItemClick(@NonNull ListView l, @NonNull View v, int position, long id) { + super.onListItemClick(l, v, position, id); + + LicenseItem item = licenses.get(position); + CharSequence[] items = {"View website", "View license"}; + new AlertDialog.Builder(getContext()) + .setTitle(item.title) + .setItems(items, (dialog, which) -> { + if (which == 0) { + IntentUtils.openInBrowser(getContext(), item.licenseUrl); + } else if (which == 1) { + showLicenseText(item.licenseTextFile); + } + }).show(); + } + + private void showLicenseText(String licenseTextFile) { + try { + BufferedReader reader = new BufferedReader(new InputStreamReader( + getContext().getAssets().open(licenseTextFile))); + StringBuilder licenseText = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + licenseText.append(line).append("\n"); + } + + new AlertDialog.Builder(getContext()) + .setMessage(licenseText) + .show(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public void onStop() { + super.onStop(); + if (licensesLoader != null) { + licensesLoader.dispose(); + } + } + + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.licenses); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutTranslatorsFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutTranslatorsFragment.java new file mode 100644 index 000000000..914dbb9a2 --- /dev/null +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/AboutTranslatorsFragment.java @@ -0,0 +1,64 @@ +package de.danoeh.antennapod.fragment.preferences; + +import android.os.Bundle; +import android.view.View; +import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.ListFragment; +import de.danoeh.antennapod.R; +import de.danoeh.antennapod.activity.PreferenceActivity; +import de.danoeh.antennapod.adapter.SimpleIconListAdapter; +import io.reactivex.Single; +import io.reactivex.SingleOnSubscribe; +import io.reactivex.android.schedulers.AndroidSchedulers; +import io.reactivex.disposables.Disposable; +import io.reactivex.schedulers.Schedulers; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.util.ArrayList; + +public class AboutTranslatorsFragment extends ListFragment { + private Disposable translatorsLoader; + + @Override + public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + getListView().setDivider(null); + getListView().setSelector(android.R.color.transparent); + + translatorsLoader = Single.create((SingleOnSubscribe<ArrayList<SimpleIconListAdapter.ListItem>>) emitter -> { + ArrayList<SimpleIconListAdapter.ListItem> translators = new ArrayList<>(); + BufferedReader reader = new BufferedReader(new InputStreamReader( + getContext().getAssets().open("translators.csv"))); + String line; + while ((line = reader.readLine()) != null) { + String[] info = line.split(";"); + translators.add(new SimpleIconListAdapter.ListItem(info[0], info[1], null)); + } + emitter.onSuccess(translators); + }) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe( + translators -> setListAdapter(new SimpleIconListAdapter<>(getContext(), translators)), + error -> Toast.makeText(getContext(), "Error while loading translators", Toast.LENGTH_LONG).show() + ); + + } + + @Override + public void onStop() { + super.onStop(); + if (translatorsLoader != null) { + translatorsLoader.dispose(); + } + } + + @Override + public void onStart() { + super.onStart(); + ((PreferenceActivity) getActivity()).getSupportActionBar().setTitle(R.string.translators); + } +} diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java index 00e69f1db..5fd38d663 100644 --- a/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java +++ b/app/src/main/java/de/danoeh/antennapod/fragment/preferences/MainPreferencesFragment.java @@ -7,7 +7,6 @@ import androidx.preference.PreferenceFragmentCompat; import com.bytehamster.lib.preferencesearch.SearchConfiguration; import com.bytehamster.lib.preferencesearch.SearchPreference; import de.danoeh.antennapod.R; -import de.danoeh.antennapod.activity.AboutActivity; import de.danoeh.antennapod.activity.BugReportActivity; import de.danoeh.antennapod.activity.PreferenceActivity; import de.danoeh.antennapod.core.util.IntentUtils; @@ -63,7 +62,8 @@ public class MainPreferencesFragment extends PreferenceFragmentCompat { findPreference(PREF_ABOUT).setOnPreferenceClickListener( preference -> { - startActivity(new Intent(getActivity(), AboutActivity.class)); + getFragmentManager().beginTransaction().replace(R.id.content, new AboutFragment()) + .addToBackStack(getString(R.string.about_pref)).commit(); return true; } ); |