Merge pull request #4132 from ByteHamster/accessibility
Improved TalkBack accessibility
This commit is contained in:
commit
b0973d5c58
@ -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();
|
||||
|
@ -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()));
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,7 +100,9 @@ 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);
|
||||
@ -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 {
|
||||
|
@ -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" />
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/teaser"
|
||||
android:importantForAccessibility="no"/>
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
<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"
|
||||
|
@ -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" />
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"/>
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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"/>
|
||||
|
@ -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"/>
|
||||
|
@ -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"
|
||||
|
@ -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 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[] 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)));
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
@ -676,8 +677,12 @@
|
||||
<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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user