Add accessibility actions for translate, download, share actions in media activity

This commit is contained in:
0xd9a 2025-08-20 00:55:04 +05:30
parent 61b2c7b1d4
commit 0d60e55565
3 changed files with 95 additions and 33 deletions

View file

@ -193,7 +193,7 @@ public class MediaActivity extends BaseBarActivity implements OnDownloadInterfac
binding.mediaDescription.setText(description); binding.mediaDescription.setText(description);
binding.translate.setOnClickListener(v -> { binding.translate.setOnClickListener(v -> {
String descriptionToTranslate = attachments.get(mediaPosition - 1).description; String descriptionToTranslate = attachments.get(mediaPosition - 1).description;
TranslateHelper.translate(MediaActivity.this, descriptionToTranslate, status!=null?status.language:"en", translated -> { TranslateHelper.translate(MediaActivity.this, descriptionToTranslate, getStatusLanguageForTranslation(), translated -> {
if (translated != null) { if (translated != null) {
attachments.get(mediaPosition - 1).translation = translated; attachments.get(mediaPosition - 1).translation = translated;
binding.mediaDescriptionTranslated.setText(translated); binding.mediaDescriptionTranslated.setText(translated);
@ -248,7 +248,7 @@ public class MediaActivity extends BaseBarActivity implements OnDownloadInterfac
} }
binding.translate.setOnClickListener(v -> { binding.translate.setOnClickListener(v -> {
String descriptionToTranslate = attachments.get(position).description; String descriptionToTranslate = attachments.get(position).description;
TranslateHelper.translate(MediaActivity.this, descriptionToTranslate, status!=null?status.language:"en", translated -> { TranslateHelper.translate(MediaActivity.this, descriptionToTranslate, getStatusLanguageForTranslation(), translated -> {
if (translated != null) { if (translated != null) {
attachments.get(position).translation = translated; attachments.get(position).translation = translated;
binding.mediaDescriptionTranslated.setText(translated); binding.mediaDescriptionTranslated.setText(translated);
@ -292,6 +292,9 @@ public class MediaActivity extends BaseBarActivity implements OnDownloadInterfac
setFullscreen(true); setFullscreen(true);
} }
public String getStatusLanguageForTranslation() {
return status != null ? status.language : "en";
}
private Spannable linkify(Context context, String content) { private Spannable linkify(Context context, String content) {
if (content == null) { if (content == null) {
@ -358,20 +361,20 @@ public class MediaActivity extends BaseBarActivity implements OnDownloadInterfac
} }
return true; return true;
} else if (item.getItemId() == R.id.action_save) { } else if (item.getItemId() == R.id.action_save) {
int position = binding.mediaViewpager.getCurrentItem(); saveMedia();
Attachment attachment = attachments.get(position); } else if (item.getItemId() == R.id.action_share) {
if (Build.VERSION.SDK_INT >= 23) { shareMedia();
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { }
if (ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { return true;
ActivityCompat.requestPermissions(MediaActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Helper.EXTERNAL_STORAGE_REQUEST_CODE_MEDIA_SAVE); }
} else {
if (attachment.type.compareTo("image") == 0) { public void saveMedia() {
MediaHelper.manageMove(MediaActivity.this, attachment.url, false); int position = binding.mediaViewpager.getCurrentItem();
} else { Attachment attachment = attachments.get(position);
MediaHelper.manageDownloadsNoPopup(MediaActivity.this, attachment.url); if (Build.VERSION.SDK_INT >= 23) {
downloadID = -1; if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
} if (ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
} ActivityCompat.requestPermissions(MediaActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Helper.EXTERNAL_STORAGE_REQUEST_CODE_MEDIA_SAVE);
} else { } else {
if (attachment.type.compareTo("image") == 0) { if (attachment.type.compareTo("image") == 0) {
MediaHelper.manageMove(MediaActivity.this, attachment.url, false); MediaHelper.manageMove(MediaActivity.this, attachment.url, false);
@ -381,33 +384,41 @@ public class MediaActivity extends BaseBarActivity implements OnDownloadInterfac
} }
} }
} else { } else {
if (attachment.type.compareToIgnoreCase("image") == 0) { if (attachment.type.compareTo("image") == 0) {
MediaHelper.manageMove(MediaActivity.this, attachment.url, false); MediaHelper.manageMove(MediaActivity.this, attachment.url, false);
} else { } else {
MediaHelper.manageDownloadsNoPopup(MediaActivity.this, attachment.url); MediaHelper.manageDownloadsNoPopup(MediaActivity.this, attachment.url);
downloadID = -1; downloadID = -1;
} }
} }
} else if (item.getItemId() == R.id.action_share) { } else {
int position = binding.mediaViewpager.getCurrentItem(); if (attachment.type.compareToIgnoreCase("image") == 0) {
Attachment attachment = attachments.get(position); MediaHelper.manageMove(MediaActivity.this, attachment.url, false);
if (attachment.type.compareTo("image") == 0) {
MediaHelper.manageMove(MediaActivity.this, attachment.url, true);
} else if (attachment.type.equalsIgnoreCase("video") || attachment.type.equalsIgnoreCase("audio") || attachment.type.equalsIgnoreCase("gifv")) {
downloadID = MediaHelper.manageDownloadsNoPopup(MediaActivity.this, attachment.url);
} else { } else {
if (Build.VERSION.SDK_INT >= 23) { MediaHelper.manageDownloadsNoPopup(MediaActivity.this, attachment.url);
if (ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { downloadID = -1;
ActivityCompat.requestPermissions(MediaActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Helper.EXTERNAL_STORAGE_REQUEST_CODE_MEDIA_SHARE); }
} else { }
downloadID = MediaHelper.manageDownloadsNoPopup(MediaActivity.this, attachment.url); }
}
public void shareMedia() {
int position = binding.mediaViewpager.getCurrentItem();
Attachment attachment = attachments.get(position);
if (attachment.type.compareTo("image") == 0) {
MediaHelper.manageMove(MediaActivity.this, attachment.url, true);
} else if (attachment.type.equalsIgnoreCase("video") || attachment.type.equalsIgnoreCase("audio") || attachment.type.equalsIgnoreCase("gifv")) {
downloadID = MediaHelper.manageDownloadsNoPopup(MediaActivity.this, attachment.url);
} else {
if (Build.VERSION.SDK_INT >= 23) {
if (ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(MediaActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(MediaActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, Helper.EXTERNAL_STORAGE_REQUEST_CODE_MEDIA_SHARE);
} else { } else {
downloadID = MediaHelper.manageDownloadsNoPopup(MediaActivity.this, attachment.url); downloadID = MediaHelper.manageDownloadsNoPopup(MediaActivity.this, attachment.url);
} }
} else {
downloadID = MediaHelper.manageDownloadsNoPopup(MediaActivity.this, attachment.url);
} }
} }
return true;
} }
@Override @Override

View file

@ -32,6 +32,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.OptIn; import androidx.annotation.OptIn;
import androidx.core.app.ActivityCompat; import androidx.core.app.ActivityCompat;
import androidx.core.view.ViewCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem;
@ -60,6 +61,7 @@ import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.helper.CacheDataSourceFactory; import app.fedilab.android.mastodon.helper.CacheDataSourceFactory;
import app.fedilab.android.mastodon.helper.Helper; import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MediaHelper; import app.fedilab.android.mastodon.helper.MediaHelper;
import app.fedilab.android.mastodon.helper.TranslateHelper;
import app.fedilab.android.mastodon.viewmodel.mastodon.TimelinesVM; import app.fedilab.android.mastodon.viewmodel.mastodon.TimelinesVM;
import es.dmoral.toasty.Toasty; import es.dmoral.toasty.Toasty;
@ -74,6 +76,8 @@ public class FragmentMedia extends Fragment {
private boolean swipeEnabled; private boolean swipeEnabled;
private FragmentSlideMediaBinding binding; private FragmentSlideMediaBinding binding;
private SlidrInterface slidrInterface; private SlidrInterface slidrInterface;
private int mediaPictureTranslateAccessibilityActionId = 0;
private int mediaVideoTranslateAccessibilityActionId = 0;
private boolean visible = false; private boolean visible = false;
@ -124,7 +128,6 @@ public class FragmentMedia extends Fragment {
enableSliding(true); enableSliding(true);
} }
}); });
binding.mediaPicture.setContentDescription(attachment.description);
binding.mediaPicture.setOnClickListener(v -> { binding.mediaPicture.setOnClickListener(v -> {
if (isAdded()) { if (isAdded()) {
((MediaActivity) requireActivity()).toogleFullScreen(); ((MediaActivity) requireActivity()).toogleFullScreen();
@ -137,6 +140,37 @@ public class FragmentMedia extends Fragment {
} }
}); });
if (attachment.description != null) {
binding.mediaPicture.setContentDescription(attachment.description);
mediaPictureTranslateAccessibilityActionId = ViewCompat.addAccessibilityAction(binding.mediaPicture, getString(R.string.translate), (view2, arguments) -> {
translate();
return true;
});
binding.mediaVideo.setContentDescription(attachment.description);
mediaVideoTranslateAccessibilityActionId = ViewCompat.addAccessibilityAction(binding.mediaVideo, getString(R.string.translate), (view2, arguments) -> {
translate();
return true;
});
}
mediaPictureTranslateAccessibilityActionId = ViewCompat.addAccessibilityAction(binding.mediaPicture, getString(R.string.download), (view2, arguments) -> {
((MediaActivity) requireActivity()).saveMedia();
return true;
});
mediaPictureTranslateAccessibilityActionId = ViewCompat.addAccessibilityAction(binding.mediaVideo, getString(R.string.download), (view2, arguments) -> {
((MediaActivity) requireActivity()).saveMedia();
return true;
});
mediaPictureTranslateAccessibilityActionId = ViewCompat.addAccessibilityAction(binding.mediaPicture, getString(R.string.share), (view2, arguments) -> {
((MediaActivity) requireActivity()).shareMedia();
return true;
});
mediaPictureTranslateAccessibilityActionId = ViewCompat.addAccessibilityAction(binding.mediaVideo, getString(R.string.share), (view2, arguments) -> {
((MediaActivity) requireActivity()).shareMedia();
return true;
});
String type = attachment.type; String type = attachment.type;
String preview_url = attachment.preview_url; String preview_url = attachment.preview_url;
if (type.equalsIgnoreCase("unknown")) { if (type.equalsIgnoreCase("unknown")) {
@ -267,6 +301,23 @@ public class FragmentMedia extends Fragment {
} }
} }
public void translate() {
if (attachment.translation == null) TranslateHelper.translate(
requireContext(),
attachment.description,
((MediaActivity) requireActivity()).getStatusLanguageForTranslation(),
translated -> {
attachment.translation = translated;
String translatedMediaDescription = getString(R.string.cd_translated_media_description, attachment.translation);
binding.mediaPicture.setContentDescription(translatedMediaDescription);
ViewCompat.removeAccessibilityAction(binding.mediaPicture, mediaPictureTranslateAccessibilityActionId);
binding.mediaVideo.setContentDescription(translatedMediaDescription);
ViewCompat.removeAccessibilityAction(binding.mediaVideo, mediaVideoTranslateAccessibilityActionId);
});
}
@androidx.annotation.OptIn(markerClass = androidx.media3.common.util.UnstableApi.class) @androidx.annotation.OptIn(markerClass = androidx.media3.common.util.UnstableApi.class)
private void loadVideo(String url, String type) { private void loadVideo(String url, String type) {
if (binding == null || !isAdded() || getActivity() == null || url == null) { if (binding == null || !isAdded() || getActivity() == null || url == null) {

View file

@ -43,6 +43,7 @@
android:visibility="gone" android:visibility="gone"
tools:visibility="visible" tools:visibility="visible"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
android:importantForAccessibility="noHideDescendants"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<TextView <TextView
@ -51,7 +52,6 @@
android:paddingTop="10dp" android:paddingTop="10dp"
android:paddingBottom="10dp" android:paddingBottom="10dp"
android:paddingEnd="10dp" android:paddingEnd="10dp"
android:importantForAccessibility="no"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:maxHeight="300dp" android:maxHeight="300dp"