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,6 +361,14 @@ 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) {
saveMedia();
} else if (item.getItemId() == R.id.action_share) {
shareMedia();
}
return true;
}
public void saveMedia() {
int position = binding.mediaViewpager.getCurrentItem(); int position = binding.mediaViewpager.getCurrentItem();
Attachment attachment = attachments.get(position); Attachment attachment = attachments.get(position);
if (Build.VERSION.SDK_INT >= 23) { if (Build.VERSION.SDK_INT >= 23) {
@ -388,7 +399,9 @@ public class MediaActivity extends BaseBarActivity implements OnDownloadInterfac
downloadID = -1; downloadID = -1;
} }
} }
} else if (item.getItemId() == R.id.action_share) { }
public void shareMedia() {
int position = binding.mediaViewpager.getCurrentItem(); int position = binding.mediaViewpager.getCurrentItem();
Attachment attachment = attachments.get(position); Attachment attachment = attachments.get(position);
if (attachment.type.compareTo("image") == 0) { if (attachment.type.compareTo("image") == 0) {
@ -407,8 +420,6 @@ public class MediaActivity extends BaseBarActivity implements OnDownloadInterfac
} }
} }
} }
return true;
}
@Override @Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

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"