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:
Jérôme Danthinne 2023-01-04 17:48:02 +01:00 committed by GitHub
parent d152f14bdc
commit 62b96cac69
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 66 additions and 23 deletions

View file

@ -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: {

View file

@ -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)

View file

@ -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

View file

@ -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))
}
}