mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2025-01-22 05:48:08 +00:00
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
4 changed files with 66 additions and 23 deletions
|
@ -75,6 +75,11 @@ struct SettingsTabs: View {
|
||||||
Text(position.description).tag(position)
|
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 {
|
Button {
|
||||||
theme.selectedSet = .iceCubeDark
|
theme.selectedSet = .iceCubeDark
|
||||||
} label: {
|
} label: {
|
||||||
|
|
|
@ -72,10 +72,6 @@ struct AccountDetailHeaderView: View {
|
||||||
private var accountAvatarView: some View {
|
private var accountAvatarView: some View {
|
||||||
HStack {
|
HStack {
|
||||||
AvatarView(url: account.avatar, size: .account)
|
AvatarView(url: account.avatar, size: .account)
|
||||||
.overlay(
|
|
||||||
RoundedRectangle(cornerRadius: 4)
|
|
||||||
.stroke(.white, lineWidth: 1)
|
|
||||||
)
|
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
Task {
|
Task {
|
||||||
await quickLook.prepareFor(urls: [account.avatar], selectedURL: account.avatar)
|
await quickLook.prepareFor(urls: [account.avatar], selectedURL: account.avatar)
|
||||||
|
|
|
@ -4,7 +4,7 @@ import SwiftUI
|
||||||
public class Theme: ObservableObject {
|
public class Theme: ObservableObject {
|
||||||
enum ThemeKey: String {
|
enum ThemeKey: String {
|
||||||
case colorScheme, tint, label, primaryBackground, secondaryBackground
|
case colorScheme, tint, label, primaryBackground, secondaryBackground
|
||||||
case avatarPosition
|
case avatarPosition, avatarShape
|
||||||
case selectedSet, selectedScheme
|
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("is_previously_set") private var isSet: Bool = false
|
||||||
@AppStorage(ThemeKey.selectedScheme.rawValue) public var selectedScheme: ColorScheme = .dark
|
@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.secondaryBackground.rawValue) public var secondaryBackgroundColor: Color = .gray
|
||||||
@AppStorage(ThemeKey.label.rawValue) public var labelColor: Color = .black
|
@AppStorage(ThemeKey.label.rawValue) public var labelColor: Color = .black
|
||||||
@AppStorage(ThemeKey.avatarPosition.rawValue) var rawAvatarPosition: String = AvatarPosition.top.rawValue
|
@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
|
@AppStorage(ThemeKey.selectedSet.rawValue) var storedSet: ColorSetName = .iceCubeDark
|
||||||
|
|
||||||
@Published public var avatarPosition: AvatarPosition = .top
|
@Published public var avatarPosition: AvatarPosition = .top
|
||||||
|
@Published public var avatarShape: AvatarShape = .rounded
|
||||||
@Published public var selectedSet: ColorSetName = .iceCubeDark
|
@Published public var selectedSet: ColorSetName = .iceCubeDark
|
||||||
|
|
||||||
private var cancellables = Set<AnyCancellable>()
|
private var cancellables = Set<AnyCancellable>()
|
||||||
|
|
||||||
public init() {
|
public init() {
|
||||||
|
@ -45,7 +61,8 @@ public class Theme: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
avatarPosition = AvatarPosition(rawValue: rawAvatarPosition) ?? .top
|
avatarPosition = AvatarPosition(rawValue: rawAvatarPosition) ?? .top
|
||||||
|
avatarShape = AvatarShape(rawValue: rawAvatarShape) ?? .rounded
|
||||||
|
|
||||||
$avatarPosition
|
$avatarPosition
|
||||||
.dropFirst()
|
.dropFirst()
|
||||||
.map(\.rawValue)
|
.map(\.rawValue)
|
||||||
|
@ -53,6 +70,14 @@ public class Theme: ObservableObject {
|
||||||
self?.rawAvatarPosition = position
|
self?.rawAvatarPosition = position
|
||||||
}
|
}
|
||||||
.store(in: &cancellables)
|
.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
|
// Workaround, since @AppStorage can't be directly observed
|
||||||
$selectedSet
|
$selectedSet
|
||||||
|
|
|
@ -3,6 +3,8 @@ import Shimmer
|
||||||
import NukeUI
|
import NukeUI
|
||||||
|
|
||||||
public struct AvatarView: View {
|
public struct AvatarView: View {
|
||||||
|
@EnvironmentObject private var theme: Theme
|
||||||
|
|
||||||
public enum Size {
|
public enum Size {
|
||||||
case account, status, embed, badge, boost
|
case account, status, embed, badge, boost
|
||||||
|
|
||||||
|
@ -41,24 +43,39 @@ public struct AvatarView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
if reasons == .placeholder {
|
Group {
|
||||||
RoundedRectangle(cornerRadius: size.cornerRadius)
|
if reasons == .placeholder {
|
||||||
.fill(.gray)
|
RoundedRectangle(cornerRadius: size.cornerRadius)
|
||||||
.frame(maxWidth: size.size.width, maxHeight: size.size.height)
|
.fill(.gray)
|
||||||
} else {
|
.frame(maxWidth: size.size.width, maxHeight: size.size.height)
|
||||||
LazyImage(url: url) { state in
|
|
||||||
if let image = state.image {
|
|
||||||
image
|
|
||||||
.resizingMode(.aspectFit)
|
|
||||||
} else if state.isLoading {
|
|
||||||
placeholderView
|
|
||||||
.shimmering()
|
|
||||||
} else {
|
} 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)])
|
.clipShape(clipShape)
|
||||||
.frame(width: size.size.width, height: size.size.height)
|
.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 a new issue