mirror of
https://github.com/oxen-io/session-android.git
synced 2025-12-11 21:41:46 +00:00
Add accessibility tags (#1054)
* adding accessibility id to new conversation button * adding accessibility ids and strings for testing * updating id tags for new conversation buttons * accessibility tags for create contact test * adding ids for message requests, config message, requests banner and conversation view * adding more tags to settings page * adding tags to different resolutions for landing page * updating display name in settings to include accessibility id * found some stashed changes which i forgot about * more stashed changes * adding tags to layout sw400dp * closed group testing, delete/unsend message testing and selecting contacts tag * adding tags for message body, selecting contacts for group creation, deleted message config, unsend message modal, and trash icon * added tags for disappearing messages menu option, time selector, clock icon, confirm of change (ok)and control message * add test for block user * docs: Adding in accessibility ID's for Appium testing * accessibility tags for conversation options, profile picture/settings and block options * Add content descriptions for better accessibility * Add more content descriptions * Add timer icon content description * Update profile picture content description * Adding accessibility ids to new conversation creation screen and to message notification settings * fix: content descriptions in their correct places and prevent a crash * build: update build number * build: update build number * Adding back in FrameLayout, making changes as request * Fixed viewPager move * Fixing changes as requested by Jubb * Adding content descriptions to mentions list, voice message settings, link preview permissions, closed group menu and slow mode notifications option * Adds content descriptions to blocked contacts heading in conversations settings, individual contacts in blocked contacts page and to empty message requests folder * Adds content descriptions to empty message request folder and text input box for username on settings page --------- Co-authored-by: charles <charles@oxen.io> Co-authored-by: hjubb <hjubb@users.noreply.github.com>
This commit is contained in:
@@ -5,8 +5,9 @@ import androidx.annotation.AttrRes
|
||||
/**
|
||||
* Represents an action to be rendered
|
||||
*/
|
||||
data class ActionItem(
|
||||
data class ActionItem @JvmOverloads constructor(
|
||||
@AttrRes val iconRes: Int,
|
||||
val title: CharSequence,
|
||||
val action: Runnable
|
||||
val action: Runnable,
|
||||
val contentDescription: String? = null
|
||||
)
|
||||
|
||||
@@ -77,6 +77,7 @@ class ContextMenuList(recyclerView: RecyclerView, onItemClick: () -> Unit) {
|
||||
context.theme.resolveAttribute(model.item.iconRes, typedValue, true)
|
||||
icon.setImageDrawable(ContextCompat.getDrawable(context, typedValue.resourceId))
|
||||
}
|
||||
itemView.contentDescription = model.item.contentDescription
|
||||
title.text = model.item.title
|
||||
itemView.setOnClickListener {
|
||||
model.item.action.run()
|
||||
|
||||
@@ -781,7 +781,9 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
val recipient = viewModel.recipient ?: return
|
||||
if (!isShowingMentionCandidatesView) {
|
||||
additionalContentContainer.removeAllViews()
|
||||
val view = MentionCandidatesView(this)
|
||||
val view = MentionCandidatesView(this).apply {
|
||||
contentDescription = context.getString(R.string.AccessibilityId_mentions_list)
|
||||
}
|
||||
view.glide = glide
|
||||
view.onCandidateSelected = { handleMentionSelected(it) }
|
||||
additionalContentContainer.addView(view)
|
||||
@@ -958,7 +960,7 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
override fun block(deleteThread: Boolean) {
|
||||
val title = R.string.RecipientPreferenceActivity_block_this_contact_question
|
||||
val message = R.string.RecipientPreferenceActivity_you_will_no_longer_receive_messages_and_calls_from_this_contact
|
||||
AlertDialog.Builder(this)
|
||||
val dialog = AlertDialog.Builder(this)
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
@@ -969,6 +971,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe
|
||||
finish()
|
||||
}
|
||||
}.show()
|
||||
val button = dialog.getButton(DialogInterface.BUTTON_POSITIVE)
|
||||
button.setContentDescription("Confirm block")
|
||||
}
|
||||
|
||||
override fun copySessionID(sessionId: String) {
|
||||
|
||||
@@ -660,10 +660,14 @@ public final class ConversationReactionOverlay extends FrameLayout {
|
||||
|
||||
String userPublicKey = TextSecurePreferences.getLocalNumber(getContext());
|
||||
// Select message
|
||||
items.add(new ActionItem(R.attr.menu_select_icon, getContext().getResources().getString(R.string.conversation_context__menu_select), () -> handleActionItemClicked(Action.SELECT)));
|
||||
items.add(new ActionItem(R.attr.menu_select_icon, getContext().getResources().getString(R.string.conversation_context__menu_select), () -> handleActionItemClicked(Action.SELECT),
|
||||
getContext().getResources().getString(R.string.AccessibilityId_select)));
|
||||
// Reply
|
||||
if (!message.isPending() && !message.isFailed()) {
|
||||
items.add(new ActionItem(R.attr.menu_reply_icon, getContext().getResources().getString(R.string.conversation_context__menu_reply), () -> handleActionItemClicked(Action.REPLY)));
|
||||
items.add(
|
||||
new ActionItem(R.attr.menu_reply_icon, getContext().getResources().getString(R.string.conversation_context__menu_reply), () -> handleActionItemClicked(Action.REPLY),
|
||||
getContext().getResources().getString(R.string.AccessibilityId_reply_message))
|
||||
);
|
||||
}
|
||||
// Copy message text
|
||||
if (!containsControlMessage && hasText) {
|
||||
@@ -671,11 +675,17 @@ public final class ConversationReactionOverlay extends FrameLayout {
|
||||
}
|
||||
// Copy Session ID
|
||||
if (recipient.isGroupRecipient() && !recipient.isOpenGroupRecipient() && !message.getRecipient().getAddress().toString().equals(userPublicKey)) {
|
||||
items.add(new ActionItem(R.attr.menu_copy_icon, getContext().getResources().getString(R.string.activity_conversation_menu_copy_session_id), () -> handleActionItemClicked(Action.COPY_SESSION_ID)));
|
||||
items.add(new ActionItem(
|
||||
R.attr.menu_copy_icon, getContext().getResources().getString(R.string.activity_conversation_menu_copy_session_id), () -> handleActionItemClicked(Action.COPY_SESSION_ID))
|
||||
);
|
||||
}
|
||||
// Delete message
|
||||
if (ConversationMenuItemHelper.userCanDeleteSelectedItems(getContext(), message, openGroup, userPublicKey, blindedPublicKey)) {
|
||||
items.add(new ActionItem(R.attr.menu_trash_icon, getContext().getResources().getString(R.string.delete), () -> handleActionItemClicked(Action.DELETE)));
|
||||
items.add(new ActionItem(R.attr.menu_trash_icon, getContext().getResources().getString(R.string.delete),
|
||||
() -> handleActionItemClicked(Action.DELETE),
|
||||
getContext().getResources().getString(R.string.AccessibilityId_delete_message)
|
||||
)
|
||||
);
|
||||
}
|
||||
// Ban user
|
||||
if (ConversationMenuItemHelper.userCanBanSelectedUsers(getContext(), message, openGroup, userPublicKey, blindedPublicKey)) {
|
||||
@@ -695,7 +705,9 @@ public final class ConversationReactionOverlay extends FrameLayout {
|
||||
}
|
||||
// Save media
|
||||
if (message.isMms() && ((MediaMmsMessageRecord)message).containsMediaSlide()) {
|
||||
items.add(new ActionItem(R.attr.menu_save_icon, getContext().getResources().getString(R.string.conversation_context_image__save_attachment), () -> handleActionItemClicked(Action.DOWNLOAD)));
|
||||
items.add(new ActionItem(R.attr.menu_save_icon, getContext().getResources().getString(R.string.conversation_context_image__save_attachment), () -> handleActionItemClicked(Action.DOWNLOAD),
|
||||
getContext().getResources().getString(R.string.AccessibilityId_save_attachment))
|
||||
);
|
||||
}
|
||||
|
||||
backgroundView.setVisibility(View.VISIBLE);
|
||||
|
||||
@@ -57,9 +57,9 @@ class InputBar : RelativeLayout, InputBarEditTextDelegate, QuoteViewDelegate, Li
|
||||
val attachmentButtonsContainerHeight: Int
|
||||
get() = binding.attachmentsButtonContainer.height
|
||||
|
||||
private val attachmentsButton by lazy { InputBarButton(context, R.drawable.ic_plus_24) }
|
||||
private val microphoneButton by lazy { InputBarButton(context, R.drawable.ic_microphone) }
|
||||
private val sendButton by lazy { InputBarButton(context, R.drawable.ic_arrow_up, true) }
|
||||
private val attachmentsButton by lazy { InputBarButton(context, R.drawable.ic_plus_24).apply { contentDescription = context.getString(R.string.AccessibilityId_attachments_button)} }
|
||||
private val microphoneButton by lazy { InputBarButton(context, R.drawable.ic_microphone).apply { contentDescription = context.getString(R.string.AccessibilityId_microphone_button)} }
|
||||
private val sendButton by lazy { InputBarButton(context, R.drawable.ic_arrow_up, true).apply { contentDescription = context.getString(R.string.AccessibilityId_send_message_button)} }
|
||||
|
||||
// region Lifecycle
|
||||
constructor(context: Context) : super(context) { initialize() }
|
||||
|
||||
@@ -7,6 +7,7 @@ import android.view.ViewGroup
|
||||
import android.widget.BaseAdapter
|
||||
import android.widget.ListView
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import network.loki.messenger.R
|
||||
import org.session.libsession.messaging.mentions.Mention
|
||||
import org.thoughtcrime.securesms.database.LokiThreadDatabase
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests
|
||||
@@ -41,7 +42,9 @@ class MentionCandidatesView(context: Context, attrs: AttributeSet?, defStyleAttr
|
||||
override fun getItem(position: Int): Mention { return candidates[position] }
|
||||
|
||||
override fun getView(position: Int, cellToBeReused: View?, parent: ViewGroup): View {
|
||||
val cell = cellToBeReused as MentionCandidateView? ?: MentionCandidateView(context)
|
||||
val cell = cellToBeReused as MentionCandidateView? ?: MentionCandidateView(context).apply {
|
||||
contentDescription = context.getString(R.string.AccessibilityId_contact)
|
||||
}
|
||||
val mentionCandidate = getItem(position)
|
||||
cell.glide = glide
|
||||
cell.candidate = mentionCandidate
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.conversation.v2.menus
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.PorterDuff
|
||||
@@ -185,7 +186,7 @@ object ConversationMenuHelper {
|
||||
private fun call(context: Context, thread: Recipient) {
|
||||
|
||||
if (!TextSecurePreferences.isCallNotificationsEnabled(context)) {
|
||||
AlertDialog.Builder(context)
|
||||
val dialog = AlertDialog.Builder(context)
|
||||
.setTitle(R.string.ConversationActivity_call_title)
|
||||
.setMessage(R.string.ConversationActivity_call_prompt)
|
||||
.setPositiveButton(R.string.activity_settings_title) { _, _ ->
|
||||
@@ -194,7 +195,10 @@ object ConversationMenuHelper {
|
||||
}
|
||||
.setNeutralButton(R.string.cancel) { d, _ ->
|
||||
d.dismiss()
|
||||
}.show()
|
||||
}.create()
|
||||
dialog.getButton(DialogInterface.BUTTON_POSITIVE)?.contentDescription = context.getString(R.string.AccessibilityId_settings)
|
||||
dialog.getButton(DialogInterface.BUTTON_NEGATIVE)?.contentDescription = context.getString(R.string.AccessibilityId_cancel_button)
|
||||
dialog.show()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ class ControlMessageView : LinearLayout {
|
||||
binding.dateBreakTextView.showDateBreak(message, previous)
|
||||
binding.iconImageView.visibility = View.GONE
|
||||
var messageBody: CharSequence = message.getDisplayBody(context)
|
||||
binding.root.contentDescription= null
|
||||
when {
|
||||
message.isExpirationTimerUpdate -> {
|
||||
binding.iconImageView.setImageDrawable(
|
||||
@@ -46,6 +47,7 @@ class ControlMessageView : LinearLayout {
|
||||
}
|
||||
message.isMessageRequestResponse -> {
|
||||
messageBody = context.getString(R.string.message_requests_accepted)
|
||||
binding.root.contentDescription=context.getString(R.string.AccessibilityId_message_request_config_message)
|
||||
}
|
||||
message.isCallLog -> {
|
||||
val drawable = when {
|
||||
|
||||
@@ -13,6 +13,9 @@ import android.view.HapticFeedbackConstants
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.core.content.ContextCompat
|
||||
@@ -194,7 +197,7 @@ class VisibleMessageView : LinearLayout {
|
||||
binding.dateBreakTextView.isVisible = showDateBreak
|
||||
// Message status indicator
|
||||
if (message.isOutgoing) {
|
||||
val (iconID, iconColor, textId) = getMessageStatusImage(message)
|
||||
val (iconID, iconColor, textId, contentDescription) = getMessageStatusImage(message)
|
||||
if (textId != null) {
|
||||
binding.messageStatusTextView.setText(textId)
|
||||
|
||||
@@ -209,6 +212,7 @@ class VisibleMessageView : LinearLayout {
|
||||
}
|
||||
binding.messageStatusImageView.setImageDrawable(drawable)
|
||||
}
|
||||
binding.messageStatusImageView.contentDescription = contentDescription
|
||||
|
||||
val lastMessageID = mmsSmsDb.getLastMessageID(message.threadId)
|
||||
binding.messageStatusTextView.isVisible = (
|
||||
@@ -283,17 +287,43 @@ class VisibleMessageView : LinearLayout {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMessageStatusImage(message: MessageRecord): Triple<Int?,Int?,Int?> {
|
||||
data class MessageStatusInfo(@DrawableRes val iconId: Int?,
|
||||
@ColorInt val iconTint: Int?,
|
||||
@StringRes val messageText: Int?,
|
||||
val contentDescription: String?)
|
||||
|
||||
private fun getMessageStatusImage(message: MessageRecord): MessageStatusInfo {
|
||||
return when {
|
||||
!message.isOutgoing -> Triple(null, null, null)
|
||||
!message.isOutgoing -> MessageStatusInfo(null,
|
||||
null,
|
||||
null,
|
||||
null)
|
||||
message.isFailed ->
|
||||
Triple(R.drawable.ic_delivery_status_failed, resources.getColor(R.color.destructive, context.theme), R.string.delivery_status_failed)
|
||||
MessageStatusInfo(
|
||||
R.drawable.ic_delivery_status_failed,
|
||||
resources.getColor(R.color.destructive, context.theme),
|
||||
R.string.delivery_status_failed,
|
||||
null
|
||||
)
|
||||
message.isPending ->
|
||||
Triple(R.drawable.ic_delivery_status_sending, context.getColorFromAttr(R.attr.message_status_color), R.string.delivery_status_sending)
|
||||
MessageStatusInfo(
|
||||
R.drawable.ic_delivery_status_sending,
|
||||
context.getColorFromAttr(R.attr.message_status_color), R.string.delivery_status_sending,
|
||||
context.getString(R.string.AccessibilityId_message_sent_status_pending)
|
||||
)
|
||||
message.isRead ->
|
||||
Triple(R.drawable.ic_delivery_status_read, context.getColorFromAttr(R.attr.message_status_color), R.string.delivery_status_read)
|
||||
MessageStatusInfo(
|
||||
R.drawable.ic_delivery_status_read,
|
||||
context.getColorFromAttr(R.attr.message_status_color), R.string.delivery_status_read,
|
||||
null
|
||||
)
|
||||
else ->
|
||||
Triple(R.drawable.ic_delivery_status_sent, context.getColorFromAttr(R.attr.message_status_color), R.string.delivery_status_sent)
|
||||
MessageStatusInfo(
|
||||
R.drawable.ic_delivery_status_sent,
|
||||
context.getColorFromAttr(R.attr.message_status_color),
|
||||
R.string.delivery_status_sent,
|
||||
context.getString(R.string.AccessibilityId_message_sent_status_tick)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.permissions;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
@@ -12,6 +13,7 @@ import android.util.DisplayMetrics;
|
||||
import android.view.Display;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -162,12 +164,13 @@ public class Permissions {
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private void executePermissionsRequestWithRationale(PermissionsRequest request) {
|
||||
RationaleDialog.createFor(permissionObject.getContext(), rationaleDialogMessage, rationalDialogHeader)
|
||||
.setPositiveButton(R.string.Permissions_continue, (dialog, which) -> executePermissionsRequest(request))
|
||||
.setNegativeButton(R.string.Permissions_not_now, (dialog, which) -> executeNoPermissionsRequest(request))
|
||||
.show()
|
||||
.getWindow()
|
||||
.setLayout((int)(permissionObject.getWindowWidth() * .75), ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
AlertDialog dialog = RationaleDialog.createFor(permissionObject.getContext(), rationaleDialogMessage, rationalDialogHeader)
|
||||
.setPositiveButton(R.string.Permissions_continue, (d, which) -> executePermissionsRequest(request))
|
||||
.setNegativeButton(R.string.Permissions_not_now, (d, which) -> executeNoPermissionsRequest(request))
|
||||
.show();
|
||||
dialog.getWindow().setLayout((int)(permissionObject.getWindowWidth() * .75), ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
positiveButton.setContentDescription("Continue");
|
||||
}
|
||||
|
||||
private void executePermissionsRequest(PermissionsRequest request) {
|
||||
@@ -353,12 +356,17 @@ public class Permissions {
|
||||
Context context = this.context.get();
|
||||
|
||||
if (context != null) {
|
||||
new AlertDialog.Builder(context, R.style.ThemeOverlay_Session_AlertDialog)
|
||||
AlertDialog alertDialog = new AlertDialog.Builder(context, R.style.ThemeOverlay_Session_AlertDialog)
|
||||
.setTitle(R.string.Permissions_permission_required)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.Permissions_continue, (dialog, which) -> context.startActivity(getApplicationSettingsIntent(context)))
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.show();
|
||||
.create();
|
||||
Button positiveButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
if (positiveButton != null) {
|
||||
positiveButton.setContentDescription(context.getString(R.string.AccessibilityId_continue));
|
||||
}
|
||||
alertDialog.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,10 +5,12 @@ import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.KeyguardManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -179,7 +181,7 @@ public class PrivacySettingsPreferenceFragment extends ListSummaryPreferenceFrag
|
||||
boolean val = (boolean) newValue;
|
||||
if (val) {
|
||||
// check if we've shown the info dialog and check for microphone permissions
|
||||
new AlertDialog.Builder(new ContextThemeWrapper(context.requireContext(), R.style.ThemeOverlay_Session_AlertDialog))
|
||||
AlertDialog dialog = new AlertDialog.Builder(new ContextThemeWrapper(context.requireContext(), R.style.ThemeOverlay_Session_AlertDialog))
|
||||
.setTitle(R.string.dialog_voice_video_title)
|
||||
.setMessage(R.string.dialog_voice_video_message)
|
||||
.setPositiveButton(R.string.dialog_link_preview_enable_button_title, (d, w) -> {
|
||||
@@ -189,7 +191,9 @@ public class PrivacySettingsPreferenceFragment extends ListSummaryPreferenceFrag
|
||||
|
||||
})
|
||||
.show();
|
||||
return false;
|
||||
Button positiveButton = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
positiveButton.setContentDescription("Enable");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user