diff --git a/src/components/views/dialogs/ForwardDialog.tsx b/src/components/views/dialogs/ForwardDialog.tsx index 2d3de09eec..8e23e3bd95 100644 --- a/src/components/views/dialogs/ForwardDialog.tsx +++ b/src/components/views/dialogs/ForwardDialog.tsx @@ -49,9 +49,9 @@ import BaseAvatar from "../avatars/BaseAvatar"; import { Action } from "../../../dispatcher/actions"; import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; import { ButtonEvent } from "../elements/AccessibleButton"; -import { roomContextDetailsText } from "../../../utils/i18n-helpers"; import { isLocationEvent } from "../../../utils/EventUtils"; import { isSelfLocation, locationEventGeoUri } from "../../../utils/location"; +import { RoomContextDetails } from "../rooms/RoomContextDetails"; const AVATAR_SIZE = 30; @@ -130,8 +130,6 @@ const Entry: React.FC = ({ room, type, content, matrixClient: cli, />; } - const detailsText = roomContextDetailsText(room); - return
= ({ room, type, content, matrixClient: cli, > { room.name } - { detailsText && - { detailsText } - } + MAX_NAME_LENGTH) { name = `${name.substring(0, MAX_NAME_LENGTH)}...`; @@ -41,12 +48,12 @@ export function PublicRoomResultDetails({ room }: { room: IPublicRoomsChunkRoom return (
- { name } - + { name } + { room.canonical_alias ?? room.room_id }
-
+
{ _t("%(count)s Members", { count: room.num_joined_members, diff --git a/src/components/views/dialogs/spotlight/SpotlightDialog.tsx b/src/components/views/dialogs/spotlight/SpotlightDialog.tsx index 341244dad0..f14d29d8ca 100644 --- a/src/components/views/dialogs/spotlight/SpotlightDialog.tsx +++ b/src/components/views/dialogs/spotlight/SpotlightDialog.tsx @@ -14,9 +14,9 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { WebSearch as WebSearchEvent } from "@matrix-org/analytics-events/types/typescript/WebSearch"; import classNames from "classnames"; import { capitalize, sum } from "lodash"; -import { WebSearch as WebSearchEvent } from "@matrix-org/analytics-events/types/typescript/WebSearch"; import { IHierarchyRoom } from "matrix-js-sdk/src/@types/spaces"; import { IPublicRoomsChunkRoom, MatrixClient, RoomMember, RoomType } from "matrix-js-sdk/src/matrix"; import { Room } from "matrix-js-sdk/src/models/room"; @@ -50,6 +50,7 @@ import { useDebouncedCallback } from "../../../../hooks/spotlight/useDebouncedCa import { useRecentSearches } from "../../../../hooks/spotlight/useRecentSearches"; import { useProfileInfo } from "../../../../hooks/useProfileInfo"; import { usePublicRoomDirectory } from "../../../../hooks/usePublicRoomDirectory"; +import { useFeatureEnabled } from "../../../../hooks/useSettings"; import { useSpaceResults } from "../../../../hooks/useSpaceResults"; import { useUserDirectory } from "../../../../hooks/useUserDirectory"; import { getKeyBindingsManager } from "../../../../KeyBindingsManager"; @@ -63,6 +64,7 @@ import SdkConfig from "../../../../SdkConfig"; import { SettingLevel } from "../../../../settings/SettingLevel"; import SettingsStore from "../../../../settings/SettingsStore"; import { BreadcrumbsStore } from "../../../../stores/BreadcrumbsStore"; +import { RoomNotificationState } from "../../../../stores/notifications/RoomNotificationState"; import { RoomNotificationStateStore } from "../../../../stores/notifications/RoomNotificationStateStore"; import { RecentAlgorithm } from "../../../../stores/room-list/algorithms/tag-sorting/RecentAlgorithm"; import { RoomViewStore } from "../../../../stores/RoomViewStore"; @@ -78,6 +80,7 @@ import DecoratedRoomAvatar from "../../avatars/DecoratedRoomAvatar"; import { SearchResultAvatar } from "../../avatars/SearchResultAvatar"; import { NetworkDropdown } from "../../directory/NetworkDropdown"; import AccessibleButton from "../../elements/AccessibleButton"; +import LabelledCheckbox from "../../elements/LabelledCheckbox"; import Spinner from "../../elements/Spinner"; import NotificationBadge from "../../rooms/NotificationBadge"; import BaseDialog from "../BaseDialog"; @@ -85,10 +88,8 @@ import FeedbackDialog from "../FeedbackDialog"; import { IDialogProps } from "../IDialogProps"; import { Option } from "./Option"; import { PublicRoomResultDetails } from "./PublicRoomResultDetails"; -import { RoomResultDetails } from "./RoomResultDetails"; +import { RoomContextDetails } from "../../rooms/RoomContextDetails"; import { TooltipOption } from "./TooltipOption"; -import LabelledCheckbox from "../../elements/LabelledCheckbox"; -import { useFeatureEnabled } from "../../../../hooks/useSettings"; const MAX_RECENT_SEARCHES = 10; const SECTION_LIMIT = 50; // only show 50 results per section for performance reasons @@ -259,6 +260,22 @@ const findVisibleRoomMembers = (cli: MatrixClient, filterDMs = true) => { ).filter(it => it.userId !== cli.getUserId()); }; +const roomAriaUnreadLabel = (room: Room, notification: RoomNotificationState): string | undefined => { + if (notification.hasMentions) { + return _t("%(count)s unread messages including mentions.", { + count: notification.count, + }); + } else if (notification.hasUnreadCount) { + return _t("%(count)s unread messages.", { + count: notification.count, + }); + } else if (notification.isUnread) { + return _t("Unread messages."); + } else { + return undefined; + } +}; + interface IDirectoryOpts { limit: number; query: string; @@ -523,6 +540,12 @@ const SpotlightDialog: React.FC = ({ initialText = "", initialFilter = n if (trimmedQuery || filter !== null) { const resultMapper = (result: Result): JSX.Element => { if (isRoomResult(result)) { + const notification = RoomNotificationStateStore.instance.getRoomState(result.room); + const unreadLabel = roomAriaUnreadLabel(result.room, notification); + const ariaProperties = { + "aria-label": unreadLabel ? `${result.room.name} ${unreadLabel}` : result.room.name, + "aria-details": `mx_SpotlightDialog_button_result_${result.room.roomId}_details`, + }; return ( ); } @@ -547,10 +579,17 @@ const SpotlightDialog: React.FC = ({ initialText = "", initialFilter = n startDm(cli, [result.member]); onFinished(); }} + aria-label={result.member instanceof RoomMember + ? result.member.rawDisplayName + : result.member.name} + aria-describedby={`mx_SpotlightDialog_button_result_${result.member.userId}_details`} > { result.member instanceof RoomMember ? result.member.rawDisplayName : result.member.name } -
+
{ result.member.userId }
@@ -575,6 +614,9 @@ const SpotlightDialog: React.FC = ({ initialText = "", initialFilter = n > { _t(clientRoom ? "View" : "Join") } } + aria-labelledby={`mx_SpotlightDialog_button_result_${result.publicRoom.room_id}_name`} + aria-describedby={`mx_SpotlightDialog_button_result_${result.publicRoom.room_id}_alias`} + aria-details={`mx_SpotlightDialog_button_result_${result.publicRoom.room_id}_details`} > = ({ initialText = "", initialFilter = n width={AVATAR_SIZE} height={AVATAR_SIZE} /> - + ); } @@ -608,8 +655,13 @@ const SpotlightDialog: React.FC = ({ initialText = "", initialFilter = n let peopleSection: JSX.Element; if (results[Section.People].length) { peopleSection = ( -
-

{ _t("Recent Conversations") }

+
+

+ { _t("Recent Conversations") } +

{ results[Section.People].slice(0, SECTION_LIMIT).map(resultMapper) }
@@ -620,8 +672,13 @@ const SpotlightDialog: React.FC = ({ initialText = "", initialFilter = n let suggestionsSection: JSX.Element; if (results[Section.Suggestions].length && filter === Filter.People) { suggestionsSection = ( -
-

{ _t("Suggestions") }

+
+

+ { _t("Suggestions") } +

{ results[Section.Suggestions].slice(0, SECTION_LIMIT).map(resultMapper) }
@@ -632,8 +689,13 @@ const SpotlightDialog: React.FC = ({ initialText = "", initialFilter = n let roomsSection: JSX.Element; if (results[Section.Rooms].length) { roomsSection = ( -
-

{ _t("Rooms") }

+
+

+ { _t("Rooms") } +

{ results[Section.Rooms].slice(0, SECTION_LIMIT).map(resultMapper) }
@@ -644,8 +706,13 @@ const SpotlightDialog: React.FC = ({ initialText = "", initialFilter = n let spacesSection: JSX.Element; if (results[Section.Spaces].length) { spacesSection = ( -
-

{ _t("Spaces you're in") }

+
+

+ { _t("Spaces you're in") } +

{ results[Section.Spaces].slice(0, SECTION_LIMIT).map(resultMapper) }
@@ -656,9 +723,14 @@ const SpotlightDialog: React.FC = ({ initialText = "", initialFilter = n let publicRoomsSection: JSX.Element; if (filter === Filter.PublicRooms) { publicRoomsSection = ( -
+
-

{ _t("Suggestions") }

+

+ { _t("Suggestions") } +

{ exploringPublicSpacesEnabled && <> = ({ initialText = "", initialFilter = n let spaceRoomsSection: JSX.Element; if (spaceResults.length && activeSpace && filter === null) { spaceRoomsSection = ( -
-

{ _t("Other rooms in %(spaceName)s", { spaceName: activeSpace.name }) }

+
+

+ { _t("Other rooms in %(spaceName)s", { spaceName: activeSpace.name }) } +

{ spaceResults.slice(0, SECTION_LIMIT).map((room: IHierarchyRoom): JSX.Element => (