Files
element-x-ios/ElementX/Sources/Other/Avatars.swift
T
Stefan Ceriu 7f1b6086ae Search tab (#5754)
* Add a developer flag for the search tab
Introduces a globalSearchEnabled user preference (off by default) with a toggle in Developer Options, used to gate the new search experience.

* Support search role tabs in the tab coordinator
Migrates the NavigationTabCoordinator to SwiftUI's value-based Tab API and adds an isSearch option so a tab can adopt the iOS 26 .search role, which detaches it into the trailing search button in the tab bar.

* Moves room search to a new screen
Adds a new screen that filters the alternate room summary provider as you type, shows an empty state, and lists matching rooms with their matrix identifier. Supports hardware keyboard selection (arrow keys to move through results, return to open) by reaching into the system search field.

* Present search in a dedicated tab
Adds the search tab to the chats flow on iOS 26 when the flag is enabled, rendered as the detached .search role button. The Cmd+K shortcut now selects this tab, and the home screen's inline search is hidden while the tab is available.

* Remove the old global search screen
The dedicated search tab replaces the Cmd+K floating window, so the GlobalSearchScreen, its window plumbing in the WindowManager, and its presentation in the chats flow are all removed.
2026-06-19 13:50:17 +03:00

168 lines
4.4 KiB
Swift

//
// Copyright 2025 Element Creations Ltd.
// Copyright 2022-2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE files in the repository root for full details.
//
import Foundation
import SwiftUI
enum Avatars {
enum Size {
case user(on: UserAvatarSizeOnScreen)
case room(on: RoomAvatarSizeOnScreen)
/// custom
case custom(CGFloat)
/// Value in UIKit points
var value: CGFloat {
switch self {
case .user(let screen):
return screen.value
case .room(let screen):
return screen.value
case .custom(let val):
return val
}
}
/// Value in pixels by using the scale of the main screen
@MainActor var scaledValue: CGFloat {
value * UIScreen.main.scale
}
@MainActor var scaledSize: CGSize {
CGSize(width: scaledValue, height: scaledValue)
}
}
@MainActor
static func generatePlaceholderAvatarImageData(name: String, id: String, size: CGSize) -> Data? {
let image = PlaceholderAvatarImage(name: name, contentID: id)
.clipShape(Circle())
.frame(width: size.width, height: size.height)
let renderer = ImageRenderer(content: image)
// Specify the scale so the image is rendered correctly. We don't have access to the screen
// here so a hardcoded 3.0 will have to do
renderer.scale = 3.0
guard let image = renderer.uiImage else {
MXLog.info("Generating notification icon placeholder failed")
return nil
}
return image.pngData()
}
}
enum UserAvatarSizeOnScreen {
case chats
case spaces
case timeline
case settings
case roomDetails
case roomMembersList
case roomChangeRoles
case dmDetails
case startChat
case memberDetails
case inviteUsers
case readReceipt
case readReceiptSheet
case editUserDetails
case spaceHeader
case completionSuggestions
case blockedUsers
case knockingUsersBannerStack
case knockingUserBanner
case knockingUserList
case mediaPreviewDetails
case sendInviteConfirmation
case sessionVerification
case threadList
case threadSummary
case map
case classicAppAccount
var value: CGFloat {
switch self {
case .readReceipt:
16
case .spaceHeader:
20
case .threadSummary:
24
case .knockingUsersBannerStack:
28
case .chats, .spaces, .map,
.timeline, .readReceiptSheet, .completionSuggestions,
.blockedUsers, .roomMembersList, .knockingUserBanner:
32
case .startChat:
36
case .roomDetails:
44
case .inviteUsers, .knockingUserList, .sessionVerification,
.settings, .threadList, .mediaPreviewDetails:
52
case .roomChangeRoles:
56
case .sendInviteConfirmation:
64
case .dmDetails:
75
case .memberDetails, .editUserDetails, .classicAppAccount:
96
}
}
}
enum RoomAvatarSizeOnScreen {
case chats
case spaces
case spaceSettings
case spaceFilters
case authorizedSpaces
case timeline
case leaveSpace
case messageForwarding
case globalSearch
case roomSelection
case details
case editRoomDetails
case notificationSettings
case roomDirectorySearch
case joinRoom
case spaceHeader
case editSpaceDetails
case spaceAddRooms
case spaceAddRoomsSelected
case completionSuggestions
case createRoomSelectSpace
var value: CGFloat {
switch self {
case .notificationSettings:
30
case .timeline, .leaveSpace, .roomDirectorySearch,
.completionSuggestions, .authorizedSpaces, .createRoomSelectSpace,
.spaceFilters, .globalSearch:
32
case .messageForwarding, .roomSelection,
.spaceAddRooms:
36
case .chats, .spaces, .spaceSettings,
.spaceAddRoomsSelected:
52
case .joinRoom, .spaceHeader, .editSpaceDetails:
64
case .details, .editRoomDetails:
96
}
}
}