Stacked Avatars View (#3504)

* stacked avatars

* fix tests

* remove comment
This commit is contained in:
Mauro
2024-11-12 14:00:51 +01:00
committed by GitHub
parent 2b153306dd
commit f7aeb3ee95
29 changed files with 144 additions and 56 deletions
+4
View File
@@ -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 */,
+3
View File
@@ -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)
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:dbba95d7bded549e3b54dd8468f44f338f75df9dc2d384c800ca69d240c526bb
size 295572
oid sha256:033f43d5be47abd91cd5f36b93a8b32b0f9800e7a8a947e0c2cd4debd8b4c694
size 295633
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0d28a596ca48a0cd680be7014adef2f2aac11aaf1592676da57b942bd3329708
size 297527
oid sha256:bc959ac1d5a22da8ca928d891e9f0a649dfa28b1cdfa7a91b0a74d2189cc38a3
size 297711
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fbfaf40b0602964736bbe6dc41beea21d1733c8ec0b84c82e0c547596c4032f0
size 180515
oid sha256:26de643c28b47f7fd0631c0c754d979c43fc51bc274e863fdb6acaf0ed299960
size 180507
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9c928084fecfee3ff804ebc41d17b3433fe7dea94f7c0c82ef7c40175203061f
size 178534
oid sha256:58ae4f390371ef48aca7b5faeb4c75ba7bdfad4294797fd422c0d102036ee4a8
size 178571
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f2cccb8af5d3b2f9caaa29584364834f3c58685da13e7b0ed9c305b9aed08954
size 76364
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:f2cccb8af5d3b2f9caaa29584364834f3c58685da13e7b0ed9c305b9aed08954
size 76364
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4ccd3bb00ea04f0482ad6fe087b3421eff7273d5ffe659b13d26b079486f22ce
size 35126
@@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:4ccd3bb00ea04f0482ad6fe087b3421eff7273d5ffe659b13d26b079486f22ce
size 35126
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:17403a44b5f71ef51b12a2392d3c8eed2b30cd4ddeb25188c29e738f8ed3c3fc
size 285676
oid sha256:7222cb8f9b8d5f35d70b7c9d6498825271f2f4701328789f29ce4434060df93b
size 285869
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:2f576e2c44ecda928a8afdbd29bf9c79631517d9c42d6b8a16b1dcdbac1885a9
size 284180
oid sha256:5c52b5f33ef60a009368a4f69841c64596c4cd3c0597206f7c6e77159b3182b9
size 284251
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fc726f43094e192a9f367c0ece419d581de5d43bab53275eaa73ae25969e65ab
size 287326
oid sha256:72f66b7d7cf29690fe5cbf3c7a624462369735231ffdab3d196c31eb285c1a3c
size 287531
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:982eb9dd6ed5fe3c4c13811ae463b80f1b571fec18953d98d641d367cd705db0
size 285493
oid sha256:7c65adc9249fe0e725160eed2ad5854e7b719b7d3c5fad3b5501b9259db582c2
size 285667
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1a39ebd070935b96d697dc0c70244962a8d55c6c9ce3e958808c35f8ed009506
size 190461
oid sha256:dd5ce3f8ce6de79110a64880e7d65132bd4eeb689562e65dda79b9fe39ef8148
size 190473
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:e4278c55045120935c02fe570409295a0eb0b984a103e5fd09d314bb2f4e09a6
size 188620
oid sha256:2edda65eb2b77d65105f17dada5fbe8be1f7610cce462e967ffe1513fdd878b0
size 188590
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:1eb05117714fb7853917a32dba87565ed0ad83b3097ca01703581dc0ec8e7b7a
size 188275
oid sha256:989002cd49c3455efc5d1f3982cf5b8efbe9527d6bef80464e01ac11452fe1c6
size 188265
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:a421129a41149ca0c3be3981ef169ddcbce8b0c57a0b94ea43a3fea2dc4202f8
size 186287
oid sha256:c0bce781f1031c33a6f2161d11f572ded92262d9e394bb82b4fdbfed15a9c41b
size 186270
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fd4120e82a247929c0b20e95e5e75889853c5aeb1ca529a4928657159781e1ba
size 74341
oid sha256:3832d15395990ba70d725f952594ba8525ae4d6e34b0c94a3518c1498c629ad7
size 74883
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9d037477f4b7663cfbe5067f1782261da930f7ded80f39d44dc6ad64ada84b15
size 74917
oid sha256:d4bf1c97977129580a538593b9a418855a7293040b0f98c4c86eaf52f89922b3
size 75388
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6b649638070c638275198e207be41db38c0ddae908bab0da10f2bd69d2c8054d
size 33967
oid sha256:1f8e0493510c102234ef73712d603f484bdee6db7393eb3ba9e4a890787fdb51
size 34021
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:74ddd0f05b73833113d6814c5c2afe86e5429bbdb01a4e82d09f075208df4362
size 34383
oid sha256:40f28da9c6ca03946b234d0b9f33b30c69d03628b3e8f1d0ced8f06e36fc050a
size 34494
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:dbba95d7bded549e3b54dd8468f44f338f75df9dc2d384c800ca69d240c526bb
size 295572
oid sha256:033f43d5be47abd91cd5f36b93a8b32b0f9800e7a8a947e0c2cd4debd8b4c694
size 295633
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:0d28a596ca48a0cd680be7014adef2f2aac11aaf1592676da57b942bd3329708
size 297527
oid sha256:bc959ac1d5a22da8ca928d891e9f0a649dfa28b1cdfa7a91b0a74d2189cc38a3
size 297711
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:fbfaf40b0602964736bbe6dc41beea21d1733c8ec0b84c82e0c547596c4032f0
size 180515
oid sha256:26de643c28b47f7fd0631c0c754d979c43fc51bc274e863fdb6acaf0ed299960
size 180507
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:9c928084fecfee3ff804ebc41d17b3433fe7dea94f7c0c82ef7c40175203061f
size 178534
oid sha256:58ae4f390371ef48aca7b5faeb4c75ba7bdfad4294797fd422c0d102036ee4a8
size 178571