Avatar shape (#30)
* Avatar shape settings * chore: fix rebase Co-authored-by: Jérôme Danthinne <jerome.danthinne@smile.eu>
This commit is contained in:
parent
d152f14bdc
commit
62b96cac69
|
@ -75,6 +75,11 @@ struct SettingsTabs: View {
|
|||
Text(position.description).tag(position)
|
||||
}
|
||||
}
|
||||
Picker("Avatar shape", selection: $theme.avatarShape) {
|
||||
ForEach(Theme.AvatarShape.allCases, id: \.rawValue) { shape in
|
||||
Text(shape.description).tag(shape)
|
||||
}
|
||||
}
|
||||
Button {
|
||||
theme.selectedSet = .iceCubeDark
|
||||
} label: {
|
||||
|
|
|
@ -72,10 +72,6 @@ struct AccountDetailHeaderView: View {
|
|||
private var accountAvatarView: some View {
|
||||
HStack {
|
||||
AvatarView(url: account.avatar, size: .account)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 4)
|
||||
.stroke(.white, lineWidth: 1)
|
||||
)
|
||||
.onTapGesture {
|
||||
Task {
|
||||
await quickLook.prepareFor(urls: [account.avatar], selectedURL: account.avatar)
|
||||
|
|
|
@ -4,7 +4,7 @@ import SwiftUI
|
|||
public class Theme: ObservableObject {
|
||||
enum ThemeKey: String {
|
||||
case colorScheme, tint, label, primaryBackground, secondaryBackground
|
||||
case avatarPosition
|
||||
case avatarPosition, avatarShape
|
||||
case selectedSet, selectedScheme
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,19 @@ public class Theme: ObservableObject {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum AvatarShape: String, CaseIterable {
|
||||
case circle, rounded
|
||||
|
||||
public var description: LocalizedStringKey {
|
||||
switch self {
|
||||
case .circle:
|
||||
return "Circle"
|
||||
case .rounded:
|
||||
return "Rounded"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@AppStorage("is_previously_set") private var isSet: Bool = false
|
||||
@AppStorage(ThemeKey.selectedScheme.rawValue) public var selectedScheme: ColorScheme = .dark
|
||||
|
@ -28,10 +41,13 @@ public class Theme: ObservableObject {
|
|||
@AppStorage(ThemeKey.secondaryBackground.rawValue) public var secondaryBackgroundColor: Color = .gray
|
||||
@AppStorage(ThemeKey.label.rawValue) public var labelColor: Color = .black
|
||||
@AppStorage(ThemeKey.avatarPosition.rawValue) var rawAvatarPosition: String = AvatarPosition.top.rawValue
|
||||
@AppStorage(ThemeKey.avatarShape.rawValue) var rawAvatarShape: String = AvatarShape.rounded.rawValue
|
||||
@AppStorage(ThemeKey.selectedSet.rawValue) var storedSet: ColorSetName = .iceCubeDark
|
||||
|
||||
@Published public var avatarPosition: AvatarPosition = .top
|
||||
@Published public var avatarShape: AvatarShape = .rounded
|
||||
@Published public var selectedSet: ColorSetName = .iceCubeDark
|
||||
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
public init() {
|
||||
|
@ -45,7 +61,8 @@ public class Theme: ObservableObject {
|
|||
}
|
||||
|
||||
avatarPosition = AvatarPosition(rawValue: rawAvatarPosition) ?? .top
|
||||
|
||||
avatarShape = AvatarShape(rawValue: rawAvatarShape) ?? .rounded
|
||||
|
||||
$avatarPosition
|
||||
.dropFirst()
|
||||
.map(\.rawValue)
|
||||
|
@ -53,6 +70,14 @@ public class Theme: ObservableObject {
|
|||
self?.rawAvatarPosition = position
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
$avatarShape
|
||||
.dropFirst()
|
||||
.map(\.rawValue)
|
||||
.sink { [weak self] shape in
|
||||
self?.rawAvatarShape = shape
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
// Workaround, since @AppStorage can't be directly observed
|
||||
$selectedSet
|
||||
|
|
|
@ -3,6 +3,8 @@ import Shimmer
|
|||
import NukeUI
|
||||
|
||||
public struct AvatarView: View {
|
||||
@EnvironmentObject private var theme: Theme
|
||||
|
||||
public enum Size {
|
||||
case account, status, embed, badge, boost
|
||||
|
||||
|
@ -41,24 +43,39 @@ public struct AvatarView: View {
|
|||
}
|
||||
|
||||
public var body: some View {
|
||||
if reasons == .placeholder {
|
||||
RoundedRectangle(cornerRadius: size.cornerRadius)
|
||||
.fill(.gray)
|
||||
.frame(maxWidth: size.size.width, maxHeight: size.size.height)
|
||||
} else {
|
||||
LazyImage(url: url) { state in
|
||||
if let image = state.image {
|
||||
image
|
||||
.resizingMode(.aspectFit)
|
||||
} else if state.isLoading {
|
||||
placeholderView
|
||||
.shimmering()
|
||||
Group {
|
||||
if reasons == .placeholder {
|
||||
RoundedRectangle(cornerRadius: size.cornerRadius)
|
||||
.fill(.gray)
|
||||
.frame(maxWidth: size.size.width, maxHeight: size.size.height)
|
||||
} else {
|
||||
placeholderView
|
||||
LazyImage(url: url) { state in
|
||||
if let image = state.image {
|
||||
image
|
||||
.resizingMode(.aspectFit)
|
||||
} else if state.isLoading {
|
||||
placeholderView
|
||||
.shimmering()
|
||||
} else {
|
||||
placeholderView
|
||||
}
|
||||
}
|
||||
.processors([.resize(size: size.size), .roundedCorners(radius: size.cornerRadius)])
|
||||
.frame(width: size.size.width, height: size.size.height)
|
||||
}
|
||||
}
|
||||
.processors([.resize(size: size.size), .roundedCorners(radius: size.cornerRadius)])
|
||||
.frame(width: size.size.width, height: size.size.height)
|
||||
}
|
||||
.clipShape(clipShape)
|
||||
.overlay(
|
||||
clipShape.stroke(Color.primary.opacity(0.25), lineWidth: 1)
|
||||
)
|
||||
}
|
||||
|
||||
private var clipShape: some Shape {
|
||||
switch theme.avatarShape {
|
||||
case .circle:
|
||||
return AnyShape(Circle())
|
||||
case .rounded:
|
||||
return AnyShape(RoundedRectangle(cornerRadius: size.cornerRadius))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue