diff --git a/ElementX/Sources/Other/SwiftUI/Views/LoadableAvatarImage.swift b/ElementX/Sources/Other/SwiftUI/Views/LoadableAvatarImage.swift index 3c7ec8795..78e0678fb 100644 --- a/ElementX/Sources/Other/SwiftUI/Views/LoadableAvatarImage.swift +++ b/ElementX/Sources/Other/SwiftUI/Views/LoadableAvatarImage.swift @@ -9,10 +9,15 @@ import SwiftUI struct LoadableAvatarImage: View { + enum Shape { + case circle + case roundedRect + } + private let url: URL? private let name: String? private let contentID: String - private let isSpace: Bool + private let shape: Shape private let avatarSize: Avatars.Size private let mediaProvider: MediaProviderProtocol? private let onTap: ((URL) -> Void)? @@ -22,14 +27,14 @@ struct LoadableAvatarImage: View { init(url: URL?, name: String?, contentID: String, - isSpace: Bool = false, + shape: LoadableAvatarImage.Shape = .circle, avatarSize: Avatars.Size, mediaProvider: MediaProviderProtocol?, onTap: ((URL) -> Void)? = nil) { self.url = url self.name = name self.contentID = contentID - self.isSpace = isSpace + self.shape = shape self.avatarSize = avatarSize self.mediaProvider = mediaProvider self.onTap = onTap @@ -54,7 +59,7 @@ struct LoadableAvatarImage: View { avatar .frame(width: frameSize, height: frameSize) .background(Color.compound.bgCanvasDefault) - .clipAvatar(isSpace: isSpace, scaledSize: _frameSize) + .avatarShape(shape, scaledSize: _frameSize) .environment(\.shouldAutomaticallyLoadImages, true) // We always load avatars. } @@ -77,35 +82,38 @@ struct LoadableAvatarImage: View { } extension View { - func clipAvatar(isSpace: Bool, size: CGFloat) -> some View { - modifier(ClipAvatarModifier(isSpace: isSpace, size: size)) + func avatarShape(_ shape: LoadableAvatarImage.Shape, size: CGFloat) -> some View { + modifier(AvatarShapeModifier(shape: shape, size: size)) } - func clipAvatar(isSpace: Bool, scaledSize: ScaledMetric) -> some View { - modifier(ClipAvatarModifier(isSpace: isSpace, scaledSize: scaledSize)) + func avatarShape(_ shape: LoadableAvatarImage.Shape, scaledSize: ScaledMetric) -> some View { + modifier(AvatarShapeModifier(shape: shape, scaledSize: scaledSize)) } } -struct ClipAvatarModifier: ViewModifier { - private let isSpace: Bool +private struct AvatarShapeModifier: ViewModifier { + private let shape: LoadableAvatarImage.Shape @ScaledMetric private var scaledSize: CGFloat - init(isSpace: Bool, size: CGFloat) { - self.isSpace = isSpace + init(shape: LoadableAvatarImage.Shape, size: CGFloat) { + self.shape = shape _scaledSize = ScaledMetric(wrappedValue: size) } - init(isSpace: Bool, scaledSize: ScaledMetric) { - self.isSpace = isSpace + init(shape: LoadableAvatarImage.Shape, scaledSize: ScaledMetric) { + self.shape = shape _scaledSize = scaledSize } func body(content: Content) -> some View { - content - .clipShape(avatarShape) - } - - private var avatarShape: some Shape { - isSpace ? AnyShape(RoundedRectangle(cornerRadius: scaledSize / 4)) : AnyShape(Circle()) + switch shape { + case .circle: + content.clipShape(Circle()) + case .roundedRect: + let shape = RoundedRectangle(cornerRadius: scaledSize / 4) + content + .clipShape(shape) + .overlay(shape.stroke(.compound.iconQuaternaryAlpha, lineWidth: 1)) + } } } diff --git a/ElementX/Sources/Other/SwiftUI/Views/OverridableAvatarImage.swift b/ElementX/Sources/Other/SwiftUI/Views/OverridableAvatarImage.swift index 30f9d7795..30bc80b76 100644 --- a/ElementX/Sources/Other/SwiftUI/Views/OverridableAvatarImage.swift +++ b/ElementX/Sources/Other/SwiftUI/Views/OverridableAvatarImage.swift @@ -14,7 +14,7 @@ struct OverridableAvatarImage: View { let url: URL? let name: String? let contentID: String - let isSpace: Bool + let shape: LoadableAvatarImage.Shape let avatarSize: Avatars.Size let mediaProvider: MediaProviderProtocol? @@ -28,12 +28,12 @@ struct OverridableAvatarImage: View { ProgressView() } .scaledFrame(size: avatarSize.value) - .clipAvatar(isSpace: isSpace, size: avatarSize.value) + .avatarShape(shape, size: avatarSize.value) } else { LoadableAvatarImage(url: url, name: name, contentID: contentID, - isSpace: isSpace, + shape: shape, avatarSize: avatarSize, mediaProvider: mediaProvider) } diff --git a/ElementX/Sources/Other/SwiftUI/Views/RoomAvatarImage.swift b/ElementX/Sources/Other/SwiftUI/Views/RoomAvatarImage.swift index 43680d491..cb19fe6e7 100644 --- a/ElementX/Sources/Other/SwiftUI/Views/RoomAvatarImage.swift +++ b/ElementX/Sources/Other/SwiftUI/Views/RoomAvatarImage.swift @@ -116,7 +116,7 @@ struct RoomAvatarImage: View { LoadableAvatarImage(url: avatarURL, name: name, contentID: id, - isSpace: true, + shape: .roundedRect, avatarSize: avatarSize, mediaProvider: mediaProvider, onTap: onAvatarTap) diff --git a/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift b/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift index c8fab4056..9ca3cdb4a 100644 --- a/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift +++ b/ElementX/Sources/Screens/RoomDetailsEditScreen/View/RoomDetailsEditScreen.swift @@ -60,7 +60,7 @@ struct RoomDetailsEditScreen: View { url: context.viewState.avatarURL, name: context.viewState.initialName, contentID: context.viewState.roomID, - isSpace: context.viewState.isSpace, + shape: context.viewState.isSpace ? .roundedRect : .circle, avatarSize: .user(on: .memberDetails), mediaProvider: context.mediaProvider) .accessibilityLabel(L10n.a11yEditAvatar) diff --git a/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/View/UserDetailsEditScreen.swift b/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/View/UserDetailsEditScreen.swift index 22f4022e8..5a617d4b6 100644 --- a/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/View/UserDetailsEditScreen.swift +++ b/ElementX/Sources/Screens/Settings/UserDetailsEditScreen/View/UserDetailsEditScreen.swift @@ -64,7 +64,7 @@ struct UserDetailsEditScreen: View { url: context.viewState.selectedAvatarURL, name: context.viewState.currentDisplayName, contentID: context.viewState.userID, - isSpace: false, + shape: .circle, avatarSize: .user(on: .editUserDetails), mediaProvider: context.mediaProvider) .overlay(alignment: .bottomTrailing) {