summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/android-emulator.yml2
-rw-r--r--app/build.gradle2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java11
-rw-r--r--app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java26
-rw-r--r--app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java2
-rw-r--r--app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java4
-rw-r--r--app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java14
-rw-r--r--app/src/main/res/layout/about_teaser.xml4
-rw-r--r--app/src/main/res/layout/audio_controls.xml20
-rw-r--r--app/src/main/res/layout/audioplayer_fragment.xml33
-rw-r--r--app/src/main/res/layout/cover_fragment.xml2
-rw-r--r--app/src/main/res/layout/download_authentication_activity.xml14
-rw-r--r--app/src/main/res/layout/episodes_apply_action_fragment.xml4
-rw-r--r--app/src/main/res/layout/external_player_fragment.xml8
-rw-r--r--app/src/main/res/layout/feeditem_fragment.xml4
-rw-r--r--app/src/main/res/layout/feeditemlist_header.xml5
-rw-r--r--app/src/main/res/layout/feeditemlist_item.xml15
-rw-r--r--app/src/main/res/layout/gpodnet_podcast_listitem.xml2
-rw-r--r--app/src/main/res/layout/itunes_podcast_listitem.xml2
-rw-r--r--app/src/main/res/layout/nav_list.xml3
-rw-r--r--app/src/main/res/layout/nav_listitem.xml2
-rw-r--r--app/src/main/res/layout/nav_section_item.xml4
-rw-r--r--app/src/main/res/layout/onlinefeedview_activity.xml2
-rw-r--r--app/src/main/res/layout/opml_selection.xml80
-rw-r--r--app/src/main/res/layout/searchlist_item.xml2
-rw-r--r--app/src/main/res/layout/simplechapter_item.xml2
-rw-r--r--app/src/main/res/layout/statistics_listitem.xml4
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java190
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndStringUtils.java14
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/Converter.java74
-rw-r--r--core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java8
-rw-r--r--core/src/main/res/values/attrs.xml1
-rw-r--r--core/src/main/res/values/colors.xml12
-rw-r--r--core/src/main/res/values/strings.xml7
-rw-r--r--core/src/main/res/values/styles.xml3
41 files changed, 326 insertions, 272 deletions
diff --git a/.github/workflows/android-emulator.yml b/.github/workflows/android-emulator.yml
index 52c6f0f69..2946b2be2 100644
--- a/.github/workflows/android-emulator.yml
+++ b/.github/workflows/android-emulator.yml
@@ -8,7 +8,7 @@ jobs:
build:
runs-on: macOS-latest
steps:
- - uses: actions/checkout@v1
+ - uses: actions/checkout@v2
- name: set up JDK 1.8
uses: actions/setup-java@v1
with:
diff --git a/app/build.gradle b/app/build.gradle
index a2e85317c..44faefeec 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -145,7 +145,7 @@ dependencies {
implementation "androidx.media:media:$mediaVersion"
implementation "androidx.preference:preference:$preferenceVersion"
implementation 'androidx.recyclerview:recyclerview:1.1.0'
- implementation 'androidx.viewpager2:viewpager2:1.0.0'
+ implementation 'androidx.viewpager2:viewpager2:1.1.0-alpha01'
implementation "androidx.work:work-runtime:$workManagerVersion"
implementation "com.google.android.material:material:$googleMaterialVersion"
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
index a0d1c17d5..84a253f0b 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OnlineFeedViewActivity.java
@@ -145,7 +145,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
}
private void showNoPodcastFoundError() {
- new AlertDialog.Builder(OnlineFeedViewActivity.this)
+ runOnUiThread(() -> new AlertDialog.Builder(OnlineFeedViewActivity.this)
.setNeutralButton(android.R.string.ok, (dialog, which) -> finish())
.setTitle(R.string.error_label)
.setMessage(R.string.null_value_podcast_error)
@@ -153,7 +153,7 @@ public class OnlineFeedViewActivity extends AppCompatActivity {
setResult(RESULT_ERROR);
finish();
})
- .show();
+ .show());
}
/**
diff --git a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
index f4d312a4f..10292b892 100644
--- a/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
+++ b/app/src/main/java/de/danoeh/antennapod/activity/OpmlImportActivity.java
@@ -18,8 +18,12 @@ import de.danoeh.antennapod.asynctask.OpmlImportWorker;
import de.danoeh.antennapod.core.export.opml.OpmlElement;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.LangUtils;
+import org.apache.commons.io.ByteOrderMark;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.input.BOMInputStream;
import org.apache.commons.lang3.ArrayUtils;
+import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
@@ -130,7 +134,12 @@ public class OpmlImportActivity extends AppCompatActivity {
/** Starts the import process. */
private void startImport() {
try {
- Reader reader = new InputStreamReader(getContentResolver().openInputStream(uri), LangUtils.UTF_8);
+ InputStream opmlFileStream = getContentResolver().openInputStream(uri);
+ BOMInputStream bomInputStream = new BOMInputStream(opmlFileStream);
+ ByteOrderMark bom = bomInputStream.getBOM();
+ String charsetName = (bom == null) ? "UTF-8" : bom.getCharsetName();
+ Reader reader = new InputStreamReader(bomInputStream, charsetName);
+
OpmlImportWorker importWorker = new OpmlImportWorker(this, reader) {
@Override
diff --git a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
index 153f4abc3..7d195a9ad 100644
--- a/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
+++ b/app/src/main/java/de/danoeh/antennapod/adapter/DownloadLogAdapter.java
@@ -73,11 +73,13 @@ public class DownloadLogAdapter extends BaseAdapter {
if (status.isSuccessful()) {
holder.icon.setTextColor(ContextCompat.getColor(context, R.color.download_success_green));
holder.icon.setText("{fa-check-circle}");
+ holder.icon.setContentDescription(context.getString(R.string.download_successful));
holder.secondaryActionButton.setVisibility(View.INVISIBLE);
holder.reason.setVisibility(View.GONE);
} else {
holder.icon.setTextColor(ContextCompat.getColor(context, R.color.download_failed_red));
holder.icon.setText("{fa-times-circle}");
+ holder.icon.setContentDescription(context.getString(R.string.error_label));
String reasonText = status.getReason().getErrorString(context);
if (status.getReasonDetailed() != null) {
reasonText += ": " + status.getReasonDetailed();
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
index abab94852..ac1e94437 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/EpisodesApplyActionFragment.java
@@ -185,6 +185,21 @@ public class EpisodesApplyActionFragment extends Fragment {
}
}
+ mSpeedDialView.setOnChangeListener(new SpeedDialView.OnChangeListener() {
+ @Override
+ public boolean onMainActionSelected() {
+ return false;
+ }
+
+ @Override
+ public void onToggleChanged(boolean open) {
+ if (open && checkedIds.size() == 0) {
+ ((MainActivity) getActivity()).showSnackbarAbovePlayer(R.string.no_items_selected,
+ Snackbar.LENGTH_SHORT);
+ mSpeedDialView.close();
+ }
+ }
+ });
mSpeedDialView.setOnActionSelectedListener(actionItem -> {
ActionBinding selectedBinding = null;
for (ActionBinding binding : actionBindings) {
@@ -204,16 +219,6 @@ public class EpisodesApplyActionFragment extends Fragment {
return view;
}
- private void showSpeedDialIfAnyChecked() {
- if (checkedIds.size() > 0) {
- if (!mSpeedDialView.isShown()) {
- mSpeedDialView.show();
- }
- } else {
- mSpeedDialView.hide(); // hide() also handles UI, e.g., overlay properly.
- }
- }
-
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
@@ -409,7 +414,6 @@ public class EpisodesApplyActionFragment extends Fragment {
mListView.setItemChecked(i, checked);
}
ActivityCompat.invalidateOptionsMenu(EpisodesApplyActionFragment.this.getActivity());
- showSpeedDialIfAnyChecked();
toolbar.setTitle(getResources().getQuantityString(R.plurals.num_selected_label,
checkedIds.size(), checkedIds.size()));
}
diff --git a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
index 83debaecb..d1ffdc148 100644
--- a/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
+++ b/app/src/main/java/de/danoeh/antennapod/dialog/PlaybackControlsDialog.java
@@ -80,7 +80,7 @@ public class PlaybackControlsDialog extends DialogFragment {
private void setupUi() {
final SeekBar barPlaybackSpeed = dialog.findViewById(R.id.playback_speed);
- final Button butDecSpeed = dialog.findViewById(R.id.butDecSpeed);
+ final TextView butDecSpeed = dialog.findViewById(R.id.butDecSpeed);
butDecSpeed.setOnClickListener(v -> {
if (controller != null && controller.canSetPlaybackSpeed()) {
barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() - 2);
@@ -88,7 +88,7 @@ public class PlaybackControlsDialog extends DialogFragment {
VariableSpeedDialog.showGetPluginDialog(getContext());
}
});
- final Button butIncSpeed = (Button) dialog.findViewById(R.id.butIncSpeed);
+ final TextView butIncSpeed = dialog.findViewById(R.id.butIncSpeed);
butIncSpeed.setOnClickListener(v -> {
if (controller != null && controller.canSetPlaybackSpeed()) {
barPlaybackSpeed.setProgress(barPlaybackSpeed.getProgress() + 2);
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
index 046a39355..546684f14 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AddFeedFragment.java
@@ -98,7 +98,7 @@ public class AddFeedFragment extends Fragment {
private void performSearch() {
String query = combinedFeedSearchBox.getText().toString();
- if (query.startsWith("http")) {
+ if (query.matches("http[s]?://.*")) {
addUrl(query);
return;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
index 7df0f5577..5ca8b666a 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/AudioPlayerFragment.java
@@ -143,7 +143,7 @@ public class AudioPlayerFragment extends Fragment implements
pageIndicator = root.findViewById(R.id.page_indicator);
pageIndicator.setViewPager(pager);
pageIndicator.setOnClickListener(v ->
- pager.setCurrentItem((pager.getCurrentItem() + 1) % pager.getChildCount()));
+ pager.setCurrentItem((pager.getCurrentItem() + 1) % NUM_CONTENT_FRAGMENTS));
return root;
}
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
index 1f96c12f2..b90da7447 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/FeedItemlistFragment.java
@@ -323,7 +323,7 @@ public class FeedItemlistFragment extends Fragment implements AdapterView.OnItem
activity.loadChildFragment(ItemPagerFragment.newInstance(ids, position));
}
- @Subscribe
+ @Subscribe(threadMode = ThreadMode.MAIN)
public void onEvent(FeedEvent event) {
Log.d(TAG, "onEvent() called with: " + "event = [" + event + "]");
if (event.feedId == feedID) {
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
index 04a62741c..3ae4cc648 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemDescriptionFragment.java
@@ -97,7 +97,7 @@ public class ItemDescriptionFragment extends Fragment {
@Nullable
private String loadData() {
- if (controller.getMedia() == null) {
+ if (controller != null && controller.getMedia() == null) {
return null;
}
Timeline timeline = new Timeline(getActivity(), controller.getMedia());
diff --git a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
index ee3f2331f..aaf0fc7d4 100644
--- a/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
+++ b/app/src/main/java/de/danoeh/antennapod/fragment/ItemFragment.java
@@ -70,6 +70,7 @@ import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
+import java.util.Date;
import java.util.List;
import java.util.Locale;
@@ -288,6 +289,7 @@ public class ItemFragment extends Fragment {
if (item.getPubDate() != null) {
String pubDateStr = DateUtils.formatAbbrev(getActivity(), item.getPubDate());
txtvPublished.setText(pubDateStr);
+ txtvPublished.setContentDescription(DateUtils.formatForAccessibility(getContext(), item.getPubDate()));
}
Glide.with(getActivity())
@@ -321,6 +323,8 @@ public class ItemFragment extends Fragment {
} else {
if (media.getDuration() > 0) {
txtvDuration.setText(Converter.getDurationStringLong(media.getDuration()));
+ txtvDuration.setContentDescription(
+ Converter.getDurationStringLocalized(getContext(), media.getDuration()));
}
if (media.isCurrentlyPlaying()) {
actionButton1 = new PauseActionButton(item);
diff --git a/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java
index 7b80c3850..8584befbc 100644
--- a/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java
+++ b/app/src/main/java/de/danoeh/antennapod/view/viewholder/EpisodeItemViewHolder.java
@@ -7,11 +7,15 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.cardview.widget.CardView;
+import androidx.core.view.AccessibilityDelegateCompat;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.joanzapata.iconify.Iconify;
@@ -57,6 +61,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
public final ImageView secondaryActionIcon;
private final CircularProgressBar secondaryActionProgress;
private final TextView separatorIcons;
+ private final View leftPadding;
public final CardView coverHolder;
private final MainActivity activity;
@@ -87,6 +92,7 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
secondaryActionButton = itemView.findViewById(R.id.secondaryActionButton);
secondaryActionIcon = itemView.findViewById(R.id.secondaryActionIcon);
coverHolder = itemView.findViewById(R.id.coverHolder);
+ leftPadding = itemView.findViewById(R.id.left_padding);
itemView.setTag(this);
}
@@ -94,11 +100,13 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
this.item = item;
placeholder.setText(item.getFeed().getTitle());
title.setText(item.getTitle());
+ leftPadding.setContentDescription(item.getTitle());
pubDate.setText(DateUtils.formatAbbrev(activity, item.getPubDate()));
+ pubDate.setContentDescription(DateUtils.formatForAccessibility(activity, item.getPubDate()));
isNew.setVisibility(item.isNew() ? View.VISIBLE : View.GONE);
isFavorite.setVisibility(item.isTagged(FeedItem.TAG_FAVORITE) ? View.VISIBLE : View.GONE);
isInQueue.setVisibility(item.isTagged(FeedItem.TAG_QUEUE) ? View.VISIBLE : View.GONE);
- itemView.setAlpha(item.isPlayed() ? 0.5f : 1.0f);
+ itemView.setAlpha(item.isPlayed() ? 0.6f : 1.0f);
ItemActionButton actionButton = ItemActionButton.forItem(item, true, true);
actionButton.configure(secondaryActionButton, secondaryActionIcon, activity);
@@ -128,6 +136,8 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
isVideo.setVisibility(media.getMediaType() == MediaType.VIDEO ? View.VISIBLE : View.GONE);
duration.setVisibility(media.getDuration() > 0 ? View.VISIBLE : View.GONE);
duration.setText(Converter.getDurationStringLong(media.getDuration()));
+ duration.setContentDescription(activity.getString(R.string.chapter_duration,
+ Converter.getDurationStringLocalized(activity, media.getDuration())));
if (media.isCurrentlyPlaying()) {
container.setBackgroundColor(ThemeUtils.getColorFromAttr(activity, R.attr.currently_playing_background));
@@ -149,6 +159,8 @@ public class EpisodeItemViewHolder extends RecyclerView.ViewHolder {
int progress = (int) (100.0 * media.getPosition() / media.getDuration());
progressBar.setProgress(progress);
position.setText(Converter.getDurationStringLong(media.getPosition()));
+ position.setContentDescription(activity.getString(R.string.position,
+ Converter.getDurationStringLocalized(activity, media.getPosition())));
progressBar.setVisibility(View.VISIBLE);
position.setVisibility(View.VISIBLE);
} else {
diff --git a/app/src/main/res/layout/about_teaser.xml b/app/src/main/res/layout/about_teaser.xml
index a9e50f6da..4e7f0454f 100644
--- a/app/src/main/res/layout/about_teaser.xml
+++ b/app/src/main/res/layout/about_teaser.xml
@@ -4,4 +4,6 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:adjustViewBounds="true"
- android:layout_height="wrap_content" app:srcCompat="@drawable/teaser" /> \ No newline at end of file
+ android:layout_height="wrap_content"
+ app:srcCompat="@drawable/teaser"
+ android:importantForAccessibility="no"/> \ No newline at end of file
diff --git a/app/src/main/res/layout/audio_controls.xml b/app/src/main/res/layout/audio_controls.xml
index 6cb87282f..9a1c525a7 100644
--- a/app/src/main/res/layout/audio_controls.xml
+++ b/app/src/main/res/layout/audio_controls.xml
@@ -41,18 +41,22 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:gravity="center_vertical">
- <Button
+ <TextView
android:id="@+id/butDecSpeed"
android:layout_width="32dp"
android:layout_height="32dp"
android:gravity="center"
android:text="-"
+ android:clickable="true"
+ android:focusable="true"
android:textStyle="bold"
- android:textColor="?attr/colorAccent"
android:textSize="24sp"
- android:background="?attr/selectableItemBackgroundBorderless" />
+ android:textColor="?attr/colorSecondary"
+ android:contentDescription="@string/decrease_volume"
+ android:background="?attr/selectableItemBackgroundBorderless"/>
<SeekBar
android:id="@+id/playback_speed"
@@ -61,16 +65,18 @@
android:max="70"
android:layout_weight="1" />
- <Button
+ <TextView
android:id="@+id/butIncSpeed"
android:layout_width="32dp"
android:layout_height="32dp"
- android:minWidth="0dp"
android:gravity="center"
android:text="+"
+ android:clickable="true"
+ android:focusable="true"
android:textStyle="bold"
- android:textColor="?attr/colorAccent"
android:textSize="24sp"
+ android:textColor="?attr/colorSecondary"
+ android:contentDescription="@string/increase_volume"
android:background="?attr/selectableItemBackgroundBorderless" />
</LinearLayout>
diff --git a/app/src/main/res/layout/audioplayer_fragment.xml b/app/src/main/res/layout/audioplayer_fragment.xml
index a9e9137f2..1935ce36c 100644
--- a/app/src/main/res/layout/audioplayer_fragment.xml
+++ b/app/src/main/res/layout/audioplayer_fragment.xml
@@ -22,6 +22,7 @@
android:layout_marginTop="-12dp"
android:padding="4dp"
android:layout_below="@id/toolbar"
+ android:contentDescription="@string/switch_pages"
android:layout_centerHorizontal="true"/>
<FrameLayout
@@ -29,9 +30,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
- android:background="?android:attr/windowBackground"
+ android:background="?attr/background_elevated"
tools:layout_height="@dimen/external_player_height"
- tools:background="@android:color/holo_green_light"
android:elevation="8dp"/>
<androidx.viewpager2.widget.ViewPager2
@@ -41,7 +41,6 @@
android:layout_above="@id/playtime_layout"
android:layout_below="@id/toolbar"
android:foreground="?android:windowContentOverlay"
- tools:background="@android:color/holo_orange_light"
android:layout_marginBottom="12dp"/>
<SeekBar
@@ -53,8 +52,7 @@
android:layout_above="@id/playtime_layout"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
- android:layoutDirection="ltr"
- tools:background="@android:color/holo_green_dark"/>
+ android:layoutDirection="ltr" />
<LinearLayout
android:id="@+id/playtime_layout"
@@ -82,8 +80,7 @@
android:layout_marginStart="16dp"
android:text="@string/position_default_label"
android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/text_size_micro"
- tools:background="@android:color/holo_green_dark"/>
+ android:textSize="@dimen/text_size_micro"/>
<TextView
android:id="@+id/txtvLength"
@@ -96,8 +93,7 @@
android:text="@string/position_default_label"
android:textColor="?android:attr/textColorSecondary"
android:textSize="@dimen/text_size_micro"
- android:background="?android:attr/selectableItemBackground"
- tools:background="@android:color/holo_green_dark"/>
+ android:background="?android:attr/selectableItemBackground"/>
</RelativeLayout>
@@ -105,8 +101,7 @@
android:id="@+id/player_control"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="24dp"
- tools:background="@android:color/holo_purple">
+ android:layout_marginBottom="24dp">
<ImageButton
android:id="@+id/butPlay"
@@ -123,8 +118,7 @@
android:contentDescription="@string/pause_label"
app:srcCompat="?attr/av_play"
android:scaleType="fitCenter"
- tools:srcCompat="@drawable/ic_av_play_white_24dp"
- tools:background="@android:color/holo_green_dark"/>
+ tools:srcCompat="@drawable/ic_av_play_white_24dp"/>
<de.danoeh.antennapod.view.CircularProgressBar
android:layout_width="@dimen/audioplayer_playercontrols_length_big"
@@ -158,8 +152,7 @@
android:contentDescription="@string/rewind_label"
app:srcCompat="?attr/av_rewind"
android:scaleType="fitCenter"
- tools:srcCompat="@drawable/ic_av_fast_rewind_white_48dp"
- tools:background="@android:color/holo_blue_dark"/>
+ tools:srcCompat="@drawable/ic_av_fast_rewind_white_48dp"/>
<TextView
android:id="@+id/txtvRev"
@@ -185,9 +178,7 @@
android:layout_centerVertical="true"
android:background="?attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/set_playback_speed_label"
- tools:srcCompat="@drawable/ic_playback_speed_white"
- tools:visibility="gone"
- tools:background="@android:color/holo_green_dark"/>
+ tools:srcCompat="@drawable/ic_playback_speed_white"/>
<TextView
android:id="@+id/txtvPlaybackSpeed"
@@ -217,8 +208,7 @@
android:contentDescription="@string/fast_forward_label"
app:srcCompat="?attr/av_fast_forward"
android:scaleType="fitCenter"
- tools:srcCompat="@drawable/ic_av_fast_forward_white_48dp"
- tools:background="@android:color/holo_blue_dark"/>
+ tools:srcCompat="@drawable/ic_av_fast_forward_white_48dp"/>
<TextView
android:id="@+id/txtvFF"
@@ -246,8 +236,7 @@
android:scaleType="fitCenter"
app:srcCompat="?attr/av_skip"
android:contentDescription="@string/skip_episode_label"
- tools:srcCompat="@drawable/ic_av_skip_white_48dp"
- tools:background="@android:color/holo_green_dark"/>
+ tools:srcCompat="@drawable/ic_av_skip_white_48dp"/>
</RelativeLayout>
</LinearLayout>
diff --git a/app/src/main/res/layout/cover_fragment.xml b/app/src/main/res/layout/cover_fragment.xml
index 31e7dbda7..28321e760 100644
--- a/app/src/main/res/layout/cover_fragment.xml
+++ b/app/src/main/res/layout/cover_fragment.xml
@@ -13,13 +13,13 @@
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
- android:contentDescription="@string/cover_label"
android:scaleType="fitCenter"
android:layout_marginLeft="32dp"
android:layout_marginRight="32dp"
android:transitionName="coverTransition"
tools:src="@android:drawable/sym_def_app_icon"
android:foreground="?attr/selectableItemBackgroundBorderless"
+ android:importantForAccessibility="no"
squareImageView:direction="minimum" />
<TextView
diff --git a/app/src/main/res/layout/download_authentication_activity.xml b/app/src/main/res/layout/download_authentication_activity.xml
index 58c2c10e6..e16a8b3a8 100644
--- a/app/src/main/res/layout/download_authentication_activity.xml
+++ b/app/src/main/res/layout/download_authentication_activity.xml
@@ -50,21 +50,15 @@
android:id="@+id/butCancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="?android:attr/selectableItemBackground"
- android:textColor="?attr/colorAccent"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:text="@string/cancel_label"/>
+ android:text="@string/cancel_label"
+ style="@style/Widget.MaterialComponents.Button.TextButton"/>
<Button
android:id="@+id/butConfirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:background="?android:attr/selectableItemBackground"
- android:textColor="?attr/colorAccent"
- android:paddingLeft="8dp"
- android:paddingRight="8dp"
- android:text="@string/confirm_label"/>
+ android:text="@string/confirm_label"
+ style="@style/Widget.MaterialComponents.Button.TextButton"/>
</LinearLayout>
</LinearLayout> \ No newline at end of file
diff --git a/app/src/main/res/layout/episodes_apply_action_fragment.xml b/app/src/main/res/layout/episodes_apply_action_fragment.xml
index 0baa2061a..304588e3e 100644
--- a/app/src/main/res/layout/episodes_apply_action_fragment.xml
+++ b/app/src/main/res/layout/episodes_apply_action_fragment.xml
@@ -24,6 +24,7 @@
android:id="@+id/fabSDOverlay"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:importantForAccessibility="no"
android:layout_below="@id/toolbar" />
<!-- The FAB SpeedDial
1. MUST be placed at the bottom of the layout xml to ensure it is at the front,
@@ -51,7 +52,8 @@
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
- />
+ android:accessibilityTraversalBefore="@android:id/list"
+ android:contentDescription="@string/apply_action" />
</ScrollView>
</RelativeLayout>
diff --git a/app/src/main/res/layout/external_player_fragment.xml b/app/src/main/res/layout/external_player_fragment.xml
index dd8f7fe40..f36baec26 100644
--- a/app/src/main/res/layout/external_player_fragment.xml
+++ b/app/src/main/res/layout/external_player_fragment.xml
@@ -9,11 +9,6 @@
android:background="?attr/selectableItemBackground"
android:orientation="vertical">
- <View
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="?android:attr/dividerHorizontal" />
-
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
@@ -22,13 +17,14 @@
<ImageView
android:id="@+id/imgvCover"
- android:contentDescription="@string/cover_label"
+ android:contentDescription="@string/media_player"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:adjustViewBounds="true"
android:cropToPadding="true"
android:maxWidth="96dp"
android:scaleType="fitCenter"
+ android:background="@color/non_square_icon_background"
tools:src="@tools:sample/avatars"/>
diff --git a/app/src/main/res/layout/feeditem_fragment.xml b/app/src/main/res/layout/feeditem_fragment.xml
index 8dfbbe562..72effc585 100644
--- a/app/src/main/res/layout/feeditem_fragment.xml
+++ b/app/src/main/res/layout/feeditem_fragment.xml
@@ -25,7 +25,7 @@
android:layout_width="@dimen/thumbnail_length_queue_item"
android:layout_height="@dimen/thumbnail_length_queue_item"
android:layout_gravity="center_vertical"
- android:contentDescription="@string/cover_label"
+ android:contentDescription="@string/open_podcast"
android:foreground="?attr/selectableItemBackground"
tools:src="@tools:sample/avatars" />
@@ -42,6 +42,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:foreground="?attr/selectableItemBackground"
+ android:importantForAccessibility="no"
tools:text="Podcast title"
tools:background="@android:color/holo_green_dark" />
@@ -77,6 +78,7 @@
android:layout_marginStart="4dp"
android:layout_marginRight="4dp"
android:layout_marginEnd="4dp"
+ android:importantForAccessibility="no"
android:text="ยท"
tools:background="@android:color/holo_blue_light" />
diff --git a/app/src/main/res/layout/feeditemlist_header.xml b/app/src/main/res/layout/feeditemlist_header.xml
index 14ba6c3d0..e74aeac0a 100644
--- a/app/src/main/res/layout/feeditemlist_header.xml
+++ b/app/src/main/res/layout/feeditemlist_header.xml
@@ -21,11 +21,10 @@
android:layout_height="100dp"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
- android:contentDescription="@string/cover_label"
+ android:importantForAccessibility="no"
tools:src="@drawable/ic_antenna"
tools:background="@android:color/holo_green_dark"/>
-
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -98,7 +97,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="2dp"
- android:background="?attr/colorPrimary"
+ android:background="?android:attr/windowBackground"
android:visibility="gone"
android:gravity="center"
tools:visibility="visible"
diff --git a/app/src/main/res/layout/feeditemlist_item.xml b/app/src/main/res/layout/feeditemlist_item.xml
index 5a7ba4754..90062bbf6 100644
--- a/app/src/main/res/layout/feeditemlist_item.xml
+++ b/app/src/main/res/layout/feeditemlist_item.xml
@@ -17,12 +17,13 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
+ android:id="@+id/left_padding"
android:minWidth="4dp">
<ImageView
android:id="@+id/drag_handle"
android:layout_width="16dp"
android:layout_height="match_parent"
- android:contentDescription="@string/drag_handle_content_description"
+ android:importantForAccessibility="no"
android:scaleType="fitCenter"
android:src="?attr/dragview_background"
android:paddingStart="0dp"
@@ -65,7 +66,7 @@
android:layout_width="@dimen/thumbnail_length_queue_item"
android:layout_height="@dimen/thumbnail_length_queue_item"
android:layout_centerVertical="true"
- android:contentDescription="@string/cover_label"
+ android:importantForAccessibility="no"
tools:src="@tools:sample/avatars"/>
</RelativeLayout>
@@ -104,6 +105,7 @@
android:layout_height="14sp"
app:srcCompat="?attr/type_video"
tools:srcCompat="@drawable/ic_videocam_black_24dp"
+ android:contentDescription="@string/media_type_video_label"
android:id="@+id/ivIsVideo"/>
<ImageView
@@ -111,6 +113,7 @@
android:layout_height="14sp"
app:srcCompat="?attr/ic_unfav"
tools:srcCompat="@drawable/ic_star_black"
+ android:contentDescription="@string/is_favorite_label"
android:id="@+id/isFavorite"/>
<ImageView
@@ -118,6 +121,7 @@
android:layout_height="14sp"
app:srcCompat="?attr/stat_playlist"
tools:srcCompat="@drawable/ic_playlist_black"
+ android:contentDescription="@string/in_queue_label"
android:id="@+id/ivInPlaylist"/>
<TextView
@@ -160,12 +164,19 @@
tools:text="10 MB"/>
</LinearLayout>
+
+ <!--
+ Warning: android:contentDescription is set to an empty string.
+ The title is read as contentDescription of left_padding to have it read first.
+ Keep this in mind when changing the order of this layout!
+ -->
<TextView
android:id="@+id/txtvTitle"
style="@style/AntennaPod.TextView.ListItemPrimaryTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="@sample/episodes.json/data/title"
+ android:importantForAccessibility="no"
android:ellipsize="end"
tools:background="@android:color/holo_blue_light"/>
diff --git a/app/src/main/res/layout/gpodnet_podcast_listitem.xml b/app/src/main/res/layout/gpodnet_podcast_listitem.xml
index 4e05f5599..9821f6e17 100644
--- a/app/src/main/res/layout/gpodnet_podcast_listitem.xml
+++ b/app/src/main/res/layout/gpodnet_podcast_listitem.xml
@@ -20,7 +20,7 @@
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
android:adjustViewBounds="true"
- android:contentDescription="@string/cover_label"
+ android:importantForAccessibility="no"
android:cropToPadding="true"
android:scaleType="fitXY"
tools:src="@drawable/ic_antenna"
diff --git a/app/src/main/res/layout/itunes_podcast_listitem.xml b/app/src/main/res/layout/itunes_podcast_listitem.xml
index 87d71720a..dcf2face6 100644
--- a/app/src/main/res/layout/itunes_podcast_listitem.xml
+++ b/app/src/main/res/layout/itunes_podcast_listitem.xml
@@ -19,7 +19,7 @@
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:adjustViewBounds="true"
- android:contentDescription="@string/cover_label"
+ android:importantForAccessibility="no"
android:cropToPadding="true"
android:scaleType="fitXY"
tools:background="@android:color/holo_green_dark"
diff --git a/app/src/main/res/layout/nav_list.xml b/app/src/main/res/layout/nav_list.xml
index 504952b08..c26d0b8ed 100644
--- a/app/src/main/res/layout/nav_list.xml
+++ b/app/src/main/res/layout/nav_list.xml
@@ -13,6 +13,7 @@
android:layout_alignParentBottom="true"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/settings_label"
+ android:accessibilityTraversalBefore="@id/nav_list"
android:orientation="horizontal"
android:focusable="true">
@@ -25,7 +26,7 @@
android:layout_marginStart="@dimen/listitem_icon_leftpadding"
android:layout_marginTop="4dp"
android:adjustViewBounds="true"
- android:contentDescription="@string/cover_label"
+ android:importantForAccessibility="no"
android:cropToPadding="true"
android:padding="8dp"
android:scaleType="centerCrop"
diff --git a/app/src/main/res/layout/nav_listitem.xml b/app/src/main/res/layout/nav_listitem.xml
index 2b7bc5715..3610ce56e 100644
--- a/app/src/main/res/layout/nav_listitem.xml
+++ b/app/src/main/res/layout/nav_listitem.xml
@@ -9,7 +9,7 @@
<ImageView
android:id="@+id/imgvCover"
- android:contentDescription="@string/cover_label"
+ android:importantForAccessibility="no"
android:layout_width="@dimen/thumbnail_length_navlist"
android:layout_height="@dimen/thumbnail_length_navlist"
android:layout_alignParentLeft="true"
diff --git a/app/src/main/res/layout/nav_section_item.xml b/app/src/main/res/layout/nav_section_item.xml
index fa1db865d..45d0dff59 100644
--- a/app/src/main/res/layout/nav_section_item.xml
+++ b/app/src/main/res/layout/nav_section_item.xml
@@ -1,11 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
-
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="16dp"
android:background="@android:color/transparent"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:importantForAccessibility="no">
<View
android:layout_width="match_parent"
diff --git a/app/src/main/res/layout/onlinefeedview_activity.xml b/app/src/main/res/layout/onlinefeedview_activity.xml
index 34dbeb6d9..cddb1048c 100644
--- a/app/src/main/res/layout/onlinefeedview_activity.xml
+++ b/app/src/main/res/layout/onlinefeedview_activity.xml
@@ -56,7 +56,7 @@
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
- android:contentDescription="@string/cover_label"
+ android:importantForAccessibility="no"
tools:src="@drawable/ic_antenna"/>
<TextView
diff --git a/app/src/main/res/layout/opml_selection.xml b/app/src/main/res/layout/opml_selection.xml
index e018ffde3..1f1d72d76 100644
--- a/app/src/main/res/layout/opml_selection.xml
+++ b/app/src/main/res/layout/opml_selection.xml
@@ -1,67 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <RelativeLayout
- android:id="@+id/footer"
- android:layout_width="fill_parent"
- android:layout_height="48dp"
- android:layout_alignParentBottom="true" >
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1dip"
- android:layout_alignParentTop="true"
- android:background="?android:attr/dividerVertical" />
-
- <View
- android:id="@+id/horizontal_divider"
- android:layout_width="1dip"
- android:layout_height="fill_parent"
- android:layout_alignParentTop="true"
- android:layout_centerHorizontal="true"
- android:layout_marginBottom="4dp"
- android:layout_marginTop="4dp"
- android:background="?android:attr/dividerVertical" />
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
- <Button
- android:id="@+id/butCancel"
+ <Button
+ android:id="@+id/butConfirm"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_alignParentTop="true"
- android:layout_toLeftOf="@id/horizontal_divider"
- android:layout_toStartOf="@id/horizontal_divider"
- android:background="?android:attr/selectableItemBackground"
- android:textColor="?android:attr/textColorPrimary"
- android:text="@string/cancel_label" />
+ android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
+ style="@style/Widget.MaterialComponents.Button.TextButton"
+ android:layout_margin="8dp"
+ android:text="@string/confirm_label"/>
- <Button
- android:id="@+id/butConfirm"
+ <Button
+ android:id="@+id/butCancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true"
- android:layout_alignParentTop="true"
- android:layout_toRightOf="@id/horizontal_divider"
- android:layout_toEndOf="@id/horizontal_divider"
- android:background="?android:attr/selectableItemBackground"
- android:textColor="?android:attr/textColorPrimary"
- android:text="@string/confirm_label" />
- </RelativeLayout>
+ android:layout_toLeftOf="@+id/butConfirm"
+ android:layout_toStartOf="@+id/butConfirm"
+ style="@style/Widget.MaterialComponents.Button.TextButton"
+ android:layout_margin="8dp"
+ android:text="@string/cancel_label"/>
<ListView
- android:id="@+id/feedlist"
- android:layout_width="match_parent"
- android:layout_height="0dp"
- android:layout_above="@id/footer"
- android:layout_alignParentTop="true"
- tools:listitem="@android:layout/simple_list_item_multiple_choice" >
+ android:id="@+id/feedlist"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_above="@id/butConfirm"
+ android:layout_alignParentTop="true"
+ tools:listitem="@android:layout/simple_list_item_multiple_choice">
</ListView>
-</RelativeLayout> \ No newline at end of file
+</RelativeLayout>
diff --git a/app/src/main/res/layout/searchlist_item.xml b/app/src/main/res/layout/searchlist_item.xml
index e8ff18c5f..608bfc3bc 100644
--- a/app/src/main/res/layout/searchlist_item.xml
+++ b/app/src/main/res/layout/searchlist_item.xml
@@ -16,7 +16,7 @@
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/listitem_threeline_horizontalpadding"
android:layout_marginStart="@dimen/listitem_threeline_horizontalpadding"
- android:contentDescription="@string/cover_label"
+ android:importantForAccessibility="no"
android:scaleType="centerCrop"
tools:src="@drawable/ic_antenna"
tools:background="@android:color/holo_green_dark"/>
diff --git a/app/src/main/res/layout/simplechapter_item.xml b/app/src/main/res/layout/simplechapter_item.xml
index 54c607d71..276ce48bc 100644
--- a/app/src/main/res/layout/simplechapter_item.xml
+++ b/app/src/main/res/layout/simplechapter_item.xml
@@ -14,7 +14,7 @@
android:id="@+id/imgvCover"
android:layout_width="@dimen/thumbnail_length_queue_item"
android:layout_height="@dimen/thumbnail_length_queue_item"
- android:contentDescription="@string/cover_label"
+ android:importantForAccessibility="no"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
tools:src="@tools:sample/avatars"/>
diff --git a/app/src/main/res/layout/statistics_listitem.xml b/app/src/main/res/layout/statistics_listitem.xml
index aaa0f666c..c41ace58b 100644
--- a/app/src/main/res/layout/statistics_listitem.xml
+++ b/app/src/main/res/layout/statistics_listitem.xml
@@ -12,7 +12,7 @@
<ImageView
android:id="@+id/imgvCover"
- android:contentDescription="@string/cover_label"
+ android:importantForAccessibility="no"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentLeft="true"
@@ -20,7 +20,7 @@
android:layout_centerVertical="true"
android:adjustViewBounds="true"
android:cropToPadding="true"
- android:scaleType="centerCrop"
+ android:scaleType="fitCenter"
tools:src="@drawable/ic_antenna"
tools:background="@android:color/holo_green_dark"/>
diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java
index e391af1b2..45c5d4884 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/namespace/NSRSS20.java
@@ -3,6 +3,7 @@ package de.danoeh.antennapod.core.syndication.namespace;
import android.text.TextUtils;
import android.util.Log;
+import de.danoeh.antennapod.core.syndication.util.SyndStringUtils;
import org.xml.sax.Attributes;
import de.danoeh.antennapod.core.feed.FeedItem;
@@ -13,16 +14,16 @@ import de.danoeh.antennapod.core.util.DateUtils;
/**
* SAX-Parser for reading RSS-Feeds
- *
+ *
* @author daniel
- *
+ *
*/
public class NSRSS20 extends Namespace {
private static final String TAG = "NSRSS20";
public static final String CHANNEL = "channel";
- public static final String ITEM = "item";
+ public static final String ITEM = "item";
private static final String GUID = "guid";
private static final String TITLE = "title";
private static final String LINK = "link";
@@ -30,118 +31,119 @@ public class NSRSS20 extends Namespace {
private static final String PUBDATE = "pubDate";
private static final String ENCLOSURE = "enclosure";
private static final String IMAGE = "image";
- private static final String URL = "url";
+ private static final String URL = "url";
private static final String LANGUAGE = "language";
private static final String ENC_URL = "url";
private static final String ENC_LEN = "length";
private static final String ENC_TYPE = "type";
- @Override
- public SyndElement handleElementStart(String localName, HandlerState state,
- Attributes attributes) {
- if (ITEM.equals(localName)) {
- state.setCurrentItem(new FeedItem());
- state.getItems().add(state.getCurrentItem());
- state.getCurrentItem().setFeed(state.getFeed());
+ @Override
+ public SyndElement handleElementStart(String localName, HandlerState state,
+ Attributes attributes) {
+ if (ITEM.equals(localName)) {
+ state.setCurrentItem(new FeedItem());
+ state.getItems().add(state.getCurrentItem());
+ state.getCurrentItem().setFeed(state.getFeed());
- } else if (ENCLOSURE.equals(localName)) {
- String type = attributes.getValue(ENC_TYPE);
- String url = attributes.getValue(ENC_URL);
+ } else if (ENCLOSURE.equals(localName)) {
+ String type = attributes.getValue(ENC_TYPE);
+ String url = attributes.getValue(ENC_URL);
- boolean validType = SyndTypeUtils.enclosureTypeValid(type);
- if(!validType) {
+ boolean validType = SyndTypeUtils.enclosureTypeValid(type);
+ if (!validType) {
type = SyndTypeUtils.getMimeTypeFromUrl(url);
validType = SyndTypeUtils.enclosureTypeValid(type);
}
boolean validUrl = !TextUtils.isEmpty(url);
- if (state.getCurrentItem() != null && state.getCurrentItem().getMedia() == null &&
- validType && validUrl) {
- long size = 0;
- try {
- size = Long.parseLong(attributes.getValue(ENC_LEN));
- if(size < 16384) {
- // less than 16kb is suspicious, check manually
- size = 0;
- }
- } catch (NumberFormatException e) {
- Log.d(TAG, "Length attribute could not be parsed.");
- }
- FeedMedia media = new FeedMedia(state.getCurrentItem(), url, size, type);
- state.getCurrentItem().setMedia(media);
- }
+ if (state.getCurrentItem() != null && state.getCurrentItem().getMedia() == null
+ && validType && validUrl) {
+ long size = 0;
+ try {
+ size = Long.parseLong(attributes.getValue(ENC_LEN));
+ if (size < 16384) {
+ // less than 16kb is suspicious, check manually
+ size = 0;
+ }
+ } catch (NumberFormatException e) {
+ Log.d(TAG, "Length attribute could not be parsed.");
+ }
+ FeedMedia media = new FeedMedia(state.getCurrentItem(), url, size, type);
+ state.getCurrentItem().setMedia(media);
+ }
- }
- return new SyndElement(localName, this);
- }
+ }
+ return new SyndElement(localName, this);
+ }
- @Override
- public void handleElementEnd(String localName, HandlerState state) {
- if (ITEM.equals(localName)) {
- if (state.getCurrentItem() != null) {
- FeedItem currentItem = state.getCurrentItem();
- // the title tag is optional in RSS 2.0. The description is used
- // as a
- // title if the item has no title-tag.
- if (currentItem.getTitle() == null) {
- currentItem.setTitle(currentItem.getDescription());
- }
+ @Override
+ public void handleElementEnd(String localName, HandlerState state) {
+ if (ITEM.equals(localName)) {
+ if (state.getCurrentItem() != null) {
+ FeedItem currentItem = state.getCurrentItem();
+ // the title tag is optional in RSS 2.0. The description is used
+ // as a
+ // title if the item has no title-tag.
+ if (currentItem.getTitle() == null) {
+ currentItem.setTitle(currentItem.getDescription());
+ }
if (state.getTempObjects().containsKey(NSITunes.DURATION)) {
if (currentItem.hasMedia()) {
- Integer duration = (Integer) state.getTempObjects().get(NSITunes.DURATION);
- currentItem.getMedia().setDuration(duration);
+ Integer duration = (Integer) state.getTempObjects().get(NSITunes.DURATION);
+ currentItem.getMedia().setDuration(duration);
}
state.getTempObjects().remove(NSITunes.DURATION);
}
- }
- state.setCurrentItem(null);
- } else if (state.getTagstack().size() >= 2 && state.getContentBuf() != null) {
- String content = state.getContentBuf().toString();
- SyndElement topElement = state.getTagstack().peek();
- String top = topElement.getName();
- SyndElement secondElement = state.getSecondTag();
- String second = secondElement.getName();
- String third = null;
- if (state.getTagstack().size() >= 3) {
- third = state.getThirdTag().getName();
- }
- if (GUID.equals(top) && ITEM.equals(second)) {
- // some feed creators include an empty or non-standard guid-element in their feed, which should be ignored
- if (!TextUtils.isEmpty(content) && state.getCurrentItem() != null) {
- state.getCurrentItem().setItemIdentifier(content);
+ }
+ state.setCurrentItem(null);
+ } else if (state.getTagstack().size() >= 2 && state.getContentBuf() != null) {
+ String contentRaw = state.getContentBuf().toString();
+ String content = SyndStringUtils.trimAllWhitespace(contentRaw);
+ SyndElement topElement = state.getTagstack().peek();
+ String top = topElement.getName();
+ SyndElement secondElement = state.getSecondTag();
+ String second = secondElement.getName();
+ String third = null;
+ if (state.getTagstack().size() >= 3) {
+ third = state.getThirdTag().getName();
+ }
+ if (GUID.equals(top) && ITEM.equals(second)) {
+ // some feed creators include an empty or non-standard guid-element in their feed,
+ // which should be ignored
+ if (!TextUtils.isEmpty(contentRaw) && state.getCurrentItem() != null) {
+ state.getCurrentItem().setItemIdentifier(contentRaw);
}
- } else if (TITLE.equals(top)) {
- String title = content.trim();
- if (ITEM.equals(second) && state.getCurrentItem() != null) {
- state.getCurrentItem().setTitle(title);
- } else if (CHANNEL.equals(second) && state.getFeed() != null) {
- state.getFeed().setTitle(title);
- }
- } else if (LINK.equals(top)) {
- if (CHANNEL.equals(second) && state.getFeed() != null) {
- state.getFeed().setLink(content);
- } else if (ITEM.equals(second) && state.getCurrentItem() != null) {
- state.getCurrentItem().setLink(content);
- }
- } else if (PUBDATE.equals(top) && ITEM.equals(second) && state.getCurrentItem() != null) {
- state.getCurrentItem().setPubDate(DateUtils.parse(content));
- } else if (URL.equals(top) && IMAGE.equals(second) && CHANNEL.equals(third)) {
- // prefer itunes:image
- if (state.getFeed() != null) {
- state.getFeed().setImageUrl(content);
- }
- } else if (DESCR.equals(localName)) {
- if (CHANNEL.equals(second) && state.getFeed() != null) {
- state.getFeed().setDescription(content);
- } else if (ITEM.equals(second) && state.getCurrentItem() != null) {
- state.getCurrentItem().setDescription(content);
- }
- } else if (LANGUAGE.equals(localName) && state.getFeed() != null) {
- state.getFeed().setLanguage(content.toLowerCase());
- }
- }
- }
+ } else if (TITLE.equals(top)) {
+ if (ITEM.equals(second) && state.getCurrentItem() != null) {
+ state.getCurrentItem().setTitle(content);
+ } else if (CHANNEL.equals(second) && state.getFeed() != null) {
+ state.getFeed().setTitle(content);
+ }
+ } else if (LINK.equals(top)) {
+ if (CHANNEL.equals(second) && state.getFeed() != null) {
+ state.getFeed().setLink(content);
+ } else if (ITEM.equals(second) && state.getCurrentItem() != null) {
+ state.getCurrentItem().setLink(content);
+ }
+ } else if (PUBDATE.equals(top) && ITEM.equals(second) && state.getCurrentItem() != null) {
+ state.getCurrentItem().setPubDate(DateUtils.parse(content));
+ } else if (URL.equals(top) && IMAGE.equals(second) && CHANNEL.equals(third)) {
+ // prefer itunes:image
+ if (state.getFeed() != null && state.getFeed().getImageUrl() == null) {
+ state.getFeed().setImageUrl(content);
+ }
+ } else if (DESCR.equals(localName)) {
+ if (CHANNEL.equals(second) && state.getFeed() != null) {
+ state.getFeed().setDescription(content);
+ } else if (ITEM.equals(second) && state.getCurrentItem() != null) {
+ state.getCurrentItem().setDescription(content);
+ }
+ } else if (LANGUAGE.equals(localName) && state.getFeed() != null) {
+ state.getFeed().setLanguage(content.toLowerCase());
+ }
+ }
+ }
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndStringUtils.java b/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndStringUtils.java
new file mode 100644
index 000000000..addcdd4b7
--- /dev/null
+++ b/core/src/main/java/de/danoeh/antennapod/core/syndication/util/SyndStringUtils.java
@@ -0,0 +1,14 @@
+package de.danoeh.antennapod.core.syndication.util;
+
+public class SyndStringUtils {
+ private SyndStringUtils() {
+
+ }
+
+ /**
+ * Trims all whitespace from beginning and ending of a String. {{@link String#trim()}} only trims spaces.
+ */
+ public static String trimAllWhitespace(String string) {
+ return string.replaceAll("(^\\s*)|(\\s*$)", "");
+ }
+}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java b/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java
index 4e7e6a6b6..e1e2818cb 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/Converter.java
@@ -14,47 +14,57 @@ public final class Converter {
/** Logging tag. */
private static final String TAG = "Converter";
-
+
private static final int HOURS_MIL = 3600000;
- private static final int MINUTES_MIL = 60000;
- private static final int SECONDS_MIL = 1000;
-
- /** Converts milliseconds to a string containing hours, minutes and seconds */
- public static String getDurationStringLong(int duration) {
- int h = duration / HOURS_MIL;
- int rest = duration - h * HOURS_MIL;
- int m = rest / MINUTES_MIL;
- rest -= m * MINUTES_MIL;
- int s = rest / SECONDS_MIL;
-
- return String.format(Locale.getDefault(), "%02d:%02d:%02d", h, m, s);
+ private static final int MINUTES_MIL = 60000;
+ private static final int SECONDS_MIL = 1000;
+
+ /**
+ * Converts milliseconds to a string containing hours, minutes and seconds.
+ */
+ public static String getDurationStringLong(int duration) {
+ int[] hms = millisecondsToHms(duration);
+ return String.format(Locale.getDefault(), "%02d:%02d:%02d", hms[0], hms[1], hms[2]);
}
-
- /** Converts milliseconds to a string containing hours and minutes or minutes and seconds*/
+
+ private static int[] millisecondsToHms(long duration) {
+ int h = (int) (duration / HOURS_MIL);
+ long rest = duration - h * HOURS_MIL;
+ int m = (int) (rest / MINUTES_MIL);
+ rest -= m * MINUTES_MIL;
+ int s = (int) (rest / SECONDS_MIL);
+ return new int[] {h, m, s};
+ }
+
+ /**
+ * Converts milliseconds to a string containing hours and minutes or minutes and seconds.
+ */
public static String getDurationStringShort(int duration, boolean durationIsInHours) {
int firstPartBase = durationIsInHours ? HOURS_MIL : MINUTES_MIL;
int firstPart = duration / firstPartBase;
int leftoverFromFirstPart = duration - firstPart * firstPartBase;
int secondPart = leftoverFromFirstPart / (durationIsInHours ? MINUTES_MIL : SECONDS_MIL);
- return String.format(Locale.getDefault(), "%02d:%02d", firstPart, secondPart);
+ return String.format(Locale.getDefault(), "%02d:%02d", firstPart, secondPart);
}
- /** Converts long duration string (HH:MM:SS) to milliseconds. */
+ /**
+ * Converts long duration string (HH:MM:SS) to milliseconds.
+ */
public static int durationStringLongToMs(String input) {
String[] parts = input.split(":");
if (parts.length != 3) {
return 0;
}
- return Integer.parseInt(parts[0]) * 3600 * 1000 +
- Integer.parseInt(parts[1]) * 60 * 1000 +
- Integer.parseInt(parts[2]) * 1000;
+ return Integer.parseInt(parts[0]) * 3600 * 1000
+ + Integer.parseInt(parts[1]) * 60 * 1000
+ + Integer.parseInt(parts[2]) * 1000;
}
/**
* Converts short duration string (XX:YY) to milliseconds. If durationIsInHours is true then the
* format is HH:MM, otherwise it's MM:SS.
- * */
+ */
public static int durationStringShortToMs(String input, boolean durationIsInHours) {
String[] parts = input.split(":");
if (parts.length != 2) {
@@ -63,18 +73,20 @@ public final class Converter {
int modifier = durationIsInHours ? 60 : 1;
- return Integer.parseInt(parts[0]) * 60 * 1000 * modifier+
- Integer.parseInt(parts[1]) * 1000 * modifier;
+ return Integer.parseInt(parts[0]) * 60 * 1000 * modifier
+ + Integer.parseInt(parts[1]) * 1000 * modifier;
}
- /** Converts milliseconds to a localized string containing hours and minutes */
+ /**
+ * Converts milliseconds to a localized string containing hours and minutes.
+ */
public static String getDurationStringLocalized(Context context, long duration) {
- int h = (int)(duration / HOURS_MIL);
- int rest = (int)(duration - h * HOURS_MIL);
+ int h = (int) (duration / HOURS_MIL);
+ int rest = (int) (duration - h * HOURS_MIL);
int m = rest / MINUTES_MIL;
String result = "";
- if(h > 0) {
+ if (h > 0) {
String hours = context.getResources().getQuantityString(R.plurals.time_hours_quantified, h, h);
result += hours + " ";
}
@@ -84,7 +96,7 @@ public final class Converter {
}
/**
- * Converts seconds to a localized representation
+ * Converts seconds to a localized representation.
* @param time The time in seconds
* @return "HH:MM hours"
*/
@@ -93,16 +105,16 @@ public final class Converter {
return String.format(Locale.getDefault(), "%.1f ", hours) + context.getString(R.string.time_hours);
}
-
/**
* Converts the volume as read as the progress from a SeekBar scaled to 100 and as saved in
* UserPreferences to the format taken by setVolume methods.
* @param progress integer between 0 to 100 taken from the SeekBar progress
* @return the appropriate volume as float taken by setVolume methods
*/
- public static float getVolumeFromPercentage(int progress){
- if (progress==100)
+ public static float getVolumeFromPercentage(int progress) {
+ if (progress == 100) {
return 1f;
+ }
return (float) (1 - (Math.log(101 - progress) / Math.log(101)));
}
}
diff --git a/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java b/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java
index 2454b6a00..e15ab2fdc 100644
--- a/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java
+++ b/core/src/main/java/de/danoeh/antennapod/core/util/DateUtils.java
@@ -5,6 +5,7 @@ import android.util.Log;
import org.apache.commons.lang3.StringUtils;
+import java.text.DateFormat;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@@ -175,4 +176,11 @@ public class DateUtils {
}
return android.text.format.DateUtils.formatDateTime(context, date.getTime(), format);
}
+
+ public static String formatForAccessibility(final Context context, final Date date) {
+ if (date == null) {
+ return "";
+ }
+ return DateFormat.getDateInstance(DateFormat.LONG).format(date);
+ }
}
diff --git a/core/src/main/res/values/attrs.xml b/core/src/main/res/values/attrs.xml
index f8b545ac0..2d8cbb4cb 100644
--- a/core/src/main/res/values/attrs.xml
+++ b/core/src/main/res/values/attrs.xml
@@ -56,6 +56,7 @@
<attr name="batch_edit_fab_icon" format="reference"/>
<attr name="action_icon_color" format="color"/>
<attr name="scrollbar_thumb" format="reference"/>
+ <attr name="background_elevated" format="color"/>
<declare-styleable name="SquareImageView">
<attr name="direction" format="enum">
diff --git a/core/src/main/res/values/colors.xml b/core/src/main/res/values/colors.xml
index cc04db2dd..a86d61eba 100644
--- a/core/src/main/res/values/colors.xml
+++ b/core/src/main/res/values/colors.xml
@@ -13,14 +13,16 @@
<!-- Theme colors -->
<color name="background_light">#FFFFFF</color>
- <color name="background_darktheme">#303030</color>
- <color name="highlight_light">#DDDDDD</color>
- <color name="highlight_dark">#414141</color>
- <color name="highlight_trueblack">#414141</color>
+ <color name="background_elevated_light">#EFEEEE</color>
+ <color name="background_darktheme">#21272b</color>
+ <color name="background_elevated_darktheme">#2D3337</color>
+ <color name="highlight_light">#46C6C6C6</color>
+ <color name="highlight_dark">#43707070</color>
+ <color name="highlight_trueblack">#43707070</color>
<color name="non_square_icon_background">#22777777</color>
<color name="accent_light">#0078C2</color>
- <color name="accent_dark">#5C9DFF</color>
+ <color name="accent_dark">#3D8BFF</color>
<color name="ic_launcher_background">#008AB8</color>
<color name="master_switch_background_light">#DDDDDD</color>
diff --git a/core/src/main/res/values/strings.xml b/core/src/main/res/values/strings.xml
index 1c2db3a5b..0168aec38 100644
--- a/core/src/main/res/values/strings.xml
+++ b/core/src/main/res/values/strings.xml
@@ -217,6 +217,7 @@
<string name="deactivate_auto_download">Deactivate Auto Download</string>
<string name="reset_position">Reset Playback Position</string>
<string name="removed_item">Item removed</string>
+ <string name="no_items_selected">No items selected</string>
<!-- Download messages and labels -->
<string name="download_successful">successful</string>
@@ -671,13 +672,19 @@
<!-- Content descriptions for image buttons -->
<string name="rewind_label">Rewind</string>
<string name="fast_forward_label">Fast forward</string>
+ <string name="increase_volume">Increase volume</string>
+ <string name="decrease_volume">Decrease volume</string>
<string name="media_type_audio_label">Audio</string>
<string name="media_type_video_label">Video</string>
<string name="navigate_upwards_label">Navigate upwards</string>
<string name="status_downloading_label">Episode is being downloaded</string>
<string name="in_queue_label">Episode is in the queue</string>
+ <string name="is_favorite_label">Episode is marked as favorite</string>
<string name="drag_handle_content_description">Drag to change the position of this item</string>
<string name="load_next_page_label">Load next page</string>
+ <string name="switch_pages">Switch pages</string>
+ <string name="position">Position: %1$s</string>
+ <string name="apply_action">Apply action</string>
<!-- Feed information screen -->
<string name="authentication_label">Authentication</string>
diff --git a/core/src/main/res/values/styles.xml b/core/src/main/res/values/styles.xml
index 2b7be1713..c72cd3e53 100644
--- a/core/src/main/res/values/styles.xml
+++ b/core/src/main/res/values/styles.xml
@@ -14,6 +14,7 @@
<item name="colorPrimaryDark">@color/accent_light</item>
<item name="android:windowBackground">@color/background_light</item>
<item name="actionBarStyle">@style/Widget.AntennaPod.ActionBar.Light</item>
+ <item name="background_elevated">@color/background_elevated_light</item>
<item name="master_switch_background">@color/master_switch_background_light</item>
<item name="currently_playing_background">@color/highlight_light</item>
<item name="action_icon_color">@color/black</item>
@@ -85,6 +86,7 @@
<item name="colorPrimaryDark">@color/background_darktheme</item>
<item name="android:windowBackground">@color/background_darktheme</item>
<item name="actionBarStyle">@style/Widget.AntennaPod.ActionBar.Dark</item>
+ <item name="background_elevated">@color/background_elevated_darktheme</item>
<item name="colorControlNormal">@color/white</item>
<item name="progressBarTheme">@style/ProgressBarDark</item>
<item name="drawer_activated_color">@color/highlight_dark</item>
@@ -159,6 +161,7 @@
<item name="android:colorBackground">@color/black</item>
<item name="android:windowBackground">@color/black</item>
<item name="android:actionBarStyle">@color/black</item>
+ <item name="background_elevated">@color/black</item>
</style>
<style name="Theme.AntennaPod.Light.NoTitle" parent="Theme.AntennaPod.Light">