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:
pandasoft0 2019-05-09 21:25:45 +03:00 committed by Konrad Pozniak
parent c75b046483
commit 5c61786e05
2 changed files with 105 additions and 56 deletions

View File

@ -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 {

View File

@ -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 -->