mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 13:37:11 +00:00
Stacked Avatars View (#3504)
* stacked avatars * fix tests * remove comment
This commit is contained in:
parent
2b153306dd
commit
f7aeb3ee95
@ -1012,6 +1012,7 @@
|
||||
E0FB26262689F04D66A949D7 /* TestablePreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = B1E227F34BE43B08E098796E /* TestablePreview.swift */; };
|
||||
E14E469CD97550D0FC58F3CA /* CancellableTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE52983FAFB4E0998C00EE8A /* CancellableTask.swift */; };
|
||||
E184FFAD32342D3D6E2F89AA /* PinnedEventsTimelineScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D53754227CEBD06358956D7 /* PinnedEventsTimelineScreenCoordinator.swift */; };
|
||||
E1C67E5D9E22135A8FEBBD60 /* StackedAvatarsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8558D41DD4B553A752C868A /* StackedAvatarsView.swift */; };
|
||||
E1DF24D085572A55C9758A2D /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E89E530A8E92EC44301CA1 /* Bundle.swift */; };
|
||||
E21FE4C5B614F311C0955859 /* UserProfileProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51C454AE59914B551A6D02C0 /* UserProfileProxy.swift */; };
|
||||
E27C4D1A1F8BB77CA790B403 /* InviteUsersScreenCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A861DA5932B128FE1DCB5CE2 /* InviteUsersScreenCoordinator.swift */; };
|
||||
@ -1946,6 +1947,7 @@
|
||||
A7D452AF7B5F7E3A0A7DB54C /* SessionVerificationScreenViewModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionVerificationScreenViewModelProtocol.swift; sourceTree = "<group>"; };
|
||||
A7E37072597F67C4DD8CC2DB /* ComposerDraftServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposerDraftServiceProtocol.swift; sourceTree = "<group>"; };
|
||||
A84D413BF49F0E980F010A6B /* LogViewerScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewerScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||
A8558D41DD4B553A752C868A /* StackedAvatarsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StackedAvatarsView.swift; sourceTree = "<group>"; };
|
||||
A861DA5932B128FE1DCB5CE2 /* InviteUsersScreenCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteUsersScreenCoordinator.swift; sourceTree = "<group>"; };
|
||||
A8DF55467ED4CE76B7AE9A33 /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||
A9873374E72AA53260AE90A2 /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = fa.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
@ -2989,6 +2991,7 @@
|
||||
7EB58E4E8D6D634C246AD5C2 /* RoomInviterLabel.swift */,
|
||||
839E2C35DF3F9C7B54C3CE49 /* RoundedCornerShape.swift */,
|
||||
AEB5FF7A09B79B0C6B528F7C /* SFNumberedListView.swift */,
|
||||
A8558D41DD4B553A752C868A /* StackedAvatarsView.swift */,
|
||||
E10DA51DBC8C7E1460DBCCBD /* UserProfileListRow.swift */,
|
||||
AD529C89924EE32CE307F36F /* VisualListItem.swift */,
|
||||
);
|
||||
@ -6952,6 +6955,7 @@
|
||||
F37629BAA5E8F50AAF2A131D /* SoftLogoutScreenViewModel.swift in Sources */,
|
||||
CF4044A8EED5C41BC0ED6ABE /* SoftLogoutScreenViewModelProtocol.swift in Sources */,
|
||||
DF004A5B2EABBD0574D06A04 /* SplashScreenCoordinator.swift in Sources */,
|
||||
E1C67E5D9E22135A8FEBBD60 /* StackedAvatarsView.swift in Sources */,
|
||||
3DAF325D8AE461F7CDB282BD /* StartChatScreen.swift in Sources */,
|
||||
6CD61FAF03E8986523C2ABB8 /* StartChatScreenCoordinator.swift in Sources */,
|
||||
C051475DFF4C8EBDDF4DC8E4 /* StartChatScreenModels.swift in Sources */,
|
||||
|
@ -46,6 +46,7 @@ enum UserAvatarSizeOnScreen {
|
||||
case editUserDetails
|
||||
case suggestions
|
||||
case blockedUsers
|
||||
case knockingUsers
|
||||
|
||||
var value: CGFloat {
|
||||
switch self {
|
||||
@ -75,6 +76,8 @@ enum UserAvatarSizeOnScreen {
|
||||
return 96
|
||||
case .dmDetails:
|
||||
return 75
|
||||
case .knockingUsers:
|
||||
return 28
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,66 @@
|
||||
//
|
||||
// Copyright 2024 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
// Please see LICENSE in the repository root for full details.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct StackedAvatarInfo {
|
||||
let url: URL?
|
||||
let name: String?
|
||||
let contentID: String
|
||||
}
|
||||
|
||||
struct StackedAvatarsView: View {
|
||||
let overlap: CGFloat
|
||||
let lineWidth: CGFloat
|
||||
var shouldStackFromLast = false
|
||||
let avatars: [StackedAvatarInfo]
|
||||
let avatarSize: AvatarSize
|
||||
let mediaProvider: MediaProviderProtocol?
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: -overlap) {
|
||||
ForEach(0..<avatars.count, id: \.self) { index in
|
||||
LoadableAvatarImage(url: avatars[index].url,
|
||||
name: avatars[index].name,
|
||||
contentID: avatars[index].contentID,
|
||||
avatarSize: avatarSize,
|
||||
mediaProvider: mediaProvider)
|
||||
.padding(lineWidth)
|
||||
.overlay {
|
||||
Circle()
|
||||
.strokeBorder(Color.compound.bgCanvasDefault, lineWidth: lineWidth)
|
||||
}
|
||||
.zIndex(shouldStackFromLast ? Double(index) : Double(avatars.count - index))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct StackedAvatarsView_Previews: PreviewProvider, TestablePreview {
|
||||
static let avatars: [StackedAvatarInfo] = [
|
||||
.init(url: nil, name: "Alice", contentID: "@alice:matrix.org"),
|
||||
.init(url: nil, name: "Bob", contentID: "@bob:matrix.org"),
|
||||
.init(url: nil, name: "Charlie", contentID: "@charlie:matrix.org"),
|
||||
.init(url: nil, name: "Dan", contentID: "@charlie:matrix.org")
|
||||
]
|
||||
|
||||
static var previews: some View {
|
||||
VStack(spacing: 10) {
|
||||
StackedAvatarsView(overlap: 16,
|
||||
lineWidth: 2,
|
||||
avatars: avatars,
|
||||
avatarSize: .user(on: .knockingUsers),
|
||||
mediaProvider: MediaProviderMock())
|
||||
StackedAvatarsView(overlap: 16,
|
||||
lineWidth: 2,
|
||||
shouldStackFromLast: true,
|
||||
avatars: avatars,
|
||||
avatarSize: .user(on: .knockingUsers),
|
||||
mediaProvider: MediaProviderMock())
|
||||
}
|
||||
}
|
||||
}
|
@ -11,25 +11,22 @@ struct TimelineReadReceiptsView: View {
|
||||
let displayNumber = 3
|
||||
let timelineItem: EventBasedTimelineItemProtocol
|
||||
@EnvironmentObject private var context: TimelineViewModel.Context
|
||||
|
||||
var avatars: [StackedAvatarInfo] {
|
||||
timelineItem.properties.orderedReadReceipts.prefix(displayNumber).map { receipt in
|
||||
StackedAvatarInfo(url: context.viewState.members[receipt.userID]?.avatarURL,
|
||||
name: context.viewState.members[receipt.userID]?.displayName,
|
||||
contentID: receipt.userID)
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 2) {
|
||||
HStack(spacing: -4) {
|
||||
let receiptsToDisplay = timelineItem.properties.orderedReadReceipts.prefix(displayNumber)
|
||||
ForEach(0..<receiptsToDisplay.count, id: \.self) { index in
|
||||
let receipt = receiptsToDisplay[index]
|
||||
LoadableAvatarImage(url: context.viewState.members[receipt.userID]?.avatarURL,
|
||||
name: context.viewState.members[receipt.userID]?.displayName,
|
||||
contentID: receipt.userID,
|
||||
avatarSize: .user(on: .readReceipt),
|
||||
mediaProvider: context.mediaProvider)
|
||||
.overlay {
|
||||
RoundedRectangle(cornerRadius: .infinity)
|
||||
.stroke(Color.compound.bgCanvasDefault, lineWidth: 1)
|
||||
}
|
||||
.zIndex(Double(displayNumber - index))
|
||||
}
|
||||
}
|
||||
StackedAvatarsView(overlap: 6,
|
||||
lineWidth: 1,
|
||||
avatars: avatars, avatarSize: .user(on: .readReceipt),
|
||||
mediaProvider: context.mediaProvider)
|
||||
.padding(-1)
|
||||
if timelineItem.properties.orderedReadReceipts.count > displayNumber {
|
||||
Text("+\(remaining)")
|
||||
.font(.compound.bodySM)
|
||||
|
@ -785,6 +785,12 @@ extension PreviewTests {
|
||||
}
|
||||
}
|
||||
|
||||
func test_stackedAvatarsView() {
|
||||
for preview in StackedAvatarsView_Previews._allPreviews {
|
||||
assertSnapshots(matching: preview)
|
||||
}
|
||||
}
|
||||
|
||||
func test_startChatScreen() {
|
||||
for preview in StartChatScreen_Previews._allPreviews {
|
||||
assertSnapshots(matching: preview)
|
||||
|
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomScreen-iPad-en-GB.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomScreen-iPad-en-GB.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomScreen-iPad-pseudo.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomScreen-iPad-pseudo.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomScreen-iPhone-16-en-GB.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomScreen-iPhone-16-en-GB.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomScreen-iPhone-16-pseudo.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_roomScreen-iPhone-16-pseudo.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_stackedAvatarsView-iPad-en-GB.1.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_stackedAvatarsView-iPad-en-GB.1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_stackedAvatarsView-iPad-pseudo.1.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_stackedAvatarsView-iPad-pseudo.1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_stackedAvatarsView-iPhone-16-en-GB.1.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_stackedAvatarsView-iPhone-16-en-GB.1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_stackedAvatarsView-iPhone-16-pseudo.1.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_stackedAvatarsView-iPhone-16-pseudo.1.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineReadReceiptsView-iPad-en-GB.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineReadReceiptsView-iPad-en-GB.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineReadReceiptsView-iPad-pseudo.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineReadReceiptsView-iPad-pseudo.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineReadReceiptsView-iPhone-16-en-GB.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineReadReceiptsView-iPhone-16-en-GB.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineReadReceiptsView-iPhone-16-pseudo.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineReadReceiptsView-iPhone-16-pseudo.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineView-iPad-en-GB.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineView-iPad-en-GB.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineView-iPad-pseudo.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineView-iPad-pseudo.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineView-iPhone-16-en-GB.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineView-iPhone-16-en-GB.1.png
(Stored with Git LFS)
Binary file not shown.
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineView-iPhone-16-pseudo.1.png
(Stored with Git LFS)
BIN
PreviewTests/Sources/__Snapshots__/PreviewTests/test_timelineView-iPhone-16-pseudo.1.png
(Stored with Git LFS)
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user