Add correct Content Description for the preview images at the Compose screen (#1188)
* Add correct Content Description for the preview images at the Compose screen. tuskyapp#1155 * Remove "unknown" string from resource. Format code * Format code * Update string resource for content description
This commit is contained in:
parent
c75b046483
commit
5c61786e05
2 changed files with 105 additions and 56 deletions
|
@ -133,6 +133,25 @@ import java.util.concurrent.CountDownLatch;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.Px;
|
||||
import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.FileProvider;
|
||||
import androidx.core.view.inputmethod.InputConnectionCompat;
|
||||
import androidx.core.view.inputmethod.InputContentInfoCompat;
|
||||
import androidx.lifecycle.Lifecycle;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.transition.TransitionManager;
|
||||
|
||||
import at.connyduck.sparkbutton.helpers.Utils;
|
||||
import io.reactivex.Single;
|
||||
import io.reactivex.SingleObserver;
|
||||
|
@ -318,12 +337,12 @@ public final class ComposeActivity
|
|||
@Override
|
||||
public void onResponse(@NonNull Call<List<Emoji>> call, @NonNull Response<List<Emoji>> response) {
|
||||
List<Emoji> emojiList = response.body();
|
||||
if(emojiList == null) {
|
||||
if (emojiList == null) {
|
||||
emojiList = Collections.emptyList();
|
||||
}
|
||||
Collections.sort(emojiList, (a, b) ->
|
||||
a.getShortcode().toLowerCase(Locale.ROOT).compareTo(
|
||||
b.getShortcode().toLowerCase(Locale.ROOT)));
|
||||
a.getShortcode().toLowerCase(Locale.ROOT).compareTo(
|
||||
b.getShortcode().toLowerCase(Locale.ROOT)));
|
||||
setEmojiList(emojiList);
|
||||
cacheInstanceMetadata(activeAccount);
|
||||
}
|
||||
|
@ -357,7 +376,7 @@ public final class ComposeActivity
|
|||
tootButton.setOnClickListener(v -> onSendClicked());
|
||||
pickButton.setOnClickListener(v -> openPickDialog());
|
||||
visibilityButton.setOnClickListener(v -> showComposeOptions());
|
||||
contentWarningButton.setOnClickListener(v-> onContentWarningChanged());
|
||||
contentWarningButton.setOnClickListener(v -> onContentWarningChanged());
|
||||
emojiButton.setOnClickListener(v -> showEmojis());
|
||||
hideMediaToggle.setOnClickListener(v -> toggleHideMedia());
|
||||
|
||||
|
@ -481,7 +500,7 @@ public final class ComposeActivity
|
|||
replyTextView.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, arrowDownIcon, null);
|
||||
|
||||
replyTextView.setOnClickListener(v -> {
|
||||
TransitionManager.beginDelayedTransition((ViewGroup)replyContentTextView.getParent());
|
||||
TransitionManager.beginDelayedTransition((ViewGroup) replyContentTextView.getParent());
|
||||
|
||||
if (replyContentTextView.getVisibility() != View.VISIBLE) {
|
||||
replyContentTextView.setVisibility(View.VISIBLE);
|
||||
|
@ -547,7 +566,7 @@ public final class ComposeActivity
|
|||
}
|
||||
|
||||
// work around Android platform bug -> https://issuetracker.google.com/issues/67102093
|
||||
if(Build.VERSION.SDK_INT == Build.VERSION_CODES.O || Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1 ) {
|
||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O || Build.VERSION.SDK_INT == Build.VERSION_CODES.O_MR1) {
|
||||
textEditor.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
|
||||
}
|
||||
|
||||
|
@ -586,7 +605,7 @@ public final class ComposeActivity
|
|||
pickMedia(uri, mediaSize, description);
|
||||
}
|
||||
} else if (!ListUtils.isEmpty(mediaAttachments)) {
|
||||
for (int mediaIndex =0; mediaIndex < mediaAttachments.size(); ++mediaIndex) {
|
||||
for (int mediaIndex = 0; mediaIndex < mediaAttachments.size(); ++mediaIndex) {
|
||||
Attachment media = mediaAttachments.get(mediaIndex);
|
||||
QueuedMedia.Type type;
|
||||
switch (media.getType()) {
|
||||
|
@ -650,15 +669,15 @@ public final class ComposeActivity
|
|||
String subject = intent.getStringExtra(Intent.EXTRA_SUBJECT);
|
||||
String text = intent.getStringExtra(Intent.EXTRA_TEXT);
|
||||
String shareBody = null;
|
||||
if(subject != null && text != null){
|
||||
if(!subject.equals(text) && !text.contains(subject)){
|
||||
if (subject != null && text != null) {
|
||||
if (!subject.equals(text) && !text.contains(subject)) {
|
||||
shareBody = String.format("%s\n%s", subject, text);
|
||||
}else{
|
||||
} else {
|
||||
shareBody = text;
|
||||
}
|
||||
}else if(text != null){
|
||||
} else if (text != null) {
|
||||
shareBody = text;
|
||||
}else if(subject != null){
|
||||
} else if (subject != null) {
|
||||
shareBody = subject;
|
||||
}
|
||||
|
||||
|
@ -725,10 +744,10 @@ public final class ComposeActivity
|
|||
}
|
||||
|
||||
private void updateHideMediaToggle() {
|
||||
TransitionManager.beginDelayedTransition((ViewGroup)hideMediaToggle.getParent());
|
||||
TransitionManager.beginDelayedTransition((ViewGroup) hideMediaToggle.getParent());
|
||||
|
||||
@ColorInt int color;
|
||||
if(mediaQueued.size() == 0) {
|
||||
if (mediaQueued.size() == 0) {
|
||||
hideMediaToggle.setVisibility(View.GONE);
|
||||
} else {
|
||||
hideMediaToggle.setVisibility(View.VISIBLE);
|
||||
|
@ -854,7 +873,7 @@ public final class ComposeActivity
|
|||
@Override
|
||||
public void onStateChanged(@NonNull View bottomSheet, int newState) {
|
||||
//Wait until bottom sheet is not collapsed and show next screen after
|
||||
if (newState==BottomSheetBehavior.STATE_COLLAPSED){
|
||||
if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
|
||||
addMediaBehavior.setBottomSheetCallback(null);
|
||||
if (ContextCompat.checkSelfPermission(ComposeActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE)
|
||||
!= PackageManager.PERMISSION_GRANTED) {
|
||||
|
@ -1112,7 +1131,7 @@ public final class ComposeActivity
|
|||
// Continue only if the File was successfully created
|
||||
if (photoFile != null) {
|
||||
photoUploadUri = FileProvider.getUriForFile(this,
|
||||
BuildConfig.APPLICATION_ID+".fileprovider",
|
||||
BuildConfig.APPLICATION_ID + ".fileprovider",
|
||||
photoFile);
|
||||
intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUploadUri);
|
||||
startActivityForResult(intent, MEDIA_TAKE_PHOTO_RESULT);
|
||||
|
@ -1169,9 +1188,9 @@ public final class ComposeActivity
|
|||
.into(view);
|
||||
}
|
||||
view.setOnClickListener(v -> onMediaClick(item, v));
|
||||
view.setContentDescription(getString(R.string.action_delete));
|
||||
mediaPreviewBar.addView(view);
|
||||
mediaQueued.add(item);
|
||||
updateContentDescription(item);
|
||||
int queuedCount = mediaQueued.size();
|
||||
if (queuedCount == 1) {
|
||||
// If there's one video in the queue it is full, so disable the button to queue more.
|
||||
|
@ -1201,6 +1220,33 @@ public final class ComposeActivity
|
|||
}
|
||||
}
|
||||
|
||||
private void updateContentDescriptionForAllImages() {
|
||||
List<QueuedMedia> items = new ArrayList<>(mediaQueued);
|
||||
for (QueuedMedia media : items) {
|
||||
updateContentDescription(media);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateContentDescription(QueuedMedia item) {
|
||||
if (item.preview != null) {
|
||||
String imageId;
|
||||
if (!TextUtils.isEmpty(item.description)) {
|
||||
imageId = item.description;
|
||||
} else {
|
||||
int idx = getImageIdx(item);
|
||||
if (idx < 0)
|
||||
imageId = null;
|
||||
else
|
||||
imageId = Integer.toString(idx + 1);
|
||||
}
|
||||
item.preview.setContentDescription(getString(R.string.compose_preview_image_description, imageId));
|
||||
}
|
||||
}
|
||||
|
||||
private int getImageIdx(QueuedMedia item) {
|
||||
return mediaQueued.indexOf(item);
|
||||
}
|
||||
|
||||
private void onMediaClick(QueuedMedia item, View view) {
|
||||
PopupMenu popup = new PopupMenu(this, view);
|
||||
final int addCaptionId = 1;
|
||||
|
@ -1239,7 +1285,8 @@ public final class ComposeActivity
|
|||
.as(autoDisposable(from(this, Lifecycle.Event.ON_DESTROY)))
|
||||
.subscribe(new SingleObserver<Bitmap>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {}
|
||||
public void onSubscribe(Disposable d) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(Bitmap bitmap) {
|
||||
|
@ -1247,7 +1294,8 @@ public final class ComposeActivity
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) { }
|
||||
public void onError(Throwable e) {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
@ -1264,38 +1312,39 @@ public final class ComposeActivity
|
|||
input.setLines(2);
|
||||
input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_CAP_SENTENCES);
|
||||
input.setText(item.description);
|
||||
input.setFilters(new InputFilter[] { new InputFilter.LengthFilter(MEDIA_DESCRIPTION_CHARACTER_LIMIT) });
|
||||
input.setFilters(new InputFilter[]{new InputFilter.LengthFilter(MEDIA_DESCRIPTION_CHARACTER_LIMIT)});
|
||||
|
||||
DialogInterface.OnClickListener okListener = (dialog, which) -> {
|
||||
Runnable updateDescription = () -> {
|
||||
mastodonApi.updateMedia(item.id, input.getText().toString()).enqueue(new Callback<Attachment>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<Attachment> call, @NonNull Response<Attachment> response) {
|
||||
Attachment attachment = response.body();
|
||||
if (response.isSuccessful() && attachment != null) {
|
||||
item.description = attachment.getDescription();
|
||||
item.preview.setChecked(item.description != null && !item.description.isEmpty());
|
||||
dialog.dismiss();
|
||||
} else {
|
||||
showFailedCaptionMessage();
|
||||
}
|
||||
item.updateDescription = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<Attachment> call, @NonNull Throwable t) {
|
||||
Runnable updateDescription = () -> {
|
||||
mastodonApi.updateMedia(item.id, input.getText().toString()).enqueue(new Callback<Attachment>() {
|
||||
@Override
|
||||
public void onResponse(@NonNull Call<Attachment> call, @NonNull Response<Attachment> response) {
|
||||
Attachment attachment = response.body();
|
||||
if (response.isSuccessful() && attachment != null) {
|
||||
item.description = attachment.getDescription();
|
||||
item.preview.setChecked(item.description != null && !item.description.isEmpty());
|
||||
dialog.dismiss();
|
||||
updateContentDescription(item);
|
||||
} else {
|
||||
showFailedCaptionMessage();
|
||||
item.updateDescription = null;
|
||||
}
|
||||
});
|
||||
};
|
||||
item.updateDescription = null;
|
||||
}
|
||||
|
||||
if (item.readyStage == QueuedMedia.ReadyStage.UPLOADED) {
|
||||
updateDescription.run();
|
||||
} else {
|
||||
// media is still uploading, queue description update for when it finishes
|
||||
item.updateDescription = updateDescription;
|
||||
}
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<Attachment> call, @NonNull Throwable t) {
|
||||
showFailedCaptionMessage();
|
||||
item.updateDescription = null;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
if (item.readyStage == QueuedMedia.ReadyStage.UPLOADED) {
|
||||
updateDescription.run();
|
||||
} else {
|
||||
// media is still uploading, queue description update for when it finishes
|
||||
item.updateDescription = updateDescription;
|
||||
}
|
||||
};
|
||||
|
||||
AlertDialog dialog = new AlertDialog.Builder(this)
|
||||
|
@ -1323,7 +1372,7 @@ public final class ComposeActivity
|
|||
if (mediaQueued.size() == 0) {
|
||||
updateHideMediaToggle();
|
||||
}
|
||||
|
||||
updateContentDescriptionForAllImages();
|
||||
enableButton(pickButton, true, true);
|
||||
cancelReadyingMedia(item);
|
||||
}
|
||||
|
@ -1345,7 +1394,7 @@ public final class ComposeActivity
|
|||
public void onSuccess(File tempFile) {
|
||||
item.uri = FileProvider.getUriForFile(
|
||||
ComposeActivity.this,
|
||||
BuildConfig.APPLICATION_ID+".fileprovider",
|
||||
BuildConfig.APPLICATION_ID + ".fileprovider",
|
||||
tempFile);
|
||||
uploadMedia(item);
|
||||
}
|
||||
|
@ -1524,7 +1573,7 @@ public final class ComposeActivity
|
|||
|
||||
private void showContentWarning(boolean show) {
|
||||
statusHideText = show;
|
||||
TransitionManager.beginDelayedTransition((ViewGroup)contentWarningBar.getParent());
|
||||
TransitionManager.beginDelayedTransition((ViewGroup) contentWarningBar.getParent());
|
||||
int color;
|
||||
if (show) {
|
||||
statusMarkSensitive = true;
|
||||
|
@ -1556,9 +1605,9 @@ public final class ComposeActivity
|
|||
@Override
|
||||
public void onBackPressed() {
|
||||
// Acting like a teen: deliberately ignoring parent.
|
||||
if(composeOptionsBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED ||
|
||||
if (composeOptionsBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED ||
|
||||
addMediaBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED ||
|
||||
emojiBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED ) {
|
||||
emojiBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {
|
||||
composeOptionsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||
addMediaBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||
emojiBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
|
||||
|
@ -1690,14 +1739,14 @@ public final class ComposeActivity
|
|||
|
||||
@Override
|
||||
public void onEmojiSelected(@NotNull String shortcode) {
|
||||
textEditor.getText().insert(textEditor.getSelectionStart(), ":"+shortcode+": ");
|
||||
textEditor.getText().insert(textEditor.getSelectionStart(), ":" + shortcode + ": ");
|
||||
}
|
||||
|
||||
private void loadCachedInstanceMetadata(@NotNull AccountEntity activeAccount) {
|
||||
InstanceEntity instanceEntity = database.instanceDao()
|
||||
.loadMetadataForInstance(activeAccount.getDomain());
|
||||
|
||||
if(instanceEntity != null) {
|
||||
if (instanceEntity != null) {
|
||||
Integer max = instanceEntity.getMaximumTootCharacters();
|
||||
maximumTootCharacters = (max == null ? STATUS_CHARACTER_LIMIT : max);
|
||||
setEmojiList(instanceEntity.getEmojiList());
|
||||
|
@ -1722,14 +1771,13 @@ public final class ComposeActivity
|
|||
}
|
||||
|
||||
// Accessors for testing, hence package scope
|
||||
int getMaximumTootCharacters()
|
||||
{
|
||||
int getMaximumTootCharacters() {
|
||||
return maximumTootCharacters;
|
||||
}
|
||||
|
||||
static boolean canHandleMimeType(@Nullable String mimeType) {
|
||||
return (mimeType != null &&
|
||||
(mimeType.startsWith("image/") || mimeType.startsWith("video/") || mimeType.equals("text/plain")));
|
||||
(mimeType.startsWith("image/") || mimeType.startsWith("video/") || mimeType.equals("text/plain")));
|
||||
}
|
||||
|
||||
public static final class QueuedMedia {
|
||||
|
|
|
@ -466,6 +466,7 @@
|
|||
<string name="pref_title_bot_overlay">Show indicator for bots</string>
|
||||
|
||||
<string name="notification_clear_text">Are you sure you want to permanently clear all your notifications?</string>
|
||||
<string name="compose_preview_image_description">Actions for image %s</string>
|
||||
|
||||
<string name="poll_info_format">
|
||||
<!-- 15 votes • 1 hour left -->
|
||||
|
|
Loading…
Reference in a new issue